diff -Nru rabbitmq-server-2.7.1/codegen/amqp_codegen.py rabbitmq-server-2.8.4/codegen/amqp_codegen.py --- rabbitmq-server-2.7.1/codegen/amqp_codegen.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen/amqp_codegen.py 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## from __future__ import nested_scopes diff -Nru rabbitmq-server-2.7.1/codegen/amqp-rabbitmq-0.8.json rabbitmq-server-2.8.4/codegen/amqp-rabbitmq-0.8.json --- rabbitmq-server-2.7.1/codegen/amqp-rabbitmq-0.8.json 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen/amqp-rabbitmq-0.8.json 2012-06-22 16:03:48.000000000 +0000 @@ -4,7 +4,7 @@ "minor-version": 0, "port": 5672, "copyright": [ - "Copyright (C) 2008-2011 VMware, Inc.\n", + "Copyright (C) 2008-2012 VMware, Inc.\n", "\n", "Permission is hereby granted, free of charge, to any person\n", "obtaining a copy of this file (the \"Software\"), to deal in the\n", diff -Nru rabbitmq-server-2.7.1/codegen/amqp-rabbitmq-0.9.1.json rabbitmq-server-2.8.4/codegen/amqp-rabbitmq-0.9.1.json --- rabbitmq-server-2.7.1/codegen/amqp-rabbitmq-0.9.1.json 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen/amqp-rabbitmq-0.9.1.json 2012-06-22 16:03:48.000000000 +0000 @@ -5,7 +5,7 @@ "revision": 1, "port": 5672, "copyright": [ - "Copyright (C) 2008-2011 VMware, Inc.\n", + "Copyright (C) 2008-2012 VMware, Inc.\n", "\n", "Permission is hereby granted, free of charge, to any person\n", "obtaining a copy of this file (the \"Software\"), to deal in the\n", diff -Nru rabbitmq-server-2.7.1/codegen/demo_extension.json rabbitmq-server-2.8.4/codegen/demo_extension.json --- rabbitmq-server-2.7.1/codegen/demo_extension.json 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen/demo_extension.json 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ "extension": { "name": "demo", "version": "1.0", - "copyright": "Copyright (C) 2009-2011 VMware, Inc." + "copyright": "Copyright (C) 2009-2012 VMware, Inc." }, "domains": [ ["foo-domain", "shortstr"] diff -Nru rabbitmq-server-2.7.1/codegen/license_info rabbitmq-server-2.8.4/codegen/license_info --- rabbitmq-server-2.7.1/codegen/license_info 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen/license_info 2012-06-22 16:03:48.000000000 +0000 @@ -1,4 +1,4 @@ The files amqp-rabbitmq-0.8.json and amqp-rabbitmq-0.9.1.json are -"Copyright (C) 2008-2011 VMware", Inc. and are covered by the MIT +"Copyright (C) 2008-2012 VMware", Inc. and are covered by the MIT license. diff -Nru rabbitmq-server-2.7.1/codegen/LICENSE-MPL-RabbitMQ rabbitmq-server-2.8.4/codegen/LICENSE-MPL-RabbitMQ --- rabbitmq-server-2.7.1/codegen/LICENSE-MPL-RabbitMQ 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen/LICENSE-MPL-RabbitMQ 2012-06-22 16:03:48.000000000 +0000 @@ -447,7 +447,7 @@ The Original Code is RabbitMQ. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2007-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2007-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/codegen.py rabbitmq-server-2.8.4/codegen.py --- rabbitmq-server-2.7.1/codegen.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/codegen.py 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## from __future__ import nested_scopes @@ -118,7 +118,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %%""" def genErl(spec): diff -Nru rabbitmq-server-2.7.1/debian/changelog rabbitmq-server-2.8.4/debian/changelog --- rabbitmq-server-2.7.1/debian/changelog 2012-03-29 14:47:46.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/changelog 2012-07-11 09:38:32.000000000 +0000 @@ -1,85 +1,44 @@ -rabbitmq-server (2.7.1-0ubuntu4) precise; urgency=low +rabbitmq-server (2.8.4-1) unstable; urgency=low - [ Dave Walker ] - * debian/rabbitmq-script-wrapper: Use start-stop-daemon instead of su - to run the commands. This also allows rabbitmq to start on the - installer if invoke-rc.d is used with --force. (LP: #966269) - - [ Andres Rodriguez ] - * debian/rabbitmq-server.init: Use --no-wait in initctl emit command to - not stall apt-get installations. (LP: #968124) - - -- Andres Rodriguez Thu, 29 Mar 2012 10:46:26 -0400 - -rabbitmq-server (2.7.1-0ubuntu3) precise; urgency=low - - * debian/rabbitmq-server.init: emit 'rabbitmq-server-running' signal for - upstart as MAAS needs it. - - -- Andres Rodriguez Tue, 27 Mar 2012 14:49:05 -0400 + * New upstream release -rabbitmq-server (2.7.1-0ubuntu2) precise; urgency=low + -- Emile Joubert Fri, 22 Jun 2012 17:48:28 +0100 - [ Marc Cluet ] - * Add new rabbitmq-erlang-client and rabbitmq-stomp binary packages as - plugins are now part of rabbitmq-server core (LP: #948993): - - d/rules: Refactored to support multiple binary packages, enable - .d style configuration of rabbitmq for plugins. - - d/rabbitmq-stomp.[postinst|postrm|install]: Install configuration - for stomp, enable/disable stomp plugin and restart as required. - - d/rabbitmq-erlang-client.[postinst|postrm]: Enable/disable amqp_client - plugin and restart as required. - - d/rabbitmq-server.*: Renamed to support multiple binary packages. - - d/rabbitmq-server.dirs: Added rabbitmq.conf.d dir for .d configuration - files. - - d/rabbitmq-server.postrm.in: Avoid deletion of rabbitmq user on purge. - * Switched to source/format 3.0 (quilt): - - d/patches/inets-plugins.patch: Fixup path to httpd.hrl. +rabbitmq-server (2.8.3-1) unstable; urgency=low - [ James Page ] - * d/control: rabbitmq-server needs to Break/Replace - rabbitmq-plugins-common < 2.7.1. - * d/rabbitmq-server.links: Fixup link to point to 2.7.1 install. - * d/rabbitmq-server.init: Restore fix to use start-stop-daemon (LP: #913464). + * New upstream release - -- Marc Cluet Mon, 12 Mar 2012 08:58:42 +0000 + -- Emile Joubert Thu, 21 Jun 2012 13:38:57 +0100 -rabbitmq-server (2.7.1-0ubuntu1) precise; urgency=low +rabbitmq-server (2.8.2-2) unstable; urgency=low - * New upstream release. (LP: #922600) - * Apply patch to include inets from the appropriate place. Fixes - FTBFS. - * d/control: adding necessary build-deps for 2.7.1 + * Add version numbers to plugins - -- Clint Byrum Tue, 28 Feb 2012 09:55:49 -0800 + -- Emile Joubert Tue, 01 May 2012 10:48:57 +0100 -rabbitmq-server (2.6.1-1ubuntu4) precise; urgency=low +rabbitmq-server (2.8.2-1) unstable; urgency=low - * Use start-stop-daemon in the init script, removing usage of su - (LP: #913464) + * New upstream release - -- Thomas Hervé Fri, 27 Jan 2012 14:58:19 +0100 + -- Emile Joubert Mon, 30 Apr 2012 14:07:32 +0100 -rabbitmq-server (2.6.1-1ubuntu3) precise; urgency=low +rabbitmq-server (2.8.1-1) unstable; urgency=low - * Fix broken init script. + * New upstream release - -- Chuck Short Sun, 13 Nov 2011 22:48:59 -0500 + -- Emile Joubert Fri, 23 Mar 2012 10:05:24 +0000 -rabbitmq-server (2.6.1-1ubuntu2) precise; urgency=low +rabbitmq-server (2.8.0-1) unstable; urgency=low - * close file handles of rabbitmq-server daemon in init script (LP: #878600) - * fix dpkg failure on purge (LP: #878597) + * New upstream release - -- Scott Moser Tue, 25 Oct 2011 12:51:20 -0400 + -- Emile Joubert Tue, 20 Mar 2012 11:55:10 +0000 -rabbitmq-server (2.6.1-1ubuntu1) precise; urgency=low +rabbitmq-server (2.6.1-2) unstable; urgency=low - * Merge from debian unstable. Remaining changes: - - symlink erlang libraries in a rabbit-common specific location. - - Added explicit log line in startup_* and shutdown_* (LP: #838959) + * Add DM-Upload-Allowed flag to control file to allow Maintainer uploads - -- Chuck Short Wed, 28 Sep 2011 01:05:54 +0000 + -- John Leuner Mon, 19 Mar 2012 21:13:54 +0200 rabbitmq-server (2.6.1-1) unstable; urgency=low @@ -87,40 +46,12 @@ -- John Leuner Tue, 27 Sep 2011 17:53:57 +0200 -rabbitmq-server (2.5.0-1ubuntu2) oneiric; urgency=low - - * Added explicit log line in startup_* and shutdown_* (LP: #838959) - - Added a log line with a timestamp to indicate either the success or - failure on startup/shutdown - - -- Marc Cluet Wed, 14 Sep 2011 17:56:32 +0200 - -rabbitmq-server (2.5.0-1ubuntu1) oneiric; urgency=low - - * Merge from Debian Unstable. Remaining changes: - - symlink erlang libraries in a rabbit-common specific location. - - -- Dave Walker (Daviey) Sun, 19 Jun 2011 18:18:49 +0100 - rabbitmq-server (2.5.0-1) unstable; urgency=low * New upstream release -- John Leuner Thu, 16 Jun 2011 09:55:40 +0200 -rabbitmq-server (2.4.1-1ubuntu2) oneiric; urgency=low - - * Fixed libraries soft link for 2.4.1 release - - -- Marc Cluet Thu, 26 May 2011 02:39:10 -0700 - -rabbitmq-server (2.4.1-1ubuntu1) oneiric; urgency=low - - * Merge from debian unstable. Remaining changes: - - symlink erlang libraries in a rabbit-cmmon specific location. - - -- Chuck Short Mon, 02 May 2011 13:15:56 +0100 - rabbitmq-server (2.4.1-1) unstable; urgency=low * New upstream release @@ -133,13 +64,6 @@ -- John Leuner Wed, 23 Mar 2011 21:11:17 +0200 -rabbitmq-server (2.3.1-1ubuntu1) natty; urgency=low - - * fix rabbitmq-stomp FTBFS, which requires erlang libraries in a - rabbit-common specific location; solve with a symlink - - -- Dustin Kirkland Tue, 19 Apr 2011 15:32:28 -0400 - rabbitmq-server (2.3.1-1) unstable; urgency=low * New upstream release, closes: #611253 @@ -298,4 +222,3 @@ * First Debian upload, closes: #507902 -- John Leuner Wed, 17 Dec 2008 18:23:47 +0000 - diff -Nru rabbitmq-server-2.7.1/debian/conf/rabbitmq.conf.d/50_stomp rabbitmq-server-2.8.4/debian/conf/rabbitmq.conf.d/50_stomp --- rabbitmq-server-2.7.1/debian/conf/rabbitmq.conf.d/50_stomp 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/conf/rabbitmq.conf.d/50_stomp 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -RABBITMQ_SERVER_START_ARGS='-rabbitmq_stomp tcp_listeners [{"0.0.0.0",61613},{"0.0.0.0",6163}]' diff -Nru rabbitmq-server-2.7.1/debian/conf/rabbitmq-env.conf rabbitmq-server-2.8.4/debian/conf/rabbitmq-env.conf --- rabbitmq-server-2.7.1/debian/conf/rabbitmq-env.conf 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/conf/rabbitmq-env.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -for CONFIGFILE in `ls /etc/rabbitmq/rabbitmq.conf.d |sort -r`; do - . /etc/rabbitmq/rabbitmq.conf.d/$CONFIGFILE -done diff -Nru rabbitmq-server-2.7.1/debian/control rabbitmq-server-2.8.4/debian/control --- rabbitmq-server-2.7.1/debian/control 2012-03-12 09:27:19.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/control 2012-07-11 09:38:32.000000000 +0000 @@ -1,36 +1,17 @@ Source: rabbitmq-server Section: net Priority: extra -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: RabbitMQ Team -Build-Depends: cdbs, debhelper (>= 5), quilt, erlang-dev, python-simplejson, xmlto, xsltproc, git, zip, unzip, erlang-asn1, erlang-inets -Standards-Version: 3.9.3 +Maintainer: RabbitMQ Team +Uploaders: Emile Joubert +DM-Upload-Allowed: yes +Build-Depends: cdbs, debhelper (>= 5), erlang-dev, python-simplejson, xmlto, xsltproc, erlang-nox (>= 1:12.b.3), erlang-src (>= 1:12.b.3), unzip, zip +Standards-Version: 3.8.0 Package: rabbitmq-server Architecture: all -Breaks: rabbitmq-plugins-common (<< 2.7.1) -Replaces: rabbitmq-plugins-common (<< 2.7.1) Depends: erlang-nox (>= 1:12.b.3), adduser, logrotate, ${misc:Depends} Description: An AMQP server written in Erlang RabbitMQ is an implementation of AMQP, the emerging standard for high performance enterprise messaging. The RabbitMQ server is a robust and scalable implementation of an AMQP broker. Homepage: http://www.rabbitmq.com/ - -Package: rabbitmq-erlang-client -Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, rabbitmq-server (= ${binary:Version}) -Description: Erlang client for RabbitMQ - This client offers both a networked version that uses standard TCP-based AMQP - framing and a direct client that uses native Erlang message passing to a - RabbitMQ broker. - -Package: rabbitmq-stomp -Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, rabbitmq-server (>= 2.7.1), - rabbitmq-erlang-client (= ${binary:Version}) -Suggests: ruby -Description: A STOMP gateway for RabbitMQ - Gateway for exposing AMQP functionality via the STOMP protocol, as - implemented by many clients for various programming languages, and a few other - servers besides RabbitMQ. diff -Nru rabbitmq-server-2.7.1/debian/copyright rabbitmq-server-2.8.4/debian/copyright --- rabbitmq-server-2.7.1/debian/copyright 2012-03-12 08:58:37.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/copyright 2012-07-11 09:38:32.000000000 +0000 @@ -3,12 +3,44 @@ It was downloaded from http://www.rabbitmq.com/ -The files codegen/amqp-rabbitmq-0.8.json and -codegen/amqp-rabbitmq-0.9.1.json are covered by the following terms: - "Copyright (C) 2008-2011 VMware, Inc. +This package, the RabbitMQ server is licensed under the MPL. - Permission is hereby granted, free of charge, to any person +If you have any questions regarding licensing, please contact us at +info@rabbitmq.com. + +The files amqp-rabbitmq-0.8.json and amqp-rabbitmq-0.9.1.json are +"Copyright (C) 2008-2012 VMware", Inc. and are covered by the MIT +license. + +Webmachine is Copyright (c) Basho Technologies and is covered by the +Apache License 2.0. It was downloaded from http://webmachine.basho.com/ + +glMatrix is "Copyright (c) 2011, Brandon Jones" and is covered by the +BSD 2-Clause license. It was downloaded from +http://code.google.com/p/glmatrix/ + +Eldap is "Copyright (c) 2010, Torbjorn Tornkvist" and is covered by +the MIT license. It was downloaded from https://github.com/etnt/eldap + +jQuery is "Copyright (c) 2010 John Resig" and is covered by the MIT +license. It was downloaded from http://jquery.com/ + +EJS is "Copyright (c) 2007 Edward Benson" and is covered by the MIT +license. It was downloaded from http://embeddedjs.com/ + +Sammy is "Copyright (c) 2008 Aaron Quint, Quirkey NYC, LLC" and is +covered by the MIT license. It was downloaded from +http://code.quirkey.com/sammy/ + +Mochiweb is "Copyright (c) 2007 Mochi Media, Inc." and is covered by +the MIT license. It was downloaded from +http://github.com/mochi/mochiweb/ + + +The MIT license is as follows: + + "Permission is hereby granted, free of charge, to any person obtaining a copy of this file (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, @@ -28,11 +60,42 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + +The BSD 2-Clause license is as follows: + + "Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the + following conditions are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + + The rest of this package is licensed under the Mozilla Public License 1.1 Authors and Copyright are as described below: The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2007-2011 VMware, Inc. All rights reserved. + Copyright (c) 2007-2012 VMware, Inc. All rights reserved. MOZILLA PUBLIC LICENSE @@ -484,7 +547,7 @@ The Original Code is RabbitMQ. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2007-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2007-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should @@ -492,11 +555,6 @@ Original Code Source Code for Your Modifications.] - - - -If you have any questions regarding licensing, please contact us at -info@rabbitmq.com. - -The Debian packaging is (C) 2007-2011, VMware, Inc. and is licensed +The Debian packaging is (C) 2007-2012, VMware, Inc. and is licensed under the MPL 1.1, see above. + diff -Nru rabbitmq-server-2.7.1/debian/dirs rabbitmq-server-2.8.4/debian/dirs --- rabbitmq-server-2.7.1/debian/dirs 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/dirs 2012-07-11 09:38:32.000000000 +0000 @@ -0,0 +1,9 @@ +usr/lib/rabbitmq/bin +usr/lib/erlang/lib +usr/sbin +usr/share/man +var/lib/rabbitmq/mnesia +var/log/rabbitmq +etc/logrotate.d +etc/rabbitmq + diff -Nru rabbitmq-server-2.7.1/debian/LICENSE.head rabbitmq-server-2.8.4/debian/LICENSE.head --- rabbitmq-server-2.7.1/debian/LICENSE.head 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/LICENSE.head 2012-07-11 09:38:32.000000000 +0000 @@ -0,0 +1,5 @@ +This package, the RabbitMQ server is licensed under the MPL. + +If you have any questions regarding licensing, please contact us at +info@rabbitmq.com. + diff -Nru rabbitmq-server-2.7.1/debian/LICENSE.tail rabbitmq-server-2.8.4/debian/LICENSE.tail --- rabbitmq-server-2.7.1/debian/LICENSE.tail 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/LICENSE.tail 2012-07-11 09:38:32.000000000 +0000 @@ -0,0 +1,516 @@ + +The MIT license is as follows: + + "Permission is hereby granted, free of charge, to any person + obtaining a copy of this file (the Software), to deal in the + Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE." + + +The BSD 2-Clause license is as follows: + + "Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the + following conditions are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + + +The rest of this package is licensed under the Mozilla Public License 1.1 +Authors and Copyright are as described below: + + The Initial Developer of the Original Code is VMware, Inc. + Copyright (c) 2007-2012 VMware, Inc. All rights reserved. + + + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is RabbitMQ. + + The Initial Developer of the Original Code is VMware, Inc. + Copyright (c) 2007-2012 VMware, Inc. All rights reserved.'' + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] diff -Nru rabbitmq-server-2.7.1/debian/patches/inets-plugins.patch rabbitmq-server-2.8.4/debian/patches/inets-plugins.patch --- rabbitmq-server-2.7.1/debian/patches/inets-plugins.patch 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/patches/inets-plugins.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ ---- rabbitmq-server-2.7.1.orig/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_inets.erl -+++ rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_inets.erl -@@ -88,14 +88,7 @@ - -module(rfc4627_jsonrpc_inets). - -include("rfc4627_jsonrpc.hrl"). - --%% The path to httpd.hrl has changed in OTP R14A and newer. Our --%% Makefile detects the change for us, and supplies a compile-time --%% macro definition to allow us to adapt to the new path. ---ifdef(new_inets). ---include_lib("inets/src/http_server/httpd.hrl"). ---else. ---include_lib("inets/src/httpd.hrl"). ---endif. -+-include_lib("inets/include/httpd.hrl"). - - -export([do/1, load/2]). - diff -Nru rabbitmq-server-2.7.1/debian/patches/series rabbitmq-server-2.8.4/debian/patches/series --- rabbitmq-server-2.7.1/debian/patches/series 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -inets-plugins.patch diff -Nru rabbitmq-server-2.7.1/debian/postinst rabbitmq-server-2.8.4/debian/postinst --- rabbitmq-server-2.7.1/debian/postinst 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/postinst 2012-07-11 09:38:32.000000000 +0000 @@ -0,0 +1,60 @@ +#!/bin/sh +# postinst script for rabbitmq +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +# create rabbitmq group +if ! getent group rabbitmq >/dev/null; then + addgroup --system rabbitmq +fi + +# create rabbitmq user +if ! getent passwd rabbitmq >/dev/null; then + adduser --system --ingroup rabbitmq --home /var/lib/rabbitmq \ + --no-create-home --gecos "RabbitMQ messaging server" \ + --disabled-login rabbitmq +fi + +chown -R rabbitmq:rabbitmq /var/lib/rabbitmq +chown -R rabbitmq:rabbitmq /var/log/rabbitmq + +case "$1" in + configure) + if [ -f /etc/rabbitmq/rabbitmq.conf ] && \ + [ ! -f /etc/rabbitmq/rabbitmq-env.conf ]; then + mv /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq-env.conf + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff -Nru rabbitmq-server-2.7.1/debian/postrm.in rabbitmq-server-2.8.4/debian/postrm.in --- rabbitmq-server-2.7.1/debian/postrm.in 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/postrm.in 2012-07-11 09:38:32.000000000 +0000 @@ -0,0 +1,65 @@ +#!/bin/sh +# postrm script for rabbitmq +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +remove_plugin_traces() { + # Remove traces of plugins + rm -rf /var/lib/rabbitmq/plugins-scratch +} + +case "$1" in + purge) + rm -f /etc/default/rabbitmq + if [ -d /var/lib/rabbitmq ]; then + rm -r /var/lib/rabbitmq + fi + if [ -d /var/log/rabbitmq ]; then + rm -r /var/log/rabbitmq + fi + if [ -d /etc/rabbitmq ]; then + rm -r /etc/rabbitmq + fi + remove_plugin_traces + if getent passwd rabbitmq >/dev/null; then + # Stop epmd if run by the rabbitmq user + pkill -u rabbitmq epmd || : + fi + ;; + + remove|upgrade) + remove_plugin_traces + ;; + + failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-erlang-client.postinst rabbitmq-server-2.8.4/debian/rabbitmq-erlang-client.postinst --- rabbitmq-server-2.7.1/debian/rabbitmq-erlang-client.postinst 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-erlang-client.postinst 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -#!/bin/sh -e - -/usr/lib/rabbitmq/bin/rabbitmq-plugins enable amqp_client -invoke-rc.d rabbitmq-server restart - -#DEBHELPER# diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-erlang-client.postrm rabbitmq-server-2.8.4/debian/rabbitmq-erlang-client.postrm --- rabbitmq-server-2.7.1/debian/rabbitmq-erlang-client.postrm 2012-03-12 09:43:56.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-erlang-client.postrm 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# postrm script for rabbitmq -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - purge) - ;; - - failed-upgrade|abort-install|abort-upgrade|disappear|remove|upgrade) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - - -if [ -x /usr/lib/rabbitmq/bin/rabbitmq-plugins ]; then /usr/lib/rabbitmq/bin/rabbitmq-plugins disable amqp_client; fi -if ! /usr/sbin/invoke-rc.d rabbitmq-server restart ; then - RESTART_RESULT=$? - if [ "$RESTART_RESULT" != "100" ] ; then - exit $RESTART_RESULT - fi -fi - -#DEBHELPER# - -exit 0 diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-plugins-common.install rabbitmq-server-2.8.4/debian/rabbitmq-plugins-common.install --- rabbitmq-server-2.7.1/debian/rabbitmq-plugins-common.install 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-plugins-common.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/conf/rabbitmq-env.conf etc/rabbitmq diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-script-wrapper rabbitmq-server-2.8.4/debian/rabbitmq-script-wrapper --- rabbitmq-server-2.7.1/debian/rabbitmq-script-wrapper 2012-03-28 18:34:02.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-script-wrapper 2012-07-11 09:38:32.000000000 +0000 @@ -12,7 +12,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## # Escape spaces and quotes, because shell is revolting. @@ -29,10 +29,12 @@ SCRIPT=`basename $0` -if [ `id -u` = 0 ] ; then - start-stop-daemon --start --pidfile /dev/null --startas "/usr/lib/rabbitmq/bin/${SCRIPT}" --chuid rabbitmq -- "$@" -elif [ `id -u` = `id -u rabbitmq` ] ; then +if [ `id -u` = `id -u rabbitmq` -a "$SCRIPT" = "rabbitmq-server" ] ; then + /usr/lib/rabbitmq/bin/rabbitmq-server "$@" > "/var/log/rabbitmq/startup_log" 2> "/var/log/rabbitmq/startup_err" +elif [ `id -u` = `id -u rabbitmq` -o "$SCRIPT" = "rabbitmq-plugins" ] ; then /usr/lib/rabbitmq/bin/${SCRIPT} "$@" +elif [ `id -u` = 0 ] ; then + su rabbitmq -s /bin/sh -c "/usr/lib/rabbitmq/bin/${SCRIPT} ${CMDLINE}" else /usr/lib/rabbitmq/bin/${SCRIPT} echo diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.default rabbitmq-server-2.8.4/debian/rabbitmq-server.default --- rabbitmq-server-2.7.1/debian/rabbitmq-server.default 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.default 2012-07-11 09:38:32.000000000 +0000 @@ -0,0 +1,9 @@ +# This file is sourced by /etc/init.d/rabbitmq-server. Its primary +# reason for existing is to allow adjustment of system limits for the +# rabbitmq-server process. +# +# Maximum number of open file handles. This will need to be increased +# to handle many simultaneous connections. Refer to the system +# documentation for ulimit (in man bash) for more information. +# +#ulimit -n 1024 diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.dirs rabbitmq-server-2.8.4/debian/rabbitmq-server.dirs --- rabbitmq-server-2.7.1/debian/rabbitmq-server.dirs 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -usr/lib/rabbitmq/bin -usr/lib/erlang/lib -usr/sbin -usr/share/man -var/lib/rabbitmq/mnesia -var/log/rabbitmq -etc/logrotate.d -etc/rabbitmq -etc/rabbitmq/rabbitmq.conf.d diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.init rabbitmq-server-2.8.4/debian/rabbitmq-server.init --- rabbitmq-server-2.7.1/debian/rabbitmq-server.init 2012-03-28 19:12:59.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.init 2012-07-11 09:38:32.000000000 +0000 @@ -18,15 +18,14 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin NAME=rabbitmq-server -DAEMON=/usr/lib/rabbitmq/bin/${NAME} +DAEMON=/usr/sbin/${NAME} CONTROL=/usr/sbin/rabbitmqctl -DESC=rabbitmq-server +DESC="message broker" USER=rabbitmq ROTATE_SUFFIX= INIT_LOG_DIR=/var/log/rabbitmq PID_FILE=/var/run/rabbitmq/pid -LOCK_FILE= test -x $DAEMON || exit 0 test -x $CONTROL || exit 0 @@ -34,6 +33,11 @@ RETVAL=0 set -e +[ -f /etc/default/${NAME} ] && . /etc/default/${NAME} + +. /lib/lsb/init-functions +. /lib/init/vars.sh + ensure_pid_dir () { PID_DIR=`dirname ${PID_FILE}` if [ ! -d ${PID_DIR} ] ; then @@ -50,33 +54,21 @@ start_rabbitmq () { status_rabbitmq quiet - if [ $RETVAL = 0 ] ; then - echo RabbitMQ is currently running - else + if [ $RETVAL != 0 ] ; then RETVAL=0 ensure_pid_dir set +e - RABBITMQ_PID_FILE=$PID_FILE start-stop-daemon --pidfile=$PID_FILE --chuid rabbitmq --exec $DAEMON --background --start + RABBITMQ_PID_FILE=$PID_FILE start-stop-daemon --quiet \ + --chuid rabbitmq --start --exec $DAEMON \ + --pidfile "$RABBITMQ_PID_FILE" --background $CONTROL wait $PID_FILE >/dev/null 2>&1 RETVAL=$? set -e - case "$RETVAL" in - 0) - echo SUCCESS - if [ -n "$LOCK_FILE" ] ; then - touch $LOCK_FILE - fi - echo "`date` - rabbitmq successfully started" >> ${INIT_LOG_DIR}/startup_log - # only emit the event on boot - [ -n "$UPSTART_JOB" ] && initctl emit --no-wait rabbitmq-server-running || true - ;; - *) - remove_pid - echo FAILED - check ${INIT_LOG_DIR}/startup_\{log, _err\} - echo "`date` - rabbitmq failed to start" >> ${INIT_LOG_DIR}/startup_err - RETVAL=1 - ;; - esac + if [ $RETVAL != 0 ] ; then + remove_pid + fi + else + RETVAL=3 fi } @@ -84,22 +76,14 @@ status_rabbitmq quiet if [ $RETVAL = 0 ] ; then set +e - start-stop-daemon --pidfile=$PID_FILE --stop + $CONTROL stop ${PID_FILE} > ${INIT_LOG_DIR}/shutdown_log 2> ${INIT_LOG_DIR}/shutdown_err RETVAL=$? set -e if [ $RETVAL = 0 ] ; then remove_pid - if [ -n "$LOCK_FILE" ] ; then - rm -f $LOCK_FILE - fi - echo "`date` - rabbitmq successfully stopped" >> ${INIT_LOG_DIR}/shutdown_log - else - echo FAILED - check ${INIT_LOG_DIR}/shutdown_log, _err - echo "`date` - rabbitmq failed to stop" >> ${INIT_LOG_DIR}/shutdown_err fi else - echo RabbitMQ is not running - RETVAL=0 + RETVAL=3 fi } @@ -118,7 +102,7 @@ rotate_logs_rabbitmq() { set +e - $CONTROL rotate_logs ${ROTATE_SUFFIX} + $CONTROL -q rotate_logs ${ROTATE_SUFFIX} if [ $? != 0 ] ; then RETVAL=1 fi @@ -130,8 +114,7 @@ if [ $RETVAL = 0 ] ; then restart_rabbitmq else - echo RabbitMQ is not runnning - RETVAL=0 + log_warning_msg "${DESC} not running" fi } @@ -140,33 +123,60 @@ start_rabbitmq } +restart_end() { + if [ $RETVAL = 0 ] ; then + log_end_msg 0 + else + log_end_msg 1 + fi +} + +start_stop_end() { + case "$RETVAL" in + 0) + [ -x /sbin/initctl ] && /sbin/initctl emit --no-wait "${NAME}-${1}" + log_end_msg 0 + ;; + 3) + log_warning_msg "${DESC} already ${1}" + log_end_msg 0 + RETVAL=0 + ;; + *) + log_warning_msg "FAILED - check ${INIT_LOG_DIR}/startup_\{log, _err\}" + log_end_msg 1 + ;; + esac +} + case "$1" in start) - echo -n "Starting $DESC: " + log_daemon_msg "Starting ${DESC}" $NAME start_rabbitmq - echo "$NAME." + start_stop_end "running" ;; stop) - echo -n "Stopping $DESC: " + log_daemon_msg "Stopping ${DESC}" $NAME stop_rabbitmq - echo "$NAME." + start_stop_end "stopped" ;; status) status_rabbitmq ;; rotate-logs) - echo -n "Rotating log files for $DESC: " + log_action_begin_msg "Rotating log files for ${DESC} ${NAME}" rotate_logs_rabbitmq + log_action_end_msg $RETVAL ;; force-reload|reload|restart) - echo -n "Restarting $DESC: " + log_daemon_msg "Restarting ${DESC}" $NAME restart_rabbitmq - echo "$NAME." + restart_end ;; try-restart) - echo -n "Restarting $DESC: " + log_daemon_msg "Restarting ${DESC}" $NAME restart_running_rabbitmq - echo "$NAME." + restart_end ;; *) echo "Usage: $0 {start|stop|status|rotate-logs|restart|condrestart|try-restart|reload|force-reload}" >&2 diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.links rabbitmq-server-2.8.4/debian/rabbitmq-server.links --- rabbitmq-server-2.7.1/debian/rabbitmq-server.links 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.links 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/rabbitmq/lib/rabbitmq_server-2.7.1 usr/lib/erlang/lib/rabbit_common diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.ocf rabbitmq-server-2.8.4/debian/rabbitmq-server.ocf --- rabbitmq-server-2.7.1/debian/rabbitmq-server.ocf 2012-03-12 08:58:37.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.ocf 2012-07-11 09:38:32.000000000 +0000 @@ -12,7 +12,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## ## diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.postinst rabbitmq-server-2.8.4/debian/rabbitmq-server.postinst --- rabbitmq-server-2.7.1/debian/rabbitmq-server.postinst 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.postinst 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -#!/bin/sh -# postinst script for rabbitmq -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -# create rabbitmq group -if ! getent group rabbitmq >/dev/null; then - addgroup --system rabbitmq -fi - -# create rabbitmq user -if ! getent passwd rabbitmq >/dev/null; then - adduser --system --ingroup rabbitmq --home /var/lib/rabbitmq \ - --no-create-home --gecos "RabbitMQ messaging server" \ - --disabled-login rabbitmq -fi - -chown -R rabbitmq:rabbitmq /var/lib/rabbitmq -chown -R rabbitmq:rabbitmq /var/log/rabbitmq - -case "$1" in - configure) - if [ -f /etc/rabbitmq/rabbitmq.conf ] && \ - [ ! -f /etc/rabbitmq/rabbitmq-env.conf ]; then - mv /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq-env.conf - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-server.postrm.in rabbitmq-server-2.8.4/debian/rabbitmq-server.postrm.in --- rabbitmq-server-2.7.1/debian/rabbitmq-server.postrm.in 2012-03-12 09:52:46.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-server.postrm.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -#!/bin/sh -# postrm script for rabbitmq -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -remove_plugin_traces() { - # Remove traces of plugins - rm -rf /var/lib/rabbitmq/plugins-scratch -} - -case "$1" in - purge) - rm -f /etc/default/rabbitmq - if [ -d /var/lib/rabbitmq ]; then - rm -r /var/lib/rabbitmq - fi - if [ -d /var/log/rabbitmq ]; then - rm -r /var/log/rabbitmq - fi - if [ -d /etc/rabbitmq ]; then - rm -r /etc/rabbitmq - fi - remove_plugin_traces - ;; - - remove|upgrade) - remove_plugin_traces - ;; - - failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-stomp.install rabbitmq-server-2.8.4/debian/rabbitmq-stomp.install --- rabbitmq-server-2.7.1/debian/rabbitmq-stomp.install 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-stomp.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/conf/rabbitmq.conf.d/50_stomp etc/rabbitmq/rabbitmq.conf.d diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-stomp.postinst rabbitmq-server-2.8.4/debian/rabbitmq-stomp.postinst --- rabbitmq-server-2.7.1/debian/rabbitmq-stomp.postinst 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-stomp.postinst 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -#!/bin/sh -e - -/usr/lib/rabbitmq/bin/rabbitmq-plugins enable rabbitmq_stomp -invoke-rc.d rabbitmq-server restart - -#DEBHELPER# diff -Nru rabbitmq-server-2.7.1/debian/rabbitmq-stomp.postrm rabbitmq-server-2.8.4/debian/rabbitmq-stomp.postrm --- rabbitmq-server-2.7.1/debian/rabbitmq-stomp.postrm 2012-03-12 09:43:11.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rabbitmq-stomp.postrm 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# postrm script for rabbitmq -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - purge) - rm -f /etc/rabbitmq/rabbitmq.conf.d/50_stomp - ;; - - failed-upgrade|abort-install|abort-upgrade|disappear|remove|upgrade) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -if [ -x /usr/lib/rabbitmq/bin/rabbitmq-plugins ]; then /usr/lib/rabbitmq/bin/rabbitmq-plugins disable rabbitmq_stomp; fi -if ! /usr/sbin/invoke-rc.d rabbitmq-server restart ; then - RESTART_RESULT=$? - if [ "$RESTART_RESULT" != "100" ] ; then - exit $RESTART_RESULT - fi -fi - -#DEBHELPER# - -exit 0 diff -Nru rabbitmq-server-2.7.1/debian/rules rabbitmq-server-2.8.4/debian/rules --- rabbitmq-server-2.7.1/debian/rules 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/rules 2012-07-11 09:38:32.000000000 +0000 @@ -3,22 +3,20 @@ include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/makefile.mk -MULTIPACKAGE_DEB_DESTDIR=debian/rabbitmq-server/ +RABBIT_LIB=$(DEB_DESTDIR)usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)/ +RABBIT_BIN=$(DEB_DESTDIR)usr/lib/rabbitmq/bin/ -RABBIT_LIB=$(MULTIPACKAGE_DEB_DESTDIR)usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)/ -RABBIT_BIN=$(MULTIPACKAGE_DEB_DESTDIR)usr/lib/rabbitmq/bin/ - -DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) MAN_DIR=$(MULTIPACKAGE_DEB_DESTDIR)usr/share/man/ +DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) MAN_DIR=$(DEB_DESTDIR)usr/share/man/ DEB_MAKE_CLEAN_TARGET:= distclean -DOCDIR=$(MULTIPACKAGE_DEB_DESTDIR)usr/share/doc/rabbitmq-server/ +DOCDIR=$(DEB_DESTDIR)usr/share/doc/rabbitmq-server/ install/rabbitmq-server:: mkdir -p $(DOCDIR) rm $(RABBIT_LIB)LICENSE* $(RABBIT_LIB)INSTALL* - for script in rabbitmqctl rabbitmq-server; do \ - install -p -D -m 0755 debian/rabbitmq-script-wrapper $(MULTIPACKAGE_DEB_DESTDIR)usr/sbin/$$script; \ + for script in rabbitmqctl rabbitmq-server rabbitmq-plugins; do \ + install -p -D -m 0755 debian/rabbitmq-script-wrapper $(DEB_DESTDIR)usr/sbin/$$script; \ done - sed -e 's|@RABBIT_LIB@|/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)|g' debian/rabbitmq-server.postrm - install -p -D -m 0755 debian/rabbitmq-server.ocf $(MULTIPACKAGE_DEB_DESTDIR)usr/lib/ocf/resource.d/rabbitmq/rabbitmq-server - install -p -m 0644 debian/conf/rabbitmq-env.conf $(MULTIPACKAGE_DEB_DESTDIR)etc/rabbitmq + sed -e 's|@RABBIT_LIB@|/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)|g' debian/postrm + install -p -D -m 0755 debian/rabbitmq-server.ocf $(DEB_DESTDIR)usr/lib/ocf/resource.d/rabbitmq/rabbitmq-server + install -p -D -m 0644 debian/rabbitmq-server.default $(DEB_DESTDIR)etc/default/rabbitmq-server diff -Nru rabbitmq-server-2.7.1/debian/source/format rabbitmq-server-2.8.4/debian/source/format --- rabbitmq-server-2.7.1/debian/source/format 2012-07-11 09:38:31.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/source/format 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -3.0 (quilt) diff -Nru rabbitmq-server-2.7.1/debian/source/options rabbitmq-server-2.8.4/debian/source/options --- rabbitmq-server-2.7.1/debian/source/options 2012-03-12 08:58:39.000000000 +0000 +++ rabbitmq-server-2.8.4/debian/source/options 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -single-debian-patch diff -Nru rabbitmq-server-2.7.1/docs/html-to-website-xml.xsl rabbitmq-server-2.8.4/docs/html-to-website-xml.xsl --- rabbitmq-server-2.7.1/docs/html-to-website-xml.xsl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/docs/html-to-website-xml.xsl 2012-06-22 16:03:48.000000000 +0000 @@ -8,8 +8,6 @@ - - @@ -28,36 +26,30 @@ <xsl:value-of select="document($original)/refentry/refnamediv/refname"/><xsl:if test="document($original)/refentry/refmeta/manvolnum">(<xsl:value-of select="document($original)/refentry/refmeta/manvolnum"/>)</xsl:if> manual page - - - + + -

- This is the manual page for - (). -

-

- See a list of all manual pages. -

+

+ This is the manual page for + (). +

+

+ See a list of all manual pages. +

-

- This is the documentation for - . -

+

+ This is the documentation for + . +

-
-

+ +

For more general documentation, please see the - administrator's guide. -

- - - Table of Contents - + administrator's guide. +

- -
+
diff -Nru rabbitmq-server-2.7.1/docs/rabbitmqctl.1.xml rabbitmq-server-2.8.4/docs/rabbitmqctl.1.xml --- rabbitmq-server-2.7.1/docs/rabbitmqctl.1.xml 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/docs/rabbitmqctl.1.xml 2012-06-22 16:03:48.000000000 +0000 @@ -266,10 +266,9 @@ When the target files do not exist they are created. - target files do not already exist. When - no is specified, the empty log - files are simply created at the original location; no - rotation takes place. + When no is specified, the empty + log files are simply created at the original location; + no rotation takes place. For example: rabbitmqctl rotate_logs .1 @@ -949,7 +948,7 @@ source_kind The kind of the source of messages to which the binding is attached. Currently always - queue. With non-ASCII characters escaped as in + exchange. With non-ASCII characters escaped as in C. @@ -1012,6 +1011,10 @@ Id of the Erlang process associated with the connection. + name + Readable name for the connection. + + address Server IP address. @@ -1067,10 +1070,26 @@ The period for which the peer's SSL certificate is valid. + + + last_blocked_by + The reason for which this connection + was last blocked. One of 'resource' - due to a memory + or disk alarm, 'flow' - due to internal flow control, or + 'none' if the connection was never + blocked. + + + last_blocked_age + Time, in seconds, since this + connection was last blocked, or + 'infinity'. + + state Connection state (one of [starting, tuning, - opening, running, closing, closed]). + opening, running, blocking, blocked, closing, closed]). channels @@ -1127,8 +1146,9 @@ - If no connectioninfoitems are specified then user, peer - address, peer port and connection state are displayed. + If no connectioninfoitems are + specified then user, peer address, peer port, time since + flow control and memory block state are displayed. @@ -1171,6 +1191,10 @@ to which the channel belongs. + name + Readable name for the channel. + + number The number of the channel, which uniquely identifies it within a connection. @@ -1273,9 +1297,10 @@ Displays broker status information such as the running applications on the current Erlang node, RabbitMQ and - Erlang versions, OS name and memory statistics. (See - the cluster_status command to find - out which nodes are clustered and running.) + Erlang versions, OS name, memory and file descriptor + statistics. (See the cluster_status + command to find out which nodes are clustered and + running.) For example: rabbitmqctl status @@ -1403,8 +1428,11 @@ fraction - The new memory threshhold fraction at which flow control is triggered, as a - floating point number between 0.0 and 1.0 with a mandatory fractional part. + + The new memory threshold fraction at which flow + control is triggered, as a floating point number + greater than or equal to 0. + diff -Nru rabbitmq-server-2.7.1/docs/rabbitmq-echopid.xml rabbitmq-server-2.8.4/docs/rabbitmq-echopid.xml --- rabbitmq-server-2.7.1/docs/rabbitmq-echopid.xml 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/docs/rabbitmq-echopid.xml 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,71 @@ + + + + + RabbitMQ Server + + The RabbitMQ Team <info@rabbitmq.com> + + + + + rabbitmq-echopid.bat + RabbitMQ Server + + + + rabbitmq-echopid.bat + return the process id of the Erlang runtime hosting RabbitMQ + + + + + rabbitmq-echopid.bat + sname + + + + + Description + + RabbitMQ is an implementation of AMQP, the emerging + standard for high performance enterprise messaging. The + RabbitMQ server is a robust and scalable implementation of + an AMQP broker. + + + Running rabbitmq-echopid will attempt to + discover and echo the process id (PID) of the Erlang runtime + process (erl.exe) that is hosting RabbitMQ. To allow erl.exe + time to start up and load RabbitMQ, the script will wait for + ten seconds before timing out if a suitable PID cannot be + found. + + + If a PID is discovered, the script will echo it to stdout + before exiting with a ERRORLEVEL of 0. If no PID is + discovered before the timeout, nothing is written to stdout + and the script exits setting ERRORLEVEL to 1. + + + Note that this script only exists on Windows due to the need + to wait for erl.exe and possibly time-out. To obtain the PID + on Unix set RABBITMQ_PID_FILE before starting + rabbitmq-server and do not use "-detached". + + + + + Options + + + sname + + +The short-name form of the RabbitMQ node name. + + + + + + diff -Nru rabbitmq-server-2.7.1/ebin/rabbit_app.in rabbitmq-server-2.8.4/ebin/rabbit_app.in --- rabbitmq-server-2.7.1/ebin/rabbit_app.in 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/ebin/rabbit_app.in 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,7 @@ {application, rabbit, %% -*- erlang -*- [{description, "RabbitMQ"}, {id, "RabbitMQ"}, - {vsn, "2.7.1"}, + {vsn, "2.8.4"}, {modules, []}, {registered, [rabbit_amqqueue_sup, rabbit_log, @@ -19,6 +19,7 @@ {ssl_listeners, []}, {ssl_options, []}, {vm_memory_high_watermark, 0.4}, + {disk_free_limit, 1000000000}, %% 1GB {msg_store_index_module, rabbit_msg_store_ets_index}, {backing_queue_module, rabbit_variable_queue}, {frame_max, 131072}, @@ -37,10 +38,13 @@ {auth_backends, [rabbit_auth_backend_internal]}, {delegate_count, 16}, {trace_vhosts, []}, + {log_levels, [{connection, info}]}, + {ssl_cert_login_from, distinguished_name}, {tcp_listen_options, [binary, {packet, raw}, {reuseaddr, true}, {backlog, 128}, {nodelay, true}, + {linger, {true, 0}}, {exit_on_close, false}]} ]}]}. diff -Nru rabbitmq-server-2.7.1/include/gm_specs.hrl rabbitmq-server-2.8.4/include/gm_specs.hrl --- rabbitmq-server-2.7.1/include/gm_specs.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/gm_specs.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -ifdef(use_specs). diff -Nru rabbitmq-server-2.7.1/include/rabbit_auth_backend_spec.hrl rabbitmq-server-2.8.4/include/rabbit_auth_backend_spec.hrl --- rabbitmq-server-2.7.1/include/rabbit_auth_backend_spec.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit_auth_backend_spec.hrl 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License -%% at http://www.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and -%% limitations under the License. -%% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. -%% - --ifdef(use_specs). - --spec(description/0 :: () -> [{atom(), any()}]). - --spec(check_user_login/2 :: (rabbit_types:username(), [term()]) -> - {'ok', rabbit_types:user()} | - {'refused', string(), [any()]} | - {'error', any()}). --spec(check_vhost_access/2 :: (rabbit_types:user(), rabbit_types:vhost()) -> - boolean() | {'error', any()}). --spec(check_resource_access/3 :: (rabbit_types:user(), - rabbit_types:r(atom()), - rabbit_access_control:permission_atom()) -> - boolean() | {'error', any()}). --endif. diff -Nru rabbitmq-server-2.7.1/include/rabbit_auth_mechanism_spec.hrl rabbitmq-server-2.8.4/include/rabbit_auth_mechanism_spec.hrl --- rabbitmq-server-2.7.1/include/rabbit_auth_mechanism_spec.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit_auth_mechanism_spec.hrl 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License -%% at http://www.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and -%% limitations under the License. -%% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. -%% - --ifdef(use_specs). - --spec(description/0 :: () -> [{atom(), any()}]). --spec(should_offer/1 :: (rabbit_net:socket()) -> boolean()). --spec(init/1 :: (rabbit_net:socket()) -> any()). --spec(handle_response/2 :: (binary(), any()) -> - {'ok', rabbit_types:user()} | - {'challenge', binary(), any()} | - {'protocol_error', string(), [any()]} | - {'refused', string(), [any()]}). - --endif. diff -Nru rabbitmq-server-2.7.1/include/rabbit_backing_queue_spec.hrl rabbitmq-server-2.8.4/include/rabbit_backing_queue_spec.hrl --- rabbitmq-server-2.7.1/include/rabbit_backing_queue_spec.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit_backing_queue_spec.hrl 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License -%% at http://www.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and -%% limitations under the License. -%% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. -%% - --type(fetch_result(Ack) :: - ('empty' | - %% Message, IsDelivered, AckTag, Remaining_Len - {rabbit_types:basic_message(), boolean(), Ack, non_neg_integer()})). --type(is_durable() :: boolean()). --type(attempt_recovery() :: boolean()). --type(purged_msg_count() :: non_neg_integer()). --type(confirm_required() :: boolean()). --type(async_callback() :: fun ((atom(), fun ((atom(), state()) -> state())) -> 'ok')). --type(duration() :: ('undefined' | 'infinity' | number())). - --spec(start/1 :: ([rabbit_amqqueue:name()]) -> 'ok'). --spec(stop/0 :: () -> 'ok'). --spec(init/3 :: (rabbit_types:amqqueue(), attempt_recovery(), - async_callback()) -> state()). --spec(terminate/2 :: (any(), state()) -> state()). --spec(delete_and_terminate/2 :: (any(), state()) -> state()). --spec(purge/1 :: (state()) -> {purged_msg_count(), state()}). --spec(publish/4 :: (rabbit_types:basic_message(), - rabbit_types:message_properties(), pid(), state()) -> - state()). --spec(publish_delivered/5 :: (true, rabbit_types:basic_message(), - rabbit_types:message_properties(), pid(), state()) - -> {ack(), state()}; - (false, rabbit_types:basic_message(), - rabbit_types:message_properties(), pid(), state()) - -> {undefined, state()}). --spec(drain_confirmed/1 :: (state()) -> {[rabbit_guid:guid()], state()}). --spec(dropwhile/2 :: - (fun ((rabbit_types:message_properties()) -> boolean()), state()) - -> state()). --spec(fetch/2 :: (true, state()) -> {fetch_result(ack()), state()}; - (false, state()) -> {fetch_result(undefined), state()}). --spec(ack/2 :: ([ack()], state()) -> {[rabbit_guid:guid()], state()}). --spec(requeue/2 :: ([ack()], state()) - -> {[rabbit_guid:guid()], state()}). --spec(len/1 :: (state()) -> non_neg_integer()). --spec(is_empty/1 :: (state()) -> boolean()). --spec(set_ram_duration_target/2 :: - (duration(), state()) -> state()). --spec(ram_duration/1 :: (state()) -> {duration(), state()}). --spec(needs_timeout/1 :: (state()) -> 'false' | 'timed' | 'idle'). --spec(timeout/1 :: (state()) -> state()). --spec(handle_pre_hibernate/1 :: (state()) -> state()). --spec(status/1 :: (state()) -> [{atom(), any()}]). --spec(invoke/3 :: (atom(), fun ((atom(), A) -> A), state()) -> state()). --spec(is_duplicate/2 :: - (rabbit_types:basic_message(), state()) -> - {'false'|'published'|'discarded', state()}). --spec(discard/3 :: (rabbit_types:basic_message(), pid(), state()) -> state()). diff -Nru rabbitmq-server-2.7.1/include/rabbit_exchange_type_spec.hrl rabbitmq-server-2.8.4/include/rabbit_exchange_type_spec.hrl --- rabbitmq-server-2.7.1/include/rabbit_exchange_type_spec.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit_exchange_type_spec.hrl 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License -%% at http://www.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and -%% limitations under the License. -%% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. -%% - --ifdef(use_specs). - --type(tx() :: 'transaction' | 'none'). --type(serial() :: pos_integer() | tx()). - --spec(description/0 :: () -> [{atom(), any()}]). --spec(serialise_events/0 :: () -> boolean()). --spec(route/2 :: (rabbit_types:exchange(), rabbit_types:delivery()) - -> rabbit_router:match_result()). --spec(validate/1 :: (rabbit_types:exchange()) -> 'ok'). --spec(create/2 :: (tx(), rabbit_types:exchange()) -> 'ok'). --spec(delete/3 :: (tx(), rabbit_types:exchange(), - [rabbit_types:binding()]) -> 'ok'). --spec(add_binding/3 :: (serial(), rabbit_types:exchange(), - rabbit_types:binding()) -> 'ok'). --spec(remove_bindings/3 :: (serial(), rabbit_types:exchange(), - [rabbit_types:binding()]) -> 'ok'). --spec(assert_args_equivalence/2 :: - (rabbit_types:exchange(), rabbit_framing:amqp_table()) - -> 'ok' | rabbit_types:connection_exit()). - --endif. diff -Nru rabbitmq-server-2.7.1/include/rabbit.hrl rabbitmq-server-2.8.4/include/rabbit.hrl --- rabbitmq-server-2.7.1/include/rabbit.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -record(user, {username, @@ -56,9 +56,11 @@ -record(binding, {source, key, destination, args = []}). -record(reverse_binding, {destination, key, source, args = []}). +-record(topic_trie_node, {trie_node, edge_count, binding_count}). -record(topic_trie_edge, {trie_edge, node_id}). -record(topic_trie_binding, {trie_binding, value = const}). +-record(trie_node, {exchange_name, node_id}). -record(trie_edge, {exchange_name, node_id, word}). -record(trie_binding, {exchange_name, node_id, destination}). @@ -84,7 +86,7 @@ %%---------------------------------------------------------------------------- --define(COPYRIGHT_MESSAGE, "Copyright (C) 2007-2011 VMware, Inc."). +-define(COPYRIGHT_MESSAGE, "Copyright (C) 2007-2012 VMware, Inc."). -define(INFORMATION_MESSAGE, "Licensed under the MPL. See http://www.rabbitmq.com/"). -define(PROTOCOL_VERSION, "AMQP 0-9-1 / 0-9 / 0-8"). -define(ERTS_MINIMUM, "5.6.3"). @@ -93,16 +95,7 @@ -define(HIBERNATE_AFTER_MIN, 1000). -define(DESIRED_HIBERNATE, 10000). +-define(CREDIT_DISC_BOUND, {2000, 500}). -define(ROUTING_HEADERS, [<<"CC">>, <<"BCC">>]). -define(DELETED_HEADER, <<"BCC">>). - --ifdef(debug). --define(LOGDEBUG0(F), rabbit_log:debug(F)). --define(LOGDEBUG(F,A), rabbit_log:debug(F,A)). --define(LOGMESSAGE(D,C,M,Co), rabbit_log:message(D,C,M,Co)). --else. --define(LOGDEBUG0(F), ok). --define(LOGDEBUG(F,A), ok). --define(LOGMESSAGE(D,C,M,Co), ok). --endif. diff -Nru rabbitmq-server-2.7.1/include/rabbit_msg_store.hrl rabbitmq-server-2.8.4/include/rabbit_msg_store.hrl --- rabbitmq-server-2.7.1/include/rabbit_msg_store.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit_msg_store.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -include("rabbit.hrl"). diff -Nru rabbitmq-server-2.7.1/include/rabbit_msg_store_index.hrl rabbitmq-server-2.8.4/include/rabbit_msg_store_index.hrl --- rabbitmq-server-2.7.1/include/rabbit_msg_store_index.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/include/rabbit_msg_store_index.hrl 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License -%% at http://www.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and -%% limitations under the License. -%% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. -%% - --include("rabbit_msg_store.hrl"). - -%%---------------------------------------------------------------------------- - --ifdef(use_specs). - --type(dir() :: any()). --type(index_state() :: any()). --type(keyvalue() :: any()). --type(fieldpos() :: non_neg_integer()). --type(fieldvalue() :: any()). - --spec(new/1 :: (dir()) -> index_state()). --spec(recover/1 :: (dir()) -> rabbit_types:ok_or_error2(index_state(), any())). --spec(lookup/2 :: - (rabbit_types:msg_id(), index_state()) -> ('not_found' | keyvalue())). --spec(insert/2 :: (keyvalue(), index_state()) -> 'ok'). --spec(update/2 :: (keyvalue(), index_state()) -> 'ok'). --spec(update_fields/3 :: (rabbit_types:msg_id(), ({fieldpos(), fieldvalue()} | - [{fieldpos(), fieldvalue()}]), - index_state()) -> 'ok'). --spec(delete/2 :: (rabbit_types:msg_id(), index_state()) -> 'ok'). --spec(delete_object/2 :: (keyvalue(), index_state()) -> 'ok'). --spec(delete_by_file/2 :: (fieldvalue(), index_state()) -> 'ok'). --spec(terminate/1 :: (index_state()) -> any()). - --endif. - -%%---------------------------------------------------------------------------- diff -Nru rabbitmq-server-2.7.1/LICENSE rabbitmq-server-2.8.4/LICENSE --- rabbitmq-server-2.7.1/LICENSE 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/LICENSE 2012-06-22 16:03:48.000000000 +0000 @@ -4,12 +4,15 @@ info@rabbitmq.com. The files amqp-rabbitmq-0.8.json and amqp-rabbitmq-0.9.1.json are -"Copyright (C) 2008-2011 VMware", Inc. and are covered by the MIT +"Copyright (C) 2008-2012 VMware", Inc. and are covered by the MIT license. -Mochiweb is "Copyright (c) 2007 Mochi Media, Inc." and is covered by -the MIT license. It was downloaded from -http://github.com/mochi/mochiweb/ +Webmachine is Copyright (c) Basho Technologies and is covered by the +Apache License 2.0. It was downloaded from http://webmachine.basho.com/ + +glMatrix is "Copyright (c) 2011, Brandon Jones" and is covered by the +BSD 2-Clause license. It was downloaded from +http://code.google.com/p/glmatrix/ Eldap is "Copyright (c) 2010, Torbjorn Tornkvist" and is covered by the MIT license. It was downloaded from https://github.com/etnt/eldap @@ -24,12 +27,9 @@ covered by the MIT license. It was downloaded from http://code.quirkey.com/sammy/ -glMatrix is "Copyright (c) 2011, Brandon Jones" and is covered by the -BSD 2-Clause license. It was downloaded from -http://code.google.com/p/glmatrix/ - -Webmachine is Copyright (c) Basho Technologies and is covered by the -Apache License 2.0. It was downloaded from http://webmachine.basho.com/ +Mochiweb is "Copyright (c) 2007 Mochi Media, Inc." and is covered by +the MIT license. It was downloaded from +http://github.com/mochi/mochiweb/ The MIT license is as follows: @@ -89,7 +89,7 @@ Authors and Copyright are as described below: The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2007-2011 VMware, Inc. All rights reserved. + Copyright (c) 2007-2012 VMware, Inc. All rights reserved. MOZILLA PUBLIC LICENSE @@ -541,7 +541,7 @@ The Original Code is RabbitMQ. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2007-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2007-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/LICENSE-MPL-RabbitMQ rabbitmq-server-2.8.4/LICENSE-MPL-RabbitMQ --- rabbitmq-server-2.7.1/LICENSE-MPL-RabbitMQ 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/LICENSE-MPL-RabbitMQ 2012-06-22 16:03:48.000000000 +0000 @@ -447,7 +447,7 @@ The Original Code is RabbitMQ Visualiser. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2011-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2011-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/Makefile rabbitmq-server-2.8.4/Makefile --- rabbitmq-server-2.7.1/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -17,7 +17,7 @@ TARGETS=$(EBIN_DIR)/rabbit.app $(INCLUDE_DIR)/rabbit_framing.hrl $(BEAM_TARGETS) plugins WEB_URL=http://www.rabbitmq.com/ MANPAGES=$(patsubst %.xml, %.gz, $(wildcard $(DOCS_DIR)/*.[0-9].xml)) -WEB_MANPAGES=$(patsubst %.xml, %.man.xml, $(wildcard $(DOCS_DIR)/*.[0-9].xml) $(DOCS_DIR)/rabbitmq-service.xml) +WEB_MANPAGES=$(patsubst %.xml, %.man.xml, $(wildcard $(DOCS_DIR)/*.[0-9].xml) $(DOCS_DIR)/rabbitmq-service.xml $(DOCS_DIR)/rabbitmq-echopid.xml) USAGES_XML=$(DOCS_DIR)/rabbitmqctl.1.xml $(DOCS_DIR)/rabbitmq-plugins.1.xml USAGES_ERL=$(foreach XML, $(USAGES_XML), $(call usage_xml_to_erl, $(XML))) QC_MODULES := rabbit_backing_queue_qc @@ -42,9 +42,9 @@ RABBIT_PLT=rabbit.plt ifndef USE_SPECS -# our type specs rely on features and bug fixes in dialyzer that are -# only available in R14B03 upwards (R14B03 is erts 5.8.4) -USE_SPECS:=$(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] >= [5,8,4]), halt().') +# our type specs rely on callback specs, which are available in R15B +# upwards. +USE_SPECS:=$(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] >= [5,9]), halt().') endif ifndef USE_PROPER_QC @@ -56,7 +56,7 @@ #other args: +native +"{hipe,[o3,verbose]}" -Ddebug=true +debug_info +no_strict_record_tests ERLC_OPTS=-I $(INCLUDE_DIR) -o $(EBIN_DIR) -Wall -v +debug_info $(call boolean_macro,$(USE_SPECS),use_specs) $(call boolean_macro,$(USE_PROPER_QC),use_proper_qc) -VERSION=0.0.0 +VERSION?=0.0.0 PLUGINS_SRC_DIR?=$(shell [ -d "plugins-src" ] && echo "plugins-src" || echo ) PLUGINS_DIR=plugins TARBALL_NAME=rabbitmq-server-$(VERSION) @@ -207,7 +207,7 @@ -rm -f $(RABBITMQ_MNESIA_DIR).pid mkdir -p $(RABBITMQ_MNESIA_DIR) setsid sh -c "$(MAKE) run-background-node > $(RABBITMQ_MNESIA_DIR)/startup_log 2> $(RABBITMQ_MNESIA_DIR)/startup_err" & - sleep 1 + ./scripts/rabbitmqctl -n $(RABBITMQ_NODENAME) wait $(RABBITMQ_MNESIA_DIR).pid kernel start-rabbit-on-node: all echo "rabbit:start()." | $(ERL_CALL) @@ -216,12 +216,12 @@ stop-rabbit-on-node: all echo "rabbit:stop()." | $(ERL_CALL) -set-memory-alarm: all - echo "alarm_handler:set_alarm({{vm_memory_high_watermark, node()}, []})." | \ +set-resource-alarm: all + echo "alarm_handler:set_alarm({{resource_limit, $(SOURCE), node()}, []})." | \ $(ERL_CALL) -clear-memory-alarm: all - echo "alarm_handler:clear_alarm({vm_memory_high_watermark, node()})." | \ +clear-resource-alarm: all + echo "alarm_handler:clear_alarm({resource_limit, $(SOURCE), node()})." | \ $(ERL_CALL) stop-node: @@ -246,7 +246,8 @@ srcdist: distclean mkdir -p $(TARGET_SRC_DIR)/codegen cp -r ebin src include LICENSE LICENSE-MPL-RabbitMQ INSTALL README $(TARGET_SRC_DIR) - sed -i.save 's/%%VSN%%/$(VERSION)/' $(TARGET_SRC_DIR)/ebin/rabbit_app.in && rm -f $(TARGET_SRC_DIR)/ebin/rabbit_app.in.save + sed 's/%%VSN%%/$(VERSION)/' $(TARGET_SRC_DIR)/ebin/rabbit_app.in > $(TARGET_SRC_DIR)/ebin/rabbit_app.in.tmp && \ + mv $(TARGET_SRC_DIR)/ebin/rabbit_app.in.tmp $(TARGET_SRC_DIR)/ebin/rabbit_app.in cp -r $(AMQP_CODEGEN_DIR)/* $(TARGET_SRC_DIR)/codegen/ cp codegen.py Makefile generate_app generate_deps calculate-relative $(TARGET_SRC_DIR) @@ -315,7 +316,7 @@ cp -r ebin include LICENSE* INSTALL $(TARGET_DIR) chmod 0755 scripts/* - for script in rabbitmq-env rabbitmq-server rabbitmqctl rabbitmq-plugins; do \ + for script in rabbitmq-env rabbitmq-server rabbitmqctl rabbitmq-plugins rabbitmq-defaults; do \ cp scripts/$$script $(TARGET_DIR)/sbin; \ [ -e $(SBIN_DIR)/$$script ] || ln -s $(SCRIPTS_REL_PATH)/$$script $(SBIN_DIR)/$$script; \ done @@ -346,10 +347,10 @@ # Note that all targets which depend on clean must have clean in their # name. Also any target that doesn't depend on clean should not have # clean in its name, unless you know that you don't need any of the -# automatic dependency generation for that target (eg cleandb). +# automatic dependency generation for that target (e.g. cleandb). # We want to load the dep file if *any* target *doesn't* contain -# "clean" - i.e. if removing all clean-like targets leaves something +# "clean" - i.e. if removing all clean-like targets leaves something. ifeq "$(MAKECMDGOALS)" "" TESTABLEGOALS:=$(.DEFAULT_GOAL) diff -Nru rabbitmq-server-2.7.1/plugins-src/do-package.mk rabbitmq-server-2.8.4/plugins-src/do-package.mk --- rabbitmq-server-2.7.1/plugins-src/do-package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/do-package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -286,7 +286,7 @@ define run_broker rm -rf $(TEST_TMPDIR) mkdir -p $(foreach D,log plugins $(NODENAME),$(TEST_TMPDIR)/$(D)) - cp -a $(PACKAGE_DIR)/dist/*.ez $(TEST_TMPDIR)/plugins + cp -p $(PACKAGE_DIR)/dist/*.ez $(TEST_TMPDIR)/plugins $(call copy,$(3),$(TEST_TMPDIR)/plugins) rm -f $(TEST_TMPDIR)/plugins/rabbit_common*.ez for plugin in \ @@ -375,7 +375,7 @@ mkdir -p $(APP_DIR)/ebin $(APP_DIR)/include @echo [elided] copy beams to ebin @$(call copy,$(EBIN_BEAMS),$(APP_DIR)/ebin) - cp -a $(APP_FILE) $(APP_DIR)/ebin/$(APP_NAME).app + cp -p $(APP_FILE) $(APP_DIR)/ebin/$(APP_NAME).app $(call copy,$(INCLUDE_HRLS),$(APP_DIR)/include) $(construct_app_commands) touch $$@ @@ -414,8 +414,8 @@ @echo [elided] generate deps @$$(if $$^,echo $$(subst : ,:,$$(foreach F,$$^,$$(abspath $$(F)):)) | escript $(abspath $(UMBRELLA_BASE_DIR)/generate_deps) $$@ '$$$$(EBIN_DIR)',echo >$$@) @echo [elided] fix test deps - @$$(foreach F,$(TEST_EBIN_BEAMS),sed -i -e 's|^$$$$(EBIN_DIR)/$$(notdir $$(F)):|$$$$(TEST_EBIN_DIR)/$$(notdir $$(F)):|' $$@ && ) : - sed -i -e 's|$$@|$$$$(DEPS_FILE)|' $$@ + @$$(foreach F,$(TEST_EBIN_BEAMS),sed -e 's|^$$$$(EBIN_DIR)/$$(notdir $$(F)):|$$$$(TEST_EBIN_DIR)/$$(notdir $$(F)):|' $$@ > $$@.tmp && mv $$@.tmp $$@ && ) : + sed -e 's|$$@|$$$$(DEPS_FILE)|' $$@ > $$@.tmp && mv $$@.tmp $$@ $(eval $(call safe_include,$(DEPS_FILE))) diff -Nru rabbitmq-server-2.7.1/plugins-src/eldap-wrapper/eldap-git/doc/draft-ietf-asid-ldap-c-api-00.txt rabbitmq-server-2.8.4/plugins-src/eldap-wrapper/eldap-git/doc/draft-ietf-asid-ldap-c-api-00.txt --- rabbitmq-server-2.7.1/plugins-src/eldap-wrapper/eldap-git/doc/draft-ietf-asid-ldap-c-api-00.txt 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/eldap-wrapper/eldap-git/doc/draft-ietf-asid-ldap-c-api-00.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,3030 +0,0 @@ - - - - - - -Network Working Group T. Howes -INTERNET-DRAFT Netscape Communications Corp. -Intended Category: Standards Track M. Smith -Obsoletes: RFC 1823 Netscape Communications Corp. -Expires: January 1998 A. Herron - Microsoft Corp. - C. Weider - Microsoft Corp. - M. Wahl - Critical Angle, Inc. - - 29 July 1997 - - - The C LDAP Application Program Interface - - - - -1. Status of this Memo - -This draft document will be submitted to the RFC Editor as a Standards -Track document. Distribution of this memo is unlimited. Please send com- -ments to the authors. - -This document is an Internet-Draft. Internet-Drafts are working docu- -ments of the Internet Engineering Task Force (IETF), its areas, and its -working groups. Note that other groups may also distribute working -documents as Internet-Drafts. - -Internet-Drafts are draft documents valid for a maximum of six months -and may be updated, replaced, or obsoleted by other documents at any -time. It is inappropriate to use Internet-Drafts as reference material -or to cite them other than as ``work in progress.'' - -To learn the current status of any Internet-Draft, please check the -``1id-abstracts.txt'' listing contained in the Internet-Drafts Shadow -Directories on ds.internic.net (US East Coast), nic.nordu.net (Europe), -ftp.isi.edu (US West Coast), or munnari.oz.au (Pacific Rim). - -2. Introduction - -This document defines a C language application program interface to the -lightweight directory access protocol (LDAP). This document replaces the -previous definition of this API, defined in RFC 1823, updating it to -include support for features found in version 3 of the LDAP protocol. -New extended operation functions were added to support LDAPv3 features -such as controls. In addition, other LDAP API changes were made to - - - -Expires: January 1998 [Page 1] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -support information hiding and thread safety. - -The C LDAP API is designed to be powerful, yet simple to use. It defines -compatible synchronous and asynchronous interfaces to LDAP to suit a -wide variety of applications. This document gives a brief overview of -the LDAP model, then an overview of how the API is used by an applica- -tion program to obtain LDAP information. The API calls are described in -detail, followed by an appendix that provides some example code demon- -strating the use of the API. This document provides information to the -Internet community. It does not specify any standard. - -3. Overview of the LDAP Model - -LDAP is the lightweight directory access protocol, described in [2] and -[6]. It can provide a lightweight frontend to the X.500 directory [1], -or a stand-alone service. In either mode, LDAP is based on a client- -server model in which a client makes a TCP connection to an LDAP server, -over which it sends requests and receives responses. - -The LDAP information model is based on the entry, which contains infor- -mation about some object (e.g., a person). Entries are composed of -attributes, which have a type and one or more values. Each attribute has -a syntax that determines what kinds of values are allowed in the attri- -bute (e.g., ASCII characters, a jpeg photograph, etc.) and how those -values behave during directory operations (e.g., is case significant -during comparisons). - -Entries may be organized in a tree structure, usually based on politi- -cal, geographical, and organizational boundaries. Each entry is uniquely -named relative to its sibling entries by its relative distinguished name -(RDN) consisting of one or more distinguished attribute values from the -entry. At most one value from each attribute may be used in the RDN. -For example, the entry for the person Babs Jensen might be named with -the "Barbara Jensen" value from the commonName attribute. - -A globally unique name for an entry, called a distinguished name or DN, -is constructed by concatenating the sequence of RDNs from the entry up -to the root of the tree. For example, if Babs worked for the University -of Michigan, the DN of her U-M entry might be "cn=Barbara Jensen, -o=University of Michigan, c=US". The DN format used by LDAP is defined -in [4]. - -Operations are provided to authenticate, search for and retrieve infor- -mation, modify information, and add and delete entries from the tree. -The next sections give an overview of how the API is used and detailed -descriptions of the LDAP API calls that implement all of these func- -tions. - - - - -Expires: January 1998 [Page 2] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -4. Overview of LDAP API Use - -An application generally uses the C LDAP API in four simple steps. - -- Initialize an LDAP session with a default LDAP server. The - ldap_init() function returns a handle to the session, allowing mul- - tiple connections to be open at once. - -- Authenticate to the LDAP server. The ldap_bind() function and - friends support a variety of authentication methods. - -- Perform some LDAP operations and obtain some results. ldap_search() - and friends return results which can be parsed by - ldap_result2error(), ldap_first_entry(), ldap_next_entry(), etc. - -- Close the session. The ldap_unbind() function closes the connec- - tion. - -Operations can be performed either synchronously or asynchronously. The -names of the synchronous functions end in _s. For example, a synchronous -search can be completed by calling ldap_search_s(). An asynchronous -search can be initiated by calling ldap_search(). All synchronous rou- -tines return an indication of the outcome of the operation (e.g, the -constant LDAP_SUCCESS or some other error code). The asynchronous rou- -tines return the message id of the operation initiated. This id can be -used in subsequent calls to ldap_result() to obtain the result(s) of the -operation. An asynchronous operation can be abandoned by calling -ldap_abandon(). - -Results and errors are returned in an opaque structure called LDAPMes- -sage. Routines are provided to parse this structure, step through -entries and attributes returned, etc. Routines are also provided to -interpret errors. Later sections of this document describe these rou- -tines in more detail. - -LDAP version 3 servers may return referrals to other servers. By -default, implementations of this API will attempt to follow referrals -automatically for the application. This behavior can be disabled glo- -bally (using the ldap_set_option() call) or on a per-request basis -through the use of a client control. - -As in the LDAPv3 protocol itself, all DNs and string values that are -passed into or produced by the C LDAP API are represented as UTF-8[10] -characters. - -For compatibility with existing applications, implementations of this -API will by default use version 2 of the LDAP protocol. Applications -that intend to take advantage of LDAP version 3 features will need to - - - -Expires: January 1998 [Page 3] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -use the ldap_set_option() call with a LDAP_OPT_PROTOCOL_VERSION to -switch to version 3. - - -5. Common Data Structures - -Some data structures that are common to several LDAP API functions are -defined here: - - typedef struct ldap LDAP; - - typedef struct ldapmsg LDAPMessage; - - struct berval { - unsigned long bv_len; - char *bv_val; - }; - - struct timeval { - long tv_sec; - long tv_usec; - }; - -The LDAP structure is an opaque data type that represents an LDAP ses- -sion Typically this corresponds to a connection to a single server, but -it may encompass several server connections in the face of LDAPv3 refer- -rals. - -The LDAPMessage structure is an opaque data type that is used to return -results and error information. - -The berval structure is used to represent arbitrary binary data and its -fields have the following meanings: - -bv_len Length of data in bytes. - -bv_val A pointer to the data itself. - - -The timeval structure is used to represent an interval of time and its -fields have the following meanings: - -tv_sec Seconds component of time interval. - -tv_usec Microseconds component of time interval. - - - - - - -Expires: January 1998 [Page 4] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -6. LDAP Error Codes - -Many of the LDAP API routines return LDAP error codes, some of which -indicate local errors and some of which may be returned by servers. -Supported error codes are (hexadecimal values are given in parentheses -after the constant): - - LDAP_SUCCESS (0x00) - LDAP_OPERATIONS_ERROR( 0x01) - LDAP_PROTOCOL_ERROR (0x02) - LDAP_TIMELIMIT_EXCEEDED (0x03) - LDAP_SIZELIMIT_EXCEEDED (0x04) - LDAP_COMPARE_FALSE (0x05) - LDAP_COMPARE_TRUE (0x06) - LDAP_STRONG_AUTH_NOT_SUPPORTED (0x07) - LDAP_STRONG_AUTH_REQUIRED (0x08) - LDAP_REFERRAL (0x0a) -- new in LDAPv3 - LDAP_ADMINLIMIT_EXCEEDED (0x0b) -- new in LDAPv3 - LDAP_UNAVAILABLE_CRITICAL_EXTENSION (0x0c) -- new in LDAPv3 - LDAP_CONFIDENTIALITY_REQUIRED (0x0d) -- new in LDAPv3 - LDAP_NO_SUCH_ATTRIBUTE (0x10) - LDAP_UNDEFINED_TYPE (0x11) - LDAP_INAPPROPRIATE_MATCHING (0x12) - LDAP_CONSTRAINT_VIOLATION (0x13) - LDAP_TYPE_OR_VALUE_EXISTS (0x14) - LDAP_INVALID_SYNTAX (0x15) - LDAP_NO_SUCH_OBJECT (0x20) - LDAP_ALIAS_PROBLEM (0x21) - LDAP_INVALID_DN_SYNTAX (0x22) - LDAP_IS_LEAF (0x23) -- not used in LDAPv3 - LDAP_ALIAS_DEREF_PROBLEM (0x24) - LDAP_INAPPROPRIATE_AUTH (0x30) - LDAP_INVALID_CREDENTIALS (0x31) - LDAP_INSUFFICIENT_ACCESS (0x32) - LDAP_BUSY (0x33) - LDAP_UNAVAILABLE (0x34) - LDAP_UNWILLING_TO_PERFORM (0x35) - LDAP_LOOP_DETECT (0x36) - LDAP_NAMING_VIOLATION (0x40) - LDAP_OBJECT_CLASS_VIOLATION (0x41) - LDAP_NOT_ALLOWED_ON_NONLEAF (0x42) - LDAP_NOT_ALLOWED_ON_RDN (0x43) - LDAP_ALREADY_EXISTS (0x44) - LDAP_NO_OBJECT_CLASS_MODS (0x45) - LDAP_RESULTS_TOO_LARGE (0x46) - LDAP_AFFECTS_MULTIPLE_DSAS (0x47) -- new in LDAPv3 - LDAP_OTHER (0x50) - LDAP_SERVER_DOWN (0x51) - - - -Expires: January 1998 [Page 5] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - LDAP_LOCAL_ERROR (0x52) - LDAP_ENCODING_ERROR (0x53) - LDAP_DECODING_ERROR (0x54) - LDAP_TIMEOUT (0x55) - LDAP_AUTH_UNKNOWN (0x56) - LDAP_FILTER_ERROR (0x57) - LDAP_USER_CANCELLED (0x58) - LDAP_PARAM_ERROR (0x59) - LDAP_NO_MEMORY (0x5a) - LDAP_CONNECT_ERROR (0x5b) - LDAP_NOT_SUPPORTED (0x5c) - LDAP_CONTROL_NOT_FOUND (0x5d) - LDAP_NO_RESULTS_RETURNED (0x5e) - LDAP_MORE_RESULTS_TO_RETURN (0x5f) - LDAP_CLIENT_LOOP (0x60) - LDAP_REFERRAL_LIMIT_EXCEEDED (0x61) - - -7. Performing LDAP Operations - -This section describes each LDAP operation API call in detail. All func- -tions take a "session handle," a pointer to an LDAP structure containing -per-connection information. Many routines return results in an LDAPMes- -sage structure. These structures and others are described as needed -below. - - -7.1. Initializing an LDAP Session - -ldap_init() initializes a session with an LDAP server. The server is not -actually contacted until an operation is performed that requires it, -allowing various options to be set after initialization. - - LDAP *ldap_init( - char *hostname, - int portno - ); - -Use of the following routine is deprecated. - - LDAP *ldap_open( - char *hostname, - int portno - ); - -Parameters are: - -hostname Contains a space-separated list of hostnames or dotted strings - - - -Expires: January 1998 [Page 6] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - representing the IP address of hosts running an LDAP server to - connect to. Each hostname in the list can include an optional - port number which is separated from the host itself with a - colon (:) character. The hosts are tried in the order listed, - stopping with the first one to which a successful connection is - made. Note that only ldap_open() attempts to make the connec- - tion before returning to the caller. ldap_init() does not con- - nect to the LDAP server. - -portno Contains the TCP port number to connect to. The default LDAP - port of 389 can be obtained by supplying the constant - LDAP_PORT. If a host includes a port number then this parame- - ter is ignored. - -ldap_init() and ldap_open() both return a "session handle," a pointer to -an opaque structure that should be passed to subsequent calls pertaining -to the session. These routines return NULL if the session cannot be ini- -tialized in which case the operating system error reporting mechanism -can be checked to see why the call failed. - -Note that if you connect to an LDAPv2 server, one of the ldap_bind() -calls described below must be completed before other operations can be -performed on the session. LDAPv3 does not require that a bind operation -be completed before other operations can be performed. - -The calling program can set various attributes of the session by calling -the routines described in the next section. - - -7.2. LDAP Session Handle Options - -The LDAP session handle returned by ldap_init() is a pointer to an -opaque data type representing an LDAP session. Formerly, this data type -was a structure exposed to the caller, and various fields in the struc- -ture could be set to control aspects of the session, such as size and -time limits on searches. - -In the interest of insulating callers from inevitable changes to this -structure, these aspects of the session are now accessed through a pair -of accessor functions, described below. - -ldap_get_option() is used to access the current value of various -session-wide parameters. ldap_set_option() is used to set the value of -these parameters. - - int ldap_get_option( - LDAP *ld, - int option, - - - -Expires: January 1998 [Page 7] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - void *outvalue - ); - - int ldap_set_option( - LDAP *ld, - int option, - void *invalue - ); - -Parameters are: - -ld The session handle. - -option The name of the option being accessed or set. This parameter - should be one of the following constants, which have the indi- - cated meanings. After the constant the actual value of the con- - stant is listed in hexadecimal in parentheses followed by the - type of the corresponding outvalue or invalue parameter. - - LDAP_OPT_DESC (0x01) int * - The underlying socket descriptor corresponding to the default - LDAP connection. - - LDAP_OPT_DEREF (0x02) int * - Controls how aliases are handled during search. It can have - one of the following values: LDAP_DEREF_NEVER (0x00), - LDAP_DEREF_SEARCHING (0x01), LDAP_DEREF_FINDING (0x02), or - LDAP_DEREF_ALWAYS (0x03). The LDAP_DEREF_SEARCHING value - means aliases should be dereferenced during the search but not - when locating the base object of the search. The - LDAP_DEREF_FINDING value means aliases should be dereferenced - when locating the base object but not during the search. - - LDAP_OPT_SIZELIMIT (0x03) int * - A limit on the number of entries to return from a search. A - value of zero means no limit. - - LDAP_OPT_TIMELIMIT (0x04) int * - A limit on the number of seconds to spend on a search. A value - of zero means no limit - - LDAP_OPT_REBIND_FN (0x06) function pointer - See the discussion of ldap_bind() and friends below. - - LDAP_OPT_REBIND_ARG (0x07) void * - See the discussion of ldap_bind() and friends below. - - LDAP_OPT_REFERRALS (0x08) void * - - - -Expires: January 1998 [Page 8] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - This option controls whether the LDAP library automatically - follows referrals returned by LDAP servers or not. It can be - set to one of the constants LDAP_OPT_ON or LDAP_OPT_OFF. - - LDAP_OPT_RESTART (0x09) void * - This option controls whether LDAP I/O operations should - automatically be restarted if they abort prematurely. It - should be set to one of the constants LDAP_OPT_ON or - LDAP_OPT_OFF. This option is useful if an LDAP I/O operation - may be interrupted prematurely, for example by a timer going - off, or other interrrupt. - - LDAP_OPT_PROTOCOL_VERSION (0x11) int * - This option indicates the version of the default LDAP server. - It can be one of the constants LDAP_VERSION2 or LDAP_VERSION3. - If no version is set the default is LDAP_VERSION2. - - LDAP_OPT_SERVER_CONTROLS (0x12) LDAPControl ** - A default list of LDAP server controls to be sent with each - request. See the Using Controls section below. - - LDAP_OPT_CLIENT_CONTROLS (0x13) LDAPControl ** - A default list of client controls that affect the LDAP ses- - sion. See the Using Controls section below. - - LDAP_OPT_HOST_NAME (0x30) char ** - The host name of the default LDAP server. - - LDAP_OPT_ERROR_NUMBER (0x31) int * - The code of the most recent LDAP error that occurred for this - session. - - LDAP_OPT_ERROR_STRING (0x32) char ** - The message returned with the most recent LDAP error that - occurred for this session. - - -outvalue The address of a place to put the value of the option. The - actual type of this parameter depends on the setting of the - option parameter. - -invalue A pointer to the value the option is to be given. The actual - type of this parameter depends on the setting of the option - parameter. The constants LDAP_OPT_ON and LDAP_OPT_OFF can be - given for options that have on or off settings. - - - - - - -Expires: January 1998 [Page 9] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -7.3. Working with controls - -LDAPv3 operations can be extended through the use of controls. Controls -may be sent to a server or returned to the client with any LDAP message. -These controls are referred to as server controls. - -The LDAP API also supports a client-side extension mechanism through the -use of client controls. These controls affect the behavior of the LDAP -API only and are never sent to a server. A common data structure is -used to represent both types of controls: - - typedef struct ldapcontrol { - char *ldctl_oid; - struct berval ldctl_value; - char ldctl_iscritical; - } LDAPControl, *PLDAPControl; - -The fields in the ldapcontrol structure have the following meanings: - -ldctl_oid The control type, represented as a string. - -ldctl_value The data associated with the control (if any). - -ldctl_iscritical Indicates whether the control is critical of not. If - this field is non-zero, the operation will only be car- - ried out if the control is recognized by the server - and/or client. - -Some LDAP API calls allocate an ldapcontrol structure or a NULL- -terminated array of ldapcontrol structures. The following routines can -be used to dispose of a single control or an array of controls: - - void ldap_control_free( LDAPControl *ctrl ); - void ldap_controls_free( LDAPControl **ctrls ); - -A set of controls that affect the entire session can be set using the -ldap_set_option() function (see above). A list of controls can also be -passed directly to some LDAP API calls such as ldap_search_ext(), in -which case any controls set for the session through the use of -ldap_set_option() are ignored. Control lists are represented as a NULL- -terminated array of pointers to ldapcontrol structures. - -Server controls are defined by LDAPv3 protocol extension documents; for -example, a control has been proposed to support server-side sorting of -search results [7]. - -No client controls are defined by this document but they may be defined -in future revisions or in any document that extends this API. - - - -Expires: January 1998 [Page 10] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -7.4. Authenticating to the directory - -The following functions are used to authenticate an LDAP client to an -LDAP directory server. - -The ldap_sasl_bind() and ldap_sasl_bind_s() functions can be used to do -general and extensible authentication over LDAP through the use of the -Simple Authentication Security Layer [8]. The routines both take the dn -to bind as, the method to use, as a dotted-string representation of an -OID identifying the method, and a struct berval holding the credentials. -The special constant value LDAP_SASL_SIMPLE ("") can be passed to -request simple authentication, or the simplified routines -ldap_simple_bind() or ldap_simple_bind_s() can be used. - - int ldap_sasl_bind( - LDAP *ld, - char *dn, - char *mechanism, - struct berval *cred, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - ); - - int ldap_sasl_bind_s( - LDAP *ld, - char *dn, - char *mechanism, - struct berval *cred, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - struct berval **servercredp - ); - - int ldap_simple_bind( - LDAP *ld, - char *dn, - char *passwd - ); - - int ldap_simple_bind_s( - LDAP *ld, - char *dn, - char *passwd - ); - - The use of the following routines is deprecated: - - - - -Expires: January 1998 [Page 11] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - int ldap_bind( LDAP *ld, char *dn, char *cred, int method ); - - int ldap_bind_s( LDAP *ld, char *dn, char *cred, int method ); - - int ldap_kerberos_bind( LDAP *ld, char *dn ); - - int ldap_kerberos_bind_s( LDAP *ld, char *dn ); - -Parameters are: - -ld The session handle. - -dn The name of the entry to bind as. - -mechanism Either LDAP_AUTH_SIMPLE_OID to get simple authentication, - or a dotted text string representing an OID identifying the - SASL method. - -cred The credentials with which to authenticate. Arbitrary - credentials can be passed using this parameter. The format - and content of the credentials depends on the setting of - the mechanism parameter. - -passwd For ldap_simple_bind(), the password to compare to the - entry's userPassword attribute. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_sasl_bind() call succeeds. - -servercredp This result parameter will be set to the credentials - returned by the server. This should be freed by calling - ldap_If no credentials are returned it will be set to NULL. - -Additional parameters for the deprecated routines are not described. -Interested readers are referred to RFC 1823. - -The ldap_sasl_bind() function initiates an asynchronous bind operation -and returns the constant LDAP_SUCCESS if the request was successfully -sent, or another LDAP error code if not. See the section below on error -handling for more information about possible errors and how to interpret -them. If successful, ldap_sasl_bind() places the message id of the -request in *msgidp. A subsequent call to ldap_result(), described below, -can be used to obtain the result of the bind. - - - - -Expires: January 1998 [Page 12] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -The ldap_simple_bind() function initiates a simple asynchronous bind -operation and returns the message id of the operation initiated. A sub- -sequent call to ldap_result(), described below, can be used to obtain -the result of the bind. In case of error, ldap_simple_bind() will return --1, setting the session error parameters in the LDAP structure appropri- -ately. - -The synchronous ldap_sasl_bind_s() and ldap_simple_bind_s() functions -both return the result of the operation, either the constant -LDAP_SUCCESS if the operation was successful, or another LDAP error code -if it was not. See the section below on error handling for more informa- -tion about possible errors and how to interpret them. - -Note that if an LDAPv2 server is contacted, no other operations over the -connection should be attempted before a bind call has successfully com- -pleted. - -Subsequent bind calls can be used to re-authenticate over the same con- -nection, and multistep SASL sequences can be accomplished through a -sequence of calls to ldap_sasl_bind() or ldap_sasl_bind_s(). - - -7.5. Closing the session - -The following functions are used to unbind from the directory, close the -connection, and dispose of the session handle. - - int ldap_unbind( LDAP *ld ); - - int ldap_unbind_s( LDAP *ld ); - -Parameters are: - -ld The session handle. - -ldap_unbind() and ldap_unbind_s() both work synchronously, unbinding -from the directory, closing the connection, and freeing up the ld struc- -ture before returning. There is no server response to an unbind opera- -tion. ldap_unbind() returns LDAP_SUCCESS (or another LDAP error code if -the request cannot be sent to the LDAP server). After a call to -ldap_unbind() or ldap_unbind_s(), the session handle ld is invalid. - - -7.6. Searching - -The following functions are used to search the LDAP directory, returning -a requested set of attributes for each entry matched. There are five -variations. - - - -Expires: January 1998 [Page 13] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - int ldap_search_ext( - LDAP *ld, - char *base, - int scope, - char *filter, - char **attrs, - int attrsonly, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - struct timeval *timeoutp, - int sizelimit, - int *msgidp - ); - - int ldap_search_ext_s( - LDAP *ld, - char *base, - int scope, - char *filter, - char **attrs, - int attrsonly, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - struct timeval *timeoutp, - int sizelimit, - LDAPMessage **res - ); - - int ldap_search( - LDAP *ld, - char *base, - int scope, - char *filter, - char **attrs, - int attrsonly - ); - - int ldap_search_s( - LDAP *ld, - char *base, - int scope, - char *filter, - char **attrs, - int attrsonly, - LDAPMessage **res - ); - - int ldap_search_st( - - - -Expires: January 1998 [Page 14] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - LDAP *ld, - char *base, - int scope, - char *filter, - char **attrs, - int attrsonly, - struct timeval *timeout, - LDAPMessage **res - ); - -Parameters are: - -ld The session handle. - -base The dn of the entry at which to start the search. - -scope One of LDAP_SCOPE_BASE (0x00), LDAP_SCOPE_ONELEVEL (0x01), - or LDAP_SCOPE_SUBTREE (0x02), indicating the scope of the - search. - -filter A character string as described in [3], representing the - search filter. - -attrs A NULL-terminated array of strings indicating which attri- - butes to return for each matching entry. Passing NULL for - this parameter causes all available attributes to be - retrieved. - -attrsonly A boolean value that should be zero if both attribute types - and values are to be returned, non-zero if only types are - wanted. - -timeout For the ldap_search_st() function, this specifies the local - search timeout value. For the ldap_search_ext() and - ldap_search_ext_s() functions, this specifies both the - local search timeout value and the operation time limit - that is sent to the server within the search request. - -res For the synchronous calls, this is a result parameter which - will contain the results of the search upon completion of - the call. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_search_ext() call succeeds. - - - -Expires: January 1998 [Page 15] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -There are three options in the session handle ld which potentially -affect how the search is performed. They are: - -LDAP_OPT_SIZELIMIT - A limit on the number of entries to return from the search. - A value of zero means no limit. Note that the value from - the session handle is ignored when using the - ldap_search_ext() or ldap_search_ext_s() functions. - -LDAP_OPT_TIMELIMIT - A limit on the number of seconds to spend on the search. A - value of zero means no limit. Note that the value from the - session handle is ignored when using the ldap_search_ext() - or ldap_search_ext_s() functions. - -LDAP_OPT_DEREF - One of LDAP_DEREF_NEVER (0x00), LDAP_DEREF_SEARCHING - (0x01), LDAP_DEREF_FINDING (0x02), or LDAP_DEREF_ALWAYS - (0x03), specifying how aliases should be handled during the - search. The LDAP_DEREF_SEARCHING value means aliases should - be dereferenced during the search but not when locating the - base object of the search. The LDAP_DEREF_FINDING value - means aliases should be dereferenced when locating the base - object but not during the search. - -The ldap_search_ext() function initiates an asynchronous search opera- -tion and returns the constant LDAP_SUCCESS if the request was success- -fully sent, or another LDAP error code if not. See the section below on -error handling for more information about possible errors and how to -interpret them. If successful, ldap_search_ext() places the message id -of the request in *msgidp. A subsequent call to ldap_result(), described -below, can be used to obtain the results from the search. These results -can be parsed using the result parsing routines described in detail -later. - -Similar to ldap_search_ext(), the ldap_search() function initiates an -asynchronous search operation and returns the message id of the opera- -tion initiated. As for ldap_search_ext(), a subsequent call to -ldap_result(), described below, can be used to obtain the result of the -bind. In case of error, ldap_search() will return -1, setting the ses- -sion error parameters in the LDAP structure appropriately. - -The synchronous ldap_search_ext_s(), ldap_search_s(), and -ldap_search_st() functions all return the result of the operation, -either the constant LDAP_SUCCESS if the operation was successful, or -another LDAP error code if it was not. See the section below on error -handling for more information about possible errors and how to interpret -them. Entries returned from the search (if any) are contained in the - - - -Expires: January 1998 [Page 16] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -res parameter. This parameter is opaque to the caller. Entries, attri- -butes, values, etc., should be extracted by calling the parsing routines -described below. The results contained in res should be freed when no -longer in use by calling ldap_msgfree(), described later. - -The ldap_search_ext() and ldap_search_ext_s() functions support LDAPv3 -server controls, client controls, and allow varying size and time limits -to be easily specified for each search operation. The ldap_search_st() -function is identical to ldap_search_s() except that it takes an addi- -tional parameter specifying a local timeout for the search. - -7.7. Reading an Entry - -LDAP does not support a read operation directly. Instead, this operation -is emulated by a search with base set to the DN of the entry to read, -scope set to LDAP_SCOPE_BASE, and filter set to "(objectclass=*)". attrs -contains the list of attributes to return. - - -7.8. Listing the Children of an Entry - -LDAP does not support a list operation directly. Instead, this operation -is emulated by a search with base set to the DN of the entry to list, -scope set to LDAP_SCOPE_ONELEVEL, and filter set to "(objectclass=*)". -attrs contains the list of attributes to return for each child entry. - -7.9. Comparing a Value Against an Entry - -The following routines are used to compare a given attribute value -assertion against an LDAP entry. There are four variations: - - int ldap_compare_ext( - LDAP *ld, - char *dn, - char *attr, - struct berval *bvalue - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - ); - - int ldap_compare_ext_s( - LDAP *ld, - char *dn, - char *attr, - struct berval *bvalue, - LDAPControl **serverctrls, - LDAPControl **clientctrls - - - -Expires: January 1998 [Page 17] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - ); - - int ldap_compare( - LDAP *ld, - char *dn, - char *attr, - char *value - ); - - int ldap_compare_s( - LDAP *ld, - char *dn, - char *attr, - char *value - ); - -Parameters are: - -ld The session handle. - -dn The name of the entry to compare against. - -attr The attribute to compare against. - -bvalue The attribute value to compare against those found in the - given entry. This parameter is used in the extended rou- - tines and is a pointer to a struct berval so it is possible - to compare binary values. - -value A string attribute value to compare against, used by the - ldap_compare() and ldap_compare_s() functions. Use - ldap_compare_ext() or ldap_compare_ext_s() if you need to - compare binary values. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_compare_ext() call succeeds. - -The ldap_compare_ext() function initiates an asynchronous compare opera- -tion and returns the constant LDAP_SUCCESS if the request was success- -fully sent, or another LDAP error code if not. See the section below on -error handling for more information about possible errors and how to -interpret them. If successful, ldap_compare_ext() places the message id -of the request in *msgidp. A subsequent call to ldap_result(), described -below, can be used to obtain the result of the compare. - - - -Expires: January 1998 [Page 18] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -Similar to ldap_compare_ext(), the ldap_compare() function initiates an -asynchronous compare operation and returns the message id of the opera- -tion initiated. As for ldap_compare_ext(), a subsequent call to -ldap_result(), described below, can be used to obtain the result of the -bind. In case of error, ldap_compare() will return -1, setting the ses- -sion error parameters in the LDAP structure appropriately. - -The synchronous ldap_compare_ext_s() and ldap_compare_s() functions both -return the result of the operation, either the constant LDAP_SUCCESS if -the operation was successful, or another LDAP error code if it was not. -See the section below on error handling for more information about pos- -sible errors and how to interpret them. - -The ldap_compare_ext() and ldap_compare_ext_s() functions support LDAPv3 -server controls and client controls. - - -7.10. Modifying an entry - -The following routines are used to modify an existing LDAP entry. There -are four variations: - - typedef struct ldapmod { - int mod_op; - char *mod_type; - union { - char **modv_strvals; - struct berval **modv_bvals; - } mod_vals; - } LDAPMod; - #define mod_values mod_vals.modv_strvals - #define mod_bvalues mod_vals.modv_bvals - - int ldap_modify_ext( - LDAP *ld, - char *dn, - LDAPMod **mods, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - ); - - int ldap_modify_ext_s( - LDAP *ld, - char *dn, - LDAPMod **mods, - LDAPControl **serverctrls, - LDAPControl **clientctrls - - - -Expires: January 1998 [Page 19] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - ); - - int ldap_modify( - LDAP *ld, - char *dn, - LDAPMod **mods - ); - - int ldap_modify_s( - LDAP *ld, - char *dn, - LDAPMod **mods - ); - -Parameters are: - -ld The session handle. - -dn The name of the entry to modify. - -mods A NULL-terminated array of modifications to make to the - entry. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_modify_ext() call succeeds. - -The fields in the LDAPMod structure have the following meanings: - -mod_op The modification operation to perform. It should be one of - LDAP_MOD_ADD (0x00), LDAP_MOD_DELETE (0x01), or - LDAP_MOD_REPLACE (0x02). This field also indicates the - type of values included in the mod_vals union. It is logi- - cally ORed with LDAP_MOD_BVALUES (0x80) to select the - mod_bvalues form. Otherwise, the mod_values form is used. - -mod_type The type of the attribute to modify. - -mod_vals The values (if any) to add, delete, or replace. Only one of - the mod_values or mod_bvalues variants should be used, - selected by ORing the mod_op field with the constant - LDAP_MOD_BVALUES. mod_values is a NULL-terminated array of - zero-terminated strings and mod_bvalues is a NULL- - terminated array of berval structures that can be used to - pass binary values such as images. - - - -Expires: January 1998 [Page 20] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -For LDAP_MOD_ADD modifications, the given values are added to the -entry, creating the attribute if necessary. - -For LDAP_MOD_DELETE modifications, the given values are deleted from the -entry, removing the attribute if no values remain. If the entire attri- -bute is to be deleted, the mod_vals field should be set to NULL. - -For LDAP_MOD_REPLACE modifications, the attribute will have the listed -values after the modification, having been created if necessary, or -removed if the mod_vals field is NULL. All modifications are performed -in the order in which they are listed. - -The ldap_modify_ext() function initiates an asynchronous modify opera- -tion and returns the constant LDAP_SUCCESS if the request was success- -fully sent, or another LDAP error code if not. See the section below on -error handling for more information about possible errors and how to -interpret them. If successful, ldap_modify_ext() places the message id -of the request in *msgidp. A subsequent call to ldap_result(), described -below, can be used to obtain the result of the modify. - -Similar to ldap_modify_ext(), the ldap_modify() function initiates an -asynchronous modify operation and returns the message id of the opera- -tion initiated. As for ldap_modify_ext(), a subsequent call to -ldap_result(), described below, can be used to obtain the result of the -modify. In case of error, ldap_modify() will return -1, setting the ses- -sion error parameters in the LDAP structure appropriately. - -The synchronous ldap_modify_ext_s() and ldap_modify_s() functions both -return the result of the operation, either the constant LDAP_SUCCESS if -the operation was successful, or another LDAP error code if it was not. -See the section below on error handling for more information about pos- -sible errors and how to interpret them. - -The ldap_modify_ext() and ldap_modify_ext_s() functions support LDAPv3 -server controls and client controls. - - -7.11. Modifying the Name of an Entry - -In LDAPv2, the ldap_modrdn() and ldap_modrdn_s() routines were used to -change the name of an LDAP entry. They could only be used to change the -least significant component of a name (the RDN or relative distinguished -name). LDAPv3 provides the Modify DN protocol operation that allows more -general name change access. The ldap_rename() and ldap_rename_s() rou- -tines are used to change the name of an entry, and the use of the -ldap_modrdn() and ldap_modrdn_s() routines is deprecated. - - int ldap_rename( - - - -Expires: January 1998 [Page 21] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - LDAP *ld, - char *dn, - char *newrdn, - char *newparent, - int deleteoldrdn, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - - ); - int ldap_rename_s( - LDAP *ld, - char *dn, - char *newrdn, - char *newparent, - int deleteoldrdn, - LDAPControl **serverctrls, - LDAPControl **clientctrls - ); - - Use of the following routines is deprecated. - - int ldap_modrdn( - LDAP *ld, - char *dn, - char *newrdn, - int deleteoldrdn - ); - int ldap_modrdn_s( - LDAP *ld, - char *dn, - char *newrdn, - int deleteoldrdn - ); - -Parameters are: - -ld The session handle. - -dn The name of the entry whose DN is to be changed. - -newrdn The new RDN to give the entry. - -newparent The new parent, or superior entry. If this parameter is - NULL, only the RDN of the entry is changed. The root DN - may be specified by passing a zero length string, "". The - newparent parameter should always be NULL when using ver- - sion 2 of the LDAP protocol; otherwise the server's - - - -Expires: January 1998 [Page 22] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - behavior is undefined. - -deleteoldrdn This parameter only has meaning on the rename routines if - newrdn is different than the old RDN. It is a boolean - value, if non-zero indicating that the old RDN value(s) - should be removed, if zero indicating that the old RDN - value(s) should be retained as non-distinguished values of - the entry. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_rename() call succeeds. - -The ldap_rename() function initiates an asynchronous modify DN operation -and returns the constant LDAP_SUCCESS if the request was successfully -sent, or another LDAP error code if not. See the section below on error -handling for more information about possible errors and how to interpret -them. If successful, ldap_rename() places the DN message id of the -request in *msgidp. A subsequent call to ldap_result(), described below, -can be used to obtain the result of the rename. - -The synchronous ldap_rename_s() returns the result of the operation, -either the constant LDAP_SUCCESS if the operation was successful, or -another LDAP error code if it was not. See the section below on error -handling for more information about possible errors and how to interpret -them. - -The ldap_rename() and ldap_rename_s() functions both support LDAPv3 -server controls and client controls. - - -7.12. Adding an entry - -The following functions are used to add entries to the LDAP directory. -There are four variations: - - int ldap_add_ext( - LDAP *ld, - char *dn, - LDAPMod **attrs, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - ); - - - - -Expires: January 1998 [Page 23] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - int ldap_add_ext_s( - LDAP *ld, - char *dn, - LDAPMod **attrs, - LDAPControl **serverctrls, - LDAPControl **clientctrls - ); - - int ldap_add( - LDAP *ld, - char *dn, - LDAPMod **attrs - ); - - int ldap_add_s( - LDAP *ld, - char *dn, - LDAPMod **attrs - ); - -Parameters are: - -ld The session handle. - -dn The name of the entry to add. - -attrs The entry's attributes, specified using the LDAPMod struc- - ture defined for ldap_modify(). The mod_type and mod_vals - fields should be filled in. The mod_op field is ignored - unless ORed with the constant LDAP_MOD_BVALUES, used to - select the mod_bvalues case of the mod_vals union. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_add_ext() call succeeds. - -Note that the parent of the entry being added must already exist or the -parent must be empty (i.e., equal to the root DN) for an add to succeed. - -The ldap_add_ext() function initiates an asynchronous add operation and -returns the constant LDAP_SUCCESS if the request was successfully sent, -or another LDAP error code if not. See the section below on error han- -dling for more information about possible errors and how to interpret -them. If successful, ldap_add_ext() places the message id of the -request in *msgidp. A subsequent call to ldap_result(), described below, - - - -Expires: January 1998 [Page 24] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -can be used to obtain the result of the add. - -Similar to ldap_add_ext(), the ldap_add() function initiates an asyn- -chronous add operation and returns the message id of the operation ini- -tiated. As for ldap_add_ext(), a subsequent call to ldap_result(), -described below, can be used to obtain the result of the add. In case of -error, ldap_add() will return -1, setting the session error parameters -in the LDAP structure appropriately. - -The synchronous ldap_add_ext_s() and ldap_add_s() functions both return -the result of the operation, either the constant LDAP_SUCCESS if the -operation was successful, or another LDAP error code if it was not. See -the section below on error handling for more information about possible -errors and how to interpret them. - -The ldap_add_ext() and ldap_add_ext_s() functions support LDAPv3 server -controls and client controls. - - - -7.13. Deleting an entry - -The following functions are used to delete a leaf entry from the LDAP -directory. There are four variations: - - int ldap_delete_ext( - LDAP *ld, - char *dn, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - ); - - int ldap_delete_ext_s( - LDAP *ld, - char *dn, - LDAPControl **serverctrls, - LDAPControl **clientctrls - ); - - int ldap_delete( - LDAP *ld, - char *dn - ); - - int ldap_delete_s( - LDAP *ld, - char *dn - - - -Expires: January 1998 [Page 25] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - ); - -Parameters are: - -ld The session handle. - -dn The name of the entry to delete. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_delete_ext() call succeeds. - -Note that the entry to delete must be a leaf entry (i.e., it must have -no children). Deletion of entire subtrees in a single operation is not -supported by LDAP. - -The ldap_delete_ext() function initiates an asynchronous delete opera- -tion and returns the constant LDAP_SUCCESS if the request was success- -fully sent, or another LDAP error code if not. See the section below on -error handling for more information about possible errors and how to -interpret them. If successful, ldap_delete_ext() places the message id -of the request in *msgidp. A subsequent call to ldap_result(), described -below, can be used to obtain the result of the delete. - -Similar to ldap_delete_ext(), the ldap_delete() function initiates an -asynchronous delete operation and returns the message id of the opera- -tion initiated. As for ldap_delete_ext(), a subsequent call to -ldap_result(), described below, can be used to obtain the result of the -delete. In case of error, ldap_delete() will return -1, setting the ses- -sion error parameters in the LDAP structure appropriately. - -The synchronous ldap_delete_ext_s() and ldap_delete_s() functions both -return the result of the operation, either the constant LDAP_SUCCESS if -the operation was successful, or another LDAP error code if it was not. -See the section below on error handling for more information about pos- -sible errors and how to interpret them. - -The ldap_delete_ext() and ldap_delete_ext_s() functions support LDAPv3 -server controls and client controls. - - -7.14. Extended Operations - -The ldap_extended_operation() and ldap_extended_operation_s() routines -allow extended LDAP operations to be passed to the server, providing a - - - -Expires: January 1998 [Page 26] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -general protocol extensibility mechanism. - - int ldap_extended_operation( - LDAP *ld, - char *exoid, - struct berval *exdata, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - int *msgidp - ); - - int ldap_extended_operation_s( - LDAP *ld, - char *exoid, - struct berval *exdata, - LDAPControl **serverctrls, - LDAPControl **clientctrls, - char **retoidp, - struct berval **retdatap - ); - -Parameters are: - -ld The session handle. - -requestoid The dotted-OID text string naming the request. - -requestdata The arbitrary data required by the operation (if NULL, no - data is sent to the server). - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -msgidp This result parameter will be set to the message id of the - request if the ldap_extended_operation() call succeeds. - -retoidp Pointer to a character string that will be set to an allo- - cated, dotted-OID text string returned by the server. This - string should be disposed of using the ldap_memfree() func- - tion. If no OID was returned, *retoidp is set to NULL. - -retdatap Pointer to a berval structure pointer that will be set an - allocated copy of the data returned by the server. This - struct berval should be disposed of using ber_bvfree(). If - no data is returned, *retdatap is set to NULL. - -The ldap_extended_operation() function initiates an asynchronous - - - -Expires: January 1998 [Page 27] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -extended operation and returns the constant LDAP_SUCCESS if the request -was successfully sent, or another LDAP error code if not. See the sec- -tion below on error handling for more information about possible errors -and how to interpret them. If successful, ldap_extended_operation() -places the message id of the request in *msgidp. A subsequent call to -ldap_result(), described below, can be used to obtain the result of the -extended operation which can be passed to ldap_parse_extended_result() -to obtain the OID and data contained in the response. - -The synchronous ldap_extended_operation_s() function returns the result -of the operation, either the constant LDAP_SUCCESS if the operation was -successful, or another LDAP error code if it was not. See the section -below on error handling for more information about possible errors and -how to interpret them. The retoid and retdata parameters are filled in -with the OID and data from the response. If no OID or data was -returned, these parameters are set to NULL. - -The ldap_extended_operation() and ldap_extended_operation_s() functions -both support LDAPv3 server controls and client controls. - - -8. Abandoning An Operation - -The following calls are used to abandon an operation in progress: - - int ldap_abandon_ext( - LDAP *ld, - int msgid, - LDAPControl **serverctrls, - LDAPControl **clientctrls - ); - - int ldap_abandon( - LDAP *ld, - int msgid - ); - - -ld The session handle. - -msgid The message id of the request to be abandoned. - -serverctrls List of LDAP server controls. - -clientctrls List of client controls. - -ldap_abandon_ext() abandons the operation with message id msgid and -returns the constant LDAP_SUCCESS if the abandon was successful or - - - -Expires: January 1998 [Page 28] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -another LDAP error code if not. See the section below on error handling -for more information about possible errors and how to interpret them. - -ldap_abandon() is identical to ldap_abandon_ext() except that it returns -zero if the abandon was successful, -1 otherwise and does not support -LDAPv3 server controls or client controls. - -After a successful call to ldap_abandon() or ldap_abandon_ext(), results -with the given message id are never returned from a subsequent call to -ldap_result(). There is no server response to LDAP abandon operations. - - -9. Obtaining Results and Peeking Inside LDAP Messages - -ldap_result() is used to obtain the result of a previous asynchronously -initiated operation. Note that depending on how it is called, -ldap_result() may actually return a list or "chain" of messages. - -ldap_msgfree() frees the results obtained from a previous call to -ldap_result(), or a synchronous search routine. - -ldap_msgtype() returns the type of an LDAP message. ldap_msgid() -returns the message ID of an LDAP message. - - int ldap_result( - LDAP *ld, - int msgid, - int all, - struct timeval *timeout, - LDAPMessage **res - ); - - int ldap_msgfree( LDAPMessage *res ); - - int ldap_msgtype( LDAPMessage *res ); - - int ldap_msgid( LDAPMessage *res ); - -Parameters are: - -ld The session handle. - -msgid The message id of the operation whose results are to be - returned, or the constant LDAP_RES_ANY (-1) if any result is - desired. - -all Specifies how many messages will be retrieved in a single call - to ldap_result(). This parameter only has meaning for search - - - -Expires: January 1998 [Page 29] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - results. Pass the constant LDAP_MSG_ONE (0x00) to retrieve one - message at a time. Pass LDAP_MSG_ALL (0x01) to request that - all results of a search be received before returning all - results in a single chain. Pass LDAP_MSG_RECEIVED (0x02) to - indicate that all results retrieved so far should be returned - in the result chain. - -timeout A timeout specifying how long to wait for results to be - returned. A NULL value causes ldap_result() to block until - results are available. A timeout value of zero seconds speci- - fies a polling behavior. - -res For ldap_result(), a result parameter that will contain the - result(s) of the operation. For ldap_msgfree(), the result - chain to be freed, obtained from a previous call to - ldap_result(), ldap_search_s(), or ldap_search_st(). - -Upon successful completion, ldap_result() returns the type of the first -result returned in the res parameter. This will be one of the following -constants. - - LDAP_RES_BIND (0x61) - LDAP_RES_SEARCH_ENTRY (0x64) - LDAP_RES_SEARCH_REFERENCE (0x73) -- new in LDAPv3 - LDAP_RES_SEARCH_RESULT (0x65) - LDAP_RES_MODIFY (0x67) - LDAP_RES_ADD (0x69) - LDAP_RES_DELETE (0x6B) - LDAP_RES_MODDN (0x6D) - LDAP_RES_COMPARE (0x6F) - LDAP_RES_EXTENDED (0x78) -- new in LDAPv3 - -ldap_result() returns 0 if the timeout expired and -1 if an error -occurs, in which case the error parameters of the LDAP session handle -will be set accordingly. - -ldap_msgfree() frees the result structure pointed to by res and returns -the type of the message it freed. - -ldap_msgtype() returns the type of the LDAP message it is passed as a -parameter. The type will be one of the types listed above, or -1 on -error. - -ldap_msgid() returns the message ID associated with the LDAP message -passed as a parameter. - - - - - - -Expires: January 1998 [Page 30] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -10. Handling Errors and Parsing Results - -The following calls are used to extract information from results and -handle errors returned by other LDAP API routines. - - int ldap_parse_result( - LDAP *ld, - LDAPMessage *res, - int *errcodep, - char **matcheddnp, - char **errmsgp, - char ***referralsp, - LDAPControl ***serverctrlsp, - int freeit - ); - - int ldap_parse_sasl_bind_result( - LDAP *ld, - LDAPMessage *res, - struct berval **servercredp, - int freeit - ); - - int ldap_parse_extended_result( - LDAP *ld, - LDAPMessage *res, - char **resultoidp, - struct berval **resultdata, - int freeit - ); - - char *ldap_err2string( int err ); - - The use of the following routines is deprecated. - - int ldap_result2error( - LDAP *ld, - LDAPMessage *res, - int freeit - ); - - void ldap_perror( LDAP *ld, char *msg ); - -Parameters are: - -ld The session handle. - -res The result of an LDAP operation as returned by - - - -Expires: January 1998 [Page 31] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - ldap_result() or one of the synchronous API operation - calls. - -errcodep This result parameter will be filled in with the LDAP error - code field from the LDAPResult message. This is the indi- - cation from the server of the outcome of the operation. - NULL may be passed to ignore this field. - -matcheddnp In the case of a return of LDAP_NO_SUCH_OBJECT, this result - parameter will be filled in with a DN indicating how much - of the name in the request was recognized. NULL may be - passed to ignore this field. The matched DN string should - be freed by calling ldap_memfree() which is described later - in this document. - -errmsgp This result parameter will be filled in with the contents - of the error message field from the LDAPResult message. - The error message string should be freed by calling - ldap_memfree() which is described later in this document. - NULL may be passed to ignore this field. - -referralsp This result parameter will be filled in with the contents - of the referrals field from the LDAPResult message, indi- - cating zero or more alternate LDAP servers where the - request should be retried. The referrals array should be - freed by calling ldap_value_free() which is described later - in this document. NULL may be passed to ignore this field. - -serverctrlsp This result parameter will be filled in with an allocated - array of controls copied out of the LDAPResult message. - The control array should be freed by calling - ldap_controls_free() which was described earlier. - -freeit A boolean that determines whether the res parameter is - disposed of or not. Pass any non-zero value to have these - routines free res after extracting the requested informa- - tion. This is provided as a convenience; you can also use - ldap_msgfree() to free the result later. - -servercredp For SASL bind results, this result parameter will be filled - in with the credentials passed back by the server for - mutual authentication, if given. An allocated berval struc- - ture is returned that should be disposed of by calling - ldap_ber_free(). NULL may be passed to ignore this field. - -resultoidp For extended results, this result parameter will be filled - in with the dotted-OID text representation of the name of - the extended operation response. This string should be - - - -Expires: January 1998 [Page 32] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - disposed of by calling ldap_memfree(). NULL may be passed - to ignore this field. - -resultdatap For extended results, this result parameter will be filled - in with a pointer to a struct berval containing the data in - the extended operation response. It should be disposed of - by calling ldap_ber_free(). NULL may be passed to ignore - this field. - -err For ldap_err2string(), an LDAP error code, as returned by - ldap_result2error() or another LDAP API call. - -Additional parameters for the deprecated routines are not described. -Interested readers are referred to RFC 1823. - -All of the ldap_parse_*_result() routines skip over messages of type -LDAP_RES_SEARCH_ENTRY and LDAP_RES_SEARCH_REFERENCE when looking for a -result message to parse. They return the constant LDAP_SUCCESS if the -result was successfully parsed and another LDAP error code if not. Note -that the LDAP error code that indicates the outcome of the operation -performed by the server is placed in the errcodep ldap_parse_result() -parameter. - -ldap_err2string() is used to convert a numeric LDAP error code, as -returned by one of the ldap_parse_*_result() routines, or one of the -synchronous API operation calls, into an informative NULL-terminated -character string message describing the error. It returns a pointer to -static data. - - -11. Stepping Through a List of Results - -The ldap_first_message() and ldap_next_message() routines are used to -step through the list of messages in a result chain returned by -ldap_result(). For search operations, the result chain may actually -include referral messages, entry messages, and result messages. -ldap_count_messages() is used to count the number of messages returned. -The ldap_msgtype() function, described above, can be used to distinguish -between the different message types. - - LDAPMessage *ldap_first_message( LDAP *ld, LDAPMessage *res ); - - LDAPMessage *ldap_next_message( LDAP *ld, LDAPMessage *msg ); - - int ldap_count_messages( LDAP *ld, LDAPMessage *res ); - -Parameters are: - - - - -Expires: January 1998 [Page 33] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -ld The session handle. - -res The result chain, as obtained by a call to one of the synchronous - search routines or ldap_result(). - -msg The message returned by a previous call to ldap_first_message() - or ldap_next_message(). - -ldap_first_message() and ldap_next_message() will return NULL when no -more messages exist in the result set to be returned. NULL is also -returned if an error occurs while stepping through the entries, in which -case the error parameters in the session handle ld will be set to indi- -cate the error. - -ldap_count_messages() returns the number of messages contained in a -chain of results. It can also be used to count the number of messages -that remain in a chain if called with a message, entry, or reference -returned by ldap_first_message(), ldap_next_message(), -ldap_first_entry(), ldap_next_entry(), ldap_first_reference(), -ldap_next_reference(). - - -12. Parsing Search Results - -The following calls are used to parse the entries and references -returned by ldap_search() and friends. These results are returned in an -opaque structure that should only be accessed by calling the routines -described below. Routines are provided to step through the entries and -references returned, step through the attributes of an entry, retrieve -the name of an entry, and retrieve the values associated with a given -attribute in an entry. - - -12.1. Stepping Through a List of Entries - -The ldap_first_entry() and ldap_next_entry() routines are used to step -through and retrieve the list of entries from a search result chain. -The ldap_first_reference() and ldap_next_reference() routines are used -to step through and retrieve the list of continuation references from a -search result chain. ldap_count_entries() is used to count the number -of entries returned. ldap_count_references() is used to count the number -of references returned. - - LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *res ); - - LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry ); - - LDAPMessage *ldap_first_reference( LDAP *ld, LDAPMessage *res ); - - - -Expires: January 1998 [Page 34] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - LDAPMessage *ldap_next_reference( LDAP *ld, LDAPMessage *ref ); - - int ldap_count_entries( LDAP *ld, LDAPMessage *res ); - - int ldap_count_references( LDAP *ld, LDAPMessage *res ); - -Parameters are: - -ld The session handle. - -res The search result, as obtained by a call to one of the synchro- - nous search routines or ldap_result(). - -entry The entry returned by a previous call to ldap_first_entry() or - ldap_next_entry(). - -ldap_first_entry() and ldap_next_entry() will return NULL when no more -entries or references exist in the result set to be returned. NULL is -also returned if an error occurs while stepping through the entries, in -which case the error parameters in the session handle ld will be set to -indicate the error. - -ldap_count_entries() returns the number of entries contained in a chain -of entries. It can also be used to count the number of entries that -remain in a chain if called with a message, entry or reference returned -by ldap_first_message(), ldap_next_message(), ldap_first_entry(), -ldap_next_entry(), ldap_first_reference(), ldap_next_reference(). - -ldap_count_references() returns the number of references contained in a -chain of search results. It can also be used to count the number of -references that remain in a chain. - - -12.2. Stepping Through the Attributes of an Entry - -The ldap_first_attribute() and ldap_next_attribute() calls are used to -step through the list of attribute types returned with an entry. - - char *ldap_first_attribute( - LDAP *ld, - LDAPMessage *entry, - BerElement **ptr - ); - - char *ldap_next_attribute( - LDAP *ld, - LDAPMessage *entry, - BerElement *ptr - - - -Expires: January 1998 [Page 35] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - ); - - void ldap_memfree( char *mem ); - -Parameters are: - -ld The session handle. - -entry The entry whose attributes are to be stepped through, as returned - by ldap_first_entry() or ldap_next_entry(). - -ptr In ldap_first_attribute(), the address of a pointer used inter- - nally to keep track of the current position in the entry. In - ldap_next_attribute(), the pointer returned by a previous call to - ldap_first_attribute(). - -mem A pointer to memory allocated by the LDAP library, such as the - attribute names returned by ldap_first_attribute() and - ldap_next_attribute, or the DN returned by ldap_get_dn(). - -ldap_first_attribute() and ldap_next_attribute() will return NULL when -the end of the attributes is reached, or if there is an error, in which -case the error parameters in the session handle ld will be set to indi- -cate the error. - -Both routines return a pointer to an allocated buffer containing the -current attribute name. This should be freed when no longer in use by -calling ldap_memfree(). - -ldap_first_attribute() will allocate and return in ptr a pointer to a -BerElement used to keep track of the current position. This pointer -should be passed in subsequent calls to ldap_next_attribute() to step -through the entry's attributes. After a set of calls to -ldap_first_attribute() and ldap_next_attibute(), if ptr is non-NULL, it -should be freed by calling ldap_ber_free( ptr, 0 ). Note that it is very -important to pass the second parameter as 0 (zero) in this call. - -The attribute names returned are suitable for passing in a call to -ldap_get_values() and friends to retrieve the associated values. - - -12.3. Retrieving the Values of an Attribute - -ldap_get_values() and ldap_get_values_len() are used to retrieve the -values of a given attribute from an entry. ldap_count_values() and -ldap_count_values_len() are used to count the returned values. -ldap_value_free() and ldap_value_free_len() are used to free the values. - - - - -Expires: January 1998 [Page 36] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - char **ldap_get_values( - LDAP *ld, - LDAPMessage *entry, - char *attr - ); - - struct berval **ldap_get_values_len( - LDAP *ld, - LDAPMessage *entry, - char *attr - ); - - int ldap_count_values( char **vals ); - - int ldap_count_values_len( struct berval **vals ); - - int ldap_value_free( char **vals ); - - int ldap_value_free_len( struct berval **vals ); - -Parameters are: - -ld The session handle. - -entry The entry from which to retrieve values, as returned by - ldap_first_entry() or ldap_next_entry(). - -attr The attribute whose values are to be retrieved, as returned by - ldap_first_attribute() or ldap_next_attribute(), or a caller- - supplied string (e.g., "mail"). - -vals The values returned by a previous call to ldap_get_values() or - ldap_get_values_len(). - -Two forms of the various calls are provided. The first form is only -suitable for use with non-binary character string data. The second _len -form is used with any kind of data. - -Note that the values returned are dynamically allocated and should be -freed by calling either ldap_value_free() or ldap_value_free_len() when -no longer in use. - - -12.4. Retrieving the name of an entry - -ldap_get_dn() is used to retrieve the name of an entry. -ldap_explode_dn() and ldap_explode_rdn() are used to break up a name -into its component parts. ldap_dn2ufn() is used to convert the name into - - - -Expires: January 1998 [Page 37] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -a more "user friendly" format. - - char *ldap_get_dn( LDAP *ld, LDAPMessage *entry ); - - char **ldap_explode_dn( char *dn, int notypes ); - - char **ldap_explode_rdn( char *rdn, int notypes ); - - char *ldap_dn2ufn( char *dn ); - -Parameters are: - -ld The session handle. - -entry The entry whose name is to be retrieved, as returned by - ldap_first_entry() or ldap_next_entry(). - -dn The dn to explode, such as returned by ldap_get_dn(). - -rdn The rdn to explode, such as returned in the components of the - array returned by ldap_explode_dn(). - -notypes A boolean parameter, if non-zero indicating that the dn or rdn - components should have their type information stripped off - (i.e., "cn=Babs" would become "Babs"). - -ldap_get_dn() will return NULL if there is some error parsing the dn, -setting error parameters in the session handle ld to indicate the error. -It returns a pointer to malloc'ed space that the caller should free by -calling ldap_memfree() when it is no longer in use. Note the format of -the DNs returned is given by [4]. - -ldap_explode_dn() returns a NULL-terminated char * array containing the -RDN components of the DN supplied, with or without types as indicated by -the notypes parameter. The array returned should be freed when it is no -longer in use by calling ldap_value_free(). - -ldap_explode_rdn() returns a NULL-terminated char * array containing the -components of the RDN supplied, with or without types as indicated by -the notypes parameter. The array returned should be freed when it is no -longer in use by calling ldap_value_free(). - -ldap_dn2ufn() converts the DN into the user friendly format described in -[5]. The UFN returned is malloc'ed space that should be freed by a call -to ldap_memfree() when no longer in use. - - - - - - -Expires: January 1998 [Page 38] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -13. Encoded ASN.1 Value Manipulation - -This section describes routines which may be used to encode and decode -BER-encoded ASN.1 values, which are often used inside of control and -extension values. - -With the exceptions of two new functions ber_flatten() and ber_init(), -these functions are compatible with the University of Michigan LDAP 3.3 -implementation of BER. - - -13.1. General - - struct berval { - unsigned long bv_len; - char *bv_val; - }; - -A struct berval contains a sequence of bytes and an indication of its -length. The bv_val is not null terminated. bv_len must always be a -nonnegative number. Applications may allocate their own berval struc- -tures. - - typedef struct berelement { - /* opaque */ - } BerElement; - -The BerElement structure contains not only a copy of the encoded value, -but also state information used in encoding or decoding. Applications -cannot allocate their own BerElement structures. The internal state is -neither thread-specific nor locked, so two threads should not manipulate -the same BerElement value simultaneously. - -A single BerElement value cannot be used for both encoding and decoding. - - void ber_bvfree ( struct berval *bv); - -ber_bvfree() frees a berval returned from this API. Both the bv->bv_val -string and the berval itself are freed. Applications should not use -ber_bvfree() with bervals which the application has allocated. - - void ber_bvecfree ( struct berval **bv ); - -ber_bvecfree() frees an array of bervals returned from this API. Each -of the bervals in the array are freed using ber_bvfree(), then the array -itself is freed. - - struct berval *ber_bvdup (struct berval *bv ); - - - -Expires: January 1998 [Page 39] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -ber_bvdup() returns a copy of a berval. The bv_val field in the -returned berval points to a different area of memory as the bv_val field -in the argument berval. The null pointer is returned on error (e.g. out -of memory). - - void ber_free ( BerElement *ber, int fbuf ); - -ber_free() frees a BerElement which is returned from the API calls -ber_alloc_t() or ber_init(). Each BerElement must be freed by the -caller. The second argument fbuf should always be set to 1. - - -13.2. Encoding - - BerElement *ber_alloc_t(int options); - -ber_alloc_t() constructs and returns BerElement. The null pointer is -returned on error. The options field contains a bitwise-or of options -which are to be used when generating the encoding of this BerElement. -One option is defined and must always be supplied: - - #define LBER_USE_DER 0x01 - -When this option is present, lengths will always be encoded in the -minimum number of octets. Note that this option does not cause values -of sets and sequences to be rearranged in tag and byte order, so these -functions are not suitable for generating DER output as defined in X.509 -and X.680. - -Unrecognized option bits are ignored. - -The BerElement returned by ber_alloc_t() is initially empty. Calls to -ber_printf() will append bytes to the end of the ber_alloc_t(). - - int ber_printf(BerElement *ber, char *fmt, ... ) - -The ber_printf() routine is used to encode a BER element in much the -same way that sprintf() works. One important difference, though, is -that state information is kept in the ber argument so that multiple -calls can be made to ber_printf() to append to the end of the BER ele- -ment. ber must be a pointer to a BerElement returned by ber_alloc_t(). -ber_printf() interprets and formats its arguments according to the for- -mat string fmt. ber_printf() returns -1 if there is an error during -encoding. As with sprintf(), each character in fmt refers to an argu- -ment to ber_printf(). - -The format string can contain the following format characters: - - - - -Expires: January 1998 [Page 40] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -'t' Tag. The next argument is an int specifying the tag to override - the next element to be written to the ber. This works across - calls. The int value must contain the tag class, constructed - bit, and tag value. The tag value must fit in a single octet - (tag value is less than 32). For example, a tag of "[3]" for a - constructed type is 0xA3. - -'b' Boolean. The next argument is an int, containing either 0 for - FALSE or 0xff for TRUE. A boolean element is output. If this - format character is not preceded by the 't' format modifier, the - tag 0x01 is used for the element. - -'i' Integer. The next argument is an int, containing the integer in - the host's byte order. An integer element is output. If this - format character is not preceded by the 't' format modifier, the - tag 0x02 is used for the element. - -'X' Bitstring. The next two arguments are a char * pointer to the - start of the bitstring, followed by an int containing the number - of bits in the bitstring. A bitstring element is output, in - primitive form. If this format character is not preceded by the - 't' format modifier, the tag 0x03 is used for the element. - -'n' Null. No argument is required. An ASN.1 NULL element is out- - put. If this format character is not preceded by the 't' format - modifier, the tag 0x05 is used for the element. - -'o' Octet string. The next two arguments are a char *, followed by - an int with the length of the string. The string may contain - null bytes and need not by null-terminated. An octet string - element is output, in primitive form. If this format character - is not preceded by the 't' format modifier, the tag 0x04 is used - for the element. - -'s' Octet string. The next argument is a char * pointing to a - null-terminated string. An octet string element in primitive - form is output, which does not include the trailing ' ' byte. If - this format character is not preceded by the 't' format modif- - ier, the tag 0x04 is used for the element. - -'v' Several octet strings. The next argument is a char **, an array - of char * pointers to null-terminated strings. The last element - in the array must be a null pointer. The octet strings do not - include the trailing SEQUENCE OF octet strings. The 't' format - modifier cannot be used with this format character. - -'V' Several octet strings. A null-terminated array of berval *'s is - supplied. Note that a construct like '{V}' is required to get an - - - -Expires: January 1998 [Page 41] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - actual SEQUENCE OF octet strings. The 't' format modifier cannot - be used with this format character. - -'{' Begin sequence. No argument is required. If this format char- - acter is not preceded by the 't' format modifier, the tag 0x30 - is used. - -'}' End sequence. No argument is required. The 't' format modifier - cannot be used with this format character. - -'[' Begin set. No argument is required. If this format character - is not preceded by the 't' format modifier, the tag 0x31 is - used. - -']' End set. No argument is required. The 't' format modifier can- - not be used with this format character. - -Each use of a '{' format character must be matched by a '}' character, -either later in the format string, or in the format string of a subse- -quent call to ber_printf() for that BerElement. The same applies to the -'[' and - -Sequences and sets nest, and implementations of this API must maintain -internal state to be able to properly calculate the lengths. - - int ber_flatten (BerElement *ber, struct berval **bvPtr); - -The ber_flatten routine allocates a struct berval whose contents are a -BER encoding taken from the ber argument. The bvPtr pointer points to -the returned berval, which must be freed using ber_bvfree(). This rou- -tine returns 0 on success and -1 on error. - -The ber_flatten API call is not present in U-M LDAP 3.3. - -The use of ber_flatten on a BerElement in which all '{' and '}' format -modifiers have not been properly matched can result in a berval whose -contents are not a valid BER encoding. - - -13.3. Encoding Example - -The following is an example of encoding the following ASN.1 data type: - - Example1Request ::= SEQUENCE { - s OCTET STRING, -- must be printable - val1 INTEGER, - val2 [0] INTEGER DEFAULT 0 - } - - - -Expires: January 1998 [Page 42] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - int encode_example1(char *s,int val1,int val2,struct berval **bvPtr) - { - BerElement *ber; - int rc; - - ber = ber_alloc_t(LBER_USE_DER); - - if (ber == NULL) return -1; - - if (ber_printf(ber,"{si",s,val1) == -1) { - ber_free(ber,1); - return -1; - } - - if (val2 != 0) { - if (ber_printf(ber,"ti",0x80,val2) == -1) { - ber_free(ber,1); - return -1; - } - } - - if (ber_printf(ber,"}") == -1) { - ber_free(ber,1); - return -1; - } - - rc = ber_flatten(ber,bvPtr); - ber_free(ber,1); - return -1; - } - - -13.4. Decoding - -The following two symbols are available to applications. - - #define LBER_ERROR 0xffffffffL - #define LBER_DEFAULT 0xffffffffL - - BerElement *ber_init (struct berval *bv); - -The ber_init functions construct BerElement and returns a new BerElement -containing a copy of the data in the bv argument. ber_init returns the -null pointer on error. - - unsigned long ber_scanf (BerElement *ber, char *fmt, ... ); - -The ber_scanf() routine is used to decode a BER element in much the same - - - -Expires: January 1998 [Page 43] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -way that sscanf() works. One important difference, though, is that some -state information is kept with the ber argument so that multiple calls -can be made to ber_scanf() to sequentially read from the BER element. -The ber argument must be a pointer to a BerElement returned by -ber_init(). ber_scanf interprets the bytes according to the format -string fmt, and stores the results in its additional arguments. -ber_scanf() returns LBER_ERROR on error, and a nonnegative number on -success. - -The format string contains conversion specifications which are used to -direct the interpretation of the BER element. The format string can -contain the following characters: - -'a' Octet string. A char ** argument should be supplied. Memory is - allocated, filled with the contents of the octet string, null- - terminated, and the pointer to the string is stored in the argu- - ment. The returned value must be freed using ldap_memfree. The - tag of the element must indicate the primitive form (constructed - strings are not supported) but is otherwise ignored and dis- - carded during the decoding. This format cannot be used with - octet strings which could contain null bytes. - -'O' Octet string. A struct berval ** argument should be supplied, - which upon return points to a allocated struct berval containing - the octet string and its length. ber_bvfree() must be called to - free the allocated memory. The tag of the element must indicate - the primitive form (constructed strings are not supported) but - is otherwise ignored during the decoding. - -'b' Boolean. A pointer to an int should be supplied. The int value - stored will be 0 for FALSE or nonzero for TRUE. The tag of the - element must indicate the primitive form but is otherwise - ignored during the decoding. - -'i' Integer. A pointer to an int should be supplied. The int value - stored will be in host byte order. The tag of the element must - indicate the primitive form but is otherwise ignored during the - decoding. ber_scanf() will return an error if the integer can- - not be stored in an int. - -'B' Bitstring. A char ** argument should be supplied which will - point to the allocated bits, followed by an unsigned long * - argument, which will point to the length (in bits) of the bit- - string returned. ldap_memfree must be called to free the bit- - string. The tag of the element must indicate the primitive form - (constructed bitstrings are not supported) but is otherwise - ignored during the decoding. - - - - -Expires: January 1998 [Page 44] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -'n' Null. No argument is required. The element is simply skipped - if it is recognized as a zero-length element. The tag is - ignored. - -'v' Several octet strings. A char *** argument should be supplied, - which upon return points to a allocated null-terminated array of - char *'s containing the octet strings. NULL is stored if the - sequence is empty. ldap_memfree must be called to free each - element of the array and the array itself. The tag of the - sequence and of the octet strings are ignored. - -'V' Several octet strings (which could contain null bytes). A - struct berval *** should be supplied, which upon return points - to a allocated null-terminated array of struct berval *'s con- - taining the octet strings and their lengths. NULL is stored if - the sequence is empty. ber_bvecfree() can be called to free the - allocated memory. The tag of the sequence and of the octet - strings are ignored. - -'x' Skip element. The next element is skipped. No argument is - required. - -'{' Begin sequence. No argument is required. The initial sequence - tag and length are skipped. - -'}' End sequence. No argument is required. - -'[' Begin set. No argument is required. The initial set tag and - length are skipped. - -']' End set. No argument is required. - - unsigned long ber_peek_tag (BerElement *ber, unsigned long *lenPtr); - -ber_peek_tag() returns the tag of the next element to be parsed in the -BerElement argument. The length of this element is stored in the -*lenPtr argument. LBER_DEFAULT is returned if there is no further data -to be read. The ber argument is not modified. - - unsigned long ber_skip_tag (BerElement *ber, unsigned long *lenPtr); - -ber_skip_tag() is similar to ber_peek_tag(), except that the state -pointer in the BerElement argument is advanced past the first tag and -length, and is pointed to the value part of the next element. This rou- -tine should only be used with constructed types and situations when a -BER encoding is used as the value of an OCTET STRING. The length of the -value is stored in *lenPtr. - - - - -Expires: January 1998 [Page 45] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - unsigned long ber_first_element(BerElement *ber, - unsigned long *lenPtr, char **opaquePtr); - - unsigned long ber_next_element (BerElement *ber, - unsigned long *lenPtr, char *opaque); - -ber_first_element() and ber_next_element() are used to traverse a SET, -SET OF, SEQUENCE or SEQUENCE OF data value. ber_first_element() calls -ber_skip_tag(), stores internal information in *lenPtr and *opaquePtr, -and calls ber_peek_tag() for the first element inside the constructed -value. LBER_DEFAULT is returned if the constructed value is empty. -ber_next_element() positions the state at the start of the next element -in the constructed type. LBER_DEFAULT is returned if there are no -further values. - -The len and opaque values should not be used by applications other than -as arguments to ber_next_element(), as shown in the example below. - - -13.5. Decoding Example - -The following is an example of decoding an ASN.1 data type: - - Example2Request ::= SEQUENCE { - dn OCTET STRING, -- must be printable - scope ENUMERATED { b (0), s (1), w (2) }, - ali ENUMERATED { n (0), s (1), f (2), a (3) }, - size INTEGER, - time INTEGER, - tonly BOOLEAN, - attrs SEQUENCE OF OCTET STRING, -- must be printable - [0] SEQUENCE OF SEQUENCE { - type OCTET STRING -- must be printable, - crit BOOLEAN DEFAULT FALSE, - value OCTET STRING - } OPTIONAL } - - #define LDAP_TAG_CONTROL_LIST 0xA0L /* context specific cons 0 */ - - int decode_example2(struct berval *bv) - { - BerElement *ber; - unsigned long len; - int scope, ali, size, time, tonly; - char *dn = NULL, **attrs = NULL; - int res,i,rc = 0; - - ber = ber_init(bv); - - - -Expires: January 1998 [Page 46] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - if (ber == NULL) { - printf("ERROR ber_init failed0); - return -1; - } - - res = ber_scanf(ber,"{aiiiiib{v}",&dn,&scope,&ali, - &size,&time,&tonly,&attrs); - - if (res == -1) { - printf("ERROR ber_scanf failed0); - ber_free(ber,1); - return -1; - } - - /* *** use dn */ - ldap_memfree(dn); - - for (i = 0; attrs != NULL && attrs[i] != NULL; i++) { - /* *** use attrs[i] */ - ldap_memfree(attrs[i]); - } - ldap_memfree(attrs); - - if (ber_peek_tag(ber,&len) == LDAP_TAG_CONTROL_LIST) { - char *opaque; - unsigned long tag; - - for (tag = ber_first_element(ber,&len,&opaque); - tag != LBER_DEFAULT; - tag = ber_next_element (ber,&len,opaque)) { - - unsigned long ttag, tlen; - char *type; - int crit; - struct berval *value; - - if (ber_scanf(ber,"{a",&type) == LBER_ERROR) { - printf("ERROR cannot parse type0); - break; - } - /* *** use type */ - ldap_memfree(type); - - ttag = ber_peek_tag(ber,&tlen); - if (ttag == 0x01) { /* boolean */ - if (ber_scanf(ber,"b", - &crit) == LBER_ERROR) { - printf("ERROR cannot parse crit0); - - - -Expires: January 1998 [Page 47] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - rc = -1; - break; - } - } else if (ttag == 0x04) { /* octet string */ - crit = 0; - } else { - printf("ERROR extra field in controls0); - break; - } - - if (ber_scanf(ber,"O}",&value) == LBER_ERROR) { - printf("ERROR cannot parse value0); - rc = -1; - break; - } - /* *** use value */ - ldap_bvfree(value); - } - } - - ber_scanf(ber,"}"); - - ber_free(ber,1); - - return rc; - } - - - -14. Security Considerations - -LDAPv2 supports security through protocol-level authentication using -clear-text passwords. LDAPv3 adds support for SASL [8] (Simple Authen- -tication Security Layer) methods. LDAPv3 also supports operation over a -secure transport layer using Transport Layer Security TLS [8]. Readers -are referred to the protocol documents for discussion of related secu- -rity considerations. - -Implementations of this API should be cautious when handling authentica- -tion credentials. In particular, keeping long-lived copies of creden- -tials without the application's knowledge is discouraged. - - -15. Acknowledgements - -Many members of the IETF ASID working group as well as members of the -Internet at large have provided useful comments and suggestions that -have been incorporated into this revision. - - - -Expires: January 1998 [Page 48] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -This original material upon which this revision is based was based upon -work supported by the National Science Foundation under Grant No. NCR- -9416667. - - -16. Bibliography - -[1] The Directory: Selected Attribute Syntaxes. CCITT, Recommendation - X.520. - -[2] M. Wahl, A. Coulbeck, T. Howes, S. Kille, W. Yeong, C. Robbins, - "Lightweight Directory Access Protocol Attribute Syntax Defini- - tions", INTERNET-DRAFT , - 11 July 1997. - -[3] T. Howes, "A String Representation of LDAP Search Filters," - INTERNET-DRAFT , May 1997. - -[4] S. Kille, M. Wahl, "A UTF-8 String Representation of Distinguished - Names", INTERNET-DRAFT , 29 April - 1997. - -[5] S. Kille, "Using the OSI Directory to Achieve User Friendly Nam- - ing," RFC 1781, March 1995. - -[6] M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access Protocol - (v3)", INTERNET-DRAFT , 11 - July 1997. - -[7] A. Herron, T. Howes, M. Wahl, "LDAP Control Extension for Server - Side Sorting of Search Result," INTERNET-DRAFT , 16 April 1997. - -[8] J. Meyers, "Simple Authentication and Security Layer", INTERNET- - DRAFT , April 1997. - -[9] "Lightweight Directory Access Protocol (v3) Extension for Transport - Layer Security", INTERNET-DRAFT , June 1997. - -[10] "UTF-8, a transformation format of Unicode and ISO 10646", RFC - 2044, October 1996. - -[11] "IP Version 6 Addressing Architecture,", RFC 1884, December 1995. - - - - - - - -Expires: January 1998 [Page 49] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -17. Author's Addresses - - Tim Howes - Netscape Communications Corp. - 501 E. Middlefield Rd., Mailstop MV068 - Mountain View, CA 94043 - USA - +1 415 937-3419 - howes@netscape.com - - - Mark Smith - Netscape Communications Corp. - 501 E. Middlefield Rd., Mailstop MV068 - Mountain View, CA 94043 - USA - +1 415 937-3477 - mcs@netscape.com - - Andy Herron - Microsoft Corp. - 1 Microsoft Way - Redmond, WA 98052 - USA - +1 425 882-8080 - andyhe@microsoft.com - - Chris Weider - Microsoft Corp. - 1 Microsoft Way - Redmond, WA 98052 - USA - +1 425 882-8080 - cweider@microsoft.com - - Mark Wahl - Critical Angle Inc. - 4815 W Braker Lane #502-385 - Austin, TX 78759 - USA - M.Wahl@critical-angle.com - - -18. Appendix A - Sample LDAP API Code - - #include - - main() - - - -Expires: January 1998 [Page 50] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - { - LDAP *ld; - LDAPMessage *res, *e; - int i; - char *a, *dn; - BerElement *ptr; - char **vals; - - /* open an LDAP session */ - if ( (ld = ldap_init( "dotted.host.name", LDAP_PORT )) == NULL ) - exit( 1 ); - - /* authenticate as nobody */ - if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) { - ldap_perror( ld, "ldap_simple_bind_s" ); - exit( 1 ); - } - - /* search for entries with cn of "Babs Jensen", return all attrs */ - if ( ldap_search_s( ld, "o=University of Michigan, c=US", - LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res ) - != LDAP_SUCCESS ) { - ldap_perror( ld, "ldap_search_s" ); - exit( 1 ); - } - - /* step through each entry returned */ - for ( e = ldap_first_entry( ld, res ); e != NULL; - e = ldap_next_entry( ld, e ) ) { - /* print its name */ - dn = ldap_get_dn( ld, e ); - printf( "dn: %s\n", dn ); - ldap_memfree( dn ); - - /* print each attribute */ - for ( a = ldap_first_attribute( ld, e, &ptr ); a != NULL; - a = ldap_next_attribute( ld, e, ptr ) ) { - printf( "attribute: %s\n", a ); - - /* print each value */ - vals = ldap_get_values( ld, e, a ); - for ( i = 0; vals[i] != NULL; i++ ) { - printf( "value: %s\n", vals[i] ); - } - ldap_value_free( vals ); - } - if ( ptr != NULL ) { - ldap_ber_free( ptr, 0 ); - - - -Expires: January 1998 [Page 51] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - - } - } - /* free the search results */ - ldap_msgfree( res ); - - /* close and free connection resources */ - ldap_unbind( ld ); - } - - - -19. Appendix B - Outstanding Issues - - -19.1. Support for multithreaded applications - -In order to support multithreaded applications in a platform-independent -way, some additions to the LDAP API are needed. Different implementors -have taken different paths to solve this problem in the past. A common -set of thread-related API calls must be defined so that application -developers are not unduly burdened. These will be added to a future -revision of this specification. - - -19.2. Using Transport Layer Security (TLS) - -The API calls used to support TLS must be specified. They will be added -to a future revision of this specification. - - -19.3. Client control for chasing referrals - -A client control has been defined that can be used to specify on a per- -operation basis whether references and external referrals are automati- -cally chased by the client library. This will be added to a future -revision of this specification. - - -19.4. Potential confusion between hostname:port and IPv6 addresses - -String representations of IPv6 network addresses [11] can contain colon -characters. The ldap_init() call is specified to take strings of the -form "hostname:port" or "ipaddress:port". If IPv6 addresses are used, -the latter could be ambiguous. A future revision of this specification -will resolve this issue. - - - - - - -Expires: January 1998 [Page 52] - -C LDAP API The C LDAP Application Program Interface 29 July 1997 - - -19.5. Need to track SASL API standardization efforts - -If a standard Simple Authentication and Security Layer API is defined, -it may be necessary to modify the LDAP API to accommodate it. - - -19.6. Support for character sets other than UTF-8? - -Some application developers would prefer to pass string data using a -character set other than UTF-8. This could be accommodated by adding a -new option to ldap_set_option() that supports choosing a character set. -If this feature is added, the number of different character sets sup- -ported should definitely be minimized. - - -19.7. Use of UTF-8 with LDAPv2 servers - -Strings are always passed as UTF-8 in this API but LDAP version 2 -servers do not support the full range of UTF-8 characters. The expected -behavior of this API when using LDAP version 2 with unsupported charac- -ters should be specified. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Expires: January 1998 [Page 53] - - - -1. Status of this Memo............................................1 -2. Introduction...................................................1 -3. Overview of the LDAP Model.....................................2 -4. Overview of LDAP API Use.......................................3 -5. Common Data Structures.........................................4 -6. LDAP Error Codes...............................................5 -7. Performing LDAP Operations.....................................6 -7.1. Initializing an LDAP Session................................6 -7.2. LDAP Session Handle Options.................................7 -7.3. Working with controls.......................................10 -7.4. Authenticating to the directory.............................11 -7.5. Closing the session.........................................13 -7.6. Searching...................................................13 -7.7. Reading an Entry............................................17 -7.8. Listing the Children of an Entry............................17 -7.9. Comparing a Value Against an Entry..........................17 -7.10. Modifying an entry..........................................19 -7.11. Modifying the Name of an Entry..............................21 -7.12. Adding an entry.............................................23 -7.13. Deleting an entry...........................................25 -7.14. Extended Operations.........................................26 -8. Abandoning An Operation........................................28 -9. Obtaining Results and Peeking Inside LDAP Messages.............29 -10. Handling Errors and Parsing Results............................31 -11. Stepping Through a List of Results.............................33 -12. Parsing Search Results.........................................34 -12.1. Stepping Through a List of Entries..........................34 -12.2. Stepping Through the Attributes of an Entry.................35 -12.3. Retrieving the Values of an Attribute.......................36 -12.4. Retrieving the name of an entry.............................37 -13. Encoded ASN.1 Value Manipulation...............................39 -13.1. General.....................................................39 -13.2. Encoding....................................................40 -13.3. Encoding Example............................................42 -13.4. Decoding....................................................43 -13.5. Decoding Example............................................46 -14. Security Considerations........................................48 -15. Acknowledgements...............................................48 -16. Bibliography...................................................49 -17. Author's Addresses.............................................50 -18. Appendix A - Sample LDAP API Code..............................50 -19. Appendix B - Outstanding Issues................................52 -19.1. Support for multithreaded applications......................52 -19.2. Using Transport Layer Security (TLS)........................52 -19.3. Client control for chasing referrals........................52 -19.4. Potential confusion between hostname:port and IPv6 addresses52 -19.5. Need to track SASL API standardization efforts..............53 -19.6. Support for character sets other than UTF-8?................53 -19.7. Use of UTF-8 with LDAPv2 servers............................53 - - - - - - - - diff -Nru rabbitmq-server-2.7.1/plugins-src/eldap-wrapper/package.mk rabbitmq-server-2.8.4/plugins-src/eldap-wrapper/package.mk --- rabbitmq-server-2.7.1/plugins-src/eldap-wrapper/package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/eldap-wrapper/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ UPSTREAM_GIT:=https://github.com/etnt/eldap.git UPSTREAM_REVISION:=e309de4db4b78d67d623 -WRAPPER_PATCHES:=eldap-appify.patch remove-eldap-fsm.patch eldap-no-ssl-seed.patch +WRAPPER_PATCHES:=eldap-appify.patch remove-eldap-fsm.patch eldap-no-ssl-seed.patch remove-ietf-doc.patch ORIGINAL_APP_FILE:=$(CLONE_DIR)/ebin/$(APP_NAME).app DO_NOT_GENERATE_APP_FILE=true diff -Nru rabbitmq-server-2.7.1/plugins-src/eldap-wrapper/remove-ietf-doc.patch rabbitmq-server-2.8.4/plugins-src/eldap-wrapper/remove-ietf-doc.patch --- rabbitmq-server-2.7.1/plugins-src/eldap-wrapper/remove-ietf-doc.patch 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/eldap-wrapper/remove-ietf-doc.patch 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,3036 @@ +diff --git a/doc/draft-ietf-asid-ldap-c-api-00.txt b/doc/draft-ietf-asid-ldap-c-api-00.txt +deleted file mode 100755 +index 5f2e856..0000000 +--- a/doc/draft-ietf-asid-ldap-c-api-00.txt ++++ /dev/null +@@ -1,3030 +0,0 @@ +- +- +- +- +- +- +-Network Working Group T. Howes +-INTERNET-DRAFT Netscape Communications Corp. +-Intended Category: Standards Track M. Smith +-Obsoletes: RFC 1823 Netscape Communications Corp. +-Expires: January 1998 A. Herron +- Microsoft Corp. +- C. Weider +- Microsoft Corp. +- M. Wahl +- Critical Angle, Inc. +- +- 29 July 1997 +- +- +- The C LDAP Application Program Interface +- +- +- +- +-1. Status of this Memo +- +-This draft document will be submitted to the RFC Editor as a Standards +-Track document. Distribution of this memo is unlimited. Please send com- +-ments to the authors. +- +-This document is an Internet-Draft. Internet-Drafts are working docu- +-ments of the Internet Engineering Task Force (IETF), its areas, and its +-working groups. Note that other groups may also distribute working +-documents as Internet-Drafts. +- +-Internet-Drafts are draft documents valid for a maximum of six months +-and may be updated, replaced, or obsoleted by other documents at any +-time. It is inappropriate to use Internet-Drafts as reference material +-or to cite them other than as ``work in progress.'' +- +-To learn the current status of any Internet-Draft, please check the +-``1id-abstracts.txt'' listing contained in the Internet-Drafts Shadow +-Directories on ds.internic.net (US East Coast), nic.nordu.net (Europe), +-ftp.isi.edu (US West Coast), or munnari.oz.au (Pacific Rim). +- +-2. Introduction +- +-This document defines a C language application program interface to the +-lightweight directory access protocol (LDAP). This document replaces the +-previous definition of this API, defined in RFC 1823, updating it to +-include support for features found in version 3 of the LDAP protocol. +-New extended operation functions were added to support LDAPv3 features +-such as controls. In addition, other LDAP API changes were made to +- +- +- +-Expires: January 1998 [Page 1] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-support information hiding and thread safety. +- +-The C LDAP API is designed to be powerful, yet simple to use. It defines +-compatible synchronous and asynchronous interfaces to LDAP to suit a +-wide variety of applications. This document gives a brief overview of +-the LDAP model, then an overview of how the API is used by an applica- +-tion program to obtain LDAP information. The API calls are described in +-detail, followed by an appendix that provides some example code demon- +-strating the use of the API. This document provides information to the +-Internet community. It does not specify any standard. +- +-3. Overview of the LDAP Model +- +-LDAP is the lightweight directory access protocol, described in [2] and +-[6]. It can provide a lightweight frontend to the X.500 directory [1], +-or a stand-alone service. In either mode, LDAP is based on a client- +-server model in which a client makes a TCP connection to an LDAP server, +-over which it sends requests and receives responses. +- +-The LDAP information model is based on the entry, which contains infor- +-mation about some object (e.g., a person). Entries are composed of +-attributes, which have a type and one or more values. Each attribute has +-a syntax that determines what kinds of values are allowed in the attri- +-bute (e.g., ASCII characters, a jpeg photograph, etc.) and how those +-values behave during directory operations (e.g., is case significant +-during comparisons). +- +-Entries may be organized in a tree structure, usually based on politi- +-cal, geographical, and organizational boundaries. Each entry is uniquely +-named relative to its sibling entries by its relative distinguished name +-(RDN) consisting of one or more distinguished attribute values from the +-entry. At most one value from each attribute may be used in the RDN. +-For example, the entry for the person Babs Jensen might be named with +-the "Barbara Jensen" value from the commonName attribute. +- +-A globally unique name for an entry, called a distinguished name or DN, +-is constructed by concatenating the sequence of RDNs from the entry up +-to the root of the tree. For example, if Babs worked for the University +-of Michigan, the DN of her U-M entry might be "cn=Barbara Jensen, +-o=University of Michigan, c=US". The DN format used by LDAP is defined +-in [4]. +- +-Operations are provided to authenticate, search for and retrieve infor- +-mation, modify information, and add and delete entries from the tree. +-The next sections give an overview of how the API is used and detailed +-descriptions of the LDAP API calls that implement all of these func- +-tions. +- +- +- +- +-Expires: January 1998 [Page 2] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-4. Overview of LDAP API Use +- +-An application generally uses the C LDAP API in four simple steps. +- +-- Initialize an LDAP session with a default LDAP server. The +- ldap_init() function returns a handle to the session, allowing mul- +- tiple connections to be open at once. +- +-- Authenticate to the LDAP server. The ldap_bind() function and +- friends support a variety of authentication methods. +- +-- Perform some LDAP operations and obtain some results. ldap_search() +- and friends return results which can be parsed by +- ldap_result2error(), ldap_first_entry(), ldap_next_entry(), etc. +- +-- Close the session. The ldap_unbind() function closes the connec- +- tion. +- +-Operations can be performed either synchronously or asynchronously. The +-names of the synchronous functions end in _s. For example, a synchronous +-search can be completed by calling ldap_search_s(). An asynchronous +-search can be initiated by calling ldap_search(). All synchronous rou- +-tines return an indication of the outcome of the operation (e.g, the +-constant LDAP_SUCCESS or some other error code). The asynchronous rou- +-tines return the message id of the operation initiated. This id can be +-used in subsequent calls to ldap_result() to obtain the result(s) of the +-operation. An asynchronous operation can be abandoned by calling +-ldap_abandon(). +- +-Results and errors are returned in an opaque structure called LDAPMes- +-sage. Routines are provided to parse this structure, step through +-entries and attributes returned, etc. Routines are also provided to +-interpret errors. Later sections of this document describe these rou- +-tines in more detail. +- +-LDAP version 3 servers may return referrals to other servers. By +-default, implementations of this API will attempt to follow referrals +-automatically for the application. This behavior can be disabled glo- +-bally (using the ldap_set_option() call) or on a per-request basis +-through the use of a client control. +- +-As in the LDAPv3 protocol itself, all DNs and string values that are +-passed into or produced by the C LDAP API are represented as UTF-8[10] +-characters. +- +-For compatibility with existing applications, implementations of this +-API will by default use version 2 of the LDAP protocol. Applications +-that intend to take advantage of LDAP version 3 features will need to +- +- +- +-Expires: January 1998 [Page 3] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-use the ldap_set_option() call with a LDAP_OPT_PROTOCOL_VERSION to +-switch to version 3. +- +- +-5. Common Data Structures +- +-Some data structures that are common to several LDAP API functions are +-defined here: +- +- typedef struct ldap LDAP; +- +- typedef struct ldapmsg LDAPMessage; +- +- struct berval { +- unsigned long bv_len; +- char *bv_val; +- }; +- +- struct timeval { +- long tv_sec; +- long tv_usec; +- }; +- +-The LDAP structure is an opaque data type that represents an LDAP ses- +-sion Typically this corresponds to a connection to a single server, but +-it may encompass several server connections in the face of LDAPv3 refer- +-rals. +- +-The LDAPMessage structure is an opaque data type that is used to return +-results and error information. +- +-The berval structure is used to represent arbitrary binary data and its +-fields have the following meanings: +- +-bv_len Length of data in bytes. +- +-bv_val A pointer to the data itself. +- +- +-The timeval structure is used to represent an interval of time and its +-fields have the following meanings: +- +-tv_sec Seconds component of time interval. +- +-tv_usec Microseconds component of time interval. +- +- +- +- +- +- +-Expires: January 1998 [Page 4] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-6. LDAP Error Codes +- +-Many of the LDAP API routines return LDAP error codes, some of which +-indicate local errors and some of which may be returned by servers. +-Supported error codes are (hexadecimal values are given in parentheses +-after the constant): +- +- LDAP_SUCCESS (0x00) +- LDAP_OPERATIONS_ERROR( 0x01) +- LDAP_PROTOCOL_ERROR (0x02) +- LDAP_TIMELIMIT_EXCEEDED (0x03) +- LDAP_SIZELIMIT_EXCEEDED (0x04) +- LDAP_COMPARE_FALSE (0x05) +- LDAP_COMPARE_TRUE (0x06) +- LDAP_STRONG_AUTH_NOT_SUPPORTED (0x07) +- LDAP_STRONG_AUTH_REQUIRED (0x08) +- LDAP_REFERRAL (0x0a) -- new in LDAPv3 +- LDAP_ADMINLIMIT_EXCEEDED (0x0b) -- new in LDAPv3 +- LDAP_UNAVAILABLE_CRITICAL_EXTENSION (0x0c) -- new in LDAPv3 +- LDAP_CONFIDENTIALITY_REQUIRED (0x0d) -- new in LDAPv3 +- LDAP_NO_SUCH_ATTRIBUTE (0x10) +- LDAP_UNDEFINED_TYPE (0x11) +- LDAP_INAPPROPRIATE_MATCHING (0x12) +- LDAP_CONSTRAINT_VIOLATION (0x13) +- LDAP_TYPE_OR_VALUE_EXISTS (0x14) +- LDAP_INVALID_SYNTAX (0x15) +- LDAP_NO_SUCH_OBJECT (0x20) +- LDAP_ALIAS_PROBLEM (0x21) +- LDAP_INVALID_DN_SYNTAX (0x22) +- LDAP_IS_LEAF (0x23) -- not used in LDAPv3 +- LDAP_ALIAS_DEREF_PROBLEM (0x24) +- LDAP_INAPPROPRIATE_AUTH (0x30) +- LDAP_INVALID_CREDENTIALS (0x31) +- LDAP_INSUFFICIENT_ACCESS (0x32) +- LDAP_BUSY (0x33) +- LDAP_UNAVAILABLE (0x34) +- LDAP_UNWILLING_TO_PERFORM (0x35) +- LDAP_LOOP_DETECT (0x36) +- LDAP_NAMING_VIOLATION (0x40) +- LDAP_OBJECT_CLASS_VIOLATION (0x41) +- LDAP_NOT_ALLOWED_ON_NONLEAF (0x42) +- LDAP_NOT_ALLOWED_ON_RDN (0x43) +- LDAP_ALREADY_EXISTS (0x44) +- LDAP_NO_OBJECT_CLASS_MODS (0x45) +- LDAP_RESULTS_TOO_LARGE (0x46) +- LDAP_AFFECTS_MULTIPLE_DSAS (0x47) -- new in LDAPv3 +- LDAP_OTHER (0x50) +- LDAP_SERVER_DOWN (0x51) +- +- +- +-Expires: January 1998 [Page 5] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- LDAP_LOCAL_ERROR (0x52) +- LDAP_ENCODING_ERROR (0x53) +- LDAP_DECODING_ERROR (0x54) +- LDAP_TIMEOUT (0x55) +- LDAP_AUTH_UNKNOWN (0x56) +- LDAP_FILTER_ERROR (0x57) +- LDAP_USER_CANCELLED (0x58) +- LDAP_PARAM_ERROR (0x59) +- LDAP_NO_MEMORY (0x5a) +- LDAP_CONNECT_ERROR (0x5b) +- LDAP_NOT_SUPPORTED (0x5c) +- LDAP_CONTROL_NOT_FOUND (0x5d) +- LDAP_NO_RESULTS_RETURNED (0x5e) +- LDAP_MORE_RESULTS_TO_RETURN (0x5f) +- LDAP_CLIENT_LOOP (0x60) +- LDAP_REFERRAL_LIMIT_EXCEEDED (0x61) +- +- +-7. Performing LDAP Operations +- +-This section describes each LDAP operation API call in detail. All func- +-tions take a "session handle," a pointer to an LDAP structure containing +-per-connection information. Many routines return results in an LDAPMes- +-sage structure. These structures and others are described as needed +-below. +- +- +-7.1. Initializing an LDAP Session +- +-ldap_init() initializes a session with an LDAP server. The server is not +-actually contacted until an operation is performed that requires it, +-allowing various options to be set after initialization. +- +- LDAP *ldap_init( +- char *hostname, +- int portno +- ); +- +-Use of the following routine is deprecated. +- +- LDAP *ldap_open( +- char *hostname, +- int portno +- ); +- +-Parameters are: +- +-hostname Contains a space-separated list of hostnames or dotted strings +- +- +- +-Expires: January 1998 [Page 6] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- representing the IP address of hosts running an LDAP server to +- connect to. Each hostname in the list can include an optional +- port number which is separated from the host itself with a +- colon (:) character. The hosts are tried in the order listed, +- stopping with the first one to which a successful connection is +- made. Note that only ldap_open() attempts to make the connec- +- tion before returning to the caller. ldap_init() does not con- +- nect to the LDAP server. +- +-portno Contains the TCP port number to connect to. The default LDAP +- port of 389 can be obtained by supplying the constant +- LDAP_PORT. If a host includes a port number then this parame- +- ter is ignored. +- +-ldap_init() and ldap_open() both return a "session handle," a pointer to +-an opaque structure that should be passed to subsequent calls pertaining +-to the session. These routines return NULL if the session cannot be ini- +-tialized in which case the operating system error reporting mechanism +-can be checked to see why the call failed. +- +-Note that if you connect to an LDAPv2 server, one of the ldap_bind() +-calls described below must be completed before other operations can be +-performed on the session. LDAPv3 does not require that a bind operation +-be completed before other operations can be performed. +- +-The calling program can set various attributes of the session by calling +-the routines described in the next section. +- +- +-7.2. LDAP Session Handle Options +- +-The LDAP session handle returned by ldap_init() is a pointer to an +-opaque data type representing an LDAP session. Formerly, this data type +-was a structure exposed to the caller, and various fields in the struc- +-ture could be set to control aspects of the session, such as size and +-time limits on searches. +- +-In the interest of insulating callers from inevitable changes to this +-structure, these aspects of the session are now accessed through a pair +-of accessor functions, described below. +- +-ldap_get_option() is used to access the current value of various +-session-wide parameters. ldap_set_option() is used to set the value of +-these parameters. +- +- int ldap_get_option( +- LDAP *ld, +- int option, +- +- +- +-Expires: January 1998 [Page 7] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- void *outvalue +- ); +- +- int ldap_set_option( +- LDAP *ld, +- int option, +- void *invalue +- ); +- +-Parameters are: +- +-ld The session handle. +- +-option The name of the option being accessed or set. This parameter +- should be one of the following constants, which have the indi- +- cated meanings. After the constant the actual value of the con- +- stant is listed in hexadecimal in parentheses followed by the +- type of the corresponding outvalue or invalue parameter. +- +- LDAP_OPT_DESC (0x01) int * +- The underlying socket descriptor corresponding to the default +- LDAP connection. +- +- LDAP_OPT_DEREF (0x02) int * +- Controls how aliases are handled during search. It can have +- one of the following values: LDAP_DEREF_NEVER (0x00), +- LDAP_DEREF_SEARCHING (0x01), LDAP_DEREF_FINDING (0x02), or +- LDAP_DEREF_ALWAYS (0x03). The LDAP_DEREF_SEARCHING value +- means aliases should be dereferenced during the search but not +- when locating the base object of the search. The +- LDAP_DEREF_FINDING value means aliases should be dereferenced +- when locating the base object but not during the search. +- +- LDAP_OPT_SIZELIMIT (0x03) int * +- A limit on the number of entries to return from a search. A +- value of zero means no limit. +- +- LDAP_OPT_TIMELIMIT (0x04) int * +- A limit on the number of seconds to spend on a search. A value +- of zero means no limit +- +- LDAP_OPT_REBIND_FN (0x06) function pointer +- See the discussion of ldap_bind() and friends below. +- +- LDAP_OPT_REBIND_ARG (0x07) void * +- See the discussion of ldap_bind() and friends below. +- +- LDAP_OPT_REFERRALS (0x08) void * +- +- +- +-Expires: January 1998 [Page 8] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- This option controls whether the LDAP library automatically +- follows referrals returned by LDAP servers or not. It can be +- set to one of the constants LDAP_OPT_ON or LDAP_OPT_OFF. +- +- LDAP_OPT_RESTART (0x09) void * +- This option controls whether LDAP I/O operations should +- automatically be restarted if they abort prematurely. It +- should be set to one of the constants LDAP_OPT_ON or +- LDAP_OPT_OFF. This option is useful if an LDAP I/O operation +- may be interrupted prematurely, for example by a timer going +- off, or other interrrupt. +- +- LDAP_OPT_PROTOCOL_VERSION (0x11) int * +- This option indicates the version of the default LDAP server. +- It can be one of the constants LDAP_VERSION2 or LDAP_VERSION3. +- If no version is set the default is LDAP_VERSION2. +- +- LDAP_OPT_SERVER_CONTROLS (0x12) LDAPControl ** +- A default list of LDAP server controls to be sent with each +- request. See the Using Controls section below. +- +- LDAP_OPT_CLIENT_CONTROLS (0x13) LDAPControl ** +- A default list of client controls that affect the LDAP ses- +- sion. See the Using Controls section below. +- +- LDAP_OPT_HOST_NAME (0x30) char ** +- The host name of the default LDAP server. +- +- LDAP_OPT_ERROR_NUMBER (0x31) int * +- The code of the most recent LDAP error that occurred for this +- session. +- +- LDAP_OPT_ERROR_STRING (0x32) char ** +- The message returned with the most recent LDAP error that +- occurred for this session. +- +- +-outvalue The address of a place to put the value of the option. The +- actual type of this parameter depends on the setting of the +- option parameter. +- +-invalue A pointer to the value the option is to be given. The actual +- type of this parameter depends on the setting of the option +- parameter. The constants LDAP_OPT_ON and LDAP_OPT_OFF can be +- given for options that have on or off settings. +- +- +- +- +- +- +-Expires: January 1998 [Page 9] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-7.3. Working with controls +- +-LDAPv3 operations can be extended through the use of controls. Controls +-may be sent to a server or returned to the client with any LDAP message. +-These controls are referred to as server controls. +- +-The LDAP API also supports a client-side extension mechanism through the +-use of client controls. These controls affect the behavior of the LDAP +-API only and are never sent to a server. A common data structure is +-used to represent both types of controls: +- +- typedef struct ldapcontrol { +- char *ldctl_oid; +- struct berval ldctl_value; +- char ldctl_iscritical; +- } LDAPControl, *PLDAPControl; +- +-The fields in the ldapcontrol structure have the following meanings: +- +-ldctl_oid The control type, represented as a string. +- +-ldctl_value The data associated with the control (if any). +- +-ldctl_iscritical Indicates whether the control is critical of not. If +- this field is non-zero, the operation will only be car- +- ried out if the control is recognized by the server +- and/or client. +- +-Some LDAP API calls allocate an ldapcontrol structure or a NULL- +-terminated array of ldapcontrol structures. The following routines can +-be used to dispose of a single control or an array of controls: +- +- void ldap_control_free( LDAPControl *ctrl ); +- void ldap_controls_free( LDAPControl **ctrls ); +- +-A set of controls that affect the entire session can be set using the +-ldap_set_option() function (see above). A list of controls can also be +-passed directly to some LDAP API calls such as ldap_search_ext(), in +-which case any controls set for the session through the use of +-ldap_set_option() are ignored. Control lists are represented as a NULL- +-terminated array of pointers to ldapcontrol structures. +- +-Server controls are defined by LDAPv3 protocol extension documents; for +-example, a control has been proposed to support server-side sorting of +-search results [7]. +- +-No client controls are defined by this document but they may be defined +-in future revisions or in any document that extends this API. +- +- +- +-Expires: January 1998 [Page 10] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-7.4. Authenticating to the directory +- +-The following functions are used to authenticate an LDAP client to an +-LDAP directory server. +- +-The ldap_sasl_bind() and ldap_sasl_bind_s() functions can be used to do +-general and extensible authentication over LDAP through the use of the +-Simple Authentication Security Layer [8]. The routines both take the dn +-to bind as, the method to use, as a dotted-string representation of an +-OID identifying the method, and a struct berval holding the credentials. +-The special constant value LDAP_SASL_SIMPLE ("") can be passed to +-request simple authentication, or the simplified routines +-ldap_simple_bind() or ldap_simple_bind_s() can be used. +- +- int ldap_sasl_bind( +- LDAP *ld, +- char *dn, +- char *mechanism, +- struct berval *cred, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- ); +- +- int ldap_sasl_bind_s( +- LDAP *ld, +- char *dn, +- char *mechanism, +- struct berval *cred, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- struct berval **servercredp +- ); +- +- int ldap_simple_bind( +- LDAP *ld, +- char *dn, +- char *passwd +- ); +- +- int ldap_simple_bind_s( +- LDAP *ld, +- char *dn, +- char *passwd +- ); +- +- The use of the following routines is deprecated: +- +- +- +- +-Expires: January 1998 [Page 11] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- int ldap_bind( LDAP *ld, char *dn, char *cred, int method ); +- +- int ldap_bind_s( LDAP *ld, char *dn, char *cred, int method ); +- +- int ldap_kerberos_bind( LDAP *ld, char *dn ); +- +- int ldap_kerberos_bind_s( LDAP *ld, char *dn ); +- +-Parameters are: +- +-ld The session handle. +- +-dn The name of the entry to bind as. +- +-mechanism Either LDAP_AUTH_SIMPLE_OID to get simple authentication, +- or a dotted text string representing an OID identifying the +- SASL method. +- +-cred The credentials with which to authenticate. Arbitrary +- credentials can be passed using this parameter. The format +- and content of the credentials depends on the setting of +- the mechanism parameter. +- +-passwd For ldap_simple_bind(), the password to compare to the +- entry's userPassword attribute. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_sasl_bind() call succeeds. +- +-servercredp This result parameter will be set to the credentials +- returned by the server. This should be freed by calling +- ldap_If no credentials are returned it will be set to NULL. +- +-Additional parameters for the deprecated routines are not described. +-Interested readers are referred to RFC 1823. +- +-The ldap_sasl_bind() function initiates an asynchronous bind operation +-and returns the constant LDAP_SUCCESS if the request was successfully +-sent, or another LDAP error code if not. See the section below on error +-handling for more information about possible errors and how to interpret +-them. If successful, ldap_sasl_bind() places the message id of the +-request in *msgidp. A subsequent call to ldap_result(), described below, +-can be used to obtain the result of the bind. +- +- +- +- +-Expires: January 1998 [Page 12] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-The ldap_simple_bind() function initiates a simple asynchronous bind +-operation and returns the message id of the operation initiated. A sub- +-sequent call to ldap_result(), described below, can be used to obtain +-the result of the bind. In case of error, ldap_simple_bind() will return +--1, setting the session error parameters in the LDAP structure appropri- +-ately. +- +-The synchronous ldap_sasl_bind_s() and ldap_simple_bind_s() functions +-both return the result of the operation, either the constant +-LDAP_SUCCESS if the operation was successful, or another LDAP error code +-if it was not. See the section below on error handling for more informa- +-tion about possible errors and how to interpret them. +- +-Note that if an LDAPv2 server is contacted, no other operations over the +-connection should be attempted before a bind call has successfully com- +-pleted. +- +-Subsequent bind calls can be used to re-authenticate over the same con- +-nection, and multistep SASL sequences can be accomplished through a +-sequence of calls to ldap_sasl_bind() or ldap_sasl_bind_s(). +- +- +-7.5. Closing the session +- +-The following functions are used to unbind from the directory, close the +-connection, and dispose of the session handle. +- +- int ldap_unbind( LDAP *ld ); +- +- int ldap_unbind_s( LDAP *ld ); +- +-Parameters are: +- +-ld The session handle. +- +-ldap_unbind() and ldap_unbind_s() both work synchronously, unbinding +-from the directory, closing the connection, and freeing up the ld struc- +-ture before returning. There is no server response to an unbind opera- +-tion. ldap_unbind() returns LDAP_SUCCESS (or another LDAP error code if +-the request cannot be sent to the LDAP server). After a call to +-ldap_unbind() or ldap_unbind_s(), the session handle ld is invalid. +- +- +-7.6. Searching +- +-The following functions are used to search the LDAP directory, returning +-a requested set of attributes for each entry matched. There are five +-variations. +- +- +- +-Expires: January 1998 [Page 13] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- int ldap_search_ext( +- LDAP *ld, +- char *base, +- int scope, +- char *filter, +- char **attrs, +- int attrsonly, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- struct timeval *timeoutp, +- int sizelimit, +- int *msgidp +- ); +- +- int ldap_search_ext_s( +- LDAP *ld, +- char *base, +- int scope, +- char *filter, +- char **attrs, +- int attrsonly, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- struct timeval *timeoutp, +- int sizelimit, +- LDAPMessage **res +- ); +- +- int ldap_search( +- LDAP *ld, +- char *base, +- int scope, +- char *filter, +- char **attrs, +- int attrsonly +- ); +- +- int ldap_search_s( +- LDAP *ld, +- char *base, +- int scope, +- char *filter, +- char **attrs, +- int attrsonly, +- LDAPMessage **res +- ); +- +- int ldap_search_st( +- +- +- +-Expires: January 1998 [Page 14] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- LDAP *ld, +- char *base, +- int scope, +- char *filter, +- char **attrs, +- int attrsonly, +- struct timeval *timeout, +- LDAPMessage **res +- ); +- +-Parameters are: +- +-ld The session handle. +- +-base The dn of the entry at which to start the search. +- +-scope One of LDAP_SCOPE_BASE (0x00), LDAP_SCOPE_ONELEVEL (0x01), +- or LDAP_SCOPE_SUBTREE (0x02), indicating the scope of the +- search. +- +-filter A character string as described in [3], representing the +- search filter. +- +-attrs A NULL-terminated array of strings indicating which attri- +- butes to return for each matching entry. Passing NULL for +- this parameter causes all available attributes to be +- retrieved. +- +-attrsonly A boolean value that should be zero if both attribute types +- and values are to be returned, non-zero if only types are +- wanted. +- +-timeout For the ldap_search_st() function, this specifies the local +- search timeout value. For the ldap_search_ext() and +- ldap_search_ext_s() functions, this specifies both the +- local search timeout value and the operation time limit +- that is sent to the server within the search request. +- +-res For the synchronous calls, this is a result parameter which +- will contain the results of the search upon completion of +- the call. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_search_ext() call succeeds. +- +- +- +-Expires: January 1998 [Page 15] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-There are three options in the session handle ld which potentially +-affect how the search is performed. They are: +- +-LDAP_OPT_SIZELIMIT +- A limit on the number of entries to return from the search. +- A value of zero means no limit. Note that the value from +- the session handle is ignored when using the +- ldap_search_ext() or ldap_search_ext_s() functions. +- +-LDAP_OPT_TIMELIMIT +- A limit on the number of seconds to spend on the search. A +- value of zero means no limit. Note that the value from the +- session handle is ignored when using the ldap_search_ext() +- or ldap_search_ext_s() functions. +- +-LDAP_OPT_DEREF +- One of LDAP_DEREF_NEVER (0x00), LDAP_DEREF_SEARCHING +- (0x01), LDAP_DEREF_FINDING (0x02), or LDAP_DEREF_ALWAYS +- (0x03), specifying how aliases should be handled during the +- search. The LDAP_DEREF_SEARCHING value means aliases should +- be dereferenced during the search but not when locating the +- base object of the search. The LDAP_DEREF_FINDING value +- means aliases should be dereferenced when locating the base +- object but not during the search. +- +-The ldap_search_ext() function initiates an asynchronous search opera- +-tion and returns the constant LDAP_SUCCESS if the request was success- +-fully sent, or another LDAP error code if not. See the section below on +-error handling for more information about possible errors and how to +-interpret them. If successful, ldap_search_ext() places the message id +-of the request in *msgidp. A subsequent call to ldap_result(), described +-below, can be used to obtain the results from the search. These results +-can be parsed using the result parsing routines described in detail +-later. +- +-Similar to ldap_search_ext(), the ldap_search() function initiates an +-asynchronous search operation and returns the message id of the opera- +-tion initiated. As for ldap_search_ext(), a subsequent call to +-ldap_result(), described below, can be used to obtain the result of the +-bind. In case of error, ldap_search() will return -1, setting the ses- +-sion error parameters in the LDAP structure appropriately. +- +-The synchronous ldap_search_ext_s(), ldap_search_s(), and +-ldap_search_st() functions all return the result of the operation, +-either the constant LDAP_SUCCESS if the operation was successful, or +-another LDAP error code if it was not. See the section below on error +-handling for more information about possible errors and how to interpret +-them. Entries returned from the search (if any) are contained in the +- +- +- +-Expires: January 1998 [Page 16] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-res parameter. This parameter is opaque to the caller. Entries, attri- +-butes, values, etc., should be extracted by calling the parsing routines +-described below. The results contained in res should be freed when no +-longer in use by calling ldap_msgfree(), described later. +- +-The ldap_search_ext() and ldap_search_ext_s() functions support LDAPv3 +-server controls, client controls, and allow varying size and time limits +-to be easily specified for each search operation. The ldap_search_st() +-function is identical to ldap_search_s() except that it takes an addi- +-tional parameter specifying a local timeout for the search. +- +-7.7. Reading an Entry +- +-LDAP does not support a read operation directly. Instead, this operation +-is emulated by a search with base set to the DN of the entry to read, +-scope set to LDAP_SCOPE_BASE, and filter set to "(objectclass=*)". attrs +-contains the list of attributes to return. +- +- +-7.8. Listing the Children of an Entry +- +-LDAP does not support a list operation directly. Instead, this operation +-is emulated by a search with base set to the DN of the entry to list, +-scope set to LDAP_SCOPE_ONELEVEL, and filter set to "(objectclass=*)". +-attrs contains the list of attributes to return for each child entry. +- +-7.9. Comparing a Value Against an Entry +- +-The following routines are used to compare a given attribute value +-assertion against an LDAP entry. There are four variations: +- +- int ldap_compare_ext( +- LDAP *ld, +- char *dn, +- char *attr, +- struct berval *bvalue +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- ); +- +- int ldap_compare_ext_s( +- LDAP *ld, +- char *dn, +- char *attr, +- struct berval *bvalue, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls +- +- +- +-Expires: January 1998 [Page 17] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- ); +- +- int ldap_compare( +- LDAP *ld, +- char *dn, +- char *attr, +- char *value +- ); +- +- int ldap_compare_s( +- LDAP *ld, +- char *dn, +- char *attr, +- char *value +- ); +- +-Parameters are: +- +-ld The session handle. +- +-dn The name of the entry to compare against. +- +-attr The attribute to compare against. +- +-bvalue The attribute value to compare against those found in the +- given entry. This parameter is used in the extended rou- +- tines and is a pointer to a struct berval so it is possible +- to compare binary values. +- +-value A string attribute value to compare against, used by the +- ldap_compare() and ldap_compare_s() functions. Use +- ldap_compare_ext() or ldap_compare_ext_s() if you need to +- compare binary values. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_compare_ext() call succeeds. +- +-The ldap_compare_ext() function initiates an asynchronous compare opera- +-tion and returns the constant LDAP_SUCCESS if the request was success- +-fully sent, or another LDAP error code if not. See the section below on +-error handling for more information about possible errors and how to +-interpret them. If successful, ldap_compare_ext() places the message id +-of the request in *msgidp. A subsequent call to ldap_result(), described +-below, can be used to obtain the result of the compare. +- +- +- +-Expires: January 1998 [Page 18] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-Similar to ldap_compare_ext(), the ldap_compare() function initiates an +-asynchronous compare operation and returns the message id of the opera- +-tion initiated. As for ldap_compare_ext(), a subsequent call to +-ldap_result(), described below, can be used to obtain the result of the +-bind. In case of error, ldap_compare() will return -1, setting the ses- +-sion error parameters in the LDAP structure appropriately. +- +-The synchronous ldap_compare_ext_s() and ldap_compare_s() functions both +-return the result of the operation, either the constant LDAP_SUCCESS if +-the operation was successful, or another LDAP error code if it was not. +-See the section below on error handling for more information about pos- +-sible errors and how to interpret them. +- +-The ldap_compare_ext() and ldap_compare_ext_s() functions support LDAPv3 +-server controls and client controls. +- +- +-7.10. Modifying an entry +- +-The following routines are used to modify an existing LDAP entry. There +-are four variations: +- +- typedef struct ldapmod { +- int mod_op; +- char *mod_type; +- union { +- char **modv_strvals; +- struct berval **modv_bvals; +- } mod_vals; +- } LDAPMod; +- #define mod_values mod_vals.modv_strvals +- #define mod_bvalues mod_vals.modv_bvals +- +- int ldap_modify_ext( +- LDAP *ld, +- char *dn, +- LDAPMod **mods, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- ); +- +- int ldap_modify_ext_s( +- LDAP *ld, +- char *dn, +- LDAPMod **mods, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls +- +- +- +-Expires: January 1998 [Page 19] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- ); +- +- int ldap_modify( +- LDAP *ld, +- char *dn, +- LDAPMod **mods +- ); +- +- int ldap_modify_s( +- LDAP *ld, +- char *dn, +- LDAPMod **mods +- ); +- +-Parameters are: +- +-ld The session handle. +- +-dn The name of the entry to modify. +- +-mods A NULL-terminated array of modifications to make to the +- entry. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_modify_ext() call succeeds. +- +-The fields in the LDAPMod structure have the following meanings: +- +-mod_op The modification operation to perform. It should be one of +- LDAP_MOD_ADD (0x00), LDAP_MOD_DELETE (0x01), or +- LDAP_MOD_REPLACE (0x02). This field also indicates the +- type of values included in the mod_vals union. It is logi- +- cally ORed with LDAP_MOD_BVALUES (0x80) to select the +- mod_bvalues form. Otherwise, the mod_values form is used. +- +-mod_type The type of the attribute to modify. +- +-mod_vals The values (if any) to add, delete, or replace. Only one of +- the mod_values or mod_bvalues variants should be used, +- selected by ORing the mod_op field with the constant +- LDAP_MOD_BVALUES. mod_values is a NULL-terminated array of +- zero-terminated strings and mod_bvalues is a NULL- +- terminated array of berval structures that can be used to +- pass binary values such as images. +- +- +- +-Expires: January 1998 [Page 20] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-For LDAP_MOD_ADD modifications, the given values are added to the +-entry, creating the attribute if necessary. +- +-For LDAP_MOD_DELETE modifications, the given values are deleted from the +-entry, removing the attribute if no values remain. If the entire attri- +-bute is to be deleted, the mod_vals field should be set to NULL. +- +-For LDAP_MOD_REPLACE modifications, the attribute will have the listed +-values after the modification, having been created if necessary, or +-removed if the mod_vals field is NULL. All modifications are performed +-in the order in which they are listed. +- +-The ldap_modify_ext() function initiates an asynchronous modify opera- +-tion and returns the constant LDAP_SUCCESS if the request was success- +-fully sent, or another LDAP error code if not. See the section below on +-error handling for more information about possible errors and how to +-interpret them. If successful, ldap_modify_ext() places the message id +-of the request in *msgidp. A subsequent call to ldap_result(), described +-below, can be used to obtain the result of the modify. +- +-Similar to ldap_modify_ext(), the ldap_modify() function initiates an +-asynchronous modify operation and returns the message id of the opera- +-tion initiated. As for ldap_modify_ext(), a subsequent call to +-ldap_result(), described below, can be used to obtain the result of the +-modify. In case of error, ldap_modify() will return -1, setting the ses- +-sion error parameters in the LDAP structure appropriately. +- +-The synchronous ldap_modify_ext_s() and ldap_modify_s() functions both +-return the result of the operation, either the constant LDAP_SUCCESS if +-the operation was successful, or another LDAP error code if it was not. +-See the section below on error handling for more information about pos- +-sible errors and how to interpret them. +- +-The ldap_modify_ext() and ldap_modify_ext_s() functions support LDAPv3 +-server controls and client controls. +- +- +-7.11. Modifying the Name of an Entry +- +-In LDAPv2, the ldap_modrdn() and ldap_modrdn_s() routines were used to +-change the name of an LDAP entry. They could only be used to change the +-least significant component of a name (the RDN or relative distinguished +-name). LDAPv3 provides the Modify DN protocol operation that allows more +-general name change access. The ldap_rename() and ldap_rename_s() rou- +-tines are used to change the name of an entry, and the use of the +-ldap_modrdn() and ldap_modrdn_s() routines is deprecated. +- +- int ldap_rename( +- +- +- +-Expires: January 1998 [Page 21] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- LDAP *ld, +- char *dn, +- char *newrdn, +- char *newparent, +- int deleteoldrdn, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- +- ); +- int ldap_rename_s( +- LDAP *ld, +- char *dn, +- char *newrdn, +- char *newparent, +- int deleteoldrdn, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls +- ); +- +- Use of the following routines is deprecated. +- +- int ldap_modrdn( +- LDAP *ld, +- char *dn, +- char *newrdn, +- int deleteoldrdn +- ); +- int ldap_modrdn_s( +- LDAP *ld, +- char *dn, +- char *newrdn, +- int deleteoldrdn +- ); +- +-Parameters are: +- +-ld The session handle. +- +-dn The name of the entry whose DN is to be changed. +- +-newrdn The new RDN to give the entry. +- +-newparent The new parent, or superior entry. If this parameter is +- NULL, only the RDN of the entry is changed. The root DN +- may be specified by passing a zero length string, "". The +- newparent parameter should always be NULL when using ver- +- sion 2 of the LDAP protocol; otherwise the server's +- +- +- +-Expires: January 1998 [Page 22] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- behavior is undefined. +- +-deleteoldrdn This parameter only has meaning on the rename routines if +- newrdn is different than the old RDN. It is a boolean +- value, if non-zero indicating that the old RDN value(s) +- should be removed, if zero indicating that the old RDN +- value(s) should be retained as non-distinguished values of +- the entry. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_rename() call succeeds. +- +-The ldap_rename() function initiates an asynchronous modify DN operation +-and returns the constant LDAP_SUCCESS if the request was successfully +-sent, or another LDAP error code if not. See the section below on error +-handling for more information about possible errors and how to interpret +-them. If successful, ldap_rename() places the DN message id of the +-request in *msgidp. A subsequent call to ldap_result(), described below, +-can be used to obtain the result of the rename. +- +-The synchronous ldap_rename_s() returns the result of the operation, +-either the constant LDAP_SUCCESS if the operation was successful, or +-another LDAP error code if it was not. See the section below on error +-handling for more information about possible errors and how to interpret +-them. +- +-The ldap_rename() and ldap_rename_s() functions both support LDAPv3 +-server controls and client controls. +- +- +-7.12. Adding an entry +- +-The following functions are used to add entries to the LDAP directory. +-There are four variations: +- +- int ldap_add_ext( +- LDAP *ld, +- char *dn, +- LDAPMod **attrs, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- ); +- +- +- +- +-Expires: January 1998 [Page 23] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- int ldap_add_ext_s( +- LDAP *ld, +- char *dn, +- LDAPMod **attrs, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls +- ); +- +- int ldap_add( +- LDAP *ld, +- char *dn, +- LDAPMod **attrs +- ); +- +- int ldap_add_s( +- LDAP *ld, +- char *dn, +- LDAPMod **attrs +- ); +- +-Parameters are: +- +-ld The session handle. +- +-dn The name of the entry to add. +- +-attrs The entry's attributes, specified using the LDAPMod struc- +- ture defined for ldap_modify(). The mod_type and mod_vals +- fields should be filled in. The mod_op field is ignored +- unless ORed with the constant LDAP_MOD_BVALUES, used to +- select the mod_bvalues case of the mod_vals union. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_add_ext() call succeeds. +- +-Note that the parent of the entry being added must already exist or the +-parent must be empty (i.e., equal to the root DN) for an add to succeed. +- +-The ldap_add_ext() function initiates an asynchronous add operation and +-returns the constant LDAP_SUCCESS if the request was successfully sent, +-or another LDAP error code if not. See the section below on error han- +-dling for more information about possible errors and how to interpret +-them. If successful, ldap_add_ext() places the message id of the +-request in *msgidp. A subsequent call to ldap_result(), described below, +- +- +- +-Expires: January 1998 [Page 24] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-can be used to obtain the result of the add. +- +-Similar to ldap_add_ext(), the ldap_add() function initiates an asyn- +-chronous add operation and returns the message id of the operation ini- +-tiated. As for ldap_add_ext(), a subsequent call to ldap_result(), +-described below, can be used to obtain the result of the add. In case of +-error, ldap_add() will return -1, setting the session error parameters +-in the LDAP structure appropriately. +- +-The synchronous ldap_add_ext_s() and ldap_add_s() functions both return +-the result of the operation, either the constant LDAP_SUCCESS if the +-operation was successful, or another LDAP error code if it was not. See +-the section below on error handling for more information about possible +-errors and how to interpret them. +- +-The ldap_add_ext() and ldap_add_ext_s() functions support LDAPv3 server +-controls and client controls. +- +- +- +-7.13. Deleting an entry +- +-The following functions are used to delete a leaf entry from the LDAP +-directory. There are four variations: +- +- int ldap_delete_ext( +- LDAP *ld, +- char *dn, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- ); +- +- int ldap_delete_ext_s( +- LDAP *ld, +- char *dn, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls +- ); +- +- int ldap_delete( +- LDAP *ld, +- char *dn +- ); +- +- int ldap_delete_s( +- LDAP *ld, +- char *dn +- +- +- +-Expires: January 1998 [Page 25] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- ); +- +-Parameters are: +- +-ld The session handle. +- +-dn The name of the entry to delete. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_delete_ext() call succeeds. +- +-Note that the entry to delete must be a leaf entry (i.e., it must have +-no children). Deletion of entire subtrees in a single operation is not +-supported by LDAP. +- +-The ldap_delete_ext() function initiates an asynchronous delete opera- +-tion and returns the constant LDAP_SUCCESS if the request was success- +-fully sent, or another LDAP error code if not. See the section below on +-error handling for more information about possible errors and how to +-interpret them. If successful, ldap_delete_ext() places the message id +-of the request in *msgidp. A subsequent call to ldap_result(), described +-below, can be used to obtain the result of the delete. +- +-Similar to ldap_delete_ext(), the ldap_delete() function initiates an +-asynchronous delete operation and returns the message id of the opera- +-tion initiated. As for ldap_delete_ext(), a subsequent call to +-ldap_result(), described below, can be used to obtain the result of the +-delete. In case of error, ldap_delete() will return -1, setting the ses- +-sion error parameters in the LDAP structure appropriately. +- +-The synchronous ldap_delete_ext_s() and ldap_delete_s() functions both +-return the result of the operation, either the constant LDAP_SUCCESS if +-the operation was successful, or another LDAP error code if it was not. +-See the section below on error handling for more information about pos- +-sible errors and how to interpret them. +- +-The ldap_delete_ext() and ldap_delete_ext_s() functions support LDAPv3 +-server controls and client controls. +- +- +-7.14. Extended Operations +- +-The ldap_extended_operation() and ldap_extended_operation_s() routines +-allow extended LDAP operations to be passed to the server, providing a +- +- +- +-Expires: January 1998 [Page 26] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-general protocol extensibility mechanism. +- +- int ldap_extended_operation( +- LDAP *ld, +- char *exoid, +- struct berval *exdata, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- int *msgidp +- ); +- +- int ldap_extended_operation_s( +- LDAP *ld, +- char *exoid, +- struct berval *exdata, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls, +- char **retoidp, +- struct berval **retdatap +- ); +- +-Parameters are: +- +-ld The session handle. +- +-requestoid The dotted-OID text string naming the request. +- +-requestdata The arbitrary data required by the operation (if NULL, no +- data is sent to the server). +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-msgidp This result parameter will be set to the message id of the +- request if the ldap_extended_operation() call succeeds. +- +-retoidp Pointer to a character string that will be set to an allo- +- cated, dotted-OID text string returned by the server. This +- string should be disposed of using the ldap_memfree() func- +- tion. If no OID was returned, *retoidp is set to NULL. +- +-retdatap Pointer to a berval structure pointer that will be set an +- allocated copy of the data returned by the server. This +- struct berval should be disposed of using ber_bvfree(). If +- no data is returned, *retdatap is set to NULL. +- +-The ldap_extended_operation() function initiates an asynchronous +- +- +- +-Expires: January 1998 [Page 27] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-extended operation and returns the constant LDAP_SUCCESS if the request +-was successfully sent, or another LDAP error code if not. See the sec- +-tion below on error handling for more information about possible errors +-and how to interpret them. If successful, ldap_extended_operation() +-places the message id of the request in *msgidp. A subsequent call to +-ldap_result(), described below, can be used to obtain the result of the +-extended operation which can be passed to ldap_parse_extended_result() +-to obtain the OID and data contained in the response. +- +-The synchronous ldap_extended_operation_s() function returns the result +-of the operation, either the constant LDAP_SUCCESS if the operation was +-successful, or another LDAP error code if it was not. See the section +-below on error handling for more information about possible errors and +-how to interpret them. The retoid and retdata parameters are filled in +-with the OID and data from the response. If no OID or data was +-returned, these parameters are set to NULL. +- +-The ldap_extended_operation() and ldap_extended_operation_s() functions +-both support LDAPv3 server controls and client controls. +- +- +-8. Abandoning An Operation +- +-The following calls are used to abandon an operation in progress: +- +- int ldap_abandon_ext( +- LDAP *ld, +- int msgid, +- LDAPControl **serverctrls, +- LDAPControl **clientctrls +- ); +- +- int ldap_abandon( +- LDAP *ld, +- int msgid +- ); +- +- +-ld The session handle. +- +-msgid The message id of the request to be abandoned. +- +-serverctrls List of LDAP server controls. +- +-clientctrls List of client controls. +- +-ldap_abandon_ext() abandons the operation with message id msgid and +-returns the constant LDAP_SUCCESS if the abandon was successful or +- +- +- +-Expires: January 1998 [Page 28] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-another LDAP error code if not. See the section below on error handling +-for more information about possible errors and how to interpret them. +- +-ldap_abandon() is identical to ldap_abandon_ext() except that it returns +-zero if the abandon was successful, -1 otherwise and does not support +-LDAPv3 server controls or client controls. +- +-After a successful call to ldap_abandon() or ldap_abandon_ext(), results +-with the given message id are never returned from a subsequent call to +-ldap_result(). There is no server response to LDAP abandon operations. +- +- +-9. Obtaining Results and Peeking Inside LDAP Messages +- +-ldap_result() is used to obtain the result of a previous asynchronously +-initiated operation. Note that depending on how it is called, +-ldap_result() may actually return a list or "chain" of messages. +- +-ldap_msgfree() frees the results obtained from a previous call to +-ldap_result(), or a synchronous search routine. +- +-ldap_msgtype() returns the type of an LDAP message. ldap_msgid() +-returns the message ID of an LDAP message. +- +- int ldap_result( +- LDAP *ld, +- int msgid, +- int all, +- struct timeval *timeout, +- LDAPMessage **res +- ); +- +- int ldap_msgfree( LDAPMessage *res ); +- +- int ldap_msgtype( LDAPMessage *res ); +- +- int ldap_msgid( LDAPMessage *res ); +- +-Parameters are: +- +-ld The session handle. +- +-msgid The message id of the operation whose results are to be +- returned, or the constant LDAP_RES_ANY (-1) if any result is +- desired. +- +-all Specifies how many messages will be retrieved in a single call +- to ldap_result(). This parameter only has meaning for search +- +- +- +-Expires: January 1998 [Page 29] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- results. Pass the constant LDAP_MSG_ONE (0x00) to retrieve one +- message at a time. Pass LDAP_MSG_ALL (0x01) to request that +- all results of a search be received before returning all +- results in a single chain. Pass LDAP_MSG_RECEIVED (0x02) to +- indicate that all results retrieved so far should be returned +- in the result chain. +- +-timeout A timeout specifying how long to wait for results to be +- returned. A NULL value causes ldap_result() to block until +- results are available. A timeout value of zero seconds speci- +- fies a polling behavior. +- +-res For ldap_result(), a result parameter that will contain the +- result(s) of the operation. For ldap_msgfree(), the result +- chain to be freed, obtained from a previous call to +- ldap_result(), ldap_search_s(), or ldap_search_st(). +- +-Upon successful completion, ldap_result() returns the type of the first +-result returned in the res parameter. This will be one of the following +-constants. +- +- LDAP_RES_BIND (0x61) +- LDAP_RES_SEARCH_ENTRY (0x64) +- LDAP_RES_SEARCH_REFERENCE (0x73) -- new in LDAPv3 +- LDAP_RES_SEARCH_RESULT (0x65) +- LDAP_RES_MODIFY (0x67) +- LDAP_RES_ADD (0x69) +- LDAP_RES_DELETE (0x6B) +- LDAP_RES_MODDN (0x6D) +- LDAP_RES_COMPARE (0x6F) +- LDAP_RES_EXTENDED (0x78) -- new in LDAPv3 +- +-ldap_result() returns 0 if the timeout expired and -1 if an error +-occurs, in which case the error parameters of the LDAP session handle +-will be set accordingly. +- +-ldap_msgfree() frees the result structure pointed to by res and returns +-the type of the message it freed. +- +-ldap_msgtype() returns the type of the LDAP message it is passed as a +-parameter. The type will be one of the types listed above, or -1 on +-error. +- +-ldap_msgid() returns the message ID associated with the LDAP message +-passed as a parameter. +- +- +- +- +- +- +-Expires: January 1998 [Page 30] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-10. Handling Errors and Parsing Results +- +-The following calls are used to extract information from results and +-handle errors returned by other LDAP API routines. +- +- int ldap_parse_result( +- LDAP *ld, +- LDAPMessage *res, +- int *errcodep, +- char **matcheddnp, +- char **errmsgp, +- char ***referralsp, +- LDAPControl ***serverctrlsp, +- int freeit +- ); +- +- int ldap_parse_sasl_bind_result( +- LDAP *ld, +- LDAPMessage *res, +- struct berval **servercredp, +- int freeit +- ); +- +- int ldap_parse_extended_result( +- LDAP *ld, +- LDAPMessage *res, +- char **resultoidp, +- struct berval **resultdata, +- int freeit +- ); +- +- char *ldap_err2string( int err ); +- +- The use of the following routines is deprecated. +- +- int ldap_result2error( +- LDAP *ld, +- LDAPMessage *res, +- int freeit +- ); +- +- void ldap_perror( LDAP *ld, char *msg ); +- +-Parameters are: +- +-ld The session handle. +- +-res The result of an LDAP operation as returned by +- +- +- +-Expires: January 1998 [Page 31] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- ldap_result() or one of the synchronous API operation +- calls. +- +-errcodep This result parameter will be filled in with the LDAP error +- code field from the LDAPResult message. This is the indi- +- cation from the server of the outcome of the operation. +- NULL may be passed to ignore this field. +- +-matcheddnp In the case of a return of LDAP_NO_SUCH_OBJECT, this result +- parameter will be filled in with a DN indicating how much +- of the name in the request was recognized. NULL may be +- passed to ignore this field. The matched DN string should +- be freed by calling ldap_memfree() which is described later +- in this document. +- +-errmsgp This result parameter will be filled in with the contents +- of the error message field from the LDAPResult message. +- The error message string should be freed by calling +- ldap_memfree() which is described later in this document. +- NULL may be passed to ignore this field. +- +-referralsp This result parameter will be filled in with the contents +- of the referrals field from the LDAPResult message, indi- +- cating zero or more alternate LDAP servers where the +- request should be retried. The referrals array should be +- freed by calling ldap_value_free() which is described later +- in this document. NULL may be passed to ignore this field. +- +-serverctrlsp This result parameter will be filled in with an allocated +- array of controls copied out of the LDAPResult message. +- The control array should be freed by calling +- ldap_controls_free() which was described earlier. +- +-freeit A boolean that determines whether the res parameter is +- disposed of or not. Pass any non-zero value to have these +- routines free res after extracting the requested informa- +- tion. This is provided as a convenience; you can also use +- ldap_msgfree() to free the result later. +- +-servercredp For SASL bind results, this result parameter will be filled +- in with the credentials passed back by the server for +- mutual authentication, if given. An allocated berval struc- +- ture is returned that should be disposed of by calling +- ldap_ber_free(). NULL may be passed to ignore this field. +- +-resultoidp For extended results, this result parameter will be filled +- in with the dotted-OID text representation of the name of +- the extended operation response. This string should be +- +- +- +-Expires: January 1998 [Page 32] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- disposed of by calling ldap_memfree(). NULL may be passed +- to ignore this field. +- +-resultdatap For extended results, this result parameter will be filled +- in with a pointer to a struct berval containing the data in +- the extended operation response. It should be disposed of +- by calling ldap_ber_free(). NULL may be passed to ignore +- this field. +- +-err For ldap_err2string(), an LDAP error code, as returned by +- ldap_result2error() or another LDAP API call. +- +-Additional parameters for the deprecated routines are not described. +-Interested readers are referred to RFC 1823. +- +-All of the ldap_parse_*_result() routines skip over messages of type +-LDAP_RES_SEARCH_ENTRY and LDAP_RES_SEARCH_REFERENCE when looking for a +-result message to parse. They return the constant LDAP_SUCCESS if the +-result was successfully parsed and another LDAP error code if not. Note +-that the LDAP error code that indicates the outcome of the operation +-performed by the server is placed in the errcodep ldap_parse_result() +-parameter. +- +-ldap_err2string() is used to convert a numeric LDAP error code, as +-returned by one of the ldap_parse_*_result() routines, or one of the +-synchronous API operation calls, into an informative NULL-terminated +-character string message describing the error. It returns a pointer to +-static data. +- +- +-11. Stepping Through a List of Results +- +-The ldap_first_message() and ldap_next_message() routines are used to +-step through the list of messages in a result chain returned by +-ldap_result(). For search operations, the result chain may actually +-include referral messages, entry messages, and result messages. +-ldap_count_messages() is used to count the number of messages returned. +-The ldap_msgtype() function, described above, can be used to distinguish +-between the different message types. +- +- LDAPMessage *ldap_first_message( LDAP *ld, LDAPMessage *res ); +- +- LDAPMessage *ldap_next_message( LDAP *ld, LDAPMessage *msg ); +- +- int ldap_count_messages( LDAP *ld, LDAPMessage *res ); +- +-Parameters are: +- +- +- +- +-Expires: January 1998 [Page 33] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-ld The session handle. +- +-res The result chain, as obtained by a call to one of the synchronous +- search routines or ldap_result(). +- +-msg The message returned by a previous call to ldap_first_message() +- or ldap_next_message(). +- +-ldap_first_message() and ldap_next_message() will return NULL when no +-more messages exist in the result set to be returned. NULL is also +-returned if an error occurs while stepping through the entries, in which +-case the error parameters in the session handle ld will be set to indi- +-cate the error. +- +-ldap_count_messages() returns the number of messages contained in a +-chain of results. It can also be used to count the number of messages +-that remain in a chain if called with a message, entry, or reference +-returned by ldap_first_message(), ldap_next_message(), +-ldap_first_entry(), ldap_next_entry(), ldap_first_reference(), +-ldap_next_reference(). +- +- +-12. Parsing Search Results +- +-The following calls are used to parse the entries and references +-returned by ldap_search() and friends. These results are returned in an +-opaque structure that should only be accessed by calling the routines +-described below. Routines are provided to step through the entries and +-references returned, step through the attributes of an entry, retrieve +-the name of an entry, and retrieve the values associated with a given +-attribute in an entry. +- +- +-12.1. Stepping Through a List of Entries +- +-The ldap_first_entry() and ldap_next_entry() routines are used to step +-through and retrieve the list of entries from a search result chain. +-The ldap_first_reference() and ldap_next_reference() routines are used +-to step through and retrieve the list of continuation references from a +-search result chain. ldap_count_entries() is used to count the number +-of entries returned. ldap_count_references() is used to count the number +-of references returned. +- +- LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *res ); +- +- LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry ); +- +- LDAPMessage *ldap_first_reference( LDAP *ld, LDAPMessage *res ); +- +- +- +-Expires: January 1998 [Page 34] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- LDAPMessage *ldap_next_reference( LDAP *ld, LDAPMessage *ref ); +- +- int ldap_count_entries( LDAP *ld, LDAPMessage *res ); +- +- int ldap_count_references( LDAP *ld, LDAPMessage *res ); +- +-Parameters are: +- +-ld The session handle. +- +-res The search result, as obtained by a call to one of the synchro- +- nous search routines or ldap_result(). +- +-entry The entry returned by a previous call to ldap_first_entry() or +- ldap_next_entry(). +- +-ldap_first_entry() and ldap_next_entry() will return NULL when no more +-entries or references exist in the result set to be returned. NULL is +-also returned if an error occurs while stepping through the entries, in +-which case the error parameters in the session handle ld will be set to +-indicate the error. +- +-ldap_count_entries() returns the number of entries contained in a chain +-of entries. It can also be used to count the number of entries that +-remain in a chain if called with a message, entry or reference returned +-by ldap_first_message(), ldap_next_message(), ldap_first_entry(), +-ldap_next_entry(), ldap_first_reference(), ldap_next_reference(). +- +-ldap_count_references() returns the number of references contained in a +-chain of search results. It can also be used to count the number of +-references that remain in a chain. +- +- +-12.2. Stepping Through the Attributes of an Entry +- +-The ldap_first_attribute() and ldap_next_attribute() calls are used to +-step through the list of attribute types returned with an entry. +- +- char *ldap_first_attribute( +- LDAP *ld, +- LDAPMessage *entry, +- BerElement **ptr +- ); +- +- char *ldap_next_attribute( +- LDAP *ld, +- LDAPMessage *entry, +- BerElement *ptr +- +- +- +-Expires: January 1998 [Page 35] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- ); +- +- void ldap_memfree( char *mem ); +- +-Parameters are: +- +-ld The session handle. +- +-entry The entry whose attributes are to be stepped through, as returned +- by ldap_first_entry() or ldap_next_entry(). +- +-ptr In ldap_first_attribute(), the address of a pointer used inter- +- nally to keep track of the current position in the entry. In +- ldap_next_attribute(), the pointer returned by a previous call to +- ldap_first_attribute(). +- +-mem A pointer to memory allocated by the LDAP library, such as the +- attribute names returned by ldap_first_attribute() and +- ldap_next_attribute, or the DN returned by ldap_get_dn(). +- +-ldap_first_attribute() and ldap_next_attribute() will return NULL when +-the end of the attributes is reached, or if there is an error, in which +-case the error parameters in the session handle ld will be set to indi- +-cate the error. +- +-Both routines return a pointer to an allocated buffer containing the +-current attribute name. This should be freed when no longer in use by +-calling ldap_memfree(). +- +-ldap_first_attribute() will allocate and return in ptr a pointer to a +-BerElement used to keep track of the current position. This pointer +-should be passed in subsequent calls to ldap_next_attribute() to step +-through the entry's attributes. After a set of calls to +-ldap_first_attribute() and ldap_next_attibute(), if ptr is non-NULL, it +-should be freed by calling ldap_ber_free( ptr, 0 ). Note that it is very +-important to pass the second parameter as 0 (zero) in this call. +- +-The attribute names returned are suitable for passing in a call to +-ldap_get_values() and friends to retrieve the associated values. +- +- +-12.3. Retrieving the Values of an Attribute +- +-ldap_get_values() and ldap_get_values_len() are used to retrieve the +-values of a given attribute from an entry. ldap_count_values() and +-ldap_count_values_len() are used to count the returned values. +-ldap_value_free() and ldap_value_free_len() are used to free the values. +- +- +- +- +-Expires: January 1998 [Page 36] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- char **ldap_get_values( +- LDAP *ld, +- LDAPMessage *entry, +- char *attr +- ); +- +- struct berval **ldap_get_values_len( +- LDAP *ld, +- LDAPMessage *entry, +- char *attr +- ); +- +- int ldap_count_values( char **vals ); +- +- int ldap_count_values_len( struct berval **vals ); +- +- int ldap_value_free( char **vals ); +- +- int ldap_value_free_len( struct berval **vals ); +- +-Parameters are: +- +-ld The session handle. +- +-entry The entry from which to retrieve values, as returned by +- ldap_first_entry() or ldap_next_entry(). +- +-attr The attribute whose values are to be retrieved, as returned by +- ldap_first_attribute() or ldap_next_attribute(), or a caller- +- supplied string (e.g., "mail"). +- +-vals The values returned by a previous call to ldap_get_values() or +- ldap_get_values_len(). +- +-Two forms of the various calls are provided. The first form is only +-suitable for use with non-binary character string data. The second _len +-form is used with any kind of data. +- +-Note that the values returned are dynamically allocated and should be +-freed by calling either ldap_value_free() or ldap_value_free_len() when +-no longer in use. +- +- +-12.4. Retrieving the name of an entry +- +-ldap_get_dn() is used to retrieve the name of an entry. +-ldap_explode_dn() and ldap_explode_rdn() are used to break up a name +-into its component parts. ldap_dn2ufn() is used to convert the name into +- +- +- +-Expires: January 1998 [Page 37] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-a more "user friendly" format. +- +- char *ldap_get_dn( LDAP *ld, LDAPMessage *entry ); +- +- char **ldap_explode_dn( char *dn, int notypes ); +- +- char **ldap_explode_rdn( char *rdn, int notypes ); +- +- char *ldap_dn2ufn( char *dn ); +- +-Parameters are: +- +-ld The session handle. +- +-entry The entry whose name is to be retrieved, as returned by +- ldap_first_entry() or ldap_next_entry(). +- +-dn The dn to explode, such as returned by ldap_get_dn(). +- +-rdn The rdn to explode, such as returned in the components of the +- array returned by ldap_explode_dn(). +- +-notypes A boolean parameter, if non-zero indicating that the dn or rdn +- components should have their type information stripped off +- (i.e., "cn=Babs" would become "Babs"). +- +-ldap_get_dn() will return NULL if there is some error parsing the dn, +-setting error parameters in the session handle ld to indicate the error. +-It returns a pointer to malloc'ed space that the caller should free by +-calling ldap_memfree() when it is no longer in use. Note the format of +-the DNs returned is given by [4]. +- +-ldap_explode_dn() returns a NULL-terminated char * array containing the +-RDN components of the DN supplied, with or without types as indicated by +-the notypes parameter. The array returned should be freed when it is no +-longer in use by calling ldap_value_free(). +- +-ldap_explode_rdn() returns a NULL-terminated char * array containing the +-components of the RDN supplied, with or without types as indicated by +-the notypes parameter. The array returned should be freed when it is no +-longer in use by calling ldap_value_free(). +- +-ldap_dn2ufn() converts the DN into the user friendly format described in +-[5]. The UFN returned is malloc'ed space that should be freed by a call +-to ldap_memfree() when no longer in use. +- +- +- +- +- +- +-Expires: January 1998 [Page 38] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-13. Encoded ASN.1 Value Manipulation +- +-This section describes routines which may be used to encode and decode +-BER-encoded ASN.1 values, which are often used inside of control and +-extension values. +- +-With the exceptions of two new functions ber_flatten() and ber_init(), +-these functions are compatible with the University of Michigan LDAP 3.3 +-implementation of BER. +- +- +-13.1. General +- +- struct berval { +- unsigned long bv_len; +- char *bv_val; +- }; +- +-A struct berval contains a sequence of bytes and an indication of its +-length. The bv_val is not null terminated. bv_len must always be a +-nonnegative number. Applications may allocate their own berval struc- +-tures. +- +- typedef struct berelement { +- /* opaque */ +- } BerElement; +- +-The BerElement structure contains not only a copy of the encoded value, +-but also state information used in encoding or decoding. Applications +-cannot allocate their own BerElement structures. The internal state is +-neither thread-specific nor locked, so two threads should not manipulate +-the same BerElement value simultaneously. +- +-A single BerElement value cannot be used for both encoding and decoding. +- +- void ber_bvfree ( struct berval *bv); +- +-ber_bvfree() frees a berval returned from this API. Both the bv->bv_val +-string and the berval itself are freed. Applications should not use +-ber_bvfree() with bervals which the application has allocated. +- +- void ber_bvecfree ( struct berval **bv ); +- +-ber_bvecfree() frees an array of bervals returned from this API. Each +-of the bervals in the array are freed using ber_bvfree(), then the array +-itself is freed. +- +- struct berval *ber_bvdup (struct berval *bv ); +- +- +- +-Expires: January 1998 [Page 39] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-ber_bvdup() returns a copy of a berval. The bv_val field in the +-returned berval points to a different area of memory as the bv_val field +-in the argument berval. The null pointer is returned on error (e.g. out +-of memory). +- +- void ber_free ( BerElement *ber, int fbuf ); +- +-ber_free() frees a BerElement which is returned from the API calls +-ber_alloc_t() or ber_init(). Each BerElement must be freed by the +-caller. The second argument fbuf should always be set to 1. +- +- +-13.2. Encoding +- +- BerElement *ber_alloc_t(int options); +- +-ber_alloc_t() constructs and returns BerElement. The null pointer is +-returned on error. The options field contains a bitwise-or of options +-which are to be used when generating the encoding of this BerElement. +-One option is defined and must always be supplied: +- +- #define LBER_USE_DER 0x01 +- +-When this option is present, lengths will always be encoded in the +-minimum number of octets. Note that this option does not cause values +-of sets and sequences to be rearranged in tag and byte order, so these +-functions are not suitable for generating DER output as defined in X.509 +-and X.680. +- +-Unrecognized option bits are ignored. +- +-The BerElement returned by ber_alloc_t() is initially empty. Calls to +-ber_printf() will append bytes to the end of the ber_alloc_t(). +- +- int ber_printf(BerElement *ber, char *fmt, ... ) +- +-The ber_printf() routine is used to encode a BER element in much the +-same way that sprintf() works. One important difference, though, is +-that state information is kept in the ber argument so that multiple +-calls can be made to ber_printf() to append to the end of the BER ele- +-ment. ber must be a pointer to a BerElement returned by ber_alloc_t(). +-ber_printf() interprets and formats its arguments according to the for- +-mat string fmt. ber_printf() returns -1 if there is an error during +-encoding. As with sprintf(), each character in fmt refers to an argu- +-ment to ber_printf(). +- +-The format string can contain the following format characters: +- +- +- +- +-Expires: January 1998 [Page 40] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-'t' Tag. The next argument is an int specifying the tag to override +- the next element to be written to the ber. This works across +- calls. The int value must contain the tag class, constructed +- bit, and tag value. The tag value must fit in a single octet +- (tag value is less than 32). For example, a tag of "[3]" for a +- constructed type is 0xA3. +- +-'b' Boolean. The next argument is an int, containing either 0 for +- FALSE or 0xff for TRUE. A boolean element is output. If this +- format character is not preceded by the 't' format modifier, the +- tag 0x01 is used for the element. +- +-'i' Integer. The next argument is an int, containing the integer in +- the host's byte order. An integer element is output. If this +- format character is not preceded by the 't' format modifier, the +- tag 0x02 is used for the element. +- +-'X' Bitstring. The next two arguments are a char * pointer to the +- start of the bitstring, followed by an int containing the number +- of bits in the bitstring. A bitstring element is output, in +- primitive form. If this format character is not preceded by the +- 't' format modifier, the tag 0x03 is used for the element. +- +-'n' Null. No argument is required. An ASN.1 NULL element is out- +- put. If this format character is not preceded by the 't' format +- modifier, the tag 0x05 is used for the element. +- +-'o' Octet string. The next two arguments are a char *, followed by +- an int with the length of the string. The string may contain +- null bytes and need not by null-terminated. An octet string +- element is output, in primitive form. If this format character +- is not preceded by the 't' format modifier, the tag 0x04 is used +- for the element. +- +-'s' Octet string. The next argument is a char * pointing to a +- null-terminated string. An octet string element in primitive +- form is output, which does not include the trailing ' ' byte. If +- this format character is not preceded by the 't' format modif- +- ier, the tag 0x04 is used for the element. +- +-'v' Several octet strings. The next argument is a char **, an array +- of char * pointers to null-terminated strings. The last element +- in the array must be a null pointer. The octet strings do not +- include the trailing SEQUENCE OF octet strings. The 't' format +- modifier cannot be used with this format character. +- +-'V' Several octet strings. A null-terminated array of berval *'s is +- supplied. Note that a construct like '{V}' is required to get an +- +- +- +-Expires: January 1998 [Page 41] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- actual SEQUENCE OF octet strings. The 't' format modifier cannot +- be used with this format character. +- +-'{' Begin sequence. No argument is required. If this format char- +- acter is not preceded by the 't' format modifier, the tag 0x30 +- is used. +- +-'}' End sequence. No argument is required. The 't' format modifier +- cannot be used with this format character. +- +-'[' Begin set. No argument is required. If this format character +- is not preceded by the 't' format modifier, the tag 0x31 is +- used. +- +-']' End set. No argument is required. The 't' format modifier can- +- not be used with this format character. +- +-Each use of a '{' format character must be matched by a '}' character, +-either later in the format string, or in the format string of a subse- +-quent call to ber_printf() for that BerElement. The same applies to the +-'[' and +- +-Sequences and sets nest, and implementations of this API must maintain +-internal state to be able to properly calculate the lengths. +- +- int ber_flatten (BerElement *ber, struct berval **bvPtr); +- +-The ber_flatten routine allocates a struct berval whose contents are a +-BER encoding taken from the ber argument. The bvPtr pointer points to +-the returned berval, which must be freed using ber_bvfree(). This rou- +-tine returns 0 on success and -1 on error. +- +-The ber_flatten API call is not present in U-M LDAP 3.3. +- +-The use of ber_flatten on a BerElement in which all '{' and '}' format +-modifiers have not been properly matched can result in a berval whose +-contents are not a valid BER encoding. +- +- +-13.3. Encoding Example +- +-The following is an example of encoding the following ASN.1 data type: +- +- Example1Request ::= SEQUENCE { +- s OCTET STRING, -- must be printable +- val1 INTEGER, +- val2 [0] INTEGER DEFAULT 0 +- } +- +- +- +-Expires: January 1998 [Page 42] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- int encode_example1(char *s,int val1,int val2,struct berval **bvPtr) +- { +- BerElement *ber; +- int rc; +- +- ber = ber_alloc_t(LBER_USE_DER); +- +- if (ber == NULL) return -1; +- +- if (ber_printf(ber,"{si",s,val1) == -1) { +- ber_free(ber,1); +- return -1; +- } +- +- if (val2 != 0) { +- if (ber_printf(ber,"ti",0x80,val2) == -1) { +- ber_free(ber,1); +- return -1; +- } +- } +- +- if (ber_printf(ber,"}") == -1) { +- ber_free(ber,1); +- return -1; +- } +- +- rc = ber_flatten(ber,bvPtr); +- ber_free(ber,1); +- return -1; +- } +- +- +-13.4. Decoding +- +-The following two symbols are available to applications. +- +- #define LBER_ERROR 0xffffffffL +- #define LBER_DEFAULT 0xffffffffL +- +- BerElement *ber_init (struct berval *bv); +- +-The ber_init functions construct BerElement and returns a new BerElement +-containing a copy of the data in the bv argument. ber_init returns the +-null pointer on error. +- +- unsigned long ber_scanf (BerElement *ber, char *fmt, ... ); +- +-The ber_scanf() routine is used to decode a BER element in much the same +- +- +- +-Expires: January 1998 [Page 43] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-way that sscanf() works. One important difference, though, is that some +-state information is kept with the ber argument so that multiple calls +-can be made to ber_scanf() to sequentially read from the BER element. +-The ber argument must be a pointer to a BerElement returned by +-ber_init(). ber_scanf interprets the bytes according to the format +-string fmt, and stores the results in its additional arguments. +-ber_scanf() returns LBER_ERROR on error, and a nonnegative number on +-success. +- +-The format string contains conversion specifications which are used to +-direct the interpretation of the BER element. The format string can +-contain the following characters: +- +-'a' Octet string. A char ** argument should be supplied. Memory is +- allocated, filled with the contents of the octet string, null- +- terminated, and the pointer to the string is stored in the argu- +- ment. The returned value must be freed using ldap_memfree. The +- tag of the element must indicate the primitive form (constructed +- strings are not supported) but is otherwise ignored and dis- +- carded during the decoding. This format cannot be used with +- octet strings which could contain null bytes. +- +-'O' Octet string. A struct berval ** argument should be supplied, +- which upon return points to a allocated struct berval containing +- the octet string and its length. ber_bvfree() must be called to +- free the allocated memory. The tag of the element must indicate +- the primitive form (constructed strings are not supported) but +- is otherwise ignored during the decoding. +- +-'b' Boolean. A pointer to an int should be supplied. The int value +- stored will be 0 for FALSE or nonzero for TRUE. The tag of the +- element must indicate the primitive form but is otherwise +- ignored during the decoding. +- +-'i' Integer. A pointer to an int should be supplied. The int value +- stored will be in host byte order. The tag of the element must +- indicate the primitive form but is otherwise ignored during the +- decoding. ber_scanf() will return an error if the integer can- +- not be stored in an int. +- +-'B' Bitstring. A char ** argument should be supplied which will +- point to the allocated bits, followed by an unsigned long * +- argument, which will point to the length (in bits) of the bit- +- string returned. ldap_memfree must be called to free the bit- +- string. The tag of the element must indicate the primitive form +- (constructed bitstrings are not supported) but is otherwise +- ignored during the decoding. +- +- +- +- +-Expires: January 1998 [Page 44] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-'n' Null. No argument is required. The element is simply skipped +- if it is recognized as a zero-length element. The tag is +- ignored. +- +-'v' Several octet strings. A char *** argument should be supplied, +- which upon return points to a allocated null-terminated array of +- char *'s containing the octet strings. NULL is stored if the +- sequence is empty. ldap_memfree must be called to free each +- element of the array and the array itself. The tag of the +- sequence and of the octet strings are ignored. +- +-'V' Several octet strings (which could contain null bytes). A +- struct berval *** should be supplied, which upon return points +- to a allocated null-terminated array of struct berval *'s con- +- taining the octet strings and their lengths. NULL is stored if +- the sequence is empty. ber_bvecfree() can be called to free the +- allocated memory. The tag of the sequence and of the octet +- strings are ignored. +- +-'x' Skip element. The next element is skipped. No argument is +- required. +- +-'{' Begin sequence. No argument is required. The initial sequence +- tag and length are skipped. +- +-'}' End sequence. No argument is required. +- +-'[' Begin set. No argument is required. The initial set tag and +- length are skipped. +- +-']' End set. No argument is required. +- +- unsigned long ber_peek_tag (BerElement *ber, unsigned long *lenPtr); +- +-ber_peek_tag() returns the tag of the next element to be parsed in the +-BerElement argument. The length of this element is stored in the +-*lenPtr argument. LBER_DEFAULT is returned if there is no further data +-to be read. The ber argument is not modified. +- +- unsigned long ber_skip_tag (BerElement *ber, unsigned long *lenPtr); +- +-ber_skip_tag() is similar to ber_peek_tag(), except that the state +-pointer in the BerElement argument is advanced past the first tag and +-length, and is pointed to the value part of the next element. This rou- +-tine should only be used with constructed types and situations when a +-BER encoding is used as the value of an OCTET STRING. The length of the +-value is stored in *lenPtr. +- +- +- +- +-Expires: January 1998 [Page 45] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- unsigned long ber_first_element(BerElement *ber, +- unsigned long *lenPtr, char **opaquePtr); +- +- unsigned long ber_next_element (BerElement *ber, +- unsigned long *lenPtr, char *opaque); +- +-ber_first_element() and ber_next_element() are used to traverse a SET, +-SET OF, SEQUENCE or SEQUENCE OF data value. ber_first_element() calls +-ber_skip_tag(), stores internal information in *lenPtr and *opaquePtr, +-and calls ber_peek_tag() for the first element inside the constructed +-value. LBER_DEFAULT is returned if the constructed value is empty. +-ber_next_element() positions the state at the start of the next element +-in the constructed type. LBER_DEFAULT is returned if there are no +-further values. +- +-The len and opaque values should not be used by applications other than +-as arguments to ber_next_element(), as shown in the example below. +- +- +-13.5. Decoding Example +- +-The following is an example of decoding an ASN.1 data type: +- +- Example2Request ::= SEQUENCE { +- dn OCTET STRING, -- must be printable +- scope ENUMERATED { b (0), s (1), w (2) }, +- ali ENUMERATED { n (0), s (1), f (2), a (3) }, +- size INTEGER, +- time INTEGER, +- tonly BOOLEAN, +- attrs SEQUENCE OF OCTET STRING, -- must be printable +- [0] SEQUENCE OF SEQUENCE { +- type OCTET STRING -- must be printable, +- crit BOOLEAN DEFAULT FALSE, +- value OCTET STRING +- } OPTIONAL } +- +- #define LDAP_TAG_CONTROL_LIST 0xA0L /* context specific cons 0 */ +- +- int decode_example2(struct berval *bv) +- { +- BerElement *ber; +- unsigned long len; +- int scope, ali, size, time, tonly; +- char *dn = NULL, **attrs = NULL; +- int res,i,rc = 0; +- +- ber = ber_init(bv); +- +- +- +-Expires: January 1998 [Page 46] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- if (ber == NULL) { +- printf("ERROR ber_init failed0); +- return -1; +- } +- +- res = ber_scanf(ber,"{aiiiiib{v}",&dn,&scope,&ali, +- &size,&time,&tonly,&attrs); +- +- if (res == -1) { +- printf("ERROR ber_scanf failed0); +- ber_free(ber,1); +- return -1; +- } +- +- /* *** use dn */ +- ldap_memfree(dn); +- +- for (i = 0; attrs != NULL && attrs[i] != NULL; i++) { +- /* *** use attrs[i] */ +- ldap_memfree(attrs[i]); +- } +- ldap_memfree(attrs); +- +- if (ber_peek_tag(ber,&len) == LDAP_TAG_CONTROL_LIST) { +- char *opaque; +- unsigned long tag; +- +- for (tag = ber_first_element(ber,&len,&opaque); +- tag != LBER_DEFAULT; +- tag = ber_next_element (ber,&len,opaque)) { +- +- unsigned long ttag, tlen; +- char *type; +- int crit; +- struct berval *value; +- +- if (ber_scanf(ber,"{a",&type) == LBER_ERROR) { +- printf("ERROR cannot parse type0); +- break; +- } +- /* *** use type */ +- ldap_memfree(type); +- +- ttag = ber_peek_tag(ber,&tlen); +- if (ttag == 0x01) { /* boolean */ +- if (ber_scanf(ber,"b", +- &crit) == LBER_ERROR) { +- printf("ERROR cannot parse crit0); +- +- +- +-Expires: January 1998 [Page 47] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- rc = -1; +- break; +- } +- } else if (ttag == 0x04) { /* octet string */ +- crit = 0; +- } else { +- printf("ERROR extra field in controls0); +- break; +- } +- +- if (ber_scanf(ber,"O}",&value) == LBER_ERROR) { +- printf("ERROR cannot parse value0); +- rc = -1; +- break; +- } +- /* *** use value */ +- ldap_bvfree(value); +- } +- } +- +- ber_scanf(ber,"}"); +- +- ber_free(ber,1); +- +- return rc; +- } +- +- +- +-14. Security Considerations +- +-LDAPv2 supports security through protocol-level authentication using +-clear-text passwords. LDAPv3 adds support for SASL [8] (Simple Authen- +-tication Security Layer) methods. LDAPv3 also supports operation over a +-secure transport layer using Transport Layer Security TLS [8]. Readers +-are referred to the protocol documents for discussion of related secu- +-rity considerations. +- +-Implementations of this API should be cautious when handling authentica- +-tion credentials. In particular, keeping long-lived copies of creden- +-tials without the application's knowledge is discouraged. +- +- +-15. Acknowledgements +- +-Many members of the IETF ASID working group as well as members of the +-Internet at large have provided useful comments and suggestions that +-have been incorporated into this revision. +- +- +- +-Expires: January 1998 [Page 48] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-This original material upon which this revision is based was based upon +-work supported by the National Science Foundation under Grant No. NCR- +-9416667. +- +- +-16. Bibliography +- +-[1] The Directory: Selected Attribute Syntaxes. CCITT, Recommendation +- X.520. +- +-[2] M. Wahl, A. Coulbeck, T. Howes, S. Kille, W. Yeong, C. Robbins, +- "Lightweight Directory Access Protocol Attribute Syntax Defini- +- tions", INTERNET-DRAFT , +- 11 July 1997. +- +-[3] T. Howes, "A String Representation of LDAP Search Filters," +- INTERNET-DRAFT , May 1997. +- +-[4] S. Kille, M. Wahl, "A UTF-8 String Representation of Distinguished +- Names", INTERNET-DRAFT , 29 April +- 1997. +- +-[5] S. Kille, "Using the OSI Directory to Achieve User Friendly Nam- +- ing," RFC 1781, March 1995. +- +-[6] M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access Protocol +- (v3)", INTERNET-DRAFT , 11 +- July 1997. +- +-[7] A. Herron, T. Howes, M. Wahl, "LDAP Control Extension for Server +- Side Sorting of Search Result," INTERNET-DRAFT , 16 April 1997. +- +-[8] J. Meyers, "Simple Authentication and Security Layer", INTERNET- +- DRAFT , April 1997. +- +-[9] "Lightweight Directory Access Protocol (v3) Extension for Transport +- Layer Security", INTERNET-DRAFT , June 1997. +- +-[10] "UTF-8, a transformation format of Unicode and ISO 10646", RFC +- 2044, October 1996. +- +-[11] "IP Version 6 Addressing Architecture,", RFC 1884, December 1995. +- +- +- +- +- +- +- +-Expires: January 1998 [Page 49] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-17. Author's Addresses +- +- Tim Howes +- Netscape Communications Corp. +- 501 E. Middlefield Rd., Mailstop MV068 +- Mountain View, CA 94043 +- USA +- +1 415 937-3419 +- howes@netscape.com +- +- +- Mark Smith +- Netscape Communications Corp. +- 501 E. Middlefield Rd., Mailstop MV068 +- Mountain View, CA 94043 +- USA +- +1 415 937-3477 +- mcs@netscape.com +- +- Andy Herron +- Microsoft Corp. +- 1 Microsoft Way +- Redmond, WA 98052 +- USA +- +1 425 882-8080 +- andyhe@microsoft.com +- +- Chris Weider +- Microsoft Corp. +- 1 Microsoft Way +- Redmond, WA 98052 +- USA +- +1 425 882-8080 +- cweider@microsoft.com +- +- Mark Wahl +- Critical Angle Inc. +- 4815 W Braker Lane #502-385 +- Austin, TX 78759 +- USA +- M.Wahl@critical-angle.com +- +- +-18. Appendix A - Sample LDAP API Code +- +- #include +- +- main() +- +- +- +-Expires: January 1998 [Page 50] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- { +- LDAP *ld; +- LDAPMessage *res, *e; +- int i; +- char *a, *dn; +- BerElement *ptr; +- char **vals; +- +- /* open an LDAP session */ +- if ( (ld = ldap_init( "dotted.host.name", LDAP_PORT )) == NULL ) +- exit( 1 ); +- +- /* authenticate as nobody */ +- if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) { +- ldap_perror( ld, "ldap_simple_bind_s" ); +- exit( 1 ); +- } +- +- /* search for entries with cn of "Babs Jensen", return all attrs */ +- if ( ldap_search_s( ld, "o=University of Michigan, c=US", +- LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res ) +- != LDAP_SUCCESS ) { +- ldap_perror( ld, "ldap_search_s" ); +- exit( 1 ); +- } +- +- /* step through each entry returned */ +- for ( e = ldap_first_entry( ld, res ); e != NULL; +- e = ldap_next_entry( ld, e ) ) { +- /* print its name */ +- dn = ldap_get_dn( ld, e ); +- printf( "dn: %s\n", dn ); +- ldap_memfree( dn ); +- +- /* print each attribute */ +- for ( a = ldap_first_attribute( ld, e, &ptr ); a != NULL; +- a = ldap_next_attribute( ld, e, ptr ) ) { +- printf( "attribute: %s\n", a ); +- +- /* print each value */ +- vals = ldap_get_values( ld, e, a ); +- for ( i = 0; vals[i] != NULL; i++ ) { +- printf( "value: %s\n", vals[i] ); +- } +- ldap_value_free( vals ); +- } +- if ( ptr != NULL ) { +- ldap_ber_free( ptr, 0 ); +- +- +- +-Expires: January 1998 [Page 51] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +- } +- } +- /* free the search results */ +- ldap_msgfree( res ); +- +- /* close and free connection resources */ +- ldap_unbind( ld ); +- } +- +- +- +-19. Appendix B - Outstanding Issues +- +- +-19.1. Support for multithreaded applications +- +-In order to support multithreaded applications in a platform-independent +-way, some additions to the LDAP API are needed. Different implementors +-have taken different paths to solve this problem in the past. A common +-set of thread-related API calls must be defined so that application +-developers are not unduly burdened. These will be added to a future +-revision of this specification. +- +- +-19.2. Using Transport Layer Security (TLS) +- +-The API calls used to support TLS must be specified. They will be added +-to a future revision of this specification. +- +- +-19.3. Client control for chasing referrals +- +-A client control has been defined that can be used to specify on a per- +-operation basis whether references and external referrals are automati- +-cally chased by the client library. This will be added to a future +-revision of this specification. +- +- +-19.4. Potential confusion between hostname:port and IPv6 addresses +- +-String representations of IPv6 network addresses [11] can contain colon +-characters. The ldap_init() call is specified to take strings of the +-form "hostname:port" or "ipaddress:port". If IPv6 addresses are used, +-the latter could be ambiguous. A future revision of this specification +-will resolve this issue. +- +- +- +- +- +- +-Expires: January 1998 [Page 52] +- +-C LDAP API The C LDAP Application Program Interface 29 July 1997 +- +- +-19.5. Need to track SASL API standardization efforts +- +-If a standard Simple Authentication and Security Layer API is defined, +-it may be necessary to modify the LDAP API to accommodate it. +- +- +-19.6. Support for character sets other than UTF-8? +- +-Some application developers would prefer to pass string data using a +-character set other than UTF-8. This could be accommodated by adding a +-new option to ldap_set_option() that supports choosing a character set. +-If this feature is added, the number of different character sets sup- +-ported should definitely be minimized. +- +- +-19.7. Use of UTF-8 with LDAPv2 servers +- +-Strings are always passed as UTF-8 in this API but LDAP version 2 +-servers do not support the full range of UTF-8 characters. The expected +-behavior of this API when using LDAP version 2 with unsupported charac- +-ters should be specified. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-Expires: January 1998 [Page 53] +- +- +- +-1. Status of this Memo............................................1 +-2. Introduction...................................................1 +-3. Overview of the LDAP Model.....................................2 +-4. Overview of LDAP API Use.......................................3 +-5. Common Data Structures.........................................4 +-6. LDAP Error Codes...............................................5 +-7. Performing LDAP Operations.....................................6 +-7.1. Initializing an LDAP Session................................6 +-7.2. LDAP Session Handle Options.................................7 +-7.3. Working with controls.......................................10 +-7.4. Authenticating to the directory.............................11 +-7.5. Closing the session.........................................13 +-7.6. Searching...................................................13 +-7.7. Reading an Entry............................................17 +-7.8. Listing the Children of an Entry............................17 +-7.9. Comparing a Value Against an Entry..........................17 +-7.10. Modifying an entry..........................................19 +-7.11. Modifying the Name of an Entry..............................21 +-7.12. Adding an entry.............................................23 +-7.13. Deleting an entry...........................................25 +-7.14. Extended Operations.........................................26 +-8. Abandoning An Operation........................................28 +-9. Obtaining Results and Peeking Inside LDAP Messages.............29 +-10. Handling Errors and Parsing Results............................31 +-11. Stepping Through a List of Results.............................33 +-12. Parsing Search Results.........................................34 +-12.1. Stepping Through a List of Entries..........................34 +-12.2. Stepping Through the Attributes of an Entry.................35 +-12.3. Retrieving the Values of an Attribute.......................36 +-12.4. Retrieving the name of an entry.............................37 +-13. Encoded ASN.1 Value Manipulation...............................39 +-13.1. General.....................................................39 +-13.2. Encoding....................................................40 +-13.3. Encoding Example............................................42 +-13.4. Decoding....................................................43 +-13.5. Decoding Example............................................46 +-14. Security Considerations........................................48 +-15. Acknowledgements...............................................48 +-16. Bibliography...................................................49 +-17. Author's Addresses.............................................50 +-18. Appendix A - Sample LDAP API Code..............................50 +-19. Appendix B - Outstanding Issues................................52 +-19.1. Support for multithreaded applications......................52 +-19.2. Using Transport Layer Security (TLS)........................52 +-19.3. Client control for chasing referrals........................52 +-19.4. Potential confusion between hostname:port and IPv6 addresses52 +-19.5. Need to track SASL API standardization efforts..............53 +-19.6. Support for character sets other than UTF-8?................53 +-19.7. Use of UTF-8 with LDAPv2 servers............................53 +- +- +- +- +- +- +- +- diff -Nru rabbitmq-server-2.7.1/plugins-src/erlando/package.mk rabbitmq-server-2.8.4/plugins-src/erlando/package.mk --- rabbitmq-server-2.7.1/plugins-src/erlando/package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlando/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -1,2 +1 @@ STANDALONE_TEST_COMMANDS:=test_do:test() test_cut:test() test_import_as:test() - diff -Nru rabbitmq-server-2.7.1/plugins-src/erlando/README.md rabbitmq-server-2.8.4/plugins-src/erlando/README.md --- rabbitmq-server-2.7.1/plugins-src/erlando/README.md 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlando/README.md 2012-06-22 16:03:48.000000000 +0000 @@ -278,7 +278,8 @@ comma(foo(), fun (A) -> comma(bar(A, dog), - fun (B) -> ok end)). + fun (B) -> ok end) + end). Thus the function `comma/2` takes all results from the previous expression, and controls how and whether they are passed to the next @@ -303,7 +304,8 @@ Monad:'>>='(foo(), fun (A) -> Monad:'>>='(bar(A, dog), - fun (B) -> ok end)). + fun (B) -> ok end) + end). There is no intention that this latter form is any more readable than the `comma/2` form - it is not. However, it should be clear that the @@ -624,4 +626,4 @@ The Original Code is Erlando. The Initial Developer of the Original Code is VMware, Inc. -Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +Copyright (c) 2011-2012 VMware, Inc. All rights reserved. diff -Nru rabbitmq-server-2.7.1/plugins-src/erlando/src/monad.erl rabbitmq-server-2.8.4/plugins-src/erlando/src/monad.erl --- rabbitmq-server-2.7.1/plugins-src/erlando/src/monad.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlando/src/monad.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is Erlando. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(monad). @@ -39,8 +39,10 @@ Y]). sequence(Monad, Xs) -> - lists:foldr(fun (X, Acc) -> - do([Monad || E <- X, - Es <- Acc, - return([E|Es])]) - end, Monad:return([]), Xs). + sequence(Monad, Xs, []). + +sequence(Monad, [], Acc) -> + do([Monad || return(lists:reverse(Acc))]); +sequence(Monad, [X|Xs], Acc) -> + do([Monad || E <- X, + sequence(Monad, Xs, [E|Acc])]). diff -Nru rabbitmq-server-2.7.1/plugins-src/erlando/test/erlando_test.erl rabbitmq-server-2.8.4/plugins-src/erlando/test/erlando_test.erl --- rabbitmq-server-2.7.1/plugins-src/erlando/test/erlando_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlando/test/erlando_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is Erlando. %% %% The Initial Developer of the Original Code is Alex Kropivny. -%% Copyright (c) 2011-2011 Alex Kropivny; VMware, Inc. +%% Copyright (c) 2011-2012 Alex Kropivny; VMware, Inc. %% All rights reserved. %% diff -Nru rabbitmq-server-2.7.1/plugins-src/erlando/test/src/test_do.erl rabbitmq-server-2.8.4/plugins-src/erlando/test/src/test_do.erl --- rabbitmq-server-2.7.1/plugins-src/erlando/test/src/test_do.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlando/test/src/test_do.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is Erlando. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(test_do). diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627.hrl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627.hrl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -1,6 +1,6 @@ %% JSON - RFC 4627 - for Erlang %%--------------------------------------------------------------------------- -%% Copyright (c) 2007-2010 Tony Garnock-Jones +%% Copyright (c) 2007-2010, 2011, 2012 Tony Garnock-Jones %% Copyright (c) 2007-2010 LShift Ltd. %% %% Permission is hereby granted, free of charge, to any person diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627_jsonrpc.hrl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627_jsonrpc.hrl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627_jsonrpc.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/include/rfc4627_jsonrpc.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -1,6 +1,6 @@ %% JSON-RPC for Erlang %%--------------------------------------------------------------------------- -%% Copyright (c) 2007-2010 Tony Garnock-Jones +%% Copyright (c) 2007-2010, 2011, 2012 Tony Garnock-Jones %% Copyright (c) 2007-2010 LShift Ltd. %% %% Permission is hereby granted, free of charge, to any person diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/Makefile rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/Makefile --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -10,18 +10,27 @@ SIGNING_KEY_ID=F8D7D525 VERSION=HEAD PACKAGE_NAME=rfc4627_jsonrpc -EZ_NAME=$(PACKAGE_NAME).ez -## The path to httpd.hrl has changed in OTP R14A and newer. Detect the -## change, and supply a compile-time macro definition to allow -## rfc4627_jsonrpc_inets.erl to adapt to the new path. -ifeq ($(shell test R14A \> $$(erl -noshell -eval 'io:format(erlang:system_info(otp_release)), halt().') && echo yes),yes) -INETS_DEF= +## The path to httpd.hrl changed at R14A, and then changed again +## between OTP R14B and R14B01. Detect the changes, and supply +## compile-time macro definitions to allow rfc4627_jsonrpc_inets.erl +## to adapt to the new paths. +ERLANG_OTP_RELEASE:=$(shell erl -noshell -eval 'io:format(erlang:system_info(otp_release)), halt().') +$(info Building for OTP release $(ERLANG_OTP_RELEASE).) +ifeq ($(shell test R14A \> $(ERLANG_OTP_RELEASE) && echo yes),yes) +$(info Using path to INETS httpd.hrl that existed before R14A.) +INETS_DEF=-Dinets_pre_r14a +else +ifeq ($(shell test R14B01 \> $(ERLANG_OTP_RELEASE) && echo yes),yes) +$(info Using path to INETS httpd.hrl that existed before R14B01.) +INETS_DEF=-Dinets_pre_r14b01 else -INETS_DEF=-Dnew_inets +$(info Using path to INETS httpd.hrl that exists in releases at and after R14B01.) +INETS_DEF= +endif endif -all: package +all: $(TARGETS) $(EBIN_DIR)/%.beam: $(SOURCE_DIR)/%.erl $(INCLUDES) erlc $(ERLC_OPTS) $< @@ -32,20 +41,10 @@ rm -rf $(DIST_DIR) rm -rf $(DOC_DIR) -dist: $(TARGETS) doc/index.html +dist: all doc/index.html mkdir -p $(DIST_DIR) cp -r doc ebin include src test Makefile $(DIST_DIR) -package: $(DIST_DIR)/$(PACKAGE).ez -$(DIST_DIR)/$(PACKAGE).ez: $(TARGETS) dist - mkdir -p $(DIST_DIR)/$(PACKAGE_NAME) - cp -r $(DIST_DIR)/$(EBIN_DIR) $(DIST_DIR)/$(PACKAGE_NAME) - cp -r $(DIST_DIR)/$(INCLUDE_DIR) $(DIST_DIR)/$(PACKAGE_NAME) - (cd $(DIST_DIR); zip -r $(EZ_NAME) $(PACKAGE_NAME)) - -echo-package-name: - @echo $(PACKAGE_NAME) - distclean: clean rm -rf $(DIST_DIR) find . -name '*~' -exec rm {} \; diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/README.md rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/README.md --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/README.md 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/README.md 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,120 @@ +# RFC4627 (JSON) and JSON-RPC for Erlang + +An implementation of JSON and JSON-RPC for Erlang. + +See +[rfc4627.erl](http://tonyg.github.com/erlang-rfc4627/doc/rfc4627.html), +the JSON/RFC4627 codec itself, to learn how to encode and decode JSON +objects from Erlang code. + +## Providing and calling JSON-RPC services + +See +[rfc4627\_jsonrpc.erl](http://tonyg.github.com/erlang-rfc4627/doc/rfc4627_jsonrpc.html), +a JSON-RPC service registry and transport-neutral service method +invocation mechanism, to learn how to expose Erlang processes as +remotely-callable JSON-RPC services, and to learn how to invoke local +JSON-RPC services from Erlang without the overhead of HTTP. + +## Exposing JSON-RPC services over HTTP + +### Using Inets + +See +[rfc4627\_jsonrpc\_inets.erl](http://tonyg.github.com/erlang-rfc4627/doc/rfc4627_jsonrpc_inets.html), +an Inets HTTP transport binding for JSON-RPC, to learn how to +configure the Inets HTTP server to respond to JSON-RPC requests. + +### Using Mochiweb + +See +[rfc4627\_jsonrpc\_mochiweb.erl](http://tonyg.github.com/erlang-rfc4627/doc/rfc4627_jsonrpc_mochiweb.html) +to learn how to delegate incoming Mochiweb HTTP requests to the +JSON-RPC service dispatcher. + +## Running the example test service that comes with the source code + +Included with the Erlang RFC4627 source code is a small Inets-based +example that defines a "hello world"-style JSON-RPC service, and calls +it from a Javascript program embedded in a web page. + +At your Erlang shell, + + - after compiling the code with `make all test-compile`, + - when your current working directory contains the `test` directory + from the distribution, such that + `./test/server_root/conf/httpd.conf` exists, + +type `test_jsonrpc_inets:start_httpd().` (Don't forget the trailing +"."!) This will + + - start the inets httpd on port 5671 (from `./test/server_root/conf/httpd.conf`) + - allow HTTP access to JSON-RPC services via a url prefix of `/rpc` (again from `httpd.conf`) + - start the `rfc4627_jsonrpc` service registry + - register the test service + +Visiting in your browser should load a page +that uses javascript to invoke the Erlang-implemented JSON-RPC test +service. + +## Invoking JSON-RPC procedures from Javascript + +See the [relevant +section](http://tonyg.github.com/erlang-rfc4627/doc/overview-summary.html#Invoking_JSON-RPC_procedures_from_Javascript) +of the `edoc` documentation included with the source code. + +## References + + - the [JSON RFC](http://www.ietf.org/rfc/rfc4627.txt). + + - the [JSON-RPC + specification](http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html) + 1.1 working draft ([mirrored + locally](http://tonyg.github.com/erlang-rfc4627/doc/JSON-RPC-1-1-WD-20060807.html)). + + - Joe Armstrong's + [message](http://erlang.org/pipermail/erlang-questions/2005-November/017805.html) + describing the basis of the JSON data type mapping that the + `rfc4627.erl` module uses. + +## Contributors + +The codebase and documentation was originally written between 2007 and +2010 by Tony Garnock-Jones while at LShift in London. Since then, it +has been maintained by Tony and enhanced with a few generous +contributions from others: + + - András Veres-Szentkirályi + - Eugene Volchek + - Simon MacMullen + - Andrey Khozov + +## Copyright and Licence + +Copyrights: + + - Copyright © 2007-2010, 2011, 2012 Tony Garnock-Jones. + - Portions copyright 2007-2010 LShift Ltd. + - Portions copyright contributors to the project, listed above. + +License (MIT): + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/doc/overview.edoc.in rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/doc/overview.edoc.in --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/doc/overview.edoc.in 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/doc/overview.edoc.in 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,7 @@ @title RFC4627 (JSON) and JSON-RPC for Erlang @author Tony Garnock-Jones @author LShift Ltd. -@copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +@copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. @version %%VERSION%% diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627.erl 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ %%--------------------------------------------------------------------------- %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person @@ -32,7 +32,7 @@ %% @reference JSON in general %% %% @reference Joe Armstrong's +%% href="http://erlang.org/pipermail/erlang-questions/2005-November/017805.html"> %% message describing the basis of the JSON data type mapping that %% this module uses %% @@ -94,7 +94,7 @@ -export([unicode_decode/1, unicode_encode/1]). -export([from_record/3, to_record/3]). -export([hex_digit/1, digit_hex/1]). --export([get_field/2, get_field/3, set_field/3]). +-export([get_field/2, get_field/3, set_field/3, exclude_field/2]). -export([equiv/2]). %% @spec () -> string() @@ -357,7 +357,7 @@ {done, Rest}; parse_codepoint([$\\, Key | Rest]) -> parse_general_char(Key, Rest); -parse_codepoint([X | Rest]) -> +parse_codepoint([X | Rest]) -> {ok, X, Rest}. parse_general_char($b, Rest) -> {ok, 8, Rest}; @@ -526,6 +526,11 @@ element(Index, Fallback) end | decode_record_fields(Values, Fallback, Index + 1, Rest)]. +%% @spec (JsonObject::jsonobj(), atom()) -> jsonobj() +%% @doc Exclude a named field from a JSON "object". +exclude_field({obj, Props}, Key) -> + {obj, lists:keydelete(Key, 1, Props)}. + %% @spec (JsonObject::jsonobj(), atom()) -> {ok, json()} | not_found %% @doc Retrieves the value of a named field of a JSON "object". get_field({obj, Props}, Key) -> diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_app.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_app.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,6 +1,6 @@ %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc.erl 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ %%--------------------------------------------------------------------------- %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person @@ -164,11 +164,6 @@ %% implementing process at all, the function object could process %% the request without sending any messages at all. %% -%% At the moment, the `rfc4627_jsonrpc' service registry -%% only allows registration of `gen_server'-based -%% pid-style services; this restriction will be lifted in a future -%% release. -%% %% To build a service descriptor object with a function handler %% instead of a pid, call `rfc4627_jsonrpc:service/5' %% instead of `rfc4627_jsonrpc:service/4': @@ -180,7 +175,8 @@ %% my_handler(ProcedureNameBin, RequestInfo, Args) -> jsonrpc_response() %% ''' %% -%% The resulting service descriptor can be used directly with {@link +%% The resulting service descriptor can be registered with {@link +%% register_service/1} as well as used directly with {@link %% invoke_service_method/8}. %% %% @type service() = #service{}. A service description record, as @@ -220,7 +216,7 @@ -export([start/0, start_link/0]). --export([lookup_service/1, register_service/2]). +-export([lookup_service/1, register_service/1, register_service/2]). -export([gen_object_name/0, system_describe/2]). -export([jsonrpc_post/3, jsonrpc_post/4, invoke_service_method/8, expand_jsonrpc_reply/2]). -export([error_response/2, error_response/3, service/4, service/5, proc/2]). @@ -242,12 +238,18 @@ lookup_service(Service) -> gen_server:call(?SERVICE, {lookup_service, Service}). +%% @spec (service()) -> ok +%% @doc Registers a JSON-RPC service. +%% +%% The name of the service is contained within its service record. +register_service(ServiceDescription) -> + gen_server:call(?SERVICE, {register_service, ServiceDescription}). + %% @spec (pid(), service()) -> ok %% @doc Registers a JSON-RPC service. %% %% The name of the service is contained within its service record. register_service(Pid, ServiceDescription) -> - %%error_logger:info_msg("Registering ~p as ~p", [Pid, ServiceDescription]), gen_server:call(?SERVICE, {register_service, Pid, ServiceDescription}). %% @spec () -> string() @@ -498,7 +500,6 @@ invoke_service1(Handler, RequestInfo, ServiceProc, Args, Timeout). invoke_service1(Handler, RequestInfo, #service_proc{name = Name, params = Params}, Args, Timeout) -> - %%error_logger:info_msg("JSONRPC invoking ~p:~p(~p)", [Handler, Name, Args]), case catch run_handler(Handler, Name, RequestInfo, coerce_args(Params, Args), Timeout) of {'EXIT', {{function_clause, _}, _}} -> error_response(404, "Undefined procedure", Name); diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_http.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_http.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_http.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_http.erl 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ %%--------------------------------------------------------------------------- %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person @@ -148,7 +148,7 @@ rfc4627:get_field(RequestObject, "id", null), Object, rfc4627:get_field(RequestObject, "method", undefined), - rfc4627:get_field(RequestObject, "params", undefined)}; + rfc4627:get_field(RequestObject, "params", [])}; _ -> %% GET, presumably. We don't really care, here. {get, diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_inets.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_inets.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_inets.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_inets.erl 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ %%--------------------------------------------------------------------------- %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person @@ -88,13 +88,17 @@ -module(rfc4627_jsonrpc_inets). -include("rfc4627_jsonrpc.hrl"). -%% The path to httpd.hrl has changed in OTP R14A and newer. Our -%% Makefile detects the change for us, and supplies a compile-time -%% macro definition to allow us to adapt to the new path. --ifdef(new_inets). +%% The path to httpd.hrl has changed with various OTP releases. Our +%% Makefile detects the changes for us, and supplies compile-time +%% macro definitions to allow us to adapt. +-ifdef(inets_pre_r14a). +-include_lib("inets/src/httpd.hrl"). +-else. +-ifdef(inets_pre_r14b01). -include_lib("inets/src/http_server/httpd.hrl"). -else. --include_lib("inets/src/httpd.hrl"). +-include_lib("inets/include/httpd.hrl"). +-endif. -endif. -export([do/1, load/2]). @@ -157,11 +161,13 @@ {ok, ResultEnc, ResponseInfo} -> {obj, ResponseHeaderFields} = rfc4627:get_field(ResponseInfo, "http_headers", {obj, []}), + StatusCode = + rfc4627:get_field(ResponseInfo, "http_status_code", 200), Headers = [{K, binary_to_list(V)} || {K,V} <- ResponseHeaderFields], {proceed, [{response, {response, - [{code, 200}, + [{code, StatusCode}, {content_length, integer_to_list(length(ResultEnc))}, - {content_type, "text/plain"}%rfc4627:mime_type()} + {content_type, rfc4627:mime_type()} | Headers], ResultEnc}} | OldData]} end. diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_mochiweb.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_mochiweb.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_mochiweb.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_mochiweb.erl 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ %%--------------------------------------------------------------------------- %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person @@ -99,8 +99,19 @@ no_match -> no_match; {ok, ResultEnc, ResponseInfo} -> + DefaultType = rfc4627:mime_type(), + RespType = case Req:accepts_content_type(DefaultType) of + true -> DefaultType; + false -> + case Req:accepts_content_type("text/plain") of + true -> "text/plain"; + false -> DefaultType + end + end, {obj, ResponseHeaderFields} = rfc4627:get_field(ResponseInfo, "http_headers", {obj, []}), + StatusCode = + rfc4627:get_field(ResponseInfo, "http_status_code", 200), Headers = [{K, binary_to_list(V)} || {K,V} <- ResponseHeaderFields], - {ok, {200, Headers ++ [{"Content-type", "text/plain"}], ResultEnc}} + {ok, {StatusCode, Headers ++ [{"Content-type", RespType}], ResultEnc}} end. diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_registry.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_registry.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_registry.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_registry.erl 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ %%--------------------------------------------------------------------------- %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person @@ -53,7 +53,7 @@ %% @doc gen_server behaviour callback. code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. %% @doc gen_server behaviour callback. handle_call({lookup_service, Service}, _From, State) -> @@ -64,6 +64,10 @@ {reply, ServiceRec, State} end; +handle_call({register_service, ServiceDescription = #service{name = Name}}, _From, State) -> + ets:insert(?TABLE_NAME, {{service, Name}, ServiceDescription}), + {reply, ok, State}; + handle_call({register_service, Pid, ServiceDescription = #service{name = Name}}, _From, State) -> SD = ServiceDescription#service{handler = {pid, Pid}}, erlang:monitor(process, Pid), @@ -81,7 +85,7 @@ case ets:lookup(?TABLE_NAME, {service_pid, DownPid}) of [] -> {noreply, State}; - [ServiceName] -> + [{_, ServiceName}] -> ets:delete(?TABLE_NAME, {service_pid, DownPid}), ets:delete(?TABLE_NAME, {service, ServiceName}), {noreply, State} diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_sup.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_sup.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/src/rfc4627_jsonrpc_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,6 +1,6 @@ %% @author Tony Garnock-Jones %% @author LShift Ltd. -%% @copyright 2007-2010 Tony Garnock-Jones and 2007-2010 LShift Ltd. +%% @copyright 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd. %% @license %% %% Permission is hereby granted, free of charge, to any person diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/index.html rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/index.html --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/index.html 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/index.html 2012-06-22 16:03:48.000000000 +0000 @@ -12,6 +12,10 @@ Expect to see: "Starting" and "ErlangServer: Hello, world!", followed by false.


+    

+ Click the following button to crash the server process: +

+ diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/test-client.js rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/test-client.js --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/test-client.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/htdocs/test-client.js 2012-06-22 16:03:48.000000000 +0000 @@ -11,4 +11,5 @@ function onReady() { testService.test_proc("Hello, world!").addCallback(log); } + Event.observe($("crashButton"), "click", function () { testService.crash() }); } diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/logs/README rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/logs/README --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/logs/README 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/server_root/logs/README 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,2 @@ +Directory in which the test_jsonrpc_inets inets httpd instance will +place its log files. diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_jsonrpc_inets.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_jsonrpc_inets.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_jsonrpc_inets.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_jsonrpc_inets.erl 2012-06-22 16:03:48.000000000 +0000 @@ -43,11 +43,18 @@ [#service_proc{name = <<"test_proc">>, idempotent = true, params = [#service_proc_param{name = <<"value">>, - type = <<"str">>}]}])). + type = <<"str">>}]}, + #service_proc{name = <<"crash">>, + idempotent = false, + params = []}])). start_httpd() -> - rfc4627_jsonrpc:start(), - httpd:start("test/server_root/conf/httpd.conf"), + ok = case rfc4627_jsonrpc:start() of + {ok, _JsonrpcPid} -> ok; + {error, {already_started, _JsonrpcPid}} -> ok + end, + ok = inets:start(), + {ok, _HttpdPid} = inets:start(httpd, [{file, "test/server_root/conf/httpd.conf"}]), start(). %--------------------------------------------------------------------------- @@ -59,10 +66,12 @@ ok. code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. handle_call({jsonrpc, <<"test_proc">>, _ModData, [Value]}, _From, State) -> - {reply, {result, <<"ErlangServer: ", Value/binary>>}, State}. + {reply, {result, <<"ErlangServer: ", Value/binary>>}, State}; +handle_call({jsonrpc, <<"crash">>, _ModData, []}, _From, _State) -> + exit(deliberate_crash). handle_cast(Request, State) -> error_logger:error_msg("Unhandled cast in test_jsonrpc: ~p", [Request]), diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_rfc4627.erl rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_rfc4627.erl --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_rfc4627.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/erlang-rfc4627-git/test/test_rfc4627.erl 2012-06-22 16:03:48.000000000 +0000 @@ -38,6 +38,7 @@ passed = test_unicode(), passed = test_equiv(), passed = test_eof_detection(), + passed = test_exclude(), passed. test_codec() -> @@ -158,6 +159,21 @@ {ok, [1, 2]} = rfc4627:get_field(Obj, "c"), passed. +test_exclude() -> + Dict = dict:store("c", 2, + dict:store("b", <<"hello">>, + dict:store("a", 123, dict:new()))), + {ok, Obj, ""} = rfc4627:decode(rfc4627:encode(Dict)), + Obj2 = rfc4627:exclude_field(Obj, "a"), + true = rfc4627:equiv({obj, [{"c", 2}, {"b", <<"hello">>}]}, Obj2), + Obj3 = rfc4627:exclude_field(Obj2, "b"), + true = rfc4627:equiv({obj, [{"c", 2}]}, Obj3), + Obj4 = rfc4627:exclude_field(Obj3, "x"), + true = rfc4627:equiv({obj, [{"c", 2}]}, Obj4), + Obj5 = rfc4627:exclude_field(Obj3, "c"), + true = rfc4627:equiv({obj, []}, Obj5), + passed. + test_equiv() -> true = rfc4627:equiv([1, 2], [1, 2]), false = rfc4627:equiv([1, 2], [2, 1]), diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/fix-ets-leak.patch rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/fix-ets-leak.patch --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/fix-ets-leak.patch 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/fix-ets-leak.patch 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,13 @@ +diff --git a/src/rfc4627_jsonrpc_registry.erl b/src/rfc4627_jsonrpc_registry.erl +index 7065a7a..f9c8289 100644 +--- a/src/rfc4627_jsonrpc_registry.erl ++++ b/src/rfc4627_jsonrpc_registry.erl +@@ -81,7 +81,7 @@ handle_info({'DOWN', _MonitorRef, process, DownPid, _Reason}, State) -> + case ets:lookup(?TABLE_NAME, {service_pid, DownPid}) of + [] -> + {noreply, State}; +- [ServiceName] -> ++ [{_, ServiceName}] -> + ets:delete(?TABLE_NAME, {service_pid, DownPid}), + ets:delete(?TABLE_NAME, {service, ServiceName}), + {noreply, State} diff -Nru rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/package.mk rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/package.mk --- rabbitmq-server-2.7.1/plugins-src/erlang-rfc4627-wrapper/package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/erlang-rfc4627-wrapper/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -2,13 +2,18 @@ DEPS:=mochiweb-wrapper UPSTREAM_GIT:=http://github.com/tonyg/erlang-rfc4627.git -UPSTREAM_REVISION:=30c84984f86a1d67083f +UPSTREAM_REVISION:=a5e7ad77963f1e7130d8ca870cfd9a7c1a12c8cc + ORIGINAL_APP_FILE=$(CLONE_DIR)/ebin/$(APP_NAME).app DO_NOT_GENERATE_APP_FILE=true ## The path to httpd.hrl has changed in OTP R14A and newer. Detect the ## change, and supply a compile-time macro definition to allow ## rfc4627_jsonrpc_inets.erl to adapt to the new path. -ifeq ($(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] >= [5,8]), halt().'),true) -PACKAGE_ERLC_OPTS+=-Dnew_inets +ifeq ($(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] < [5,8]), halt().'),true) +PACKAGE_ERLC_OPTS+=-Dinets_pre_r14a +else +ifeq ($(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] < [5,8,2]), halt().'),true) +PACKAGE_ERLC_OPTS+=-Dinets_pre_r14b01 +endif endif diff -Nru rabbitmq-server-2.7.1/plugins-src/licensing/LICENSE-MPL-RabbitMQ rabbitmq-server-2.8.4/plugins-src/licensing/LICENSE-MPL-RabbitMQ --- rabbitmq-server-2.7.1/plugins-src/licensing/LICENSE-MPL-RabbitMQ 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/licensing/LICENSE-MPL-RabbitMQ 2012-06-22 16:03:48.000000000 +0000 @@ -447,7 +447,7 @@ The Original Code is RabbitMQ Visualiser. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2011-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2011-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/plugins-src/Makefile rabbitmq-server-2.8.4/plugins-src/Makefile --- rabbitmq-server-2.7.1/plugins-src/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -14,6 +14,7 @@ rabbitmq-erlang-client \ rabbitmq-external-exchange \ rabbitmq-federation \ + rabbitmq-federation-management \ rabbitmq-ha-test \ rabbitmq-jsonrpc \ rabbitmq-jsonrpc-channel \ @@ -62,7 +63,7 @@ plugins-dist: release rm -rf $(PLUGINS_DIST_DIR) mkdir -p $(PLUGINS_DIST_DIR) - $(MAKE) -f all-packages.mk copy-releasable VERSION=$(VERSION) $(PLUGINS_DIST_DIR)=$(PLUGINS_DIST_DIR) + $(MAKE) -f all-packages.mk copy-releasable VERSION=$(VERSION) PLUGINS_DIST_DIR=$(PLUGINS_DIST_DIR) plugins-srcdist: rm -rf $(PLUGINS_SRC_DIST_DIR) @@ -74,7 +75,7 @@ rsync -a --exclude '.hg*' rabbitmq-server $(PLUGINS_SRC_DIST_DIR)/ touch $(PLUGINS_SRC_DIST_DIR)/rabbitmq-server/.srcdist_done - $(MAKE) -f all-packages.mk copy-srcdist VERSION=$(VERSION) $(PLUGINS_SRC_DIST_DIR)=$(PLUGINS_SRC_DIST_DIR) + $(MAKE) -f all-packages.mk copy-srcdist VERSION=$(VERSION) PLUGINS_SRC_DIST_DIR=$(PLUGINS_SRC_DIST_DIR) cp Makefile *.mk generate* $(PLUGINS_SRC_DIST_DIR)/ echo "This is the released version of rabbitmq-public-umbrella. \ You can clone the full version with: hg clone http://hg.rabbitmq.com/rabbitmq-public-umbrella" > $(PLUGINS_SRC_DIST_DIR)/README diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/package.mk rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/package.mk --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,7 @@ RELEASABLE:=true DEPS:=rabbitmq-server rabbitmq-erlang-client eldap-wrapper -ifeq ($(shell nmap -p 389 localhost | grep '389/tcp open' > /dev/null && echo true),true) +ifeq ($(shell nc -z localhost 389 && echo true),true) WITH_BROKER_TEST_COMMANDS:=eunit:test(rabbit_auth_backend_ldap_test,[verbose]) WITH_BROKER_TEST_CONFIG:=$(PACKAGE_DIR)/etc/rabbit-test endif diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/README 2012-06-22 16:03:48.000000000 +0000 @@ -62,23 +62,54 @@ user_dn_pattern --------------- -Default: "cn=${username},ou=People,dc=example,dc=com" +Default: "${username}" -Pattern for a user's DN. Must contain exactly one instance of -"${username}". This will be where the username supplied by the client -is substituted. You almost certainly want to change this. +There are two ways to convert a username as provided through AMQP to a +Distinguished Name. The simplest way is via string substitution with +user_dn_pattern. To do this, set user_dn_pattern to a string +containing exactly one instance of "${username}". + +For example, setting user_dn_pattern to: + "cn=${username},ou=People,dc=example,dc=com" + +would cause the username "simon" to be converted to the DN + "cn=simon,ou=People,dc=example,dc=com" + +dn_lookup_attribute and dn_lookup_base +-------------------------------------- + +Default: 'none' and 'none' + +The other way to convert a username to a Distinguished Name is via an +LDAP lookup after binding. In order for this to work your LDAP server +needs to be configured to allow binding with the unadorned username +(Microsoft Active Directory typically does this). + +To do this, set dn_lookup_attribute to the name of the attribute the +represents the user name, and dn_lookup_base to the base DN for the +query. + +For example, if I set + + {dn_lookup_attribute, "userPrincipalName"}, + {dn_lookup_base, "DC=vmware,DC=com"} + +I can authenticate as "smacmullen@vmware.com" and have my local Active +Directory server return my real DN. other_bind ---------- -Default: anon +Default: as_user -Normally for authentication this plugin binds to the LDAP server as +For authentication this plugin binds to the LDAP server as the user it is trying to authenticate. This option controls how to bind for authorisation queries, and to retrieve the details of a user who is logging in without presenting a password (e.g. SASL EXTERNAL). -This option must either be the atom anon, or a tuple {UserDN, Password}. +This option must either be one of the atoms 'as_user' or 'anon', or a +tuple {UserDN, Password}. 'as_user' means to bind as the authenticated +user. use_ssl ------- @@ -102,7 +133,7 @@ Set to true to cause LDAP traffic to be written to the RabbitMQ log. You probably only want to use this for debugging, since it will -usually cause passwords to be written to the logs. +usually cause passwords to be written to the logs, and is rather verbose. Example configuration file ========================== @@ -121,8 +152,8 @@ =========== Currently this plugin is rather chatty with LDAP connections when -doing authorisation over LDAP. +doing authorisation over LDAP - every time RabbitMQ needs to do an +authorisation query it starts a new LDAP connection. However, RabbitMQ +does have a per-channel authorisation cache, so this is not too awful. There might need to be more types of queries. - -It hasn't received much testing. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2010 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap_app). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% The Original Code is RabbitMQ. +%% The Original Code is RabbitMQ. %% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2010 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap). @@ -37,7 +22,6 @@ -include_lib("rabbit_common/include/rabbit.hrl"). -behaviour(rabbit_auth_backend). --include_lib("rabbit_common/include/rabbit_auth_backend_spec.hrl"). -export([description/0]). -export([check_user_login/2, check_vhost_access/2, check_resource_access/3]). @@ -52,6 +36,8 @@ -record(state, { servers, user_dn_pattern, + dn_lookup_attribute, + dn_lookup_base, other_bind, vhost_access_query, resource_access_query, @@ -60,6 +46,8 @@ log, port }). +-record(impl, { user_dn, password }). + %%-------------------------------------------------------------------- description() -> @@ -81,13 +69,14 @@ exit({unknown_auth_props, Username, AuthProps}). check_vhost_access(User = #user{username = Username, - impl = UserDN}, VHost) -> + impl = #impl{user_dn = UserDN}}, VHost) -> gen_server:call(?SERVER, {check_vhost, [{username, Username}, {user_dn, UserDN}, {vhost, VHost}], User}, infinity). -check_resource_access(User = #user{username = Username, impl = UserDN}, +check_resource_access(User = #user{username = Username, + impl = #impl{user_dn = UserDN}}, #resource{virtual_host = VHost, kind = Type, name = Name}, Permission) -> gen_server:call(?SERVER, {check_resource, [{username, Username}, @@ -118,7 +107,8 @@ Filter = eldap:present("objectClass"), object_exists(DNPattern, Filter, Args, LDAP); -evaluate({in_group, DNPattern}, Args, #user{impl = UserDN}, LDAP) -> +evaluate({in_group, DNPattern}, Args, #user{impl = #impl{user_dn = UserDN}}, + LDAP) -> Filter = eldap:equalityMatch("member", UserDN), object_exists(DNPattern, Filter, Args, LDAP); @@ -143,11 +133,12 @@ case eldap:search(LDAP, [{base, DN}, {filter, Filter}, + {attributes, ["objectClass"]}, %% Reduce verbiage {scope, eldap:baseObject()}]) of {ok, #eldap_search_result{entries = Entries}} -> length(Entries) > 0; - {error, _} -> - false + {error, _} = E -> + E end. attribute(DNPattern, AttributeName, Args, LDAP) -> @@ -161,25 +152,22 @@ Attr; {ok, #eldap_search_result{entries = _}} -> false; - {error, _} -> - false + {error, _} = E -> + E end. evaluate_ldap(Q, Args, User, State) -> - with_ldap(fun(LDAP) -> evaluate(Q, Args, User, LDAP) end, State). + with_ldap(creds(User, State), + fun(LDAP) -> evaluate(Q, Args, User, LDAP) end, State). %%-------------------------------------------------------------------- -with_ldap(Fun, State = #state{ other_bind = BindOpts }) -> - with_ldap(BindOpts, Fun, State). - %% TODO - ATM we create and destroy a new LDAP connection on every %% call. This could almost certainly be more efficient. -with_ldap(BindOpts, Fun, - State = #state{ servers = Servers, - use_ssl = SSL, - log = Log, - port = Port }) -> +with_ldap(Creds, Fun, State = #state{servers = Servers, + use_ssl = SSL, + log = Log, + port = Port}) -> Opts0 = [{ssl, SSL}, {port, Port}], Opts = case Log of true -> @@ -194,7 +182,7 @@ case eldap:open(Servers, Opts) of {ok, LDAP} -> Reply = try - case BindOpts of + case Creds of anon -> Fun(LDAP); {UserDN, Password} -> @@ -220,11 +208,13 @@ {ok, V} = application:get_env(F), V. -do_login(Username, LDAP, State = #state{ tag_queries = TagQueries }) -> - UserDN = username_to_dn(Username, State), +do_login(Username, Password, LDAP, + State = #state{ tag_queries = TagQueries }) -> + UserDN = username_to_dn(Username, LDAP, State), User = #user{username = Username, auth_backend = ?MODULE, - impl = UserDN}, + impl = #impl{user_dn = UserDN, + password = Password}}, TagRes = [{Tag, evaluate(Q, [{username, Username}, {user_dn, UserDN}], User, LDAP)} || {Tag, Q} <- TagQueries], @@ -233,9 +223,38 @@ [E | _] -> E end. -username_to_dn(Username, #state{ user_dn_pattern = UserDNPattern }) -> +username_to_dn(Username, _LDAP, State = #state{dn_lookup_attribute = none}) -> + fill_user_dn_pattern(Username, State); + +username_to_dn(Username, LDAP, State = #state{dn_lookup_attribute = Attr, + dn_lookup_base = Base}) -> + Filled = fill_user_dn_pattern(Username, State), + case eldap:search(LDAP, + [{base, Base}, + {filter, eldap:equalityMatch(Attr, Filled)}, + {attributes, ["distinguishedName"]}]) of + {ok, #eldap_search_result{entries = [#eldap_entry{attributes = A}]}} -> + [DN] = proplists:get_value("distinguishedName", A), + DN; + {ok, #eldap_search_result{entries = Entries}} -> + rabbit_log:warning("Searching for DN for ~s, got back ~p~n", + [Filled, Entries]), + Filled; + {error, _} = E -> + exit(E) + end. + +fill_user_dn_pattern(Username, #state{user_dn_pattern = UserDNPattern}) -> rabbit_auth_backend_ldap_util:fill(UserDNPattern, [{username, Username}]). +creds(none, #state{other_bind = as_user}) -> + exit(as_user_no_password); +creds(#user{impl = #impl{user_dn = UserDN, password = Password}}, + #state{other_bind = as_user}) -> + {UserDN, Password}; +creds(_, #state{other_bind = Creds}) -> + Creds. + %%-------------------------------------------------------------------- init([]) -> @@ -244,11 +263,13 @@ handle_call({login, Username}, _From, State) -> %% Without password, e.g. EXTERNAL - with_ldap(fun(LDAP) -> do_login(Username, LDAP, State) end, State); + with_ldap(creds(none, State), + fun(LDAP) -> do_login(Username, none, LDAP, State) end, State); handle_call({login, Username, Password}, _From, State) -> - with_ldap({username_to_dn(Username, State), Password}, - fun(LDAP) -> do_login(Username, LDAP, State) end, State); + with_ldap({fill_user_dn_pattern(Username, State), Password}, + fun(LDAP) -> do_login(Username, Password, LDAP, State) end, + State); handle_call({check_vhost, Args, User}, _From, State = #state{vhost_access_query = Q}) -> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2010 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2010 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap_util). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbitmq_auth_backend_ldap.app.src rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbitmq_auth_backend_ldap.app.src --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/src/rabbitmq_auth_backend_ldap.app.src 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/src/rabbitmq_auth_backend_ldap.app.src 2012-06-22 16:03:48.000000000 +0000 @@ -6,8 +6,10 @@ {registered, []}, {mod, {rabbit_auth_backend_ldap_app, []}}, {env, [ {servers, ["ldap"]}, - {user_dn_pattern, "cn=${username},ou=People,dc=example,dc=com"}, - {other_bind, anon}, + {user_dn_pattern, "${username}"}, + {dn_lookup_attribute, none}, + {dn_lookup_base, none}, + {other_bind, as_user}, {vhost_access_query, {constant, true}}, {resource_access_query, {constant, true}}, {tag_queries, [{administrator, {constant, false}}]}, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap_test). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/README 2012-06-22 16:03:48.000000000 +0000 @@ -1,5 +1,5 @@ -Authenticates the user taking the Common Name of the client's SSL -certificate as the username. The user's password is not checked. +Authenticates the user, obtaining the username from the client's +SSL certificate. The user's password is not checked. In order to use this mechanism the client must connect over SSL, and present a client certificate. @@ -8,6 +8,24 @@ fail_if_no_peer_cert set to true and verify set to verify_peer, to force all SSL clients to have a verifiable client certificate. +By default this will set the username to an RFC4514-ish string form of +the certificate's subject's Distinguished Name, similar to that +produced by OpenSSL's "-nameopt RFC2253" option. + +You can obtain this string form from a certificate with a command like: + +$ openssl x509 -in path/to/cert.pem -nameopt RFC2253 -subject -noout + +or from an existing amqps connection with commands like: + +$ rabbitmqctl list_connections peer_cert_subject + +To use the Common Name instead, set: + +{rabbit, [{ssl_cert_login_from, common_name}]} + +in your configuration. + Note that the authenticated user will then be looked up in the configured authentication / authorisation backend(s) - this will be the mnesia-based user database by default, but could include other diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2010 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_ssl_app). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbit_auth_mechanism_ssl.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,34 +1,20 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2010 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_auth_mechanism_ssl). -behaviour(rabbit_auth_mechanism). @@ -36,7 +22,6 @@ -export([description/0, should_offer/1, init/1, handle_response/2]). -include_lib("rabbit_common/include/rabbit.hrl"). --include_lib("rabbit_common/include/rabbit_auth_mechanism_spec.hrl"). -include_lib("public_key/include/public_key.hrl"). -rabbit_boot_step({?MODULE, @@ -66,14 +51,10 @@ init(Sock) -> Username = case rabbit_net:peercert(Sock) of {ok, C} -> - CN = case rabbit_ssl:peer_cert_subject_item( - C, ?'id-at-commonName') of - not_found -> {refused, "no CN found", []}; - CN0 -> list_to_binary(CN0) - end, - case config_sane() of - true -> CN; - false -> {refused, "configuration unsafe", []} + case rabbit_ssl:peer_cert_auth_name(C) of + unsafe -> {refused, "configuration unsafe", []}; + not_found -> {refused, "no name found", []}; + Name -> Name end; {error, no_peercert} -> {refused, "no peer certificate", []}; @@ -89,17 +70,3 @@ _ -> rabbit_access_control:check_user_login(Username, []) end. - -%%-------------------------------------------------------------------------- -config_sane() -> - {ok, Opts} = application:get_env(ssl_options), - case {proplists:get_value(fail_if_no_peer_cert, Opts), - proplists:get_value(verify, Opts)} of - {true, verify_peer} -> - true; - {F, V} -> - rabbit_log:warning("EXTERNAL mechanism disabled, " - "fail_if_no_peer_cert=~p; " - "verify=~p~n", [F, V]), - false - end. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbitmq_auth_mechanism_ssl.app.src rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbitmq_auth_mechanism_ssl.app.src --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbitmq_auth_mechanism_ssl.app.src 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-auth-mechanism-ssl/src/rabbitmq_auth_mechanism_ssl.app.src 2012-06-22 16:03:48.000000000 +0000 @@ -5,5 +5,5 @@ {modules, []}, {registered, []}, {mod, {rabbit_auth_mechanism_ssl_app, []}}, - {env, [] }, + {env, [{name_from, distinguished_name}] }, {applications, [kernel, stdlib]}]}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-consistent-hash-exchange/LICENSE-MPL-RabbitMQ rabbitmq-server-2.8.4/plugins-src/rabbitmq-consistent-hash-exchange/LICENSE-MPL-RabbitMQ --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-consistent-hash-exchange/LICENSE-MPL-RabbitMQ 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-consistent-hash-exchange/LICENSE-MPL-RabbitMQ 2012-06-22 16:03:48.000000000 +0000 @@ -447,7 +447,7 @@ The Original Code is RabbitMQ Consistent Hash Exchange. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2011-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2011-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Consistent Hash Exchange. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type_consistent_hash). @@ -23,7 +23,6 @@ -export([validate/1, create/2, delete/3, add_binding/3, remove_bindings/3, assert_args_equivalence/2]). -export([init/0]). --include_lib("rabbit_common/include/rabbit_exchange_type_spec.hrl"). -record(bucket, {source_number, destination, binding}). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Consistent Hash Exchange. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type_consistent_hash_test). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/common.mk rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/common.mk --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/common.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/common.mk 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ # The Original Code is RabbitMQ. # # The Initial Developer of the Original Code is VMware, Inc. -# Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +# Copyright (c) 2007-2012 VMware, Inc. All rights reserved. # # The client library can either be built from source control or by downloading @@ -32,7 +32,6 @@ # tarball version. This avoids duplicating make definitions and rules and # helps keep the Makefile maintenence well factored. - ifndef TMPDIR TMPDIR := /tmp endif diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/include/amqp_client.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/include/amqp_client.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/include/amqp_client.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/include/amqp_client.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -ifndef(AMQP_CLIENT_HRL). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/include/amqp_gen_consumer_spec.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/include/amqp_gen_consumer_spec.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/include/amqp_gen_consumer_spec.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/include/amqp_gen_consumer_spec.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,11 +11,12 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -include("amqp_client.hrl"). +-ifndef(edoc). -type(state() :: any()). -type(consume() :: #'basic.consume'{}). -type(consume_ok() :: #'basic.consume_ok'{}). @@ -38,3 +39,4 @@ {reply, any(), state()} | {noreply, state()} | {error, reason(), state()}). -spec(terminate/2 :: (any(), state()) -> state()). +-endif. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/Makefile rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/Makefile --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ # The Original Code is RabbitMQ. # # The Initial Developer of the Original Code is VMware, Inc. -# Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +# Copyright (c) 2007-2012 VMware, Inc. All rights reserved. # VERSION=0.0.0 @@ -26,6 +26,8 @@ INFILES=$(shell find . -name '*.app.in') INTARGETS=$(patsubst %.in, %, $(INFILES)) +WEB_URL=http://www.rabbitmq.com/ + include common.mk run_in_broker: compile $(BROKER_DEPS) $(EBIN_DIR)/$(PACKAGE).app @@ -39,7 +41,7 @@ %.app: %.app.in $(SOURCES) $(BROKER_DIR)/generate_app escript $(BROKER_DIR)/generate_app $< $@ $(SOURCE_DIR) - sed -i.save 's/%%VSN%%/$(VERSION)/' $@ && rm $@.save + sed 's/%%VSN%%/$(VERSION)/' $@ > $@.tmp && mv $@.tmp $@ ############################################################################### ## Dialyzer @@ -65,7 +67,7 @@ sed -e 's:%%VERSION%%:$(VERSION):g' < $< > $@ $(DOC_DIR)/index.html: $(DEPS_DIR)/$(COMMON_PACKAGE_DIR) $(DOC_DIR)/overview.edoc $(SOURCES) - $(LIBS_PATH) erl -noshell -eval 'edoc:application(amqp_client, ".", [{preprocess, true}])' -run init stop + $(LIBS_PATH) erl -noshell -eval 'edoc:application(amqp_client, ".", [{preprocess, true}, {macros, [{edoc, true}]}])' -run init stop ############################################################################### ## Testing @@ -103,7 +105,8 @@ source_tarball: $(DIST_DIR)/$(COMMON_PACKAGE_EZ) $(EBIN_DIR)/$(PACKAGE).app | $(DIST_DIR) mkdir -p $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(DIST_DIR) $(COPY) $(DIST_DIR)/$(COMMON_PACKAGE_EZ) $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(DIST_DIR)/ - $(COPY) README $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ + $(COPY) README.in $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/README + elinks -dump -no-references -no-numbering $(WEB_URL)build-erlang-client.html >> $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/README $(COPY) common.mk $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ $(COPY) test.mk $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ sed 's/%%VSN%%/$(VERSION)/' Makefile.in > $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/Makefile diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/Makefile.in rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/Makefile.in --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/Makefile.in 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/Makefile.in 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ # The Original Code is RabbitMQ. # # The Initial Developer of the Original Code is VMware, Inc. -# Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +# Copyright (c) 2007-2012 VMware, Inc. All rights reserved. # VERSION=%%VSN%% diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in 2012-06-22 16:03:48.000000000 +0000 @@ -2,6 +2,7 @@ [{description, "RabbitMQ Common Libraries"}, {vsn, "%%VSN%%"}, {modules, [ + pmon, gen_server2, mirrored_supervisor, priority_queue, @@ -20,6 +21,7 @@ rabbit_misc, rabbit_msg_store_index, rabbit_net, + rabbit_nodes, rabbit_reader, rabbit_writer, rabbit_queue_collector, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -AMQP client for Erlang -====================== -This code implements a client for AMQP in the Erlang programming -language. - -This client offers both a networked version that uses standard -TCP-based AMQP framing and a direct client that uses native Erlang -message passing to a RabbitMQ broker. - -The API exposed to the user is common to both clients, so each version -can be used interchangeably without having to modify any client code. - -The TCP networked client has been tested with RabbitMQ server 1.4.0, -but should theoretically work with any 0-8 compliant AMQP server. - -The direct client is bound to an 0-8 compliant broker using native -Erlang message passing, which in the absence of an alternative Erlang -AMQP implementation means that it only works with RabbitMQ. - -It does however provide a level of abstraction above the internal -server API of RabbitMQ, meaning that you can write client code in -Erlang and still remain isolated from any API changes in the -underlying broker. - -It also provides a client-orientated API into RabbitMQ, allowing the -user to reuse AMQP knowledge gained by using AMQP clients in other -languages. - -The advantage of the direct client is that it eliminates the network -overhead as well as the marshaling to and from the AMQP wire format, -so that neither side has to decode or encode any AMQP frames. - -Prerequisites -------------- -In order to compile/run this code you must have the following -installed: - -- Erlang/OTP, R11B-5 or later, http://www.erlang.org/download.html -- The RabbitMQ server, 93cc2ca0ba62 or later -- Eunit, the Erlang unit testing framework - currently the whole build process - depends on eunit because all of the modules are compiled together. - A future version of the build process could remove this dependency when you - only want to compile the core libraries. - -Getting Eunit -------------- -The test suite uses eunit which is either available bundled with OTP from -release R12B-5 onwards or as a separate download that you will need to build -yourself if you are using an older version of Erlang. - -* If you are using R12B-5 or newer: - -Just skip to the next section. - -* If you are using R12B-4 or older: - -Check out eunit from their Subversion repository and build it: - - $ svn co http://svn.process-one.net/contribs/trunk/eunit eunit - $ cd eunit - $ make - -After this has sucessfully been built, you will need to create a symlink to -the eunit directory in your OTP installation directory: - - $ cd $OTP_HOME/lib/erlang/lib - $ ln -sf PATH_TO_EUNIT eunit - -where $OTP_HOME is the location of your Erlang/OTP installation. - -Compiling the Erlang client -------------------------- -You will need to get a copy of the server in order to be able to use it's -header files and runtime libraries. A good place to put this is in the sibling -directory to the Erlang client (i.e: ../rabbitmq-server), which is the default -that the Makefile expects. In this case, you can just run make: - - $ make - -If the source tree for the server is not in the sibling directory, you will -need to specify the path to this directory: - - $ make BROKER_DIR=/path/to/server - -In this case, make sure you specify BROKER_DIR every time you run a make target. - -Running the network client, direct client and packaging tests -------------------------------------------------------------- -The direct client has to be run in the same Erlang VM instance as the -RabbitMQ server. In order to use the makefile to run tests, you will need to -shutdown any other running instance of RabbitMQ server that you may have on -your machine. This is because the Makefile test targets boot their own instance -of RabbitMQ with settings depending on the test. -To run these tests, use either of the following targets: - - $ make test_network - $ make test_direct - $ make test_common_package - -Or to run all tests: - - $ make all_tests - -If any test fails, the make command will return a non-zero exit code. The reason -is logged by the server in /tmp/rabbit-sasl.log by default. - -The network client test can also be run from a separate Erlang VM instance from -RabbitMQ server. You can *start an instance of the server* and then, in the -rabbitmq-erlang-client folder, type - - rabbitmq-erlang-client $ make compile_tests - rabbitmq-erlang-client $ make run - erl -pa ebin ../rabbitmq-server/ebin tests - Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:4] \ - [async-threads:0] [hipe] [kernel-poll:false] - - Eshell V5.6.5 (abort with ^G) - 1> network_client_SUITE:test(). - -To get more examples of the API, look at the functions in the test_util module. - -Make targets ------------- -Interesting rabbitmq-erlang-client make targets include - -all - The default target. Builds the client (does not compile the tests). - -compile - Builds the client. - -compile_tests - Builds the client test modules. - -run - Builds the client and starts an Erlang shell with both the client and the - server in the load path. - -run_in_broker - Builds the client and starts RabbitMQ server with shell and the client - included in load path. - -clean - Removes build products and wipes all files produced by any other - rabbitmq-erlang-client make targets or client errors. - -dialyze - Analyses the client source code with dialyzer. Uses PLT file from default - location: ~/.dialyzer_plt. Use - - $ make PLT=/path/to/plt dialyze - - to override this. Add broker to PLT beforehand, otherwise you will a lot - of 'unknown function' warnings. See add_broker_to_plt make target. - -dialyze_all - Same as dialyze, except that this also analyses tests source code. - -add_broker_to_plt - Adds broker .beam files to default plt. Use - - $ make PLT=/path/to/plt add_broker_to_plt - - to override default plt location ( ~/.dialyzer_plt ). - -source_tarball - Creates tarball of all the client source code. - -package - Creates an erlang archive of the client. - -common_package - Creates an erlang archive of the server modules required by the erlang - client. - -all_tests - Clean compiles the client and client tests source code and runs - network_client_SUITE, direct_client_SUITE and packaging tests. During the - testing, this make target runs an instance of the broker, so make sure - there is no other instance of RabbitMQ server running. - diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/README.in rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/README.in --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/README.in 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/README.in 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,11 @@ +README.in: + +Please see http://www.rabbitmq.com/build-erlang-client.html for build +instructions. + +For your convenience, a text copy of these instructions is available +below. Please be aware that the instructions here may not be as up to +date as those at the above URL. + +=========================================================================== + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_auth_mechanisms.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_auth_mechanisms.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_auth_mechanisms.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_auth_mechanisms.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channel.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channel.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channel.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channel.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @type close_reason(Type) = {shutdown, amqp_reason(Type)}. @@ -66,13 +66,13 @@ -behaviour(gen_server). --export([call/2, call/3, cast/2, cast/3]). +-export([call/2, call/3, cast/2, cast/3, cast_flow/3]). -export([close/1, close/3]). -export([register_return_handler/2, register_flow_handler/2, register_confirm_handler/2]). -export([call_consumer/2, subscribe/3]). --export([next_publish_seqno/1, wait_for_confirms/1, - wait_for_confirms_or_die/1]). +-export([next_publish_seqno/1, wait_for_confirms/1, wait_for_confirms/2, + wait_for_confirms_or_die/1, wait_for_confirms_or_die/2]). -export([start_link/5, connection_closing/3, open/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, @@ -158,7 +158,7 @@ %% @spec (Channel, Method) -> ok %% @doc This is equivalent to amqp_channel:cast(Channel, Method, none). cast(Channel, Method) -> - gen_server:cast(Channel, {cast, Method, none, self()}). + gen_server:cast(Channel, {cast, Method, none, self(), noflow}). %% @spec (Channel, Method, Content) -> ok %% where @@ -170,7 +170,17 @@ %% This function is not recommended with synchronous methods, since there is no %% way to verify that the server has received the method. cast(Channel, Method, Content) -> - gen_server:cast(Channel, {cast, Method, Content, self()}). + gen_server:cast(Channel, {cast, Method, Content, self(), noflow}). + +%% @spec (Channel, Method, Content) -> ok +%% where +%% Channel = pid() +%% Method = amqp_method() +%% Content = amqp_msg() | none +%% @doc Like cast/3, with flow control. +cast_flow(Channel, Method, Content) -> + credit_flow:send(Channel), + gen_server:cast(Channel, {cast, Method, Content, self(), flow}). %% @spec (Channel) -> ok | closing %% where @@ -198,14 +208,25 @@ next_publish_seqno(Channel) -> gen_server:call(Channel, next_publish_seqno, infinity). -%% @spec (Channel) -> boolean() +%% @spec (Channel) -> boolean() | 'timeout' %% where %% Channel = pid() %% @doc Wait until all messages published since the last call have %% been either ack'd or nack'd by the broker. Note, when called on a %% non-Confirm channel, waitForConfirms returns true immediately. wait_for_confirms(Channel) -> - gen_server:call(Channel, wait_for_confirms, infinity). + wait_for_confirms(Channel, infinity). + +%% @spec (Channel, Timeout) -> boolean() | 'timeout' +%% where +%% Channel = pid() +%% Timeout = non_neg_integer() | 'infinity' +%% @doc Wait until all messages published since the last call have +%% been either ack'd or nack'd by the broker or the timeout expires. +%% Note, when called on a non-Confirm channel, waitForConfirms returns +%% true immediately. +wait_for_confirms(Channel, Timeout) -> + gen_server:call(Channel, {wait_for_confirms, Timeout}, infinity). %% @spec (Channel) -> true %% where @@ -214,7 +235,24 @@ %% received, the calling process is immediately sent an %% exit(nack_received). wait_for_confirms_or_die(Channel) -> - gen_server:call(Channel, {wait_for_confirms_or_die, self()}, infinity). + wait_for_confirms_or_die(Channel, infinity). + +%% @spec (Channel, Timeout) -> true +%% where +%% Channel = pid() +%% Timeout = non_neg_integer() | 'infinity' +%% @doc Behaves the same as wait_for_confirms/1, but if a nack is +%% received, the calling process is immediately sent an +%% exit(nack_received). If the timeout expires, the calling process is +%% sent an exit(timeout). +wait_for_confirms_or_die(Channel, Timeout) -> + case wait_for_confirms(Channel, Timeout) of + timeout -> close(Channel, 200, <<"Confirm Timeout">>), + exit(timeout); + false -> close(Channel, 200, <<"Nacks Received">>), + exit(nacks_received); + true -> true + end. %% @spec (Channel, ReturnHandler) -> ok %% where @@ -296,13 +334,13 @@ %% @private handle_call(open, From, State) -> - {noreply, rpc_top_half(#'channel.open'{}, none, From, none, State)}; + {noreply, rpc_top_half(#'channel.open'{}, none, From, none, noflow, State)}; %% @private handle_call({close, Code, Text}, From, State) -> handle_close(Code, Text, From, State); %% @private handle_call({call, Method, AmqpMsg, Sender}, From, State) -> - handle_method_to_server(Method, AmqpMsg, From, Sender, State); + handle_method_to_server(Method, AmqpMsg, From, Sender, noflow, State); %% Handles the delivery of messages from a direct channel %% @private handle_call({send_command_sync, Method, Content}, From, State) -> @@ -319,25 +357,23 @@ handle_call(next_publish_seqno, _From, State = #state{next_pub_seqno = SeqNo}) -> {reply, SeqNo, State}; - -handle_call(wait_for_confirms, From, State) -> - handle_wait_for_confirms(From, none, true, State); - -%% Lets the channel know that the process should be sent an exit -%% signal if a nack is received. -handle_call({wait_for_confirms_or_die, Pid}, From, State) -> - handle_wait_for_confirms(From, Pid, ok, State); +handle_call({wait_for_confirms, Timeout}, From, State) -> + handle_wait_for_confirms(From, Timeout, State); %% @private handle_call({call_consumer, Msg}, _From, State = #state{consumer = Consumer}) -> {reply, amqp_gen_consumer:call_consumer(Consumer, Msg), State}; %% @private handle_call({subscribe, BasicConsume, Subscriber}, From, State) -> - handle_method_to_server(BasicConsume, none, From, Subscriber, State). + handle_method_to_server(BasicConsume, none, From, Subscriber, noflow, + State). %% @private -handle_cast({cast, Method, AmqpMsg, Sender}, State) -> - handle_method_to_server(Method, AmqpMsg, none, Sender, State); +handle_cast({cast, Method, AmqpMsg, Sender, noflow}, State) -> + handle_method_to_server(Method, AmqpMsg, none, Sender, noflow, State); +handle_cast({cast, Method, AmqpMsg, Sender, flow}, State) -> + credit_flow:ack(Sender), + handle_method_to_server(Method, AmqpMsg, none, Sender, flow, State); %% @private handle_cast({register_return_handler, ReturnHandler}, State) -> erlang:monitor(process, ReturnHandler), @@ -352,7 +388,7 @@ {noreply, State#state{flow_handler_pid = FlowHandler}}; %% Received from channels manager %% @private -handle_cast({method, Method, Content}, State) -> +handle_cast({method, Method, Content, noflow}, State) -> handle_method_from_server(Method, Content, State); %% Handles the situation when the connection closes without closing the channel %% beforehand. The channel must block all further RPCs, @@ -387,6 +423,10 @@ ok = rabbit_channel:ready_for_close(ChPid), {noreply, State}; %% @private +handle_info({bump_credit, Msg}, State) -> + credit_flow:handle_bump_msg(Msg), + {noreply, State}; +%% @private handle_info(timed_out_flushing_channel, State) -> ?LOG_WARN("Channel (~p) closing: timed out flushing while " "connection closing~n", [self()]), @@ -408,7 +448,18 @@ State = #state{flow_handler_pid = FlowHandler}) -> ?LOG_WARN("Channel (~p): Unregistering flow handler ~p because it died. " "Reason: ~p~n", [self(), FlowHandler, Reason]), - {noreply, State#state{flow_handler_pid = none}}. + {noreply, State#state{flow_handler_pid = none}}; +handle_info({'DOWN', _, process, QPid, _Reason}, State) -> + rabbit_amqqueue:notify_sent_queue_down(QPid), + {noreply, State}; +handle_info({confirm_timeout, From}, State = #state{waiting_set = WSet}) -> + case gb_trees:lookup(From, WSet) of + none -> + {noreply, State}; + {value, _} -> + gen_server:reply(From, timeout), + {noreply, State#state{waiting_set = gb_trees:delete(From, WSet)}} + end. %% @private terminate(_Reason, State) -> @@ -416,13 +467,13 @@ %% @private code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. %%--------------------------------------------------------------------------- %% RPC mechanism %%--------------------------------------------------------------------------- -handle_method_to_server(Method, AmqpMsg, From, Sender, +handle_method_to_server(Method, AmqpMsg, From, Sender, Flow, State = #state{unconfirmed_set = USet}) -> case {check_invalid_method(Method), From, check_block(Method, AmqpMsg, State)} of @@ -440,7 +491,7 @@ State end, {noreply, rpc_top_half(Method, build_content(AmqpMsg), - From, Sender, State1)}; + From, Sender, Flow, State1)}; {ok, none, BlockReply} -> ?LOG_WARN("Channel (~p): discarding method ~p in cast.~n" "Reason: ~p~n", [self(), Method, BlockReply]), @@ -461,22 +512,23 @@ class_id = 0, method_id = 0}, case check_block(Close, none, State) of - ok -> {noreply, rpc_top_half(Close, none, From, none, State)}; + ok -> {noreply, rpc_top_half(Close, none, From, none, noflow, + State)}; BlockReply -> {reply, BlockReply, State} end. -rpc_top_half(Method, Content, From, Sender, +rpc_top_half(Method, Content, From, Sender, Flow, State0 = #state{rpc_requests = RequestQueue}) -> State1 = State0#state{ - rpc_requests = - queue:in({From, Sender, Method, Content}, RequestQueue)}, + rpc_requests = queue:in({From, Sender, Method, Content, Flow}, + RequestQueue)}, IsFirstElement = queue:is_empty(RequestQueue), if IsFirstElement -> do_rpc(State1); true -> State1 end. rpc_bottom_half(Reply, State = #state{rpc_requests = RequestQueue}) -> - {{value, {From, _Sender, _Method, _Content}}, RequestQueue1} = + {{value, {From, _Sender, _Method, _Content, _Flow}}, RequestQueue1} = queue:out(RequestQueue), case From of none -> ok; @@ -487,9 +539,9 @@ do_rpc(State = #state{rpc_requests = Q, closing = Closing}) -> case queue:out(Q) of - {{value, {From, Sender, Method, Content}}, NewQ} -> + {{value, {From, Sender, Method, Content, Flow}}, NewQ} -> State1 = pre_do(Method, Content, Sender, State), - DoRet = do(Method, Content, State1), + DoRet = do(Method, Content, Flow, State1), case ?PROTOCOL:is_method_synchronous(Method) of true -> State1; false -> case {From, DoRet} of @@ -513,7 +565,7 @@ end. pending_rpc_method(#state{rpc_requests = Q}) -> - {value, {_From, _Sender, Method, _Content}} = queue:peek(Q), + {value, {_From, _Sender, Method, _Content, _Flow}} = queue:peek(Q), Method. pre_do(#'channel.open'{}, none, _Sender, State) -> @@ -562,13 +614,13 @@ State = #state{closing = {just_channel, _}}) -> %% Both client and server sent close at the same time. Don't shutdown yet, %% wait for close_ok. - do(#'channel.close_ok'{}, none, State), + do(#'channel.close_ok'{}, none, noflow, State), {noreply, State#state{ closing = {just_channel, {server_initiated_close, Code, Text}}}}; handle_method_from_server1(#'channel.close'{reply_code = Code, reply_text = Text}, none, State) -> - do(#'channel.close_ok'{}, none, State), + do(#'channel.close_ok'{}, none, noflow, State), handle_shutdown({server_initiated_close, Code, Text}, State); handle_method_from_server1(#'channel.close_ok'{}, none, State = #state{closing = Closing}) -> @@ -604,7 +656,7 @@ %% flushed beforehand. Methods that made it to the queue are not %% blocked in any circumstance. {noreply, rpc_top_half(#'channel.flow_ok'{active = Active}, none, none, - none, State#state{flow_active = Active})}; + none, noflow, State#state{flow_active = Active})}; handle_method_from_server1( #'basic.return'{} = BasicReturn, AmqpMsg, State = #state{return_handler_pid = ReturnHandler}) -> @@ -629,12 +681,12 @@ #state{confirm_handler_pid = none} = State) -> ?LOG_WARN("Channel (~p): received ~p but there is no " "confirm handler registered~n", [self(), BasicNack]), - {noreply, update_confirm_set(BasicNack, handle_nack(State))}; + {noreply, update_confirm_set(BasicNack, State)}; handle_method_from_server1( #'basic.nack'{} = BasicNack, none, #state{confirm_handler_pid = ConfirmHandler} = State) -> ConfirmHandler ! BasicNack, - {noreply, update_confirm_set(BasicNack, handle_nack(State))}; + {noreply, update_confirm_set(BasicNack, State)}; handle_method_from_server1(Method, none, State) -> {noreply, rpc_bottom_half(Method, State)}; @@ -693,14 +745,15 @@ %% Internal plumbing %%--------------------------------------------------------------------------- -do(Method, Content, #state{driver = Driver, writer = W}) -> +do(Method, Content, Flow, #state{driver = Driver, writer = W}) -> %% Catching because it expects the {channel_exit, _, _} message on error - catch case {Driver, Content} of - {network, none} -> rabbit_writer:send_command_sync(W, Method); - {network, _} -> rabbit_writer:send_command_sync(W, Method, - Content); - {direct, none} -> rabbit_channel:do(W, Method); - {direct, _} -> rabbit_channel:do(W, Method, Content) + catch case {Driver, Content, Flow} of + {network, none, _} -> rabbit_writer:send_command_sync(W, Method); + {network, _, _} -> rabbit_writer:send_command_sync(W, Method, + Content); + {direct, none, _} -> rabbit_channel:do(W, Method); + {direct, _, flow} -> rabbit_channel:do_flow(W, Method, Content); + {direct, _, noflow} -> rabbit_channel:do(W, Method, Content) end. start_writer(State = #state{start_writer_fun = SWF}) -> @@ -757,14 +810,6 @@ {noreply, State} end. -handle_nack(State = #state{waiting_set = WSet}) -> - DyingPids = [Pid || {_, Pid} <- gb_trees:to_list(WSet), Pid =/= none], - case DyingPids of - [] -> State; - _ -> [exit(Pid, nack_received) || Pid <- DyingPids], - close(self(), 200, <<"Nacks Received">>) - end. - update_confirm_set(#'basic.ack'{delivery_tag = SeqNo, multiple = Multiple}, State = #state{unconfirmed_set = USet}) -> @@ -796,20 +841,33 @@ true -> notify_confirm_waiters(State) end. -notify_confirm_waiters(State = #state{waiting_set = WSet, +notify_confirm_waiters(State = #state{waiting_set = WSet, only_acks_received = OAR}) -> - [gen_server:reply(From, OAR) || {From, _} <- gb_trees:to_list(WSet)], - State#state{waiting_set = gb_trees:empty(), + [begin + safe_cancel_timer(TRef), + gen_server:reply(From, OAR) + end || {From, TRef} <- gb_trees:to_list(WSet)], + State#state{waiting_set = gb_trees:empty(), only_acks_received = true}. -handle_wait_for_confirms(From, Notify, EmptyReply, +handle_wait_for_confirms(From, Timeout, State = #state{unconfirmed_set = USet, waiting_set = WSet}) -> case gb_sets:is_empty(USet) of - true -> {reply, EmptyReply, State}; - false -> {noreply, State#state{waiting_set = - gb_trees:insert(From, Notify, WSet)}} + true -> + {reply, true, State}; + false -> + TRef = case Timeout of + infinity -> undefined; + _ -> erlang:send_after(Timeout * 1000, self(), + {confirm_timeout, From}) + end, + {noreply, + State#state{waiting_set = gb_trees:insert(From, TRef, WSet)}} end. call_to_consumer(Method, Args, #state{consumer = Consumer}) -> amqp_gen_consumer:call_consumer(Consumer, Method, Args). + +safe_cancel_timer(undefined) -> ok; +safe_cancel_timer(TRef) -> erlang:cancel_timer(TRef). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channels_manager.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channels_manager.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channels_manager.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channels_manager.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private @@ -22,7 +22,8 @@ -behaviour(gen_server). -export([start_link/2, open_channel/4, set_channel_max/2, is_empty/1, - num_channels/1, pass_frame/3, signal_connection_closing/3]). + num_channels/1, pass_frame/3, signal_connection_closing/3, + process_channel_frame/4]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]). @@ -59,6 +60,19 @@ signal_connection_closing(ChMgr, ChannelCloseType, Reason) -> gen_server:cast(ChMgr, {connection_closing, ChannelCloseType, Reason}). +process_channel_frame(Frame, Channel, ChPid, AState) -> + case rabbit_command_assembler:process(Frame, AState) of + {ok, NewAState} -> NewAState; + {ok, Method, NewAState} -> rabbit_channel:do(ChPid, Method), + NewAState; + {ok, Method, Content, NewAState} -> rabbit_channel:do(ChPid, Method, + Content), + NewAState; + {error, Reason} -> ChPid ! {channel_exit, Channel, + Reason}, + AState + end. + %%--------------------------------------------------------------------------- %% gen_server callbacks %%--------------------------------------------------------------------------- @@ -70,7 +84,7 @@ ok. code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. handle_call({open_channel, ProposedNumber, Consumer, InfraArgs}, _, State = #state{closing = false}) -> @@ -195,10 +209,10 @@ case internal_lookup_npa(Number, State) of undefined -> ?LOG_INFO("Dropping frame ~p for invalid or closed " - "channel number ~p~n", [Frame, Number]); + "channel number ~p~n", [Frame, Number]), + State; {ChPid, AState} -> - NewAState = rabbit_reader:process_channel_frame( - Frame, ChPid, Number, ChPid, AState), + NewAState = process_channel_frame(Frame, Number, ChPid, AState), internal_update_npa(Number, ChPid, NewAState, State) end. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private @@ -44,12 +44,13 @@ %% Internal plumbing %%--------------------------------------------------------------------------- -start_writer_fun(_Sup, direct, [ConnectionPid, Node, User, VHost, Collector], +start_writer_fun(_Sup, direct, [ConnPid, ConnName, Node, User, VHost, + Collector], ChNumber) -> fun () -> {ok, RabbitCh} = rpc:call(Node, rabbit_direct, start_channel, - [ChNumber, self(), ConnectionPid, ?PROTOCOL, User, + [ChNumber, self(), ConnPid, ConnName, ?PROTOCOL, User, VHost, ?CLIENT_CAPABILITIES, Collector]), link(RabbitCh), {ok, RabbitCh} diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_channel_sup_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_client.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_client.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_client.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_client.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_connection.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_connection.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_connection.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_connection.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @type close_reason(Type) = {shutdown, amqp_reason(Type)}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_connection_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_connection_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_connection_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_connection_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_connection_type_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_connection_type_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_connection_type_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_connection_type_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_direct_connection.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_direct_connection.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_direct_connection.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_direct_connection.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private @@ -21,6 +21,8 @@ -behaviour(amqp_gen_connection). +-export([server_close/3]). + -export([init/1, terminate/2, connect/4, do/2, open_channel_args/1, i/2, info_keys/0, handle_message/2, closing/3, channels_terminated/1]). @@ -41,14 +43,24 @@ %%--------------------------------------------------------------------------- +%% amqp_connection:close() logically closes from the client end. We may +%% want to close from the server end. +server_close(ConnectionPid, Code, Text) -> + Close = #'connection.close'{reply_text = Text, + reply_code = Code, + class_id = 0, + method_id = 0}, + amqp_gen_connection:server_close(ConnectionPid, Close). + init([]) -> {ok, #state{}}. open_channel_args(#state{node = Node, user = User, vhost = VHost, + adapter_info = Info, collector = Collector}) -> - [self(), Node, User, VHost, Collector]. + [self(), Info#adapter_info.name, Node, User, VHost, Collector]. do(_Method, _State) -> ok. @@ -129,9 +141,7 @@ ensure_adapter_info(A#adapter_info{protocol = {'Direct', ?PROTOCOL:version()}}); -ensure_adapter_info(A = #adapter_info{name = unknown, - peer_address = unknown, - peer_port = unknown}) -> +ensure_adapter_info(A = #adapter_info{name = unknown}) -> Name = list_to_binary(rabbit_misc:pid_to_string(self())), ensure_adapter_info(A#adapter_info{name = Name}); diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_direct_consumer.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_direct_consumer.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_direct_consumer.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_direct_consumer.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% %% @doc This module is an implementation of the amqp_gen_consumer diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_gen_connection.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_gen_connection.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_gen_connection.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_gen_connection.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private @@ -23,7 +23,7 @@ -export([start_link/5, connect/1, open_channel/3, hard_error_in_channel/3, channel_internal_error/3, server_misbehaved/2, channels_terminated/1, - close/2, info/2, info_keys/0, info_keys/1]). + close/2, server_close/2, info/2, info_keys/0, info_keys/1]). -export([behaviour_info/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]). @@ -83,6 +83,9 @@ close(Pid, Close) -> gen_server:call(Pid, {command, {close, Close}}, infinity). +server_close(Pid, Close) -> + gen_server:cast(Pid, {server_close, Close}). + info(Pid, Items) -> gen_server:call(Pid, {info, Items}, infinity). @@ -176,10 +179,10 @@ {error, _} = Error -> {stop, {shutdown, Error}, Error, State0} end; -handle_call({command, Command}, From, State = #state{closing = Closing}) -> - case Closing of false -> handle_command(Command, From, State); - _ -> {reply, closing, State} - end; +handle_call({command, Command}, From, State = #state{closing = false}) -> + handle_command(Command, From, State); +handle_call({command, _Command}, _From, State) -> + {reply, closing, State}; handle_call({info, Items}, _From, State) -> {reply, [{Item, i(Item, State)} || Item <- Items], State}; handle_call(info_keys, _From, State = #state{module = Mod}) -> @@ -195,7 +198,7 @@ channel_max = ChannelMax, module_state = NewMState}. -handle_cast({method, Method, none}, State) -> +handle_cast({method, Method, none, noflow}, State) -> handle_method(Method, State); handle_cast(channels_terminated, State) -> handle_channels_terminated(State); @@ -206,7 +209,9 @@ [self(), Pid, Reason]), internal_error(State); handle_cast({server_misbehaved, AmqpError}, State) -> - server_misbehaved_close(AmqpError, State). + server_misbehaved_close(AmqpError, State); +handle_cast({server_close, #'connection.close'{} = Close}, State) -> + server_initiated_close(Close, State). handle_info(Info, State) -> callback(handle_message, [Info], State). @@ -215,7 +220,7 @@ Mod:terminate(Reason, MState). code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. %%--------------------------------------------------------------------------- %% Infos diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_gen_consumer.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_gen_consumer.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_gen_consumer.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_gen_consumer.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% %% @doc A behaviour module for implementing consumers for @@ -249,4 +249,4 @@ ConsumerModule:terminate(Reason, MState). code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_main_reader.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_main_reader.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_main_reader.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_main_reader.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private @@ -44,15 +44,17 @@ %%--------------------------------------------------------------------------- init([Sock, Connection, ChMgr, AState]) -> - {ok, _Ref} = rabbit_net:async_recv(Sock, 7, infinity), - {ok, #state{sock = Sock, connection = Connection, - channels_manager = ChMgr, astate = AState}}. + case next(7, #state{sock = Sock, connection = Connection, + channels_manager = ChMgr, astate = AState}) of + {noreply, State} -> {ok, State}; + {stop, Reason, _State} -> {stop, Reason} + end. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. handle_call(Call, From, State) -> {stop, {unexpected_call, Call, From}, State}. @@ -60,35 +62,25 @@ handle_cast(Cast, State) -> {stop, {unexpected_cast, Cast}, State}. -handle_info({inet_async, _, _, _} = InetAsync, State) -> - handle_inet_async(InetAsync, State). +handle_info({inet_async, Sock, _, {ok, <>}}, + State = #state{sock = Sock, message = none}) -> + next(Length + 1, State#state{message = {Type, Channel, Length}}); +handle_info({inet_async, Sock, _, {ok, Data}}, + State = #state{sock = Sock, message = {Type, Channel, L}}) -> + <> = Data, + next(7, process_frame(Type, Channel, Payload, State#state{message = none})); +handle_info({inet_async, Sock, _, {error, Reason}}, + State = #state{sock = Sock}) -> + handle_error(Reason, State). %%--------------------------------------------------------------------------- %% Internal plumbing %%--------------------------------------------------------------------------- -handle_inet_async({inet_async, Sock, _, Msg}, - State = #state{sock = Sock, message = CurMessage}) -> - {Type, Number, Length} = case CurMessage of {T, N, L} -> {T, N, L}; - none -> {none, none, none} - end, - case Msg of - {ok, <>} -> - State1 = process_frame(Type, Number, Payload, State), - {ok, _Ref} = rabbit_net:async_recv(Sock, 7, infinity), - {noreply, State1#state{message = none}}; - {ok, <>} -> - {ok, _Ref} = rabbit_net:async_recv(Sock, NewLength + 1, infinity), - {noreply, State#state{message={NewType, NewChannel, NewLength}}}; - {error, closed} -> - State#state.connection ! socket_closed, - {noreply, State}; - {error, Reason} -> - State#state.connection ! {socket_error, Reason}, - {stop, {socket_error, Reason}, State} - end. - -process_frame(Type, ChNumber, Payload, State = #state{connection = Connection}) -> +process_frame(Type, ChNumber, Payload, + State = #state{connection = Connection, + channels_manager = ChMgr, + astate = AState}) -> case rabbit_command_assembler:analyze_frame(Type, Payload, ?PROTOCOL) of heartbeat when ChNumber /= 0 -> amqp_gen_connection:server_misbehaved( @@ -99,13 +91,23 @@ %% Match heartbeats but don't do anything with them heartbeat -> State; + AnalyzedFrame when ChNumber /= 0 -> + amqp_channels_manager:pass_frame(ChMgr, ChNumber, AnalyzedFrame), + State; AnalyzedFrame -> - pass_frame(ChNumber, AnalyzedFrame, State) + State#state{astate = amqp_channels_manager:process_channel_frame( + AnalyzedFrame, 0, Connection, AState)} end. -pass_frame(0, Frame, State = #state{connection = Conn, astate = AState}) -> - State#state{astate = rabbit_reader:process_channel_frame(Frame, Conn, - 0, Conn, AState)}; -pass_frame(Number, Frame, State = #state{channels_manager = ChMgr}) -> - amqp_channels_manager:pass_frame(ChMgr, Number, Frame), - State. +next(Length, State = #state{sock = Sock}) -> + case rabbit_net:async_recv(Sock, Length, infinity) of + {ok, _} -> {noreply, State}; + {error, Reason} -> handle_error(Reason, State) + end. + +handle_error(closed, State = #state{connection = Conn}) -> + Conn ! socket_closed, + {noreply, State}; +handle_error(Reason, State = #state{connection = Conn}) -> + Conn ! {socket_error, Reason}, + {stop, {socket_error, Reason}, State}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_network_connection.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_network_connection.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_network_connection.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_network_connection.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private @@ -68,7 +68,17 @@ handle_message({channel_exit, Reason}, State) -> {stop, {channel0_died, Reason}, State}; handle_message(heartbeat_timeout, State) -> - {stop, heartbeat_timeout, State}. + {stop, heartbeat_timeout, State}; +%% see http://erlang.org/pipermail/erlang-bugs/2012-June/002933.html +handle_message({Ref, {error, Reason}}, + State = #state{waiting_socket_close = Waiting, + closing_reason = CloseReason}) + when is_reference(Ref) -> + {stop, case {Reason, Waiting} of + {closed, true} -> {shutdown, CloseReason}; + {closed, false} -> socket_closed_unexpectedly; + {_, _} -> {socket_error, Reason} + end, State}. closing(_ChannelCloseType, Reason, State) -> {ok, State#state{closing_reason = Reason}}. @@ -245,7 +255,7 @@ {<<"version">>, longstr, list_to_binary(Vsn)}, {<<"platform">>, longstr, <<"Erlang">>}, {<<"copyright">>, longstr, - <<"Copyright (c) 2007-2011 VMware, Inc.">>}, + <<"Copyright (c) 2007-2012 VMware, Inc.">>}, {<<"information">>, longstr, <<"Licensed under the MPL. " "See http://www.rabbitmq.com/">>}, @@ -256,7 +266,7 @@ handshake_recv(Expecting) -> receive - {'$gen_cast', {method, Method, none}} -> + {'$gen_cast', {method, Method, none, noflow}} -> case {Expecting, element(1, Method)} of {E, M} when E =:= M -> Method; diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_client.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_client.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_client.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_client.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @doc This module allows the simple execution of an asynchronous RPC over @@ -168,4 +168,4 @@ %% @private code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_server.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_server.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_server.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_rpc_server.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @doc This is a utility module that is used to expose an arbitrary function @@ -130,4 +130,4 @@ %% @private code_change(_OldVsn, State, _Extra) -> - State. + {ok, State}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_selective_consumer.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_selective_consumer.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_selective_consumer.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_selective_consumer.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% %% @doc This module is an implementation of the amqp_gen_consumer diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% @private diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_uri.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_uri.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/amqp_uri.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/amqp_uri.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(amqp_uri). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/overview.edoc.in rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/overview.edoc.in --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/overview.edoc.in 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/overview.edoc.in 2012-06-22 16:03:48.000000000 +0000 @@ -1,6 +1,6 @@ @title AMQP Client for Erlang @author VMware Inc. -@copyright 2007-2011 VMware, Inc. +@copyright 2007-2012 VMware, Inc. @version %%VERSION%% diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/uri_parser.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/uri_parser.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/src/uri_parser.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/src/uri_parser.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,7 @@ %% This file is a copy of http_uri.erl from the R13B-1 Erlang/OTP %% distribution with several modifications. -%% All modifications are Copyright (c) 2009-2011 VMware, Ltd. +%% All modifications are Copyright (c) 2009-2012 VMware, Ltd. %% ``The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/amqp_client_SUITE.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/amqp_client_SUITE.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/amqp_client_SUITE.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/amqp_client_SUITE.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(amqp_client_SUITE). @@ -23,7 +23,10 @@ -define(FUNCTION, begin catch throw(x), - [{_, Fun, _} | _] = erlang:get_stacktrace(), + Fun = case erlang:get_stacktrace() of + [{_, F, _} | _] -> F; %% < R15 + [{_, F, _, _} | _] -> F %% >= R15 + end, list_to_atom(string:strip(atom_to_list(Fun), right, $_)) end). @@ -62,6 +65,8 @@ confirm_test_() -> ?RUN([]). confirm_barrier_test_() -> ?RUN([]). confirm_barrier_nop_test_() -> ?RUN([]). +confirm_barrier_timeout_test_() -> ?RUN([]). +confirm_barrier_die_timeout_test_() -> ?RUN([]). default_consumer_test() -> ?RUN([]). subscribe_nowait_test_() -> ?RUN([]). @@ -93,7 +98,7 @@ true -> negative_test_util; false -> test_util end, - {timeout, proplists:get_value(timeout, Props, 5), + {timeout, proplists:get_value(timeout, Props, 10), fun () -> lists:foreach( fun (_) -> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/amqp_dbg.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/amqp_dbg.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/amqp_dbg.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/amqp_dbg.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(amqp_dbg). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/Makefile rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/Makefile --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ # The Original Code is RabbitMQ. # # The Initial Developer of the Original Code is VMware, Inc. -# Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +# Copyright (c) 2007-2012 VMware, Inc. All rights reserved. # TEST_SOURCES=$(wildcard *.erl) diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/negative_test_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/negative_test_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/negative_test_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/negative_test_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(negative_test_util). @@ -151,7 +151,7 @@ case amqp_connection:info(Connection, [type]) of [{type, direct}] -> Channel ! {send_command, #'connection.open'{}}; [{type, network}] -> gen_server:cast(Channel, - {method, #'connection.open'{}, none}) + {method, #'connection.open'{}, none, noflow}) end, assert_down_with_error(MonitorRef, command_invalid), ?assertNot(is_process_alive(Channel)), @@ -162,7 +162,7 @@ %% command_invalid - this only applies to the network case command_invalid_over_channel0_test() -> {ok, Connection} = test_util:new_connection(just_network), - gen_server:cast(Connection, {method, #'basic.ack'{}, none}), + gen_server:cast(Connection, {method, #'basic.ack'{}, none, noflow}), MonitorRef = erlang:monitor(process, Connection), assert_down_with_error(MonitorRef, command_invalid), ok. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/test_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/test_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test/test_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test/test_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(test_util). @@ -632,6 +632,34 @@ true = amqp_channel:wait_for_confirms(Channel), teardown(Connection, Channel). +confirm_barrier_timeout_test() -> + {ok, Connection} = new_connection(), + {ok, Channel} = amqp_connection:open_channel(Connection), + #'confirm.select_ok'{} = amqp_channel:call(Channel, #'confirm.select'{}), + [amqp_channel:call(Channel, #'basic.publish'{routing_key = <<"whoosh">>}, + #amqp_msg{payload = <<"foo">>}) + || _ <- lists:seq(1, 1000)], + case amqp_channel:wait_for_confirms(Channel, 0) of + true -> ok; + timeout -> ok + end, + teardown(Connection, Channel). + +confirm_barrier_die_timeout_test() -> + {ok, Connection} = new_connection(), + {ok, Channel} = amqp_connection:open_channel(Connection), + #'confirm.select_ok'{} = amqp_channel:call(Channel, #'confirm.select'{}), + [amqp_channel:call(Channel, #'basic.publish'{routing_key = <<"whoosh">>}, + #amqp_msg{payload = <<"foo">>}) + || _ <- lists:seq(1, 1000)], + try amqp_channel:wait_for_confirms_or_die(Channel, 0) of + true -> ok + catch + exit:timeout -> ok + end, + amqp_connection:close(Connection), + wait_for_death(Connection). + default_consumer_test() -> {ok, Connection} = new_connection(), {ok, Channel} = amqp_connection:open_channel(Connection), @@ -939,7 +967,7 @@ {verify, verify_peer}, {fail_if_no_peer_cert, true}]}] ++ Params); {_, "direct"} -> - make_direct_params([{node, rabbit_misc:makenode(rabbit)}] ++ + make_direct_params([{node, rabbit_nodes:make(rabbit)}] ++ Params) end, amqp_connection:start(Params1). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test.mk rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test.mk --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-erlang-client/test.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-erlang-client/test.mk 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ # The Original Code is RabbitMQ. # # The Initial Developer of the Original Code is VMware, Inc. -# Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +# Copyright (c) 2007-2012 VMware, Inc. All rights reserved. # IS_SUCCESS:=egrep "All .+ tests (successful|passed)." diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/etc/hare-no-federation.config rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/etc/hare-no-federation.config --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/etc/hare-no-federation.config 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/etc/hare-no-federation.config 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1 @@ +[]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/etc/no_plugins rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/etc/no_plugins --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/etc/no_plugins 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/etc/no_plugins 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1 @@ +[]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/include/rabbit_federation.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/include/rabbit_federation.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/include/rabbit_federation.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/include/rabbit_federation.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -record(upstream, {params, @@ -21,6 +21,9 @@ reconnect_delay, expires, message_ttl, + ha_policy, connection_name}). --define(SUPERVISOR, rabbit_federation_sup). +-define(ROUTING_HEADER, <<"x-received-from">>). +-define(MAX_HOPS_ARG, <<"x-max-hops">>). +-define(DEFAULT_PREFETCH, 1000). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/Makefile rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/Makefile --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -3,6 +3,7 @@ OTHER_NODE=undefined OTHER_PORT=undefined OTHER_CONFIG=undefined +OTHER_PLUGINS=undefined PID_FILE=/tmp/$(OTHER_NODE).pid start-other-node: @@ -12,6 +13,7 @@ RABBITMQ_NODENAME=$(OTHER_NODE) \ RABBITMQ_NODE_PORT=$(OTHER_PORT) \ RABBITMQ_CONFIG_FILE=etc/$(OTHER_CONFIG) \ + RABBITMQ_ENABLED_PLUGINS_FILE=${OTHER_PLUGINS} \ RABBITMQ_PLUGINS_DIR=/tmp/rabbitmq-test/plugins \ RABBITMQ_PLUGINS_EXPAND_DIR=/tmp/rabbitmq-$(OTHER_NODE)-plugins-expand \ RABBITMQ_PID_FILE=$(PID_FILE) \ diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/README 2012-06-22 16:03:48.000000000 +0000 @@ -1,273 +1,4 @@ -Purpose -======= +Generic build instructions are at: + http://www.rabbitmq.com/plugin-development.html -The high level goal is to transmit messages between brokers without -requiring clustering. This is useful for the following reasons: - -1) Federated brokers may be in different administrative - domains. Clustered brokers form a single administrative domain. - - a) Federated brokers may have different users and virtual hosts. - Federated brokers only need to partially trust each other. - - b) Federated brokers may run different versions of RabbitMQ and - Erlang. - -2) Federated brokers only speak AMQP to each other, and the federation - mechanism is designed to deal with intermittent connectivity. - Federation is therefore much more WAN-friendly. - -3) Brokers can contain federated and local-only components - you don't - need to federate everything if you don't want to. - -4) Ultimately, greater scalability should be possible, since more complex - routing topologies avoid the need for n^2 connections between n - brokers. - -For the time being, federation is primarily useful in pub/sub scenarios. - - -Limitations -=========== - -You can't federate headers exchanges. You can't make a broker federate -with a new upstream without restarting it. There's no status -reporting. These will likely get fixed. - - -HOWTO -===== - -The plugin provides a federated exchange type. A federated exchange -has type 'x-federation'. However, this type does not provide any -routing logic. The routing logic is implemented by a backing type, -provided to the exchange as an argument. - -Messages can be published to a federated exchange like any -other. However, a federated exchange also receives messages from -one or more "upstream" exchanges, located on remote brokers. - -(Well, you don't need to have upstream exchanges, and they don't need -to be remote. But then you don't get anything very useful.) - -An upstream exchange can be a regular exchange or a federation -exchange. It is expected that upstream and downstream exchanges have -the same type (or backing type). Mixing types will lead to strange -routing behaviour. - -Inter-broker communication is implemented using AMQP (optionally -secured with SSL). Bindings are grouped together and bind / unbind -commands are sent to the upstream exchange. Therefore the federation -plugin only receives messages over the wire for which the downstream -exchange has a subscription. To promote scalability the bindings are -sent upstream asynchronously - so the effect of adding or removing a -binding is only guaranteed to be seen eventually. - -A typical use would be to have the same "logical" exchange distributed -over many brokers. This would be achieved by having the exchange -declared as a federated exchange in each broker, with upstreams -corresponding to all the other brokers. - -Another would be massive fanout - a single "root" exchange in one -broker can be treated as an upstream by many other brokers. In turn -each of these can be the upstream for many more downstreams, and so -on. - -Other topologies are of course possible. - -Federated exchanges can be set up statically via broker configuration, -or declared dynamically over AMQP. - - -Static Configuration -==================== - -A verbose static configuration might look like: - - {rabbitmq_federation, - [ {exchanges, [[{exchange, "my-exchange"}, - {virtual_host, "/"}, - {type, "topic"}, - {durable, true}, - {auto_delete, false}, - {internal, false}, - {upstream_set, "my-upstreams"}] - ]}, - {upstream_sets, [{"my-upstreams", [[{connection, "upstream-server"}, - {exchange, "my-upstream-x"}, - {max_hops, 2}], - [{connection, "another-server"}] - ]} - ]}, - {connections, [{"upstream-server", [{host, "upstream-server"}, - {protocol, "amqps"}, - {port, 5671}, - {virtual_host, "/"}, - {username, "myusername"}, - {password, "secret"}, - {mechanism, default}, - {prefetch_count, 1000}, - {reconnect_delay, 5}, - {heartbeat, 1}, - {queue_expires, 30000}, - {message_ttl, 10000}, - {ssl_options, - [{cacertfile, "/path/to/cacert.pem"}, - {certfile, "/path/to/cert.pem"}, - {keyfile, "/path/to/key.pem"}, - {verify, verify_peer}, - {fail_if_no_peer_cert, true} - ]} - ]}, - {"another-server", [...elided...]} - ]}, - {local_username, "myusername"}, - {local_nodename, "my-server"} - ] - } - -The list of exchanges looks like a set of exchange.declares for the -most part, but with each declaration including the name of an -"upstream_set", representing a list of remote exchanges whose messages -should be federated to the local exchange. Note that the type -parameter must match the type of the upstream exchanges for routing to -work at all sensibly. - -Each element in the upstream_set contains a mapping from a name to a -list of upstreams. Each element in this list can contain the following -properties: - -connection - - name of a connection from the connection list. Mandatory. - -exchange - - name for exchange to connect to. Default is to use the same name - as the downstream exchange. (Therefore one upstream_set can be - refered to by many local exchanges as long as exchange names are - the same across all the nodes in your federation.) - -max_hops - - the maximum number of times a message received over this link may - have been forwarded (including traversing this link). The default - for max_hops is 1. This prevents messages from looping forever - when there are circular topologies, and can reduce or prevent - message duplication. - -Note that the static configuration will declare the downstream -exchanges (on the local broker). It does not ensure the upstream -exchanges exist. - -The connections list provides information on how to connect to brokers -mentioned in the upstream sets. It can contain the following properties: - -host - - hostname to connect to - -protocol - - "amqp" or "amqps". Default is "amqp". - -port - - port to connect to. Default is 5672, or 5671 when using SSL. - -virtual_host - - virtual host to connect to. Default is to use the virtual host for - the downstream exchange. - -username - - user to connect as. Default is "guest". The user will need the - ability to create exchanges and queues with names beginning with - "federation:". It will also need to be able to bind to the upstream - exchange. - -password - - password to use. Default is "guest". - -mechanism - - SASL mechanism to use. One of: - 'default' - to use PLAIN or AMQPLAIN by negotiation (this is the default) - 'EXTERNAL' - to use SASL EXTERNAL authentication - e.g. - rabbitmq-auth-mechanism-ssl - -prefetch_count - - limit on the maximum number of unacknowledged messages in flight - per link. Default is 'none'. - -reconnect_delay - - time in seconds to wait to reconnect to the broker after being - disconnected. Default is 1. - -heartbeat - - AMQP heartbeat interval (in seconds) on the connection, or none. Default - is 'none'. - -expires - - Messages are buffered in the upstream broker in a queue before being - sent downstream. This setting controls how long the upstream queue - lasts before being deleted if the downstream is disconnected (i.e. - it controls the "x-expires" argument for the upstream queue). The - value is in milliseconds. Default is 'none', meaning the queue should - never expire. - -message_ttl - - Controls how long to keep upstream messages buffered, in milliseconds - (i.e. the "x-message-ttl" argument for the upstream queue). Default is - 'none', meaning messages should never expire. - -ssl_options - - Specifies how to make client SSL connections. See the Erlang - client documentation for more details. - -The local_username parameter specifies how to connect to the local -broker. The default is "guest". This user will need the ability to -publish messages to the downstream exchange. - -The local_nodename parameter specifies the name this node should use -to identify itself in the federation. If not specified it will attempt -to build a "long form" version of the usual Erlang node name (but -using the machine's FQDN). You should only have to specify this if -your DNS will not give each machine in the federation unique names. - -Declaring Federation Exchanges Over AMQP -======================================== - -This is a less common case, but in case you want to do this: - - * Declare the downstream exchange with type "x-federation". - - * Give it arguments "type" and "upstream-set", both of type "long - string". "type" should refer to its backing type; the type of the - upstream exchanges. "upstream-set" should be the name of an - upstream_set from the static configuration (note that it's a hyphen - over AMQP but an underscore in the configuration). - -Example using the Java API: - -Map args = new HashMap(); -args.put("type", "topic"); -args.put("upstream-set", "my-upstream-set"); - -Channel ch = ...; -ch.exchangeDeclare("my-federated-exchange", "x-federation", true, false, args); - -Note On Clustering -================== - -When using federation with clustering, all cluster nodes must have the -federation plugin installed. Any node may establish connections to -upstream exchanges. If a node fails, any upstream links will fail over -to a surviving node. - -Possible Future Enhancements -============================ - -* Simple status reporting, similar to the shovel - -* Modify upstream sets dynamically - -* Mode to federate all exchanges - -* Status information and control in the management plugin - -* Smarter routing logic - -* Support for RPC-like patterns +See http://www.rabbitmq.com/federation.html diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_app). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_db.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_db.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_db.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_db.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_db). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_exchange.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_exchange.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_exchange.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_exchange.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_exchange). @@ -23,7 +23,6 @@ {requires, rabbit_registry}, {enables, recovery}]}). --include_lib("rabbit_common/include/rabbit_exchange_type_spec.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). -behaviour(rabbit_exchange_type). @@ -32,8 +31,6 @@ -export([validate/1, create/2, delete/3, add_binding/3, remove_bindings/3, assert_args_equivalence/2]). --export([fail/2]). - %%---------------------------------------------------------------------------- description() -> @@ -46,8 +43,8 @@ validate(#exchange{name = XName, arguments = Args} = X) -> - validate_arg(<<"upstream-set">>, longstr, Args), - validate_arg(<<"type">>, longstr, Args), + rabbit_federation_util:validate_arg(<<"upstream-set">>, longstr, Args), + rabbit_federation_util:validate_arg(<<"type">>, longstr, Args), {longstr, SetName} = rabbit_misc:table_lookup(Args, <<"upstream-set">>), case rabbit_federation_upstream:from_set(SetName, XName) of {error, E} -> fail_error(SetName, E); @@ -55,7 +52,8 @@ end, {longstr, TypeBin} = rabbit_misc:table_lookup(Args, <<"type">>), case rabbit_exchange:check_type(TypeBin) of - 'x-federation' -> fail("Type argument must not be x-federation.", []); + 'x-federation' -> rabbit_federation_util:fail( + "Type argument must not be x-federation.", []); _ -> ok end, with_module(X, fun (M) -> M:validate(X) end). @@ -67,14 +65,15 @@ {longstr, Set} = rabbit_misc:table_lookup(Args, <<"upstream-set">>), {ok, Upstreams} = rabbit_federation_upstream:from_set(Set, XName), ok = rabbit_federation_db:prune_scratch(XName, Upstreams), - {ok, _} = rabbit_federation_sup:start_child(XName, {Set, XName}), + {ok, _} = rabbit_federation_link_sup_sup:start_child(XName, {Set, XName}), with_module(X, fun (M) -> M:create(none, X) end). delete(transaction, X, Bs) -> with_module(X, fun (M) -> M:delete(transaction, X, Bs) end); delete(none, X = #exchange{name = XName}, Bs) -> rabbit_federation_link:stop(XName), - ok = rabbit_federation_sup:stop_child(XName), + ok = rabbit_federation_link_sup_sup:stop_child(XName), + rabbit_federation_status:remove(XName), with_module(X, fun (M) -> M:delete(none, X, Bs) end). add_binding(transaction, X, B) -> @@ -110,18 +109,9 @@ exchange, list_to_existing_atom(binary_to_list(Type))), Fun(Module). -validate_arg(Name, Type, Args) -> - case rabbit_misc:table_lookup(Args, Name) of - {Type, _} -> ok; - undefined -> fail("Argument ~s missing", [Name]); - _ -> fail("Argument ~s must be of type ~s", [Name, Type]) - end. - -fail(Fmt, Args) -> rabbit_misc:protocol_error(precondition_failed, Fmt, Args). - fail_error(SetName, Reason) -> {Fmt, Args} = error_text(Reason), - fail("upstream-set ~s: " ++ Fmt, [SetName | Args]). + rabbit_federation_util:fail("upstream-set ~s: " ++ Fmt, [SetName | Args]). error_text(set_not_found) -> {"set not found", []}; error_text(no_connection_name) -> {"no connection name", []}; diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_link.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_link.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_link.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_link.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_link). @@ -30,9 +30,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([add_routing_to_headers/2]). - --define(ROUTING_HEADER, <<"x-received-from">>). +-import(rabbit_misc, [pget/2]). -record(state, {upstream, connection, @@ -70,7 +68,8 @@ start_link(Args) -> gen_server2:start_link(?MODULE, Args, [{timeout, infinity}]). -init(Args = {_, XName}) -> +init(Args = {Upstream, XName}) -> + rabbit_federation_status:report(Upstream, XName, starting), join(rabbit_federation_exchanges), join({rabbit_federation_exchange, XName}), gen_server2:cast(self(), maybe_go), @@ -129,10 +128,13 @@ unacked = Unacked}) -> Headers0 = extract_headers(Msg), %% TODO add user information here? - case should_forward(Headers0, MaxHops) of + %% We need to check should_forward/2 here in case the upstream + %% does not have federation and thus is using a fanout exchange. + case rabbit_federation_util:should_forward(Headers0, MaxHops) of true -> {table, Info0} = rabbit_federation_upstream:to_table(Upstream), Info = Info0 ++ [{<<"redelivered">>, bool, Redelivered}], - Headers = add_routing_to_headers(Headers0, Info), + Headers = rabbit_basic:append_table_header( + ?ROUTING_HEADER, Info, Headers0), Seq = amqp_channel:next_publish_seqno(DCh), amqp_channel:cast(DCh, #'basic.publish'{exchange = XNameBin, routing_key = Key}, @@ -153,7 +155,7 @@ %% log it and die quietly. handle_info({'DOWN', _Ref, process, Ch, {shutdown, Reason}}, State = #state{channel = Ch}) -> - connection_error({upstream_channel_down, Reason}, State); + connection_error(remote, {upstream_channel_down, Reason}, State); handle_info({'DOWN', _Ref, process, Ch, Reason}, State = #state{channel = Ch}) -> @@ -232,11 +234,17 @@ true -> State end. +open_monitor(Params) -> + case open(Params) of + {ok, Conn, Ch} -> erlang:monitor(process, Ch), + {ok, Conn, Ch}; + E -> E + end. + open(Params) -> case amqp_connection:start(Params) of {ok, Conn} -> case amqp_connection:open_channel(Conn) of - {ok, Ch} -> erlang:monitor(process, Ch), - {ok, Conn, Ch}; + {ok, Ch} -> {ok, Conn, Ch}; E -> catch amqp_connection:close(Conn), E end; @@ -301,12 +309,12 @@ %% us to exit. We can therefore only trap exits when past that %% point. Bug 24372 may help us do something nicer. process_flag(trap_exit, true), - case open(rabbit_federation_util:local_params(DownVHost)) of + case open_monitor(rabbit_federation_util:local_params(DownVHost)) of {ok, DConn, DCh} -> #'confirm.select_ok'{} = amqp_channel:call(DCh, #'confirm.select'{}), amqp_channel:register_confirm_handler(DCh, self()), - case open(Upstream#upstream.params) of + case open_monitor(Upstream#upstream.params) of {ok, Conn, Ch} -> {Serial, Bindings} = rabbit_misc:execute_mnesia_transaction( @@ -321,43 +329,68 @@ %% serial we will process. Since it compares larger than %% any number we never process any commands. And we will %% soon get told to stop anyway. - State = ensure_upstream_bindings( - consume_from_upstream_queue( - #state{upstream = Upstream, - connection = Conn, - channel = Ch, - next_serial = Serial, - downstream_connection = DConn, - downstream_channel = DCh, + try + State = ensure_upstream_bindings( + consume_from_upstream_queue( + #state{upstream = Upstream, + connection = Conn, + channel = Ch, + next_serial = Serial, + downstream_connection = DConn, + downstream_channel = DCh, downstream_exchange = DownXName}), - Bindings), - rabbit_log:info("Federation ~s connected to ~s~n", - [rabbit_misc:rs(DownXName), - rabbit_federation_upstream:to_string( - Upstream)]), - {noreply, State}; - + Bindings), + rabbit_log:info("Federation ~s connected to ~s~n", + [rabbit_misc:rs(DownXName), + rabbit_federation_upstream:to_string( + Upstream)]), + Name = pget(name, amqp_connection:info(DConn, [name])), + rabbit_federation_status:report( + Upstream, DownXName, {running, Name}), + {noreply, State} + catch exit:E -> + %% terminate/2 will not get this, as we + %% have not put them in our state yet + ensure_closed(DConn, DCh), + ensure_closed(Conn, Ch), + connection_error(remote, E, S0) + end; E -> ensure_closed(DConn, DCh), - connection_error(E, S0) + connection_error(remote, E, S0) end; E -> - connection_error(E, S0) + connection_error(local, E, S0) end. -connection_error(E, State = {not_started, {U, XName}}) -> - rabbit_log:info("Federation ~s failed to establish connection to ~s~n~p~n", +connection_error(remote, E, State = {not_started, {U, XName}}) -> + rabbit_federation_status:report(U, XName, clean_reason(E)), + rabbit_log:warning("Federation ~s did not connect to ~s~n~p~n", + [rabbit_misc:rs(XName), + rabbit_federation_upstream:to_string(U), E]), + {stop, {shutdown, restart}, State}; + +connection_error(remote, E, State = #state{upstream = U, + downstream_exchange = XName}) -> + rabbit_federation_status:report(U, XName, clean_reason(E)), + rabbit_log:info("Federation ~s disconnected from ~s~n~p~n", [rabbit_misc:rs(XName), rabbit_federation_upstream:to_string(U), E]), - {stop, {shutdown, E}, State}; + {stop, {shutdown, restart}, State}; -connection_error(E, State = #state{upstream = U, - downstream_exchange = XName}) -> - rabbit_log:info("Federation ~s disconnected from ~s:~n~p~n", - [rabbit_misc:rs(XName), - rabbit_federation_upstream:to_string(U), E]), - {stop, {shutdown, E}, State}. +connection_error(local, E, State = {not_started, {U, XName}}) -> + rabbit_federation_status:report(U, XName, clean_reason(E)), + rabbit_log:warning("Federation ~s did not connect locally~n~p~n", + [rabbit_misc:rs(XName), E]), + {stop, {shutdown, restart}, State}. + +%% If we terminate due to a gen_server call exploding (almost +%% certainly due to an amqp_channel:call() exploding) then we do not +%% want to report the gen_server call in our status. +clean_reason({E = {shutdown, _}, _}) -> E; +clean_reason(E) -> E. +%% local / disconnected never gets invoked, see handle_info({'DOWN', ... consume_from_upstream_queue( State = #state{upstream = Upstream, @@ -367,9 +400,12 @@ prefetch_count = Prefetch, expires = Expiry, message_ttl = TTL, + ha_policy = HA, params = #amqp_params_network{virtual_host = VHost}} = Upstream, Q = upstream_queue_name(XNameBin, VHost, DownXName), + %% TODO it would be nice to just pass through args, but let's do that as + %% part of bug 23908. ExpiryArg = case Expiry of none -> []; _ -> [{<<"x-expires">>, long, Expiry}] @@ -378,14 +414,15 @@ none -> []; _ -> [{<<"x-message-ttl">>, long, TTL}] end, - Args = ExpiryArg ++ TTLArg, + HAArg = case HA of + none -> []; + _ -> [{<<"x-ha-policy">>, longstr, list_to_binary(HA)}] + end, + Args = ExpiryArg ++ TTLArg ++ HAArg, amqp_channel:call(Ch, #'queue.declare'{queue = Q, durable = true, arguments = Args}), - case Prefetch of - none -> ok; - _ -> amqp_channel:call(Ch, #'basic.qos'{prefetch_count = Prefetch}) - end, + amqp_channel:call(Ch, #'basic.qos'{prefetch_count = Prefetch}), #'basic.consume_ok'{} = amqp_channel:subscribe(Ch, #'basic.consume'{queue = Q, no_ack = false}, self()), @@ -405,15 +442,7 @@ <<"B">> -> <<"A">> end, IntXNameBin = upstream_exchange_name(XNameBin, VHost, DownXName, Suffix), - delete_upstream_exchange(Conn, IntXNameBin), - amqp_channel:call( - Ch, #'exchange.declare'{ - exchange = IntXNameBin, - type = <<"fanout">>, - durable = true, - internal = true, - auto_delete = true, - arguments = []}), + ensure_upstream_exchange(IntXNameBin, State), amqp_channel:call(Ch, #'queue.bind'{exchange = IntXNameBin, queue = Q}), State1 = State#state{internal_exchange = IntXNameBin}, State2 = lists:foldl(fun add_binding/2, State1, Bindings), @@ -423,6 +452,23 @@ delete_upstream_exchange(Conn, OldIntXNameBin), State2. +ensure_upstream_exchange(IntXNameBin, + #state{upstream = #upstream{max_hops = MaxHops, + params = Params}, + connection = Conn, + channel = Ch}) -> + delete_upstream_exchange(Conn, IntXNameBin), + Base = #'exchange.declare'{exchange = IntXNameBin, + durable = true, + internal = true, + auto_delete = true}, + XFU = Base#'exchange.declare'{type = <<"x-federation-upstream">>, + arguments = [{?MAX_HOPS_ARG, long, MaxHops}]}, + Fan = Base#'exchange.declare'{type = <<"fanout">>}, + disposable_connection_call(Params, XFU, fun(?COMMAND_INVALID, _Text) -> + amqp_channel:call(Ch, Fan) + end). + upstream_queue_name(XNameBin, VHost, #resource{name = DownXNameBin, virtual_host = DownVHost}) -> Node = local_nodename(), @@ -443,11 +489,11 @@ local_nodename() -> {ok, Explicit} = application:get_env(rabbitmq_federation, local_nodename), case Explicit of - automatic -> {ID, _} = rabbit_misc:nodeparts(node()), + automatic -> {ID, _} = rabbit_nodes:parts(node()), {ok, Host} = inet:gethostname(), {ok, #hostent{h_name = FQDN}} = inet:gethostbyname(Host), list_to_binary(atom_to_list( - rabbit_misc:makenode({ID, FQDN}))); + rabbit_nodes:make({ID, FQDN}))); _ -> list_to_binary(Explicit) end. @@ -455,14 +501,31 @@ disposable_channel_call(Conn, #'exchange.delete'{exchange = XNameBin}). disposable_channel_call(Conn, Method) -> + disposable_channel_call(Conn, Method, fun(_, _) -> ok end). + +disposable_channel_call(Conn, Method, ErrFun) -> {ok, Ch} = amqp_connection:open_channel(Conn), try amqp_channel:call(Ch, Method) - catch exit:{{shutdown, {server_initiated_close, _, _}}, _} -> - ok + catch exit:{{shutdown, {server_initiated_close, Code, Text}}, _} -> + ErrFun(Code, Text) end, ensure_closed(Ch). +disposable_connection_call(Params, Method, ErrFun) -> + case open(Params) of + {ok, Conn, Ch} -> + try + amqp_channel:call(Ch, Method) + catch exit:{{shutdown, {connection_closing, + {server_initiated_close, Code, Txt}}}, _} -> + ErrFun(Code, Txt) + end, + ensure_closed(Conn, Ch); + E -> + E + end. + ensure_closed(Conn, Ch) -> ensure_closed(Ch), catch amqp_connection:close(Conn). @@ -486,26 +549,8 @@ end end. -should_forward(undefined, _MaxHops) -> - true; -should_forward(Headers, MaxHops) -> - case rabbit_misc:table_lookup(Headers, ?ROUTING_HEADER) of - undefined -> true; - {array, A} -> length(A) < MaxHops - end. - extract_headers(#amqp_msg{props = #'P_basic'{headers = Headers}}) -> Headers. update_headers(Headers, Msg = #amqp_msg{props = Props}) -> Msg#amqp_msg{props = Props#'P_basic'{headers = Headers}}. - -add_routing_to_headers(undefined, Info) -> - add_routing_to_headers([], Info); -add_routing_to_headers(Headers, Info) -> - Prior = case rabbit_misc:table_lookup(Headers, ?ROUTING_HEADER) of - undefined -> []; - {array, Existing} -> Existing - end, - rabbit_misc:set_table_value( - Headers, ?ROUTING_HEADER, array, [{table, Info} | Prior]). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_link_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup_sup.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_link_sup_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,50 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ Federation. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% + +-module(rabbit_federation_link_sup_sup). + +-behaviour(mirrored_supervisor). + +-include_lib("rabbit_common/include/rabbit.hrl"). +-define(SUPERVISOR, rabbit_federation_link_sup_sup). + +-export([start_link/0, start_child/2, stop_child/1]). + +-export([init/1]). + +%%---------------------------------------------------------------------------- + +start_link() -> + mirrored_supervisor:start_link({local, ?SUPERVISOR}, + ?SUPERVISOR, ?MODULE, []). + +start_child(Id, Args) -> + {ok, Pid} = mirrored_supervisor:start_child( + ?SUPERVISOR, + {Id, {rabbit_federation_link_sup, start_link, [Args]}, + transient, ?MAX_WAIT, supervisor, + [rabbit_federation_link_sup]}), + {ok, Pid}. + +stop_child(Id) -> + ok = mirrored_supervisor:terminate_child(?SUPERVISOR, Id), + ok = mirrored_supervisor:delete_child(?SUPERVISOR, Id), + ok. + +%%---------------------------------------------------------------------------- + +init([]) -> + {ok, {{one_for_one, 3, 10}, []}}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_status.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_status.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_status.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_status.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,91 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ Federation. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% + +-module(rabbit_federation_status). +-behaviour(gen_server). + +-include_lib("amqp_client/include/amqp_client.hrl"). +-include("rabbit_federation.hrl"). + +-export([start_link/0]). + +-export([report/3, remove/1, status/0]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). +-define(ETS_NAME, ?MODULE). + +-record(state, {}). +-record(entry, {key, status, timestamp}). + +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +report(Upstream, XName, Status) -> + gen_server:cast(?SERVER, {report, Upstream, XName, Status, + calendar:local_time()}). + +remove(XName) -> + gen_server:call(?SERVER, {remove, XName}, infinity). + +status() -> + gen_server:call(?SERVER, status, infinity). + +init([]) -> + ?ETS_NAME = ets:new(?ETS_NAME, + [named_table, {keypos, #entry.key}, private]), + {ok, #state{}}. + +handle_call({remove, XName}, _From, State) -> + true = ets:match_delete(?ETS_NAME, #entry{key = {XName, '_'}, + status = '_', + timestamp = '_'}), + {reply, ok, State}; + +handle_call(status, _From, State) -> + Entries = ets:tab2list(?ETS_NAME), + {reply, [format(Entry) || Entry <- Entries], State}. + +handle_cast({report, Upstream, XName, Status, Timestamp}, State) -> + true = ets:insert(?ETS_NAME, #entry{key = {XName, Upstream}, + status = Status, + timestamp = Timestamp}), + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +format(#entry{key = {#resource{virtual_host = VHost, + kind = exchange, + name = XNameBin}, + #upstream{connection_name = Connection, + exchange = UXNameBin}}, + status = Status, + timestamp = Timestamp}) -> + [{exchange, XNameBin}, + {vhost, VHost}, + {connection, list_to_binary(Connection)}, + {upstream_exchange, UXNameBin}, + {status, Status}, + {timestamp, Timestamp}]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,19 +11,19 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_sup). --behaviour(mirrored_supervisor). +-behaviour(supervisor). %% Supervises everything. There is just one of these. --include("rabbit_federation.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). +-define(SUPERVISOR, rabbit_federation_sup). --export([start_link/0, start_child/2, stop_child/1]). +-export([start_link/0]). -export([init/1]). @@ -40,22 +40,15 @@ %%---------------------------------------------------------------------------- start_link() -> - mirrored_supervisor:start_link({local, ?SUPERVISOR}, - ?SUPERVISOR, ?MODULE, []). - -start_child(Id, Args) -> - {ok, Pid} = mirrored_supervisor:start_child( - ?SUPERVISOR, - {Id, {rabbit_federation_link_sup, start_link, [Args]}, - transient, ?MAX_WAIT, supervisor, - [rabbit_federation_link_sup]}), - {ok, Pid}. - -stop_child(Id) -> - ok = mirrored_supervisor:terminate_child(?SUPERVISOR, Id), - ok = mirrored_supervisor:delete_child(?SUPERVISOR, Id), - ok. + supervisor:start_link({local, ?SUPERVISOR}, ?MODULE, []). %%---------------------------------------------------------------------------- -init([]) -> {ok, {{one_for_one, 3, 10},[]}}. +init([]) -> + Status = {status, {rabbit_federation_status, start_link, []}, + transient, ?MAX_WAIT, worker, + [rabbit_federation_status]}, + LinkSupSup = {links, {rabbit_federation_link_sup_sup, start_link, []}, + transient, ?MAX_WAIT, supervisor, + [rabbit_federation_link_sup_sup]}, + {ok, {{one_for_one, 3, 10}, [Status, LinkSupSup]}}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_upstream). @@ -96,11 +96,13 @@ XNameBin = pget_bin(exchange, Upst, DefaultXNameBin), #upstream{params = set_extra_params(Params, Conn), exchange = XNameBin, - prefetch_count = pget(prefetch_count, Conn, none), + prefetch_count = pget(prefetch_count, Conn, + ?DEFAULT_PREFETCH), reconnect_delay = pget(reconnect_delay, Conn, 1), max_hops = pget(max_hops, Upst, 1), expires = pget(expires, Conn, none), message_ttl = pget(message_ttl, Conn, none), + ha_policy = pget(ha_policy, Conn, none), connection_name = ConnName} end. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream_exchange.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream_exchange.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream_exchange.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream_exchange.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,62 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ Federation. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(rabbit_federation_upstream_exchange). + +-rabbit_boot_step({?MODULE, + [{description, "federation upstream exchange type"}, + {mfa, {rabbit_registry, register, + [exchange, <<"x-federation-upstream">>, ?MODULE]}}, + {requires, rabbit_registry}, + {enables, recovery}]}). + +-include_lib("rabbit_common/include/rabbit.hrl"). +-include("rabbit_federation.hrl"). + +-behaviour(rabbit_exchange_type). + +-export([description/0, serialise_events/0, route/2]). +-export([validate/1, create/2, delete/3, + add_binding/3, remove_bindings/3, assert_args_equivalence/2]). + +%%---------------------------------------------------------------------------- + +description() -> + [{name, <<"x-federation-upstream">>}, + {description, <<"Federation upstream helper exchange">>}]. + +serialise_events() -> false. + +route(X = #exchange{arguments = Args}, + D = #delivery{message = #basic_message{content = Content}}) -> + {long, MaxHops} = rabbit_misc:table_lookup(Args, ?MAX_HOPS_ARG), + Headers = rabbit_basic:extract_headers(Content), + case rabbit_federation_util:should_forward(Headers, MaxHops) of + true -> rabbit_exchange_type_fanout:route(X, D); + false -> [] + end. + +validate(#exchange{arguments = Args}) -> + rabbit_federation_util:validate_arg(?MAX_HOPS_ARG, long, Args). + +create(_Tx, _X) -> ok. +delete(_Tx, _X, _Bs) -> ok. +add_binding(_Tx, _X, _B) -> ok. +remove_bindings(_Tx, _X, _Bs) -> ok. +assert_args_equivalence(X = #exchange{name = Name, + arguments = Args}, ReqArgs) -> + rabbit_misc:assert_args_equivalence(Args, ReqArgs, Name, [?MAX_HOPS_ARG]), + rabbit_exchange:assert_args_equivalence(X, Args). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/src/rabbit_federation_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/src/rabbit_federation_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_util). @@ -19,7 +19,8 @@ -include_lib("amqp_client/include/amqp_client.hrl"). -include("rabbit_federation.hrl"). --export([local_params/1, pget_bin/2, pget_bin/3]). +-export([local_params/1, pget_bin/2, pget_bin/3, should_forward/2]). +-export([validate_arg/3, fail/2]). -import(rabbit_misc, [pget_or_die/2, pget/3]). @@ -34,3 +35,20 @@ pget_bin(K, T, D) when is_binary(D) -> pget_bin(K, T, binary_to_list(D)); pget_bin(K, T, D) when is_list(D) -> list_to_binary(pget(K, T, D)). + +should_forward(undefined, _MaxHops) -> + true; +should_forward(Headers, MaxHops) -> + case rabbit_misc:table_lookup(Headers, ?ROUTING_HEADER) of + undefined -> true; + {array, A} -> length(A) < MaxHops + end. + +validate_arg(Name, Type, Args) -> + case rabbit_misc:table_lookup(Args, Name) of + {Type, _} -> ok; + undefined -> fail("Argument ~s missing", [Name]); + _ -> fail("Argument ~s must be of type ~s", [Name, Type]) + end. + +fail(Fmt, Args) -> rabbit_misc:protocol_error(precondition_failed, Fmt, Args). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/test/src/rabbit_federation_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/test/src/rabbit_federation_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/test/src/rabbit_federation_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/test/src/rabbit_federation_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_test). @@ -20,6 +20,8 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). +-import(rabbit_misc, [pget/2]). + -define(UPSTREAM_DOWNSTREAM, [x(<<"upstream">>), fed(<<"downstream">>, <<"upstream">>)]). @@ -193,8 +195,8 @@ ok. suffix({Nodename, _}, X) -> - {_, NodeHost} = rabbit_misc:nodeparts(node()), - Node = rabbit_misc:makenode({Nodename, NodeHost}), + {_, NodeHost} = rabbit_nodes:parts(node()), + Node = rabbit_nodes:make({Nodename, NodeHost}), rpc:call(Node, rabbit_federation_db, get_active_suffix, [rabbit_misc:r(<<"/">>, exchange, <<"downstream">>), #upstream{connection_name = Nodename, @@ -272,12 +274,32 @@ stop_other_node(?COTTONTAIL), ok. +upstream_has_no_federation_test_() -> + {timeout, 60, fun upstream_has_no_federation/0}. + +upstream_has_no_federation() -> + with_ch( + fun (Downstream) -> + Upstream = start_other_node( + ?HARE, "hare-no-federation", "no_plugins"), + declare_exchange(Upstream, x(<<"upstream">>)), + declare_exchange(Downstream, + fed(<<"downstream">>, <<"upstream5673">>)), + Q = bind_queue(Downstream, <<"downstream">>, <<"routing">>), + publish(Upstream, <<"upstream">>, <<"routing">>, <<"HELLO">>), + expect(Downstream, Q, [<<"HELLO">>]), + delete_exchange(Downstream, <<"downstream">>), + delete_exchange(Upstream, <<"upstream">>), + stop_other_node(?HARE) + end, []). + %%---------------------------------------------------------------------------- with_ch(Fun, Xs) -> {ok, Conn} = amqp_connection:start(#amqp_params_network{}), {ok, Ch} = amqp_connection:open_channel(Conn), declare_all(Ch, Xs), + assert_status(Xs), Fun(Ch), delete_all(Ch, Xs), amqp_connection:close(Conn), @@ -291,10 +313,15 @@ start_other_node({Name, Port}, Name). start_other_node({Name, Port}, Config) -> + start_other_node({Name, Port}, Config, + os:getenv("RABBITMQ_ENABLED_PLUGINS_FILE")). + +start_other_node({Name, Port}, Config, PluginsFile) -> %% ?assertCmd seems to hang if you background anything. Bah! Res = os:cmd("make -C " ++ plugin_dir() ++ " OTHER_NODE=" ++ Name ++ " OTHER_PORT=" ++ integer_to_list(Port) ++ " OTHER_CONFIG=" ++ Config ++ + " OTHER_PLUGINS=" ++ PluginsFile ++ " start-other-node ; echo $?"), LastLine = hd(lists:reverse(string:tokens(Res, "\n"))), ?assertEqual("0", LastLine), @@ -364,7 +391,7 @@ publish(Ch, X, Key, Payload) -> %% The trouble is that we transmit bindings upstream asynchronously... - timer:sleep(200), + timer:sleep(1000), amqp_channel:call(Ch, #'basic.publish'{exchange = X, routing_key = Key}, #amqp_msg{payload = Payload}). @@ -421,3 +448,34 @@ type = <<"x-federation">>, arguments = Args}), delete_exchange(Ch, <<"test">>). + +assert_status(Xs) -> + Links = lists:append([links(X) || X <- Xs]), + Remaining = lists:foldl(fun assert_link_status/2, + rabbit_federation_status:status(), Links), + ?assertEqual([], remove_configured_links(Remaining)), + ok. + +assert_link_status({DXNameBin, ConnectionName, UXNameBin}, Status) -> + {[_], Rest} = lists:partition( + fun(St) -> + pget(connection, St) =:= ConnectionName andalso + pget(exchange, St) =:= DXNameBin andalso + pget(upstream_exchange, St) =:= UXNameBin + end, Status), + Rest. + +links(#'exchange.declare'{exchange = Name, + type = <<"x-federation">>, + arguments = Args}) -> + {longstr, Set} = rabbit_misc:table_lookup(Args, <<"upstream-set">>), + {ok, Upstreams} = rabbit_federation_upstream:from_set( + Set, rabbit_misc:r(<<"/">>, exchange, Name)), + [{Name, list_to_binary(U#upstream.connection_name), U#upstream.exchange} || + U <- Upstreams]; + +links(#'exchange.declare'{}) -> + []. + +remove_configured_links(Status) -> + [St || St <- Status, pget(exchange, St) =/= <<"down-conf">>]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/test/src/rabbit_federation_unit_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/test/src/rabbit_federation_unit_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation/test/src/rabbit_federation_unit_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation/test/src/rabbit_federation_unit_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,14 +11,11 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_federation_unit_test). --define(INFO, [{<<"baz">>, longstr, <<"bam">>}]). --define(H, <<"x-received-from">>). - -define(US_NAME, <<"upstream">>). -define(DS_NAME, <<"downstream">>). @@ -26,26 +23,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). -%% Test that we add routing information to message headers sensibly. -routing_test() -> - ?assertEqual([{?H, array, [{table, ?INFO}]}], - add(undefined)), - - ?assertEqual([{?H, array, [{table, ?INFO}]}], - add([])), - - ?assertEqual([{<<"foo">>, longstr, <<"bar">>}, - {?H, array, [{table, ?INFO}]}], - add([{<<"foo">>, longstr, <<"bar">>}])), - - ?assertEqual([{?H, array, [{table, ?INFO}, - {table, ?INFO}]}], - add([{?H, array, [{table, ?INFO}]}])), - ok. - -add(Table) -> - rabbit_federation_link:add_routing_to_headers(Table, ?INFO). - %% Test that we apply binding changes in the correct order even when %% they arrive out of order. serialisation_test() -> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/Makefile rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/Makefile --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1 @@ +include ../umbrella.mk diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/package.mk rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/package.mk --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/package.mk 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,7 @@ +RELEASABLE:=true +DEPS:=rabbitmq-management + +CONSTRUCT_APP_PREREQS:=$(shell find $(PACKAGE_DIR)/priv -type f) +define construct_app_commands + cp -r $(PACKAGE_DIR)/priv $(APP_DIR) +endef diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,11 @@ +dispatcher_add(function(sammy) { + sammy.get('#/federation-links', function() { + render({'links': '/federation-links'}, + 'federation-links', '#/federation-links'); + }); +}); + +$("#tabs").append('
  • Federation
  • '); + +VHOST_QUERIES["/federation-links"] = ""; +SORT_QUERIES["/federation-links"] = ""; diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/priv/www/js/tmpl/federation-links.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/priv/www/js/tmpl/federation-links.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/priv/www/js/tmpl/federation-links.ejs 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/priv/www/js/tmpl/federation-links.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,64 @@ +

    Federation links

    +
    +<% if (links.length > 0) { %> + + + + +<% if (vhosts_interesting) { %> + +<% } %> + +<% if (nodes_interesting) { %> + +<% } %> + + + + + + +<% + for (var i = 0; i < links.length; i++) { + var link = links[i]; +%> + > + +<% if (vhosts_interesting) { %> + +<% } %> + +<% if (nodes_interesting) { %> + +<% } %> +<% if (link.error) { %> + + + + +<% } else { %> + + + + +<% } %> + <% } %> + +
    ConnectionVirtual HostExchangeNodeStateInbound message rateLast changed
    + <%= fmt_string(link.connection) %> + <% if (link.exchange != link.upstream_exchange) { %> + <%= fmt_string(link.upstream_exchange) %> + <% } %> + <%= fmt_string(link.vhost) %><%= link_exchange(link.vhost, link.exchange) %><%= fmt_string(link.node) %> +
    <%= link.status %>
    +
    <%= link.timestamp %>
    +
    <%= link.status %>
    +
    + <% if (link.local_channel) { %> + <%= fmt_rate(link.local_channel.message_stats, 'confirm') %> + <% } %> + <%= link.timestamp %>
    +<% } else { %> +

    ... no links ...

    +<% } %> +
    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/README 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/README 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,8 @@ +Adds information on federation link status to the management +plugin. Build it like any other plugin. + +If you have a heterogenous cluster (where the nodes have different +plugins installed), this should be installed on the same nodes as the +management plugin. + +The HTTP API is very simple: GET /api/federation-links. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/src/rabbit_federation_mgmt.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/src/rabbit_federation_mgmt.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/src/rabbit_federation_mgmt.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/src/rabbit_federation_mgmt.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,100 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% + +-module(rabbit_federation_mgmt). + +-behaviour(rabbit_mgmt_extension). + +-export([dispatcher/0, web_ui/0]). +-export([init/1, to_json/2, resource_exists/2, content_types_provided/2, + is_authorized/2]). + +-import(rabbit_misc, [pget/2]). + +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). + +dispatcher() -> [{["federation-links"], ?MODULE, []}, + {["federation-links", vhost], ?MODULE, []}]. +web_ui() -> [{javascript, <<"federation.js">>}]. + +%%-------------------------------------------------------------------- + +init(_Config) -> {ok, #context{}}. + +content_types_provided(ReqData, Context) -> + {[{"application/json", to_json}], ReqData, Context}. + +resource_exists(ReqData, Context) -> + {case rabbit_mgmt_util:vhost(ReqData) of + not_found -> false; + _ -> true + end, ReqData, Context}. + +to_json(ReqData, Context) -> + rabbit_mgmt_util:reply_list( + filter_vhost(status(), ReqData), ReqData, Context). + +is_authorized(ReqData, Context) -> + rabbit_mgmt_util:is_authorized_monitor(ReqData, Context). + +%%-------------------------------------------------------------------- + +filter_vhost(List, ReqData) -> + rabbit_mgmt_util:all_or_one_vhost( + ReqData, + fun(V) -> lists:filter(fun(I) -> pget(vhost, I) =:= V end, List) end). + +status() -> + lists:append([status(Node) || Node <- [node() | nodes()]]). + +status(Node) -> + case rpc:call(Node, rabbit_federation_status, status, [], infinity) of + {badrpc, {'EXIT', {undef, _}}} -> []; + {badrpc, {'EXIT', {noproc, _}}} -> []; + Status -> [format(Node, I) || I <- Status] + end. + +format(Node, Info0) -> + Info1 = proplists:delete(status, Info0), + Info = case pget(status, Info0) of + {running, Name} -> [{status, running}, + {local_connection, Name} | Info1]; + {Status, E} -> Fmted = rabbit_mgmt_format:print("~p", [E]), + [{status, Status}, + {error, Fmted} | Info1]; + S when is_atom(S) -> [{status, S} | Info1] + end, + LocalCh = case rabbit_mgmt_format:strip_pids( + [Ch || Ch <- rabbit_mgmt_db:get_all_channels(basic), + pget(name, pget(connection_details, Ch)) + =:= pget(local_connection, Info)]) of + [Ch] -> [{local_channel, Ch}]; + [] -> [] + end, + [{node, Node} | format_info(Info)] ++ LocalCh. + +format_info(Items) -> + [format_item(I) || I <- Items]. + +format_item({timestamp, {{Y, M, D}, {H, Min, S}}}) -> + {timestamp, print("~w-~2.2.0w-~2.2.0w ~w:~2.2.0w:~2.2.0w", + [Y, M, D, H, Min, S])}; +format_item(I) -> + I. + +print(Fmt, Val) -> + list_to_binary(io_lib:format(Fmt, Val)). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/src/rabbitmq_federation_management.app.src rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/src/rabbitmq_federation_management.app.src --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-federation-management/src/rabbitmq_federation_management.app.src 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-federation-management/src/rabbitmq_federation_management.app.src 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,8 @@ +{application, rabbitmq_federation_management, + [{description, "RabbitMQ Federation Management"}, + {vsn, "%%VSN%%"}, + {modules, []}, + {registered, []}, + {env, []}, + {applications, [kernel, stdlib, rabbitmq_management]} + ]}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc/src/rabbit_jsonrpc.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc/src/rabbit_jsonrpc.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc/src/rabbit_jsonrpc.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc/src/rabbit_jsonrpc.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_jsonrpc). -behaviour(application). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/jsonrpc.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/jsonrpc.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/jsonrpc.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/jsonrpc.js 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://www.mozilla.org/MPL/ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License +// at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -// License for the specific language governing rights and limitations -// under the License. +// The Original Code is RabbitMQ. // -// The Original Code is RabbitMQ. -// -// The Initial Developers of the Original Code are LShift Ltd, -// Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -// Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -// are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -// Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -// Ltd. Portions created by Cohesive Financial Technologies LLC are -// Copyright (C) 2007-2009 Cohesive Financial Technologies -// LLC. Portions created by Rabbit Technologies Ltd are Copyright -// (C) 2007-2009 Rabbit Technologies Ltd. -// -// All Rights Reserved. -// -// Contributor(s): ______________________________________. +// The Initial Developer of the Original Code is VMware, Inc. +// Copyright (c) 2007-2012 VMware, Inc. All rights reserved. // function JsonRpc_ModuleFactory(Support) { diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-jquery.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-jquery.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-jquery.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-jquery.js 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://www.mozilla.org/MPL/ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License +// at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -// License for the specific language governing rights and limitations -// under the License. -// -// The Original Code is RabbitMQ. -// -// The Initial Developers of the Original Code are LShift Ltd, -// Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -// Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -// are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -// Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -// Ltd. Portions created by Cohesive Financial Technologies LLC are -// Copyright (C) 2007-2009 Cohesive Financial Technologies -// LLC. Portions created by Rabbit Technologies Ltd are Copyright -// (C) 2007-2009 Rabbit Technologies Ltd. -// -// All Rights Reserved. -// -// Contributor(s): ______________________________________. +// The Original Code is RabbitMQ. // +// The Initial Developer of the Original Code is VMware, Inc. +// Copyright (c) 2007-2012 VMware, Inc. All rights reserved. // var JsonRpc; diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq.js 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://www.mozilla.org/MPL/ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License +// at http://www.mozilla.org/MPL/ // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -// License for the specific language governing rights and limitations -// under the License. +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. // -// The Original Code is RabbitMQ. -// -// The Initial Developers of the Original Code are LShift Ltd, -// Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -// Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -// are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -// Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -// Ltd. Portions created by Cohesive Financial Technologies LLC are -// Copyright (C) 2007-2009 Cohesive Financial Technologies -// LLC. Portions created by Rabbit Technologies Ltd are Copyright -// (C) 2007-2009 Rabbit Technologies Ltd. -// -// All Rights Reserved. -// -// Contributor(s): ______________________________________. +// The Original Code is RabbitMQ. // +// The Initial Developer of the Original Code is VMware, Inc. +// Copyright (c) 2007-2012 VMware, Inc. All rights reserved. // function RabbitMQ_ModuleFactory(JsonRpc, Support) { diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-prototype.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-prototype.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-prototype.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/priv/www/rabbitmq-prototype.js 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://www.mozilla.org/MPL/ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License +// at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -// License for the specific language governing rights and limitations -// under the License. -// -// The Original Code is RabbitMQ. -// -// The Initial Developers of the Original Code are LShift Ltd, -// Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -// Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -// are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -// Technologies LLC, and Rabbit Technologies Ltd. -// -// Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -// Ltd. Portions created by Cohesive Financial Technologies LLC are -// Copyright (C) 2007-2009 Cohesive Financial Technologies -// LLC. Portions created by Rabbit Technologies Ltd are Copyright -// (C) 2007-2009 Rabbit Technologies Ltd. -// -// All Rights Reserved. -// -// Contributor(s): ______________________________________. +// The Original Code is RabbitMQ. // +// The Initial Developer of the Original Code is VMware, Inc. +// Copyright (c) 2007-2012 VMware, Inc. All rights reserved. // var JsonRpc; diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/README 2012-06-22 16:03:48.000000000 +0000 @@ -3,6 +3,12 @@ rabbitmq-plugins enable rabbitmq_jsonrpc_channel +You may wish to also use: + + rabbitmq-plugins enable rabbitmq_jsonrpc_channel_examples + +to serve a couple of demo webapps. + You can also compile and install it like any other plugin (see http://www.rabbitmq.com/plugin-development.html). @@ -14,11 +20,11 @@ Once the server starts successfully, you should be able to point your web browser at - http://localhost:55672/rpc/rabbitmq + http://localhost:55670/rpc/rabbitmq and get an error along the lines of - {"version":"1.1","id":null,"error":{"name":"JSONRPCError","code":404,"message":"Procedure not found","error":["http://localhost:55672/rpc/rabbitmq",""]}} + {"version":"1.1","id":null,"error":{"name":"JSONRPCError","code":404,"message":"Procedure not found","error":["http://localhost:55670/rpc/rabbitmq",""]}} which confirms that the RabbitMQ JSON-RPC channel is ready to accept requests. @@ -30,10 +36,10 @@ with the examples configured. You should be able to point your web browser at - http://localhost:55672/ + http://localhost:55670/ and get a webpage. Clicking on "Simple JSONRPC test" will run a small -test application. Successful output of http://localhost:55672/test/index.html +test application. Successful output of http://localhost:55670/test/index.html at the time of writing is: test_main diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_jsonrpc_channel_app). -behaviour(application). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_app_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_jsonrpc_channel_app_sup). -behaviour(supervisor). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% The Original Code is RabbitMQ. +%% The Original Code is RabbitMQ. %% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_jsonrpc_channel). -behaviour(gen_server). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_factory.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_factory.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_factory.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_factory.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_jsonrpc_channel_factory). -behaviour(gen_server). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel/src/rabbit_jsonrpc_channel_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_jsonrpc_channel_sup). -behaviour(supervisor). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel-examples/src/rabbit_jsonrpc_channel_test_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel-examples/src/rabbit_jsonrpc_channel_test_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-jsonrpc-channel-examples/src/rabbit_jsonrpc_channel_test_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-jsonrpc-channel-examples/src/rabbit_jsonrpc_channel_test_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_jsonrpc_channel_test_app). -behaviour(application). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/bin/rabbitmqadmin rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/bin/rabbitmqadmin --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/bin/rabbitmqadmin 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/bin/rabbitmqadmin 2012-06-22 16:03:48.000000000 +0000 @@ -13,9 +13,11 @@ # The Original Code is RabbitMQ Management Plugin. # # The Initial Developer of the Original Code is VMware, Inc. -# Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +# Copyright (c) 2010-2012 VMware, Inc. All rights reserved. -from optparse import OptionParser +from ConfigParser import ConfigParser +from ConfigParser import Error as ConfigParserError +from optparse import OptionParser, TitledHelpFormatter import sys import httplib import urllib @@ -24,10 +26,11 @@ import os import socket -LISTABLE = ['connections', 'channels', 'exchanges', 'queues', 'bindings', - 'users', 'vhosts', 'permissions', 'nodes'] +LISTABLE = {'connections': False, 'channels': False, 'exchanges': True, + 'queues': True, 'bindings': True, 'users': False, + 'vhosts': False, 'permissions': False, 'nodes': False} -SHOWABLE = ['overview'] +SHOWABLE = {'overview': False} PROMOTE_COLUMNS = ['vhost', 'name', 'type', 'source', 'destination', 'destination_type', 'routing_key'] @@ -47,7 +50,8 @@ 'optional': {'auto_delete': 'false', 'durable': 'true', 'internal': 'false'}}, 'queue': {'mandatory': ['name'], - 'optional': {'auto_delete': 'false', 'durable': 'true'}}, + 'optional': {'auto_delete': 'false', 'durable': 'true', + 'node': None}}, 'binding': {'mandatory': ['source', 'destination_type', 'destination', 'routing_key'], 'optional': {}}, @@ -89,7 +93,7 @@ 'uri': '/exchanges/{vhost}/{exchange}/publish'}, 'get': {'mandatory': ['queue'], 'optional': {'count': '1', 'requeue': 'true', - 'payload_file': None}, + 'payload_file': None, 'encoding': 'auto'}, 'uri': '/queues/{vhost}/{queue}/get'} } @@ -101,32 +105,89 @@ DELETABLE[k]['optional'] = {} DELETABLE['binding']['uri'] = URIS['binding_del'] -def make_usage(): - usage = """usage: %prog [options] cmd -where cmd is one of: +def short_usage(): + return "rabbitmqadmin [options] subcommand" + +def title(name): + return "\n%s\n%s\n\n" % (name, '=' * len(name)) + +def subcommands_usage(): + usage = """Usage +===== + """ + short_usage() + """ + + where subcommand is one of: +""" + title("Display") -""" for l in LISTABLE: usage += " list {0} [...]\n".format(l) for s in SHOWABLE: usage += " show {0} [...]\n".format(s) + usage += title("Object Manipulation") usage += fmt_usage_stanza(DECLARABLE, 'declare') usage += fmt_usage_stanza(DELETABLE, 'delete') usage += fmt_usage_stanza(CLOSABLE, 'close') usage += fmt_usage_stanza(PURGABLE, 'purge') + usage += title("Broker Definitions") + usage += """ export + import +""" + usage += title("Publishing and Consuming") usage += fmt_usage_stanza(EXTRA_VERBS, '') usage += """ - export - import - * If payload is not specified on publish, standard input is used * If payload_file is not specified on get, the payload will be shown on standard output along with the message metadata - * If payload_file is specified on get, count must not be set""" + * If payload_file is specified on get, count must not be set +""" + return usage + +def config_usage(): + usage = "Usage\n=====\n" + short_usage() + usage += "\n" + title("Configuration File") + usage += """ It is possible to specify a configuration file from the command line. + Hosts can be configured easily in a configuration file and called + from the command line. +""" + usage += title("Example") + usage += """ # rabbitmqadmin.conf.example START + + [host_normal] + hostname = localhost + port = 55672 + username = guest + password = guest + declare_vhost = / # Used as default for declare / delete only + vhost = / # Used as default for declare / delete / list + + [host_ssl] + hostname = otherhost + port = 55672 + username = guest + password = guest + ssl = True + ssl_key_file = /path/to/key.pem + ssl_cert_file = /path/to/cert.pem + + # rabbitmqadmin.conf.example END +""" + usage += title("Use") + usage += """ rabbitmqadmin -c rabbitmqadmin.conf.example -N host_normal ...""" return usage +def more_help(): + return """ +More Help +========= + +For more help use the help subcommand: + + rabbitmqadmin help subcommands # For a list of available subcommands + rabbitmqadmin help config # For help with the configuration file +""" + def fmt_usage_stanza(root, verb): def fmt_args(args): res = " ".join(["{0}=...".format(a) for a in args['mandatory']]) @@ -135,46 +196,108 @@ res += " [{0}]".format(opts) return res - text = "\n" + text = "" if verb != "": verb = " " + verb for k in root.keys(): text += " {0} {1} {2}\n".format(verb, k, fmt_args(root[k])) return text -parser = OptionParser(usage=make_usage()) +default_options = { "hostname" : "localhost", + "port" : "55672", + "declare_vhost" : "/", + "username" : "guest", + "password" : "guest", + "ssl" : False, + "verbose" : True, + "format" : "table", + "depth" : 1, + "bash_completion" : False } + + +class MyFormatter(TitledHelpFormatter): + def format_epilog(self, epilog): + return epilog + +parser = OptionParser(usage=short_usage(), + formatter=MyFormatter(), + epilog=more_help()) def make_parser(): - parser.add_option("-H", "--host", dest="hostname", default="localhost", - help="connect to host HOST [default: %default]", - metavar="HOST") - parser.add_option("-P", "--port", dest="port", default="55672", - help="connect to port PORT [default: %default]", - metavar="PORT") - parser.add_option("-V", "--vhost", dest="vhost", - help="connect to vhost VHOST [default: all vhosts for list, '/' for declare]", - metavar="VHOST") - parser.add_option("-u", "--username", dest="username", default="guest", - help="connect using username USERNAME [default: %default]", - metavar="USERNAME") - parser.add_option("-p", "--password", dest="password", default="guest", - help="connect using password PASSWORD [default: %default]", - metavar="PASSWORD") - parser.add_option("-q", "--quiet", action="store_false", dest="verbose", - default=True, help="suppress status messages") - parser.add_option("-s", "--ssl", action="store_true", dest="ssl", - default=False, help="connect with ssl") - parser.add_option("--ssl-key-file", dest="ssl_key_file", default=None, - help="PEM format key file for SSL [default: none]") - parser.add_option("--ssl-cert-file", dest="ssl_cert_file", default=None, - help="PEM format certificate file for SSL [default: none]") - parser.add_option("-f", "--format", dest="format", default="table", - help="format for listing commands - one of [" + ", ".join(FORMATS.keys()) + "] [default: %default]") - parser.add_option("-d", "--depth", dest="depth", default="1", - help="maximum depth to recurse for listing tables [default: %default]") - parser.add_option("--bash-completion", action="store_true", - dest="bash_completion", default=False, - help="Print bash completion script") + def add(*args, **kwargs): + key = kwargs['dest'] + if key in default_options: + default = " [default: %s]" % default_options[key] + kwargs['help'] = kwargs['help'] + default + parser.add_option(*args, **kwargs) + + add("-c", "--config", dest="config", + help="configuration file [default: ~/.rabbitmqadmin.conf]", + metavar="CONFIG") + add("-N", "--node", dest="node", + help="node described in the configuration file [default: 'default'" + \ + " only if configuration file is specified]", + metavar="NODE") + add("-H", "--host", dest="hostname", + help="connect to host HOST" , + metavar="HOST") + add("-P", "--port", dest="port", + help="connect to port PORT", + metavar="PORT") + add("-V", "--vhost", dest="vhost", + help="connect to vhost VHOST [default: all vhosts for list, '/' for declare]", + metavar="VHOST") + add("-u", "--username", dest="username", + help="connect using username USERNAME", + metavar="USERNAME") + add("-p", "--password", dest="password", + help="connect using password PASSWORD", + metavar="PASSWORD") + add("-q", "--quiet", action="store_false", dest="verbose", + help="suppress status messages") + add("-s", "--ssl", action="store_true", dest="ssl", + help="connect with ssl") + add("--ssl-key-file", dest="ssl_key_file", + help="PEM format key file for SSL") + add("--ssl-cert-file", dest="ssl_cert_file", + help="PEM format certificate file for SSL") + add("-f", "--format", dest="format", + help="format for listing commands - one of [" + ", ".join(FORMATS.keys()) + "]") + add("-d", "--depth", dest="depth", + help="maximum depth to recurse for listing tables") + add("--bash-completion", action="store_true", + dest="bash_completion", + help="Print bash completion script") + +def make_configuration(): + make_parser() + (options, args) = parser.parse_args() + setattr(options, "declare_vhost", None) + if options.node is None and options.config: + options.node = "default" + elif options.node and options.config is None: + home = os.getenv('USERPROFILE') or os.getenv('HOME') + setattr(options, "config", home + os.sep + ".rabbitmqadmin.conf") + if options.node: + config = ConfigParser() + try: + config.read(options.config) + new_conf = dict(config.items(options.node)) + except ConfigParserError as error: + assert_usage(False, ("Could not read section '%s' in config file" + + " '%s':\n %s") % + (options.node, options.config, error)) + new_opts = default_options.copy() + for (key, val) in new_conf.items(): + new_opts[key] = val + for (key, val) in new_opts.items(): + if getattr(options, key) is None: + setattr(options, key, val) + else: + for (key, val) in default_options.items(): + if getattr(options, key) is None: + setattr(options, key, val) + return (options, args) def assert_usage(expr, error): if not expr: @@ -189,8 +312,7 @@ return (2, col) def main(): - make_parser() - (options, args) = parser.parse_args() + (options, args) = make_configuration() if options.bash_completion: print_bash_completion() exit(0) @@ -206,7 +328,7 @@ print maybe_utf8(s, sys.stdout) def die(s): - sys.stderr.write(maybe_utf8("*** {0}".format(s), sys.stderr)) + sys.stderr.write(maybe_utf8("*** {0}\n".format(s), sys.stderr)) exit(1) def maybe_utf8(s, stream): @@ -272,10 +394,23 @@ assert_usage(len(self.args) == 1, 'Exactly one argument required') return self.args[0] + def invoke_help(self): + help_cmd = self.get_arg() + if help_cmd == 'subcommands': + usage = subcommands_usage() + elif help_cmd == 'config': + usage = config_usage() + else: + assert_usage(False, """help topic must be one of: + subcommands + config""") + print usage + exit(0) + def invoke_publish(self): (uri, upload) = self.parse_args(self.args, EXTRA_VERBS['publish']) upload['properties'] = {} # TODO do we care here? - if not upload['payload']: + if not 'payload' in upload: data = sys.stdin.read() upload['payload'] = base64.b64encode(data) upload['payload_encoding'] = 'base64' @@ -287,7 +422,7 @@ def invoke_get(self): (uri, upload) = self.parse_args(self.args, EXTRA_VERBS['get']) - payload_file = upload['payload_file'] + payload_file = 'payload_file' in upload and upload['payload_file'] or None assert_usage(not payload_file or upload['count'] == '1', 'Cannot get multiple messages using payload_file') result = self.post(uri, json.dumps(upload)) @@ -329,8 +464,9 @@ obj_type = self.args[0] assert_usage(obj_type in obj_types, "Don't know how to {0} {1}".format(verb, obj_type)) + vhostable = obj_types[obj_type] uri = "/%s" % obj_type - if self.options.vhost: + if vhostable and self.options.vhost: uri += "/%s" % urllib.quote_plus(self.options.vhost) if cols != []: uri += "?columns=" + ",".join(cols) @@ -374,7 +510,8 @@ uri_template = obj['uri'] upload = {} for k in optional.keys(): - upload[k] = optional[k] + if optional[k]: + upload[k] = optional[k] for arg in args: assert_usage("=" in arg, 'Argument "{0}" not in format name=value'.format(arg)) @@ -386,7 +523,8 @@ assert_usage(m in upload.keys(), 'mandatory argument "{0}" required'.format(m)) upload['arguments'] = {} - upload['vhost'] = self.options.vhost or '/' + if 'vhost' not in mandatory: + upload['vhost'] = self.options.vhost or self.options.declare_vhost uri_args = {} for k in upload: v = upload[k] @@ -438,15 +576,22 @@ def add(prefix, depth, item, fun): for key in item: column = prefix == '' and key or (prefix + '.' + key) - if type(item[key]) == dict: + subitem = item[key] + if type(subitem) == dict: if depth < max_depth: - add(column, depth + 1, item[key], fun) - elif type(item[key]) == list: - # TODO - ATM this is only applications inside nodes. Not - # sure how to handle this sensibly. - pass + add(column, depth + 1, subitem, fun) + elif type(subitem) == list: + # The first branch has slave nodes in queues in + # mind (which come out looking decent); the second + # one has applications in nodes (which look less + # so, but what would look good?). + if [x for x in subitem if type(x) != unicode] == []: + serialised = " ".join(subitem) + else: + serialised = json.dumps(subitem) + fun(column, serialised) else: - fun(column, item[key]) + fun(column, subitem) def add_to_columns(col, val): columns[col] = True @@ -478,15 +623,11 @@ self.options = options def display_list(self, columns, table): - head = "" - for col in columns: - head += col + "\t" + head = "\t".join(columns) self.verbose(head) for row in table: - line = "" - for cell in row: - line += cell + "\t" + line = "\t".join(row) output(line) class LongList(Lister): @@ -603,7 +744,7 @@ cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="list show declare delete close purge import export get publish" + opts="list show declare delete close purge import export get publish help" fargs="--help --host --port --vhost --username --password --format --depth" case "${prev}" in @@ -639,6 +780,11 @@ COMPREPLY=( $(compgen -f ${cur}) ) return 0 ;; + help) + opts="subcommands config" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; -@(H|-host)) COMPREPLY=( $(compgen -A hostname ${cur}) ) return 0 diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/etc/bunny.config rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/etc/bunny.config --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/etc/bunny.config 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/etc/bunny.config 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1 @@ +[{rabbitmq_mochiweb, [{listeners,[{mgmt, [{port, 55674}]}]}]}]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/include/rabbit_mgmt.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/include/rabbit_mgmt.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/include/rabbit_mgmt.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/include/rabbit_mgmt.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -record(context, {user}). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/LICENSE-MPL-RabbitMQ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/LICENSE-MPL-RabbitMQ --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/LICENSE-MPL-RabbitMQ 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/LICENSE-MPL-RabbitMQ 2012-06-22 16:03:48.000000000 +0000 @@ -447,7 +447,7 @@ The Original Code is RabbitMQ Management Plugin. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2010-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2010-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/Makefile rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/Makefile --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/Makefile 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/Makefile 2012-06-22 16:03:48.000000000 +0000 @@ -2,24 +2,27 @@ RABBITMQCTL=../rabbitmq-server/scripts/rabbitmqctl TEST_TMPDIR=/tmp/rabbitmq-test +OTHER_NODE=undefined +OTHER_PORT=undefined - -start-second-node: - rm -f $(TEST_TMPDIR)/rabbitmq-hare-pid - RABBITMQ_MNESIA_BASE=$(TEST_TMPDIR)/rabbitmq-hare-mnesia \ - RABBITMQ_PID_FILE=$(TEST_TMPDIR)/rabbitmq-hare-pid \ +start-other-node: + rm -f $(TEST_TMPDIR)/rabbitmq-$(OTHER_NODE)-pid + RABBITMQ_MNESIA_BASE=$(TEST_TMPDIR)/rabbitmq-$(OTHER_NODE)-mnesia \ + RABBITMQ_PID_FILE=$(TEST_TMPDIR)/rabbitmq-$(OTHER_NODE)-pid \ RABBITMQ_LOG_BASE=$(TEST_TMPDIR)/log \ - RABBITMQ_NODENAME=hare \ - RABBITMQ_NODE_PORT=5673 \ - RABBITMQ_CONFIG_FILE=etc/hare \ + RABBITMQ_NODENAME=$(OTHER_NODE) \ + RABBITMQ_NODE_PORT=$(OTHER_PORT) \ + RABBITMQ_CONFIG_FILE=etc/$(OTHER_NODE) \ RABBITMQ_PLUGINS_DIR=$(TEST_TMPDIR)/plugins \ - RABBITMQ_PLUGINS_EXPAND_DIR=$(TEST_TMPDIR)/hare-plugins-expand \ - ../rabbitmq-server/scripts/rabbitmq-server & - $(RABBITMQCTL) -n hare wait $(TEST_TMPDIR)/rabbitmq-hare-pid - $(RABBITMQCTL) -n hare stop_app - $(RABBITMQCTL) -n hare reset - $(RABBITMQCTL) -n hare cluster rabbit-test@`hostname -s` - $(RABBITMQCTL) -n hare start_app + RABBITMQ_PLUGINS_EXPAND_DIR=$(TEST_TMPDIR)/$(OTHER_NODE)-plugins-expand \ + ../rabbitmq-server/scripts/rabbitmq-server >/tmp/$(OTHER_NODE).out 2>/tmp/$(OTHER_NODE).err & + $(RABBITMQCTL) -n $(OTHER_NODE) wait $(TEST_TMPDIR)/rabbitmq-$(OTHER_NODE)-pid + +cluster-other-node: + $(RABBITMQCTL) -n $(OTHER_NODE) stop_app + $(RABBITMQCTL) -n $(OTHER_NODE) reset + $(RABBITMQCTL) -n $(OTHER_NODE) cluster rabbit-test@`hostname -s` + $(RABBITMQCTL) -n $(OTHER_NODE) start_app -stop-second-node: - $(RABBITMQCTL) -n hare stop \ No newline at end of file +stop-other-node: + $(RABBITMQCTL) -n $(OTHER_NODE) stop \ No newline at end of file diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/package.mk rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/package.mk --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -2,6 +2,7 @@ DEPS:=rabbitmq-mochiweb webmachine-wrapper rabbitmq-server rabbitmq-erlang-client rabbitmq-management-agent WITH_BROKER_TEST_COMMANDS:=rabbit_mgmt_test_all:all_tests() WITH_BROKER_TEST_CONFIG:=$(PACKAGE_DIR)/etc/rabbit-test +WITH_BROKER_TEST_SCRIPTS:=$(PACKAGE_DIR)/test/src/rabbitmqadmin-test.py CONSTRUCT_APP_PREREQS:=$(shell find $(PACKAGE_DIR)/priv -type f) $(PACKAGE_DIR)/bin/rabbitmqadmin define construct_app_commands diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/api/index.html rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/api/index.html --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/api/index.html 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/api/index.html 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ table { border-collapse: collapse; } table th, table td { vertical-align: top; border: 1px solid #bbb; padding: 5px; } code { background: #ffa; } - pre { background: black; color: #0f0; padding: 10px; } + pre { background: black; color: #0f0; padding: 10px; word-wrap: break-word;} table pre { background: #ffa; color: black; } @@ -49,6 +49,10 @@ nested component of the listed items; it does not allow you to sort by more than one field. See the example below.

    +

    You can also restrict what information is returned per item + with the columns parameter. This is a comma-separated + list of subfields separated by dots. See the example below.

    +

    Examples

    A few quick examples, using the Unix command line @@ -67,8 +71,9 @@ [{"name":"/"}]

  • - Get a list of channels, fast publishers first: -
    $ curl -i -u guest:guest 'http://localhost:55672/api/channels?sort=message_stats.publish_details.rate&sort_reverse=true'
    +        Get a list of channels, fast publishers first, restricting the info
    +        items we get back:
    +
    $ curl -i -u guest:guest 'http://localhost:55672/api/channels?sort=message_stats.publish_details.rate&sort_reverse=true&columns=name,message_stats.publish_details.rate,message_stats.deliver_get_details.rate'
     HTTP/1.1 200 OK
     Server: MochiWeb/1.1 WebMachine/1.7 (participate in the frantic)
     Date: Tue, 12 Oct 2010 10:03:21 GMT
    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/css/main.css rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/css/main.css
    --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/css/main.css	2011-12-16 12:24:15.000000000 +0000
    +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/css/main.css	2012-06-22 16:03:48.000000000 +0000
    @@ -33,6 +33,7 @@
     table.list th, table.list td { border-left: 1px solid #ccc; border-right: 1px solid #ccc; }
     table.list th { text-align: center; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; }
     table.list td a { display: block; width: 100%; }
    +table.list td.status a { display: inline; }
     table.list th a.sort { display: block; width: 100%; cursor: pointer; }
     table.list th a.sort .arrow { color: #888; }
     table.list td p { margin: 0; padding: 1px 0 0 0; }
    @@ -145,6 +146,8 @@
     
     acronym.warning { background: #daa; }
     
    +.status acronym, small acronym { background: none; color: inherit; padding: 0; border-bottom: 1px dotted; cursor: default; }
    +
     table.bindings { margin-bottom: 1em; }
     td.binding-endpoint span.object { border: 1px solid #bbb; padding: 10px; border-radius: 10px; -moz-border-radius: 10px; }
     td.binding-endpoint span.arrow { font-size: 200%; }
    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/dispatcher.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/dispatcher.js
    --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/dispatcher.js	2011-12-16 12:24:15.000000000 +0000
    +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/dispatcher.js	2012-06-22 16:03:48.000000000 +0000
    @@ -127,11 +127,16 @@
                         'vhosts': '/vhosts/'}, 'user',
                        '#/users');
             });
    -    sammy.put('#/users', function() {
    +    sammy.put('#/users-add', function() {
                 if (sync_put(this, '/users/:username'))
                     update();
                 return false;
             });
    +    sammy.put('#/users-modify', function() {
    +            if (sync_put(this, '/users/:username'))
    +                go_to('#/users');
    +            return false;
    +        });
         sammy.del('#/users', function() {
                 if (sync_delete(this, '/users/:username'))
                     go_to('#/users');
    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/formatters.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/formatters.js
    --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/formatters.js	2011-12-16 12:24:15.000000000 +0000
    +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/formatters.js	2012-06-22 16:03:48.000000000 +0000
    @@ -11,11 +11,6 @@
         return fmt_escape_html("" + str);
     }
     
    -function fmt_num(num) {
    -    if (num == undefined) return UNKNOWN_REPR;
    -    return num.toFixed(0);
    -}
    -
     function fmt_bytes(bytes) {
         if (bytes == undefined) return UNKNOWN_REPR;
     
    @@ -27,7 +22,7 @@
         var num_power = f(bytes, 0);
         var num = num_power[0];
         var power = num_power[1];
    -    var powers = ['B', 'kB', 'MB', 'GB', 'TB'];
    +    var powers = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
         return (power == 0 ? num.toFixed(0) : num.toFixed(1)) + powers[power];
     }
     
    @@ -43,7 +38,7 @@
         }
     
         return d.getFullYear() + "-" + f(d.getMonth() + 1) + "-" +
    -        f(d.getDay() + 1) + " " + f(d.getHours()) + ":" + f(d.getMinutes()) +
    +        f(d.getDate()) + " " + f(d.getHours()) + ":" + f(d.getMinutes()) +
             ":" + f(d.getSeconds());
     }
     
    @@ -141,7 +136,7 @@
     }
     
     function fmt_rate(obj, name, show_total, cssClass) {
    -    var res = fmt_rate0(obj, name, fmt_num, show_total);
    +    var res = fmt_rate0(obj, name, fmt_rate_num, show_total);
         if (cssClass == undefined || res == '') {
             return res;
         }
    @@ -150,6 +145,13 @@
         }
     }
     
    +function fmt_rate_num(num) {
    +    if (num == undefined) return UNKNOWN_REPR;
    +    else if (num < 1)     return num.toFixed(2);
    +    else if (num < 10)    return num.toFixed(1);
    +    else                  return num.toFixed(0);
    +}
    +
     function fmt_rate_bytes(obj, name) {
         return fmt_rate0(obj, name, fmt_bytes, true);
     }
    @@ -197,6 +199,17 @@
         return name == '' ? '(AMQP default)' : fmt_escape_html(name);
     }
     
    +function fmt_exchange_type(type) {
    +    for (var i in exchange_types) {
    +        if (exchange_types[i].name == type) {
    +            return fmt_escape_html(type);
    +        }
    +    }
    +    return '
    ' + fmt_escape_html(type) + + '
    '; +} + function fmt_exchange_url(name) { return name == '' ? 'amq.default' : fmt_escape_html(name); } @@ -207,6 +220,15 @@ (now.getMonth() + 1) + "-" + now.getDate() + ".json"; } +function fmt_fd_used(used) { + if (used == 'install_handle_from_sysinternals') { + return '?'; + } + else { + return used; + } +} + function fmt_table_short(table) { return '' + fmt_table_body(table, ':') + '
    '; } @@ -307,9 +329,17 @@ } function fmt_escape_html(txt) { - return txt.replace(/'); +} + +function fmt_escape_html_one_line(txt) { + return fmt_escape_html0(txt).replace(/\n/g, ''); +} + +function fmt_escape_html0(txt) { + return txt.replace(/&/g, '&') + .replace(//g, '>') - .replace(/\n/g, '
    ') .replace(/\"/g, '"'); } @@ -340,6 +370,39 @@ return host + ' (' + node_host + ')'; } +function fmt_connection_state(conn) { + if (conn.state == undefined) return ''; + + var colour = 'green'; + var text = conn.state; + var explanation; + + if (conn.last_blocked_by == 'mem' && conn.state == 'blocked') { + colour = 'red'; + explanation = 'Memory alarm: Connection blocked.'; + } + else if (conn.state == 'blocking') { + colour = 'yellow'; + explanation = 'Memory alarm: Connection will block on publish.'; + } + else if (conn.last_blocked_by == 'flow') { + var age = conn.last_blocked_age.toFixed(); + if (age < 5) { + colour = 'yellow'; + text = 'flow'; + explanation = 'Publishing rate recently restricted by server.'; + } + } + + if (explanation) { + return '
    ' + text + '
    '; + } + else { + return '
    ' + text + '
    '; + } +} + function alt_rows(i) { return (i % 2 == 0) ? ' class="alt1"' : ' class="alt2"'; } @@ -349,36 +412,36 @@ } function link_conn(name) { - return link_to(name, '#/connections/' + esc(name)) + return _link_to(fmt_escape_html(name), '#/connections/' + esc(name)) } function link_channel(name) { - return link_to(name, '#/channels/' + esc(name)) + return _link_to(fmt_escape_html(name), '#/channels/' + esc(name)) } function link_exchange(vhost, name) { var url = esc(vhost) + '/' + (name == '' ? 'amq.default' : esc(name)); - return link_to(fmt_exchange(name), '#/exchanges/' + url) + return _link_to(fmt_exchange(name), '#/exchanges/' + url) } function link_queue(vhost, name) { - return link_to(name, '#/queues/' + esc(vhost) + '/' + esc(name)) + return _link_to(fmt_escape_html(name), '#/queues/' + esc(vhost) + '/' + esc(name)) } function link_vhost(name) { - return link_to(name, '#/vhosts/' + esc(name)) + return _link_to(fmt_escape_html(name), '#/vhosts/' + esc(name)) } function link_user(name) { - return link_to(name, '#/users/' + esc(name)) + return _link_to(fmt_escape_html(name), '#/users/' + esc(name)) } function link_node(name) { - return link_to(name, '#/nodes/' + esc(name)) + return _link_to(fmt_escape_html(name), '#/nodes/' + esc(name)) } -function link_to(name, url) { - return '' + fmt_escape_html(name) + ''; +function _link_to(name, url) { + return '' + name + ''; } function message_rates(stats) { @@ -397,7 +460,7 @@ var key = items[i][1] + '_details'; if (key in stats) { res += '
    ' + name; - res += '' + Math.round(stats[key].rate) + ''; + res += '' + fmt_rate_num(stats[key].rate) + ''; res += 'msg/s
    '; } } @@ -417,9 +480,9 @@ var rateMsg = ' '; var detail = stats[key + '_details'] if (detail != undefined) { - var rate = Math.round(detail.rate); - if (rate > 0) rateMsg = '+' + rate + ' msg/s'; - else if (rate < 0) rateMsg = rate + ' msg/s'; + var rate = detail.rate; + if (rate > 0) rateMsg = '+' + fmt_rate_num(rate) + ' msg/s'; + else if (rate < 0) rateMsg = '-' + fmt_rate_num(-rate) + ' msg/s'; } return '
    ' + name + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/global.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/global.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/global.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/global.js 2012-06-22 16:03:48.000000000 +0000 @@ -21,10 +21,12 @@ '/queues', '/exchanges']); // Extension arguments that we know about and present specially in the UI. -var KNOWN_ARGS = {'alternate-exchange': {'short': 'AE', 'type': 'string'}, - 'x-message-ttl': {'short': 'TTL', 'type': 'int'}, - 'x-expires': {'short': 'Exp', 'type': 'int'}, - 'x-ha-policy': {'short': 'HA', 'type': 'string'}}; +var KNOWN_ARGS = {'alternate-exchange': {'short': 'AE', 'type': 'string'}, + 'x-message-ttl': {'short': 'TTL', 'type': 'int'}, + 'x-expires': {'short': 'Exp', 'type': 'int'}, + 'x-ha-policy': {'short': 'HA', 'type': 'string'}, + 'x-dead-letter-exchange': {'short': 'DLX', 'type': 'string'}, + 'x-dead-letter-routing-key': {'short': 'DLK', 'type': 'string'}}; // Things that are like arguments that we format the same way in listings. var IMPLICIT_ARGS = {'durable': {'short': 'D', 'type': 'boolean'}, @@ -59,9 +61,12 @@ // The dispatcher needs access to the Sammy app var app; +var exchange_types; + // Set up the above vars function setup_global_vars() { - statistics_level = JSON.parse(sync_get('/overview')).statistics_level; + var overview = JSON.parse(sync_get('/overview')); + statistics_level = overview.statistics_level; var user = JSON.parse(sync_get('/whoami')); replace_content('login', '

    User: ' + user.name + '

    '); var tags = user.tags.split(","); @@ -72,6 +77,7 @@ JSON.parse(sync_get('/nodes')).length > 1; vhosts_interesting = JSON.parse(sync_get('/vhosts')).length > 1; current_vhost = get_pref('vhost'); + exchange_types = overview.exchange_types; } //////////////////////////////////////////////////// diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/help.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/help.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/help.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/help.js 2012-06-22 16:03:48.000000000 +0000 @@ -17,6 +17,12 @@ 'queue-auto-delete': 'If yes, the queue will delete itself after at least one consumer has connected, and then all consumers have disconnected.', + 'queue-dead-letter-exchange': + 'Optional name of an exchange to which messages will be republished if they are rejected or expire.
    (Sets the "x-dead-letter-exchange" argument.)', + + 'queue-dead-letter-routing-key': + 'Optional replacement routing key to use when a message is dead-lettered. If this is not set, the message\'s original routing key will be used.
    (Sets the "x-dead-letter-routing-key" argument.)', + 'internal-users-only': 'Only users within the internal RabbitMQ database are shown here. Other users (e.g. those authenticated over LDAP) will not appear.', @@ -64,6 +70,11 @@ incoming network traffic until the memory usage drops below \ the watermark.', + 'disk-free-alarm': + 'The disk free space alarm for this node has gone off. It will block \ + incoming network traffic until the amount of free space exceeds \ + the limit.', + 'message-get-requeue': '

    Clicking "Get Message(s)" will consume messages from the queue. \ If requeue is set the message will be re-added to the queue, \ @@ -164,9 +175,11 @@

    Rate at which basic.return is sent to publishers for undeliverable messages published with the \'immediate\' flag set.
    \ ', + 'disk-monitoring-no-watermark' : 'There is no disk space low watermark set. RabbitMQ will not take any action to avoid running out of disk space.', + 'foo': 'foo' // No comma. }; function help(id) { show_popup('help', HELP[id]); -} \ No newline at end of file +} diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/main.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/main.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/main.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/main.js 2012-06-22 16:03:48.000000000 +0000 @@ -272,7 +272,7 @@ update_multifields(); }); $('.controls-appearance').change(function() { - var controls = $(this).attr('controls'); + var controls = $(this).attr('controls-divs'); if ($(this).val() == 'true') { $('#' + controls + '-yes').slideDown(100); $('#' + controls + '-no').slideUp(100); @@ -644,6 +644,9 @@ function check_password(params) { if (params['password'] != undefined) { + if (params['password'] == '') { + throw("Please specify a password."); + } if (params['password'] != params['password_confirm']) { throw("Passwords do not match."); } diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/channels-list.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/channels-list.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/channels-list.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/channels-list.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -97,11 +97,10 @@ <% } %> <%= fmt_string(channel.user) %> <% } %> - + <%= fmt_channel_mode(channel) %> <% if (channel.transactional) { %> - <%= channel.messages_uncommitted %> uncommitted messages - <%= channel.acks_uncommitted %> uncommitted acks + <%= channel.messages_uncommitted %>m/<%= channel.acks_uncommitted %>a <% } %> <%= channel.prefetch_count %> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/connection.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/connection.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/connection.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/connection.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -66,11 +66,15 @@ - + - + + + + +
    State<%= connection.state %><%= fmt_connection_state(connection) %>
    Timeout<%= connection.timeout %><% if (connection.timeout != 0) { %><%= connection.timeout %>s<% } %>
    Frame max<%= connection.frame_max %> bytes
    <% } %> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/connections.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/connections.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/connections.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/connections.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -5,17 +5,18 @@ - - + + - + <% if (nodes_interesting) { %> <% } %> + <% if (vhosts_interesting) { %> @@ -42,12 +43,13 @@ <% } %> + <% if (vhosts_interesting) { %> <% } %> - + <% } %> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchange.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchange.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchange.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchange.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -6,7 +6,7 @@
    NetworkOverviewNetworkOverview
    <%= fmt_sort('Protocol', 'protocol') %><%= fmt_sort('Peer address', 'name') %><%= fmt_sort('Name', 'name') %><%= fmt_sort('Node', 'node') %><%= fmt_sort('From client', 'recv_oct_details.rate') %> <%= fmt_sort('To client', 'send_oct_details.rate') %><%= fmt_sort('Timeout', 'timeout') %> <%= fmt_sort('Channels', 'channels') %><%= fmt_sort('Virtual host', 'vhost') %><%= fmt_rate_bytes(connection, 'recv_oct') %> <%= fmt_rate_bytes(connection, 'send_oct') %><% if (connection.timeout != undefined) { %><%= connection.timeout %>s<% } %> <%= connection.channels %><%= fmt_string(connection.vhost) %><%= fmt_string(connection.user) %><%= connection.state %><%= fmt_connection_state(connection) %>
    - + @@ -93,58 +93,7 @@ <% if (!exchange.internal) { %> -
    -

    Publish message

    -
    -
    - - - -
    Type<%= fmt_string(exchange.type) %><%= fmt_exchange_type(exchange.type) %>
    Parameters
    - - - - - - - - - - - - - - - - - - - - -
    - -
    - - - -
    - - - -
    - - -
    - +<%= format('publish', {'mode': 'exchange', 'exchange': exchange}) %> <% } %> <% if (exchange.name != "") { %> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchanges.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchanges.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchanges.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/exchanges.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -27,7 +27,7 @@ <%= fmt_string(exchange.vhost) %> <% } %> <%= link_exchange(exchange.vhost, exchange.name) %> - <%= fmt_string(exchange.type) %> + <%= fmt_exchange_type(exchange.type) %> <%= fmt_parameters_short(exchange) %> <%= fmt_rate(exchange.message_stats_in, 'publish', false) %> @@ -62,7 +62,13 @@ - * + + + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/node.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/node.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/node.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/node.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -17,7 +17,7 @@
    - <%= node.fd_used %> / <%= node.fd_total %> + <%= fmt_fd_used(node.fd_used) %> / <%= node.fd_total %>
    @@ -33,8 +33,6 @@ - - +
    Erlang processes @@ -47,6 +45,8 @@
    + + + + +
    Memory @@ -69,6 +69,32 @@ <% } %>
    + Disk space + +<% if (node.disk_free_limit != 'disk_free_monitoring_disabled') { %> + <% if (node.disk_free_alarm) { %> +
    + <%= fmt_bytes(node.disk_free) %> + +
    + <% } else { %> +
    + <%= fmt_bytes(node.disk_free) %> +
    + <% } %> + <% if (node.disk_free_limit == 0) { %> + No low watermark + <% } else { %> + <%= fmt_bytes(node.disk_free_limit) %> low watermark + <% } %> +<% } else { %> + (not available) +<% } %> +
    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/overview.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/overview.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/overview.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/overview.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -1,17 +1,65 @@

    Overview

    +
    +<% +var rabbit_version = 'unknown'; +var erlang_version = 'unknown'; +var version_warning = false; +if (user_monitor) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var r = fmt_rabbit_version(node.applications); + var e = node.erlang_version; + if (rabbit_version == 'unknown') { + rabbit_version = r; + erlang_version = e; + } else { + if (r != 'unknown' && (rabbit_version != r || erlang_version != e)) { + version_warning = true; + } + } + } +} +if (version_warning) { +%> +

    + Version mismatch

    + The nodes in this cluster are running different versions of + RabbitMQ and / or Erlang. This cluster may behave unpredictably. + You are very strongly recommended to ensure that all nodes in this cluster + run the same versions of RabbitMQ and Erlang. +

    +
    + + + + + +<% + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; +%> + > + + + + +<% } %> +
    NameRabbitMQ versionErlang version
    <%= fmt_string(node.name) %><%= fmt_rabbit_version(node.applications) %><%= node.erlang_version %>
    +<% } %> +

    Totals

    <% if (overview.statistics_db_node != 'not_running') { %> -

    Queued messages

    +

    Queued messages

    <%= queue_length(overview.queue_totals, 'Ready', 'messages_ready') %> <%= queue_length(overview.queue_totals, 'Unacknowledged', 'messages_unacknowledged') %> <%= queue_length(overview.queue_totals, 'Total', 'messages') %>
    <% if (statistics_level == 'fine') { %> -

    Message rates

    +

    Message rates

    <%= message_rates(overview.message_stats) %>
    @@ -44,11 +92,10 @@ Memory - Uptime - Version - (RabbitMQ / Erlang) + Disk space + Uptime Type <% @@ -75,7 +122,7 @@
    - <%= node.fd_used %> / <%= node.fd_total %> + <%= fmt_fd_used(node.fd_used) %> / <%= node.fd_total %>
    @@ -107,12 +154,31 @@ <%= fmt_bytes(node.mem_used) %> <% } %> + +<% if (node.disk_free_limit != 'disk_free_monitoring_disabled') { %> + <% if (node.disk_free_alarm) { %> +
    + <%= fmt_bytes(node.disk_free) %> + +
    + <% } else { %> +
    + <%= fmt_bytes(node.disk_free) %> +
    + <% } %> + <% if (node.disk_free_limit == 0) { %> + No low watermark + <% } else { %> + <%= fmt_bytes(node.disk_free_limit) %> low watermark + <% } %> + +<% } else { %> + (not available) +<% } %> + <%= fmt_uptime(node.uptime) %> - - <%= fmt_rabbit_version(node.applications) %> / <%= node.erlang_version %> - <% } %> <% if (node.type == 'disc') { %> @@ -130,6 +196,11 @@ <% } %> +<% if (!version_warning) { %> +

    + RabbitMQ <%= rabbit_version %> on Erlang <%= erlang_version %> +

    +<% } %> <% if (overview.statistics_db_node == 'not_running') { %>

    Statistics database could not be contacted. Message rates and queue lengths will not be shown.

    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/permissions.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/permissions.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/permissions.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/permissions.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,8 @@ -<% if (permissions.length > 0) { %>

    Permissions

    +

    Current permissions

    + <% if (permissions.length > 0) { %> @@ -23,9 +24,9 @@ %> > <% if (mode == 'vhost') { %> - + <% } else { %> - + <% } %> @@ -41,13 +42,11 @@ <% } %>
    <%= link_to(permission.user, '#/users/' + esc(permission.user)) %><%= link_user(permission.user) %><%= link_to(permission.vhost, '#/vhosts/' + esc(permission.vhost)) %><%= link_vhost(permission.vhost) %><%= fmt_string(permission.configure) %> <%= fmt_string(permission.write) %>
    -
    -
    -<% } %> + <% } else { %> +

    ... no permissions ...

    + <% } %> -
    -

    Set permission

    -
    +

    Set permission

    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/publish.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/publish.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/publish.ejs 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/publish.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,63 @@ +
    +

    Publish message

    +
    + +<% if (mode == 'queue') { %> + + +<% } else { %> + + +<% } %> + +
    +<% if (mode == 'queue') { %> + + + +<% } else { %> + + + + +<% } %> + + + + + + + + + + + + + + + + +
    Message will be published to the default exchange with routing key <%= fmt_string(queue.name) %>, routing it to this queue.
    + +
    + + + +
    + + + +
    + +
    +
    +
    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/queue.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/queue.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/queue.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/queue.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -129,6 +129,8 @@
    +<%= format('publish', {'mode': 'queue', 'queue': queue}) %> +

    Get messages

    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/queues.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/queues.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/queues.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/queues.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -143,7 +143,7 @@ <% } %> - + ms - + ms + + + + + + + + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/user.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/user.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/user.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/user.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -26,6 +26,54 @@ <%= format('permissions', {'mode': 'user', 'permissions': permissions, 'vhosts': vhosts, 'parent': user}) %>
    +

    Update this user

    +
    +
    + + + + + + + + + + +
    + + +
    + + *
    + + * + (confirm) +
    + +
    + + + + [Admin] + [Monitoring] + [Management] + [None] + +
    + +
    +
    +
    + + +

    Delete this user

    diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/users.ejs rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/users.ejs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/priv/www/js/tmpl/users.ejs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/priv/www/js/tmpl/users.ejs 2012-06-22 16:03:48.000000000 +0000 @@ -8,6 +8,7 @@ <%= fmt_sort('Name', 'name') %> <%= fmt_sort('Tags', 'tags') %> Can access virtual hosts + Has password @@ -20,6 +21,7 @@ <%= fmt_string(user.tags) %> <%= fmt_permissions(user, permissions, 'user', 'vhost', '

    No access

    ') %> + <%= fmt_boolean(user.password_hash.length > 0) %> <% } %> @@ -29,9 +31,9 @@
    -

    Add / update a user

    +

    Add a user

    - + @@ -43,7 +45,7 @@ diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/README 2012-06-22 16:03:48.000000000 +0000 @@ -13,4 +13,3 @@ Documentation for the HTTP API can be found at http://:55672/api/ - diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_app). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_db.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_db.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_db.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_db.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_db). @@ -314,9 +314,8 @@ handle_deleted(queue_stats, Event, State); handle_event(#event{type = connection_created, props = Stats}, State) -> - Name = rabbit_mgmt_format:connection(Stats), handle_created( - connection_stats, [{name, Name} | proplists:delete(name, Stats)], + connection_stats, Stats, [{fun rabbit_mgmt_format:addr/1, [address, peer_address]}, {fun rabbit_mgmt_format:port/1, [port, peer_port]}, {fun rabbit_mgmt_format:protocol/1, [protocol]}, @@ -331,14 +330,8 @@ handle_event(Event = #event{type = connection_closed}, State) -> handle_deleted(connection_stats, Event, State); -handle_event(#event{type = channel_created, props = Stats}, - State = #state{tables = Tables}) -> - ConnTable = orddict:fetch(connection_stats, Tables), - Conn = lookup_element(ConnTable, {id(pget(connection, Stats)), create}), - Name = rabbit_mgmt_format:print("~s:~w", - [pget(name, Conn), - pget(number, Stats)]), - handle_created(channel_stats, [{name, Name}|Stats], [], State); +handle_event(#event{type = channel_created, props = Stats}, State) -> + handle_created(channel_stats, Stats, [], State); handle_event(#event{type = channel_stats, props = Stats, timestamp = Timestamp}, State) -> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_dispatcher.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_dispatcher.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_dispatcher.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_dispatcher.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_dispatcher). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_extension.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_extension.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_extension.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_extension.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_extension). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_format). @@ -23,7 +23,7 @@ -export([pack_binding_props/2, unpack_binding_props/1, tokenise/1]). -export([to_amqp_table/1, listener/1, properties/1, basic_properties/1]). -export([record/2, to_basic_properties/1]). --export([connection/1, addr/1, port/1]). +-export([addr/1, port/1]). -include_lib("rabbit_common/include/rabbit.hrl"). -include_lib("rabbit_common/include/rabbit_framing.hrl"). @@ -129,7 +129,7 @@ unknown; timestamp(Timestamp) -> {{Y, M, D}, {H, Min, S}} = calendar:now_to_local_time(Timestamp), - print("~w-~w-~w ~w:~w:~w", [Y, M, D, H, Min, S]). + print("~w-~2.2.0w-~2.2.0w ~w:~2.2.0w:~2.2.0w", [Y, M, D, H, Min, S]). resource(unknown) -> unknown; resource(Res) -> resource(name, Res). @@ -237,14 +237,6 @@ url(Fmt, Vals) -> print(Fmt, [mochiweb_util:quote_plus(V) || V <- Vals]). -connection(Props) -> - case proplists:get_value(name, Props, unknown) of - unknown -> print("~s:~w", - [addr(proplists:get_value(peer_address, Props)), - port(proplists:get_value(peer_port, Props))]); - Name -> Name - end. - exchange(X) -> format(X, [{fun resource/1, [name]}, {fun amqp_table/1, [arguments]}]). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_load_definitions.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_load_definitions.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_load_definitions.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_load_definitions.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,48 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_load_definitions). + +-export([maybe_load_definitions/0]). + +%% We want to A) make sure we apply defintions before being open for +%% business (hence why we don't do this in the mgmt app startup) and +%% B) in fact do it before empty_db_check (so the defaults will not +%% get created if we don't need 'em). + +-rabbit_boot_step({load_definitions, + [{description, "configured definitions"}, + {mfa, {rabbit_mgmt_load_definitions, + maybe_load_definitions, + []}}, + {requires, recovery}, + {enables, empty_db_check}]}). + +maybe_load_definitions() -> + {ok, File} = application:get_env(rabbitmq_management, load_definitions), + case File of + none -> ok; + _ -> case file:read_file(File) of + {ok, Body} -> rabbit_log:info( + "Applying definitions from: ~s~n", [File]), + load_definitions(Body); + {error, E} -> exit({could_not_read_defs, {File, E}}) + end + end. + +load_definitions(Body) -> + rabbit_mgmt_wm_definitions:apply_defs( + Body, fun rabbit_misc:const_ok/0, fun (E) -> exit(E) end). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_util). @@ -27,7 +27,8 @@ -export([with_channel/4, with_channel/5]). -export([props_to_method/2, props_to_method/4]). -export([all_or_one_vhost/2, http_to_amqp/5, reply/3, filter_vhost/3]). --export([filter_conn_ch_list/3, with_decode/5, decode/1, redirect/2, args/1]). +-export([filter_conn_ch_list/3, with_decode/5, decode/1, decode/2, redirect/2, + args/1]). -export([reply_list/3, reply_list/4, sort_list/2, destination_type/1]). -export([post_respond/1, columns/1, want_column/2, is_monitor/1]). -export([list_visible_vhosts/1, b64decode_or_throw/1]). @@ -265,7 +266,7 @@ try Node = case pget(<<"node">>, Props) of undefined -> node(); - N -> rabbit_misc:makenode( + N -> rabbit_nodes:make( binary_to_list(N)) end, amqp_request(VHost, ReqData, Context, Node, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_aliveness_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_aliveness_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_aliveness_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_aliveness_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_aliveness_test). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_binding.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_binding.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_binding.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_binding.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_binding). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_bindings.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_bindings.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_bindings.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_bindings.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_bindings). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channel.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channel.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channel.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channel.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_channel). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channels.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channels.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channels.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_channels.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_channels). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection_channels.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection_channels.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection_channels.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection_channels.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_connection_channels). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connection.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_connection). @@ -48,7 +48,7 @@ Pid = proplists:get_value(pid, Conn), Reason = "Closed via management plugin", case proplists:get_value(type, Conn) of - direct -> amqp_connection:close(Pid, 200, Reason); + direct -> amqp_direct_connection:server_close(Pid, 320, Reason); network -> rabbit_networking:close_connection(Pid, Reason) end, {true, ReqData, Context}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connections.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connections.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connections.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_connections.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_connections). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_definitions.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_definitions.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_definitions.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_definitions.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_definitions). @@ -20,6 +20,8 @@ -export([content_types_accepted/2, allowed_methods/2, accept_json/2]). -export([post_is_create/2, create_path/2, accept_multipart/2]). +-export([apply_defs/3]). + -import(rabbit_misc, [pget/2]). -include("rabbit_mgmt.hrl"). @@ -100,23 +102,27 @@ %%-------------------------------------------------------------------- accept(Body, ReqData, Context) -> - rabbit_mgmt_util:with_decode( - [users, vhosts, permissions, queues, exchanges, bindings], - Body, ReqData, Context, - fun([Users, VHosts, Permissions, Queues, Exchanges, Bindings], _) -> - try - for_all(Users, fun add_user/1), - for_all(VHosts, fun add_vhost/1), - for_all(Permissions, fun add_permission/1), - for_all(Queues, fun add_queue/1), - for_all(Exchanges, fun add_exchange/1), - for_all(Bindings, fun add_binding/1), - {true, ReqData, Context} - catch - exit:E -> - rabbit_mgmt_util:bad_request(E, ReqData, Context) - end - end). + apply_defs(Body, fun() -> {true, ReqData, Context} end, + fun(E) -> rabbit_mgmt_util:bad_request(E, ReqData, Context) end). + +apply_defs(Body, SuccessFun, ErrorFun) -> + case rabbit_mgmt_util:decode( + [users, vhosts, permissions, queues, exchanges, bindings], Body) of + {error, E} -> + ErrorFun(E); + {ok, [Users, VHosts, Permissions, Queues, Exchanges, Bindings], _} -> + try + for_all(Users, fun add_user/1), + for_all(VHosts, fun add_vhost/1), + for_all(Permissions, fun add_permission/1), + for_all(Queues, fun add_queue/1), + for_all(Exchanges, fun add_exchange/1), + for_all(Bindings, fun add_binding/1), + SuccessFun() + catch {error, E} -> ErrorFun(E); + exit:E -> ErrorFun(E) + end + end. get_part(Name, Parts) -> Filtered = [Value || {N, _Meta, Value} <- Parts, N == Name], diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_exchange). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange_publish.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange_publish.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange_publish.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchange_publish.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_exchange_publish). @@ -80,6 +80,10 @@ erlang:demonitor(MRef), rabbit_mgmt_util:reply([{routed, Routed}], ReqData, Context). +bad({shutdown, {connection_closing, + {server_initiated_close, Code, Reason}}}, ReqData, Context) -> + rabbit_mgmt_util:bad_request_exception(Code, Reason, ReqData, Context); + bad({shutdown, {server_initiated_close, Code, Reason}}, ReqData, Context) -> rabbit_mgmt_util:bad_request_exception(Code, Reason, ReqData, Context). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchanges.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchanges.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchanges.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_exchanges.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_exchanges). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_extensions.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_extensions.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_extensions.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_extensions.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_extensions). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_node.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_node.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_node.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_node.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_node). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_nodes.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_nodes.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_nodes.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_nodes.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_nodes). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_overview.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_overview.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_overview.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_overview.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_overview). @@ -31,11 +31,12 @@ to_json(ReqData, Context = #context{user = User = #user{tags = Tags}}) -> {ok, StatsLevel} = application:get_env(rabbit, collect_statistics), - %% NB: node and stats level duplicate what's in /nodes but we want - %% to (a) know which node we're talking to and (b) use the stats - %% level to switch features on / off in the UI. + %% NB: this duplicates what's in /nodes but we want a global idea + %% of this. And /nodes is not accepssible to non-monitor users. + ExchangeTypes = rabbit_mgmt_external_stats:list_registry_plugins(exchange), Overview0 = [{management_version, version()}, - {statistics_level, StatsLevel}], + {statistics_level, StatsLevel}, + {exchange_types, ExchangeTypes}], Overview = case rabbit_mgmt_util:is_monitor(Tags) of true -> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permission.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permission.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permission.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permission.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permission). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permissions). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_user.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_user.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_user.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_user.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permissions_user). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_vhost.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_vhost.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_vhost.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_permissions_vhost.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permissions_vhost). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queue). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_get.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_get.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_get.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_get.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queue_get). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_purge.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_purge.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_purge.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queue_purge.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queue_purge). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queues.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queues.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queues.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_queues.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queues). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_user.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_user.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_user.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_user.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_user). @@ -86,19 +86,22 @@ put_user(User, PWArg, PWFun) -> Username = pget(name, User), - Tags = case pget(tags, User) of - undefined -> case rabbit_mgmt_util:parse_bool( - pget(administrator, User)) of - true -> [administrator]; - false -> [] - end; - TagsS -> [list_to_atom(string:strip(T)) || - T <- string:tokens(binary_to_list(TagsS), ",")] + Tags = case {pget(tags, User), pget(administrator, User)} of + {undefined, undefined} -> + throw({error, tags_not_present}); + {undefined, AdminS} -> + case rabbit_mgmt_util:parse_bool(AdminS) of + true -> [administrator]; + false -> [] + end; + {TagsS, _} -> + [list_to_atom(string:strip(T)) || + T <- string:tokens(binary_to_list(TagsS), ",")] end, case rabbit_auth_backend_internal:lookup_user(Username) of {error, not_found} -> rabbit_auth_backend_internal:add_user( - Username, rabbit_guid:binstring_guid("tmp")); + Username, rabbit_guid:binary(rabbit_guid:gen_secure(), "tmp")); _ -> ok end, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_users.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_users.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_users.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_users.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_users). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhost.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhost.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhost.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhost.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_vhost). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhosts.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhosts.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhosts.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_vhosts.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_vhosts). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_whoami.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_whoami.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_whoami.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbit_mgmt_wm_whoami.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_whoami). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbitmq_management.app.src rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbitmq_management.app.src --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/src/rabbitmq_management.app.src 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/src/rabbitmq_management.app.src 2012-06-22 16:03:48.000000000 +0000 @@ -4,6 +4,7 @@ {modules, []}, {registered, []}, {mod, {rabbit_mgmt_app, []}}, - {env, [{http_log_dir, none}]}, - {applications, [kernel, stdlib, rabbit, rabbitmq_mochiweb, amqp_client, + {env, [{http_log_dir, none}, + {load_definitions, none}]}, + {applications, [kernel, stdlib, rabbit, xmerl, rabbitmq_mochiweb, amqp_client, rabbitmq_management_agent]}]}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_all.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_all.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_all.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_all.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_test_all). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_clustering.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_clustering.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_clustering.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_clustering.erl 2012-06-22 16:03:48.000000000 +0000 @@ -29,14 +29,26 @@ %%---------------------------------------------------------------------------- -start_second_node() -> +start_second_node() -> start_other_node(hare, 5673), + cluster_other_node(hare). +stop_second_node() -> stop_other_node(hare). + +start_other_node(Name, Port) -> %% ?assertCmd seems to hang if you background anything. Bah! - Res = os:cmd("make -C " ++ plugin_dir() ++ " start-second-node ; echo $?"), + Res = os:cmd("make -C " ++ plugin_dir() ++ " OTHER_NODE=" ++ + atom_to_list(Name) ++ + " OTHER_PORT=" ++ integer_to_list(Port) ++ + " start-other-node ; echo $?"), LastLine = hd(lists:reverse(string:tokens(Res, "\n"))), ?assertEqual("0", LastLine). -stop_second_node() -> - ?assertCmd("make -C " ++ plugin_dir() ++ " stop-second-node"). +cluster_other_node(Name) -> + ?assertCmd("make -C " ++ plugin_dir() ++ " OTHER_NODE=" ++ + atom_to_list(Name) ++ " cluster-other-node"). + +stop_other_node(Name) -> + ?assertCmd("make -C " ++ plugin_dir() ++ " OTHER_NODE=" ++ + atom_to_list(Name) ++ " stop-other-node"). plugin_dir() -> {ok, [[File]]} = init:get_argument(config), @@ -96,9 +108,17 @@ ?assertEqual(1, length(Act)), assert_node(Exp, hd(Act)). +assert_nodes(Exp, Act0) -> + Act = [read_node(A) || A <- Act0], + ?debugVal({Exp, Act}), + ?assertEqual(length(Exp), length(Act)), + [?assert(lists:member(E, Act)) || E <- Exp]. + assert_node(Exp, Act) -> - ?assertEqual(Exp, - list_to_atom(hd(string:tokens(binary_to_list(Act), "@")))). + ?assertEqual(Exp, read_node(Act)). + +read_node(N) -> + list_to_atom(hd(string:tokens(binary_to_list(N), "@"))). restart_node() -> stop_second_node(), diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_db.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_db.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_db.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_db.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_test_db). @@ -193,6 +193,9 @@ X2 = <<"channel-aggregation-exch2">>, declare_exchange(Chan, X1), declare_exchange(Chan, X2), + Q = declare_queue(Chan), + bind_queue(Chan, X1, Q), + bind_queue(Chan, X2, Q), publish(Chan, X1, <<"">>, 10), publish(Chan, X2, <<"">>, 100), @@ -266,8 +269,8 @@ get_channel(C, Number) -> Port = local_port(C), hd(rabbit_mgmt_db:get_channels( - [list_to_binary("127.0.0.1:" ++ integer_to_list(Port) ++ ":" ++ - integer_to_list(Number))], full)). + [rabbit_mgmt_format:print( + "127.0.0.1:~w -> 127.0.0.1:5672 (~w)", [Port, Number])], full)). get_exchange(XName) -> X = rabbit_mgmt_wm_exchange:exchange(<<"/">>, XName), diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_http.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_http.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_http.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_http.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_test_http). @@ -104,6 +104,17 @@ http_get("/users/myuser", ?NOT_FOUND), ok. +users_legacy_administrator_test() -> + http_put("/users/myuser1", [{administrator, <<"true">>}], ?NO_CONTENT), + http_put("/users/myuser2", [{administrator, <<"false">>}], ?NO_CONTENT), + assert_item([{name, <<"myuser1">>}, {tags, <<"administrator">>}], + http_get("/users/myuser1")), + assert_item([{name, <<"myuser2">>}, {tags, <<"">>}], + http_get("/users/myuser2")), + http_delete("/users/myuser1", ?NO_CONTENT), + http_delete("/users/myuser2", ?NO_CONTENT), + ok. + permissions_validation_test() -> Good = [{configure, <<".*">>}, {write, <<".*">>}, {read, <<".*">>}], http_put("/permissions/wrong/guest", Good, ?BAD_REQUEST), @@ -178,7 +189,8 @@ LocalPort = rabbit_mgmt_test_db:local_port(Conn), Path = binary_to_list( rabbit_mgmt_format:print( - "/connections/127.0.0.1%3A~w", [LocalPort])), + "/connections/127.0.0.1%3A~w%20->%20127.0.0.1%3A5672", + [LocalPort])), http_get(Path, ?OK), http_delete(Path, ?NO_CONTENT), %% TODO rabbit_reader:shutdown/2 returns before the connection is @@ -473,10 +485,12 @@ LocalPort = rabbit_mgmt_test_db:local_port(Conn), ConnPath = binary_to_list( rabbit_mgmt_format:print( - "/connections/127.0.0.1%3A~w", [LocalPort])), + "/connections/127.0.0.1%3A~w%20->%20127.0.0.1%3A5672", + [LocalPort])), ChPath = binary_to_list( rabbit_mgmt_format:print( - "/channels/127.0.0.1%3A~w%3A1", [LocalPort])), + "/channels/127.0.0.1%3A~w%20->%20127.0.0.1%3A5672%20(1)", + [LocalPort])), {Conn, ConnPath, ChPath}. permissions_connection_channel_test() -> diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_unit.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_unit.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_unit.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbit_mgmt_test_unit.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_test_unit). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,188 @@ +#!/usr/bin/env python + +import unittest +import os +import os.path +import socket +import subprocess +import sys + +# TODO test: SSL, depth, config file, encodings(?), completion(???) + +class TestRabbitMQAdmin(unittest.TestCase): + def test_no_args(self): + self.run_fail([]) + + def test_help(self): + self.run_success(['--help']) + self.run_success(['help', 'subcommands']) + self.run_success(['help', 'config']) + self.run_fail(['help', 'astronomy']) + + def test_host(self): + self.run_success(['show', 'overview']) + self.run_success(['--host', 'localhost', 'show', 'overview']) + self.run_success(['--host', socket.gethostname(), 'show', 'overview']) + self.run_fail(['--host', 'some-host-that-does-not-exist', 'show', 'overview']) + + def test_port(self): + self.run_success(['--port', '55672', 'show', 'overview']) + self.run_fail(['--port', '55673', 'show', 'overview']) + self.run_fail(['--port', '5672', 'show', 'overview']) + + def test_user(self): + self.run_success(['--user', 'guest', '--password', 'guest', 'show', 'overview']) + self.run_fail(['--user', 'no', '--password', 'guest', 'show', 'overview']) + self.run_fail(['--user', 'guest', '--password', 'no', 'show', 'overview']) + + def test_fmt_long(self): + self.assert_output(""" +-------------------------------------------------------------------------------- + + name: / +tracing: False + +-------------------------------------------------------------------------------- + +""", ['--format', 'long', 'list', 'vhosts']) + + def test_fmt_kvp(self): + self.assert_output("""name="/" tracing="False" +""", ['--format', 'kvp', 'list', 'vhosts']) + + def test_fmt_tsv(self): + self.assert_output("""name tracing +/ False +""", ['--format', 'tsv', 'list', 'vhosts']) + + def test_fmt_table(self): + out = """+------+---------+ +| name | tracing | ++------+---------+ +| / | False | ++------+---------+ +""" + self.assert_output(out, ['list', 'vhosts']) + self.assert_output(out, ['--format', 'table', 'list', 'vhosts']) + + def test_fmt_bash(self): + self.assert_output("""/ +""", ['--format', 'bash', 'list', 'vhosts']) + + def test_vhosts(self): + self.assert_list(['/'], l('vhosts')) + self.run_success(['declare', 'vhost', 'name=foo']) + self.assert_list(['/', 'foo'], l('vhosts')) + self.run_success(['delete', 'vhost', 'name=foo']) + self.assert_list(['/'], l('vhosts')) + + def test_users(self): + self.assert_list(['guest'], l('users')) + self.run_fail(['declare', 'user', 'name=foo']) + self.run_success(['declare', 'user', 'name=foo', 'password=pass', 'tags=']) + self.assert_list(['foo', 'guest'], l('users')) + self.run_success(['delete', 'user', 'name=foo']) + self.assert_list(['guest'], l('users')) + + def test_permissions(self): + self.run_success(['declare', 'vhost', 'name=foo']) + self.run_success(['declare', 'user', 'name=bar', 'password=pass', 'tags=']) + self.assert_table([['guest', '/']], ['list', 'permissions', 'user', 'vhost']) + self.run_success(['declare', 'permission', 'user=bar', 'vhost=foo', 'configure=.*', 'write=.*', 'read=.*']) + self.assert_table([['guest', '/'], ['bar', 'foo']], ['list', 'permissions', 'user', 'vhost']) + self.run_success(['delete', 'user', 'name=bar']) + self.run_success(['delete', 'vhost', 'name=foo']) + + def test_alt_vhost(self): + self.run_success(['declare', 'vhost', 'name=foo']) + self.run_success(['declare', 'permission', 'user=guest', 'vhost=foo', 'configure=.*', 'write=.*', 'read=.*']) + self.run_success(['declare', 'queue', 'name=in_/']) + self.run_success(['--vhost', 'foo', 'declare', 'queue', 'name=in_foo']) + self.assert_table([['/', 'in_/'], ['foo', 'in_foo']], ['list', 'queues', 'vhost', 'name']) + self.run_success(['--vhost', 'foo', 'delete', 'queue', 'name=in_foo']) + self.run_success(['delete', 'queue', 'name=in_/']) + self.run_success(['delete', 'vhost', 'name=foo']) + + def test_exchanges(self): + self.run_success(['declare', 'exchange', 'name=foo', 'type=direct']) + self.assert_list(['', 'amq.direct', 'amq.fanout', 'amq.headers', 'amq.match', 'amq.rabbitmq.log', 'amq.rabbitmq.trace', 'amq.topic', 'foo'], l('exchanges')) + self.run_success(['delete', 'exchange', 'name=foo']) + + def test_queues(self): + self.run_success(['declare', 'queue', 'name=foo']) + self.assert_list(['foo'], l('queues')) + self.run_success(['delete', 'queue', 'name=foo']) + + def test_bindings(self): + self.run_success(['declare', 'queue', 'name=foo']) + self.run_success(['declare', 'binding', 'source=amq.direct', 'destination=foo', 'destination_type=queue', 'routing_key=test']) + self.assert_table([['', 'foo', 'queue', 'foo'], ['amq.direct', 'foo', 'queue', 'test']], ['list', 'bindings', 'source', 'destination', 'destination_type', 'routing_key']) + self.run_success(['delete', 'queue', 'name=foo']) + + def test_publish(self): + self.run_success(['declare', 'queue', 'name=test']) + self.run_success(['publish', 'routing_key=test', 'payload=test_1']) + self.run_success(['publish', 'routing_key=test', 'payload=test_2']) + self.run_success(['publish', 'routing_key=test'], stdin='test_3') + self.assert_table([exp_msg('test', 2, False, 'test_1')], ['get', 'queue=test', 'requeue=false']) + self.assert_table([exp_msg('test', 1, False, 'test_2')], ['get', 'queue=test', 'requeue=true']) + self.assert_table([exp_msg('test', 1, True, 'test_2')], ['get', 'queue=test', 'requeue=false']) + self.assert_table([exp_msg('test', 0, False, 'test_3')], ['get', 'queue=test', 'requeue=false']) + self.run_success(['publish', 'routing_key=test'], stdin='test_4') + filename = '/tmp/rabbitmq-test/get.txt' + self.run_success(['get', 'queue=test', 'requeue=false', 'payload_file=' + filename]) + with open(filename) as f: + self.assertEqual('test_4', f.read()) + os.remove(filename) + self.run_success(['delete', 'queue', 'name=test']) + + def test_ignore_vhost(self): + self.run_success(['--vhost', '/', 'show', 'overview']) + self.run_success(['--vhost', '/', 'list', 'users']) + self.run_success(['--vhost', '/', 'list', 'vhosts']) + self.run_success(['--vhost', '/', 'list', 'nodes']) + self.run_success(['--vhost', '/', 'list', 'permissions']) + self.run_success(['--vhost', '/', 'declare', 'user', 'name=foo', 'password=pass', 'tags=']) + self.run_success(['delete', 'user', 'name=foo']) + + # --------------------------------------------------------------------------- + + def run_success(self, args, **kwargs): + self.assertEqual(0, run(args, **kwargs)[1]) + + def run_fail(self, args): + self.assertNotEqual(0, run(args)[1]) + + def assert_output(self, expected, args): + self.assertEqual(expected, run(args)[0]) + + def assert_list(self, expected, args0): + args = ['-f', 'tsv', '-q'] + args.extend(args0) + self.assertEqual(expected, run(args)[0].splitlines()) + + def assert_table(self, expected, args0): + args = ['-f', 'tsv', '-q'] + args.extend(args0) + self.assertEqual(expected, [l.split('\t') for l in run(args)[0].splitlines()]) + +def run(args, stdin=None): + path = os.path.normpath(os.path.join(os.getcwd(), sys.argv[0], '../../../bin/rabbitmqadmin')) + cmdline = [path] + cmdline.extend(args) + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = proc.communicate(stdin) + returncode = proc.returncode + return (stdout, returncode) + +def l(thing): + return ['list', thing, 'name'] + +def exp_msg(key, count, redelivered, payload): + # routing_key, exchange, message_count, payload, payload_bytes, payload_encoding, properties, redelivered + return [key, '', str(count), payload, str(len(payload)), 'string', '', str(redelivered)] + +if __name__ == '__main__': + print "\nrabbitmqadmin tests\n===================\n" + suite = unittest.TestLoader().loadTestsFromTestCase(TestRabbitMQAdmin) + unittest.TextTestRunner(verbosity=2).run(suite) diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_agent_app). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_agent_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_agent_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_db_handler.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_db_handler.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_db_handler.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_db_handler.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_db_handler). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_external_stats.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_external_stats.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_external_stats.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-agent/src/rabbit_mgmt_external_stats.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mgmt_external_stats). @@ -24,12 +24,15 @@ -export([info/1, info/2]). +-export([list_registry_plugins/1]). + -include_lib("rabbit_common/include/rabbit.hrl"). -define(REFRESH_RATIO, 5000). -define(KEYS, [os_pid, mem_ets, mem_binary, mem_proc, mem_proc_used, mem_atom, mem_atom_used, mem_code, fd_used, fd_total, sockets_used, sockets_total, mem_used, mem_limit, mem_alarm, + disk_free_limit, disk_free, disk_free_alarm, proc_used, proc_total, statistics_level, erlang_version, uptime, run_queue, processors, exchange_types, auth_mechanisms, applications]). @@ -69,6 +72,16 @@ {error, _} -> get_used_fd({unix, generic}) end; +get_used_fd({unix, BSD}) + when BSD == openbsd; BSD == freebsd; BSD == netbsd -> + Digit = fun (D) -> lists:member(D, "0123456789*") end, + length( + lists:filter( + fun (Line) -> + lists:all(Digit, (lists:nth(4, string:tokens(Line, " ")))) + end, + string:tokens(os:cmd("fstat -p " ++ os:getpid()), "\n"))); + get_used_fd({unix, _}) -> get_used_fd_lsof(); @@ -124,11 +137,17 @@ find_files_line([_H | T]) -> find_files_line(T). -get_memory_limit() -> +-define(SAFE_CALL(Fun, NoProcFailResult), try - vm_memory_monitor:get_memory_limit() - catch exit:{noproc, _} -> memory_monitoring_disabled - end. + Fun + catch exit:{noproc, _} -> NoProcFailResult + end). + +get_disk_free_limit() -> ?SAFE_CALL(rabbit_disk_monitor:get_disk_free_limit(), + disk_free_monitoring_disabled). + +get_disk_free() -> ?SAFE_CALL(rabbit_disk_monitor:get_disk_free(), + disk_free_monitoring_disabled). %%-------------------------------------------------------------------- @@ -136,25 +155,29 @@ i(fd_used, #state{fd_used = FdUsed}) -> FdUsed; i(fd_total, #state{fd_total = FdTotal}) -> FdTotal; -i(sockets_used, _State) -> - proplists:get_value(obtain_count, file_handle_cache:info([obtain_count])); -i(sockets_total, _State) -> - proplists:get_value(obtain_limit, file_handle_cache:info([obtain_limit])); -i(os_pid, _State) -> list_to_binary(os:getpid()); -i(mem_ets, _State) -> erlang:memory(ets); -i(mem_binary, _State) -> erlang:memory(binary); -i(mem_proc, _State) -> erlang:memory(processes); -i(mem_proc_used, _State) -> erlang:memory(processes_used); -i(mem_atom, _State) -> erlang:memory(atom); -i(mem_atom_used, _State) -> erlang:memory(atom_used); -i(mem_code, _State) -> erlang:memory(code); -i(mem_used, _State) -> erlang:memory(total); -i(mem_limit, _State) -> get_memory_limit(); -i(proc_used, _State) -> erlang:system_info(process_count); -i(proc_total, _State) -> erlang:system_info(process_limit); -i(erlang_version, _State) -> list_to_binary(erlang:system_info(otp_release)); -i(run_queue, _State) -> erlang:statistics(run_queue); -i(processors, _State) -> erlang:system_info(logical_processors); +i(sockets_used, _State) -> + proplists:get_value(sockets_used, file_handle_cache:info([sockets_used])); +i(sockets_total, _State) -> + proplists:get_value(sockets_limit, file_handle_cache:info([sockets_limit])); +i(os_pid, _State) -> list_to_binary(os:getpid()); +i(mem_ets, _State) -> erlang:memory(ets); +i(mem_binary, _State) -> erlang:memory(binary); +i(mem_proc, _State) -> erlang:memory(processes); +i(mem_proc_used, _State) -> erlang:memory(processes_used); +i(mem_atom, _State) -> erlang:memory(atom); +i(mem_atom_used, _State) -> erlang:memory(atom_used); +i(mem_code, _State) -> erlang:memory(code); +i(mem_used, _State) -> erlang:memory(total); +i(mem_limit, _State) -> vm_memory_monitor:get_memory_limit(); +i(mem_alarm, _State) -> resource_alarm_set(memory); +i(proc_used, _State) -> erlang:system_info(process_count); +i(proc_total, _State) -> erlang:system_info(process_limit); +i(erlang_version, _State) -> list_to_binary(erlang:system_info(otp_release)); +i(run_queue, _State) -> erlang:statistics(run_queue); +i(processors, _State) -> erlang:system_info(logical_processors); +i(disk_free_limit, _State) -> get_disk_free_limit(); +i(disk_free, _State) -> get_disk_free(); +i(disk_free_alarm, _State) -> resource_alarm_set(disk); i(uptime, _State) -> {Total, _} = erlang:statistics(wall_clock), Total; @@ -170,9 +193,11 @@ fun (N) -> lists:member(list_to_atom(binary_to_list(N)), Mechanisms) end); i(applications, _State) -> [format_application(A) || - A <- lists:keysort(1, application:which_applications(infinity))]; -i(mem_alarm, _State) -> lists:member({{vm_memory_high_watermark, node()}, []}, - alarm_handler:get_alarms()). + A <- lists:keysort(1, application:which_applications(infinity))]. + +resource_alarm_set(Source) -> + lists:member({{resource_limit, Source, node()},[]}, + alarm_handler:get_alarms()). list_registry_plugins(Type) -> list_registry_plugins(Type, fun(_) -> true end). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/LICENSE-MPL-RabbitMQ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/LICENSE-MPL-RabbitMQ --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/LICENSE-MPL-RabbitMQ 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/LICENSE-MPL-RabbitMQ 2012-06-22 16:03:48.000000000 +0000 @@ -447,7 +447,7 @@ The Original Code is RabbitMQ Visualiser. The Initial Developer of the Original Code is VMware, Inc. - Copyright (c) 2011-2011 VMware, Inc. All rights reserved.'' + Copyright (c) 2011-2012 VMware, Inc. All rights reserved.'' [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/priv/www/visualiser/js/model.js rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/priv/www/visualiser/js/model.js --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/priv/www/visualiser/js/model.js 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/priv/www/visualiser/js/model.js 2012-06-22 16:03:48.000000000 +0000 @@ -761,7 +761,6 @@ ctx.bezierCurveTo(xCtl2, yCtl2 + 1, xCtl1, yCtl1 + 1, source.xMax, source.pos[octtree.y] + 1); ctx.moveTo(source.xMax, source.pos[octtree.y]); - ctx.closePath(); this.preStroke(source, destination, model, ctx); // draw an arrow head diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/src/rabbit_mgmt_wm_all.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/src/rabbit_mgmt_wm_all.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/src/rabbit_mgmt_wm_all.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/src/rabbit_mgmt_wm_all.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Visualiser. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. -module(rabbit_mgmt_wm_all). -export([init/1, to_json/2, content_types_provided/2, is_authorized/2, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Visualiser. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_visualiser_mgmt). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_mochiweb_app). -behaviour(application). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_mochiweb). -export([all_listeners/0]). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_registry.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_registry.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_registry.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_registry.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_mochiweb_registry). -behaviour(gen_server). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_mochiweb_sup). -behaviour(supervisor). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,22 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ Mochiweb Embedding. -%% -%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. -%% -%% Copyright (C) 2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mochiweb_util). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_web.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_web.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_web.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_mochiweb_web.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_mochiweb_web). -export([start/1, stop/1]). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_webmachine.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_webmachine.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/src/rabbit_webmachine.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/src/rabbit_webmachine.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,7 @@ %% This file contains an adapted version of webmachine_mochiweb:loop/1 %% from webmachine (revision 0c4b60ac68b4). -%% All modifications are (C) 2011 VMware, Inc. +%% All modifications are (C) 2011-2012 VMware, Inc. -module(rabbit_webmachine). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,3 +1,19 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. +%% + -module(rabbit_mochiweb_test). -include_lib("eunit/include/eunit.hrl"). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test_unit.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test_unit.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test_unit.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-mochiweb/test/src/rabbit_mochiweb_test_unit.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,22 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ Mochiweb Embedding. -%% -%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. -%% -%% Copyright (C) 2011 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mochiweb_test_unit). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/include/rabbit_shovel.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/include/rabbit_shovel.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/include/rabbit_shovel.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/include/rabbit_shovel.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -record(endpoint, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/README 2012-06-22 16:03:48.000000000 +0000 @@ -1,292 +1,4 @@ -RabbitMQ-shovel -=============== +Generic build instructions are at: + http://www.rabbitmq.com/plugin-development.html - -Introduction ------------- - -This is a plug-in for RabbitMQ that shovels messages from a queue on -one broker to an exchange on another broker. The two brokers may be -the same. The plug-in allows several shovels to be specified at the -same time. Each shovel may have a number of source and destination -brokers specified, and one of each is chosen whenever the shovel -attempts to make a connection: this permits simple round-rabbit load -balancing. - -Resources can be declared upon connection to both the source and -destination brokers, and parameters can be specified for both the -reception and publishing of messages. - - -Requirements ------------- - -You can build and install it like any other plugin (see -http://www.rabbitmq.com/plugin-development.html). - - -Configuration -------------- - -The RabbitMQ configuration file specifies the shovel -configurations. This exists by default, in -/etc/rabbitmq/rabbitmq.config under Linux systems, -%RABBITMQ_BASE%\rabbitmq.config under Windows or somewhere else under -OS X. This file configures both RabbitMQ-server and all the plugins -installed in it. It is an Erlang-syntax file of the form: - -[{section1, [section1-config]}, - {section2, [section2-config]}, - ... - {sectionN, [sectionN-config]} -]. - -thus a list of tuples, where the left element of each tuple names the -applications being configured. Don't forget the last element of the -list doesn't have a trailing comma, and don't forget the full-stop is -needed after closing the list. Hence if you configure RabbitMQ-server -and the RabbitMQ-shovel, then the configuration file may have a -structure like this: - -[{rabbit, [configuration-for-RabbitMQ-server]}, - {rabbit-shovel, [configuration-for-RabbitMQ-shovel]} -]. - -A full example of the shovel configuration is: - -{rabbitmq_shovel, - [{shovels, - [{my_first_shovel, - [{sources, [{brokers, - ["amqp://fred:secret@host1.domain/my_vhost", - "amqp://john:secret@host2.domain/my_vhost" - ]}, - {declarations, - ['queue.declare', - {'queue.bind', - [{exchange, <<"my_exchange">>}, - {queue, <<>>}]} - ]}]}, - {destinations, [{broker, "amqp://"}, - {declarations, - [{'exchange.declare', - [{exchange, <<"my_exchange">>}, - {type, <<"direct">>}, - durable]} - ]}]}, - {queue, <<>>}, - {prefetch_count, 10}, - {ack_mode, on_confirm}, - {publish_properties, [{delivery_mode, 2}]}, - {publish_fields, [{exchange, <<"my_exchange">>}, - {routing_key, <<"from_shovel">>}]}, - {reconnect_delay, 5} - ]} - ] - }] -} - -Firstly, all shovels are named. Here we have one shovel, called -'my_first_shovel'. We can have multiple shovels if you wish. Secondly, -every shovel must have the subfields sources, destinations and queue -specified, whereas the other fields (prefetch_count, ack_mode, -publish_properties, publish_fields, reconnect_delay) are optional and -have defaults as follows: - -{prefetch_count, 0} -{ack_mode, on_confirm} -{publish_properties, []} -{publish_fields, []} -{reconnect_delay, 5} - - -Sources and Destinations ------------------------- - -Sources and destinations specify respectively where messages are -fetched from and delivered too. One of 'broker' and 'brokers' must be -specified, and 'broker' is simply shorthand for when only one broker -needs specifying. Using 'brokers' allows a list of brokers to be -specified: whenever the connection to a broker is lost, another one is -chosen at random from the list and a connection attempt is made to -that. The syntax for broker URIs is: - -amqp://username:password@host:port/vhost?key1=value1&key2=value2... - -If username or password are omitted, the default values of guest and -guest are used. If the vhost is omitted, the default value of / is -used. If the host is omitted, then the plugin uses the "direct" -connection internally rather than a network connection: this means it -connects to the RabbitMQ-server node on which it is running without -going through the network stack. This is much more efficient. If port -is omitted then the default value is used (5672 or 5671 if SSL is -used). - -SSL is implemented, for which additional parameters are needed: - -amqps://username:password@host:port/vhost?cacertfile=/path/to/cacert.pem&certfile=/path/to/certfile.pem&keyfile=/path/to/keyfile.pem&verify=verifyOption&fail_if_no_peer_cert=failOption - -All five parameters (3 paths: cacertfile, certfile and keyfile; 2 -options: verify, fail_if_no_peer_cert) must be specified. See the SSL -guide at http://www.rabbitmq.com/ssl.html#configure-erlang for details -of SSL in RabbitMQ in general and specifically for the Erlang client -(on which the shovel is built). - -Note that SSL cannot be used with the direct connection (i.e. a host -must be specified when using SSL), and that it is preferable to use -the non-SSL direct connection when connecting to the same node that's -running the shovel. - -The query part of the URI permits the configuration of additional -connection parameters, permitting heartbeat, channel_max, and -frame_max to be specified. These can be given in any order, and -omitted fields assume default values. For example: - -amqp://myhost?heartbeat=5&frame_max=8192 - -Specifies a non-encrypted network connection to the host 'myhost', -using default username, password, port, vhost and channel_max, but -specifying the heartbeat interval of 5 seconds, and the maximum frame -size of 8192 bytes. - - -Resource Declarations ---------------------- - -Both sources and destinations can have an optional 'declarations' -clause. The value of this is a list, consisting of AMQP Methods. If -default values are sufficient, then the method name alone can be -specified - e.g. 'queue.declare'. If parameters need to be set then -the method should be given as a tuple, with the right hand side a -proplist specifying which fields need altering from their default -values. E.g: - {'exchange.declare',[{exchange, <<"my_exchange">>}, - {type, <<"direct">>}, - durable]}, - -One very useful feature here is the Most-Recently-Declared-Queue -feature, in which RabbitMQ remembers the name of the most recently -declared queue. This means that you can declare a private queue, and -then bind it to exchanges without ever needing to know its name. - - -queue :: binary ---------------- - -This parameter specifies the name of the queue on the source brokers -to consume from. This queue must exist. Use the resource declarations -to create the queue (or ensure it exists) first. Note again that the -Most-Recently-Declared-Queue feature can be used here, thus an -anonymous queue can be used: use <<>> to indicate the -Most-Recently-Declared-Queue. - - -prefetch_count :: non-negative-integer --------------------------------------- - -The shovel consumes from a queue. This parameter imposes a limit on -the number of messages which are sent to the shovel in advance of the -message the shovel is currently processing. - - -ack_mode :: 'no_ack' | 'on_publish' | 'on_confirm' --------------------------------------------------- - -This setting controls if or when acknowledgements to the source broker -are issued by the shovel. The default is 'on_confirm'. - -'no_ack' - The shovel consumes from its queue with no_ack = 'true': -i.e. the shovel does not issue explicit acks for messages it receives, -and the source broker considers messages acknowledged as soon as it -has sent them to the shovel. - -'on_publish' - the shovel consumes from its queue with no_ack = -'false', and a message is acknowledged to the source broker as soon as -it has been published to the destination broker. - -'on_confirm' - the shovel consumes from its queue with no_ack = -'false' and it requests publisher confirmations from the destination -broker. It only issues acknowledgements to the source broker when it -has received confirmation from the destination broker that each -message has been successfully received. This setting gives a guarantee -that messages will not be discarded from the source broker until after -the destination broker has confirmed receipt of the message. - -'on_confirm' is strongly recommended. However the destination broker -must support publish confirms, meaning it can only be used with -RabbitMQ 2.3.1 and up. - -publish_properties ------------------- - -This is a list of tuples which override fields in the basic class -properties when publishing to the destination. This can be used to -override any of the following fields: content_type, content_encoding, -headers, delivery_mode, priority, correlation_id, reply_to, -expiration, message_id, timestamp, type, user_id, app_id, cluster_id. - -By default, all the properties of the basic class that are received -with the delivery are passed through to the destination, but this -field can be used to override them. - - -publish_fields --------------- - -This is a list of tuples which override fields in the publish method -when publishing to the destination. This can be used to direct -messages to a particular exchange on the destination, for example, or -change the routing key. By default, the exchange and the routing key -of the message as it is received by the shovel is passed through, but -this can be overridden as necessary. - - -reconnect_delay :: non-negative-number --------------------------------------- - -When an error occurs, the shovel will disconnect from both the source -and destination broker immediately. This will force uncommitted -transactions at the destination to be rolled back, and delivered but -unacknowledged messages from the source to be requeued. The shovel -will then try connecting again. If this is unsuccessful, then it's not -a good idea for the shovel to very quickly and repeatedly try to -reconnect. The value specified here is determines the delay, in -seconds, between each connection attempt. - -Note that if set to 0, the shovel will never try to reconnect: it'll -stop after the first error. - -Also, the value can be a floating point number, thus permitting the -specification of delays at a granularity smaller than whole seconds. - - -Obtaining shovel statuses -------------------------- - -From the broker Erlang prompt, call -rabbit_shovel_status:status(). This will return a list, with one row -for each configured shovel. Each row has three fields: the shovel -name, the shovel status, and the timestamp (a local calendar time of -{{YYYY,MM,DD},{HH,MM,SS}}). There are 3 possible statuses: - -'starting': The shovel is starting up, connecting and creating - resources. - -{'running'|'blocked', {'source', Source}, - {'destination', Destination}}: - - When 'running', the shovel is up and running, shovelling - messages. When 'blocked', the destination has raised channel.flow, - preventing the shovel from sending messages to the - destination. The shovel will raise channel.flow to the source, - asking the source to stop sending further messages to the - shovel. Any messages that are received by the shovel before the - source observes the channel.flow are correctly buffered and - maintained in order, and are published to the destination as soon - as the destination drops the channel.flow block. - - Source and Destination give the connection parameters used to - connect to the endpoints. - -{'terminated', Reason}: Something's gone wrong. The Reason should give - a further indication of where the fault lies. +See the http://www.rabbitmq.com/shovel.html page for full instructions. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_shovel). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel_status.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel_status.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel_status.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel_status.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_shovel_status). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_shovel_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel_worker.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel_worker.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/src/rabbit_shovel_worker.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/src/rabbit_shovel_worker.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_shovel_worker). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/test/src/rabbit_shovel_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/test/src/rabbit_shovel_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel/test/src/rabbit_shovel_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel/test/src/rabbit_shovel_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_shovel_test). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel-management/README rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel-management/README --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel-management/README 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel-management/README 2012-06-22 16:03:48.000000000 +0000 @@ -1,6 +1,5 @@ Adds information on shovel status to the management plugin. Build it -like any other plugin. You need branch bug23890 of rabbitmq-mochiweb -and rabbitmq-management. +like any other plugin. If you have a heterogenous cluster (where the nodes have different plugins installed), this should be installed on the same nodes as the diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel-management/src/rabbit_shovel_mgmt.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel-management/src/rabbit_shovel_mgmt.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-shovel-management/src/rabbit_shovel_mgmt.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-shovel-management/src/rabbit_shovel_mgmt.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_shovel_mgmt). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/compat rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/compat --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/compat 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -5 diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/control rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/control --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/control 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Source: rabbitmq-stomp -Section: net -Priority: extra -Maintainer: Tony Garnock-Jones -Build-Depends: debhelper (>= 7), erlang-dev, ejabberd -Standards-Version: 3.8.1 -Homepage: http://www.rabbitmq.com/ -Vcs-Browser: http://hg.rabbitmq.com/rabbitmq-stomp - -Package: rabbitmq-stomp -Architecture: all -Depends: rabbitmq-server -Description: A STOMP (Simple Text-Oriented Messaging Protocol) gateway for RabbitMQ diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/copyright rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/copyright --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/copyright 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/copyright 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -This package was debianized by Tony Garnock-Jones on -Tue, 14 Jul 2009 17:35:50 +0100. - -Upstream Author: Tony Garnock-Jones - -Copyright: 2009 Tony Garnock-Jones, 2009 LShift Ltd. - -License: The RabbitMQ STOMP gateway is open-source software, licensed under -the MPL 1.1: - - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is RabbitMQ. - - The Initial Developers of the Original Code are LShift Ltd, - Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. - - Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, - Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd - are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial - Technologies LLC, and Rabbit Technologies Ltd. - - Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift - Ltd. Portions created by Cohesive Financial Technologies LLC are - Copyright (C) 2007-2009 Cohesive Financial Technologies - LLC. Portions created by Rabbit Technologies Ltd are Copyright - (C) 2007-2009 Rabbit Technologies Ltd. - - All Rights Reserved. - - Contributor(s): ______________________________________. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.docs rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.docs --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.docs 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.docs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -README -examples diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.install rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.install --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.install 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/rabbitmq-stomp.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/rules rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/rules --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/debian/rules 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/debian/rules 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -#!/usr/bin/make -f - -# Common useful variables (from cdbs) -DEB_SOURCE_PACKAGE := $(strip $(shell egrep '^Source: ' debian/control | cut -f 2 -d ':')) -DEB_VERSION := $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') -DEB_NOEPOCH_VERSION := $(shell echo $(DEB_VERSION) | cut -d: -f2-) -DEB_UPSTREAM_VERSION := $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//') -DEB_ISNATIVE := $(shell dpkg-parsechangelog | egrep '^Version:' | perl -ne 'print if not /^Version:\s*.*-/;') - -DESTDIR=$(CURDIR)/debian/tmp -TARGET_DIR=usr/lib/erlang/lib/rabbitmq-stomp-$(DEB_UPSTREAM_VERSION) - -build: build-stamp -build-stamp: - dh build --before auto_test - dh build --after auto_test - touch build-stamp - -clean: - dh clean - rm -f build-stamp - rm -f install-stamp - -install: build install-stamp -install-stamp: - dh install --sourcedir=$(DESTDIR) --before=auto_install - install -d $(DESTDIR)/$(TARGET_DIR)/ebin - install -d $(DESTDIR)/$(TARGET_DIR)/include - install ebin/*.beam $(DESTDIR)/$(TARGET_DIR)/ebin - install include/*.hrl $(DESTDIR)/$(TARGET_DIR)/include - dh install --sourcedir=$(DESTDIR) --after=auto_install - touch install-stamp - -binary-arch: install - dh binary-arch - -binary-indep: install - dh binary-indep - -binary: binary-arch binary-indep diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp_frame.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp_frame.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp_frame.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp_frame.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -1,31 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -record(stomp_frame, {command, headers, body_iolist}). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -define(HEADER_ACCEPT_VERSION, "accept-version"). @@ -31,9 +31,11 @@ -define(HEADER_PRIORITY, "priority"). -define(HEADER_RECEIPT, "receipt"). -define(HEADER_REPLY_TO, "reply-to"). +-define(HEADER_SERVER, "server"). -define(HEADER_SESSION, "session"). -define(HEADER_VERSION, "version"). -define(MESSAGE_ID_SEPARATOR, "@@"). --define(HEADERS_NOT_ON_SEND, [?HEADER_MESSAGE_ID]). \ No newline at end of file +-define(HEADERS_NOT_ON_SEND, [?HEADER_MESSAGE_ID]). + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,8 +11,10 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -record(stomp_configuration, {default_login, default_passcode, - implicit_connect}). + implicit_connect, + ssl_cert_login}). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp_prefixes.hrl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp_prefixes.hrl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/include/rabbit_stomp_prefixes.hrl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/include/rabbit_stomp_prefixes.hrl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -define(QUEUE_PREFIX, "/queue"). @@ -25,3 +25,5 @@ -define(VALID_DEST_PREFIXES, [?EXCHANGE_PREFIX, ?TOPIC_PREFIX, ?QUEUE_PREFIX, ?AMQQUEUE_PREFIX, ?TEMP_QUEUE_PREFIX, ?REPLY_QUEUE_PREFIX]). + +-define(TEMP_QUEUE_ID_PREFIX, "/temp-queue/"). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/package.mk rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/package.mk --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/package.mk 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/package.mk 2012-06-22 16:03:48.000000000 +0000 @@ -2,7 +2,7 @@ DEPS:=rabbitmq-server rabbitmq-erlang-client STANDALONE_TEST_COMMANDS:=eunit:test([rabbit_stomp_test_util,rabbit_stomp_test_frame],[verbose]) WITH_BROKER_TEST_SCRIPTS:=$(PACKAGE_DIR)/test/src/test.py $(PACKAGE_DIR)/test/src/test_connect_options.py -WITH_BROKER_TEST_COMMANDS:=rabbit_stomp_amqqueue_test:all_tests() +WITH_BROKER_TEST_COMMANDS:=rabbit_stomp_test:all_tests() rabbit_stomp_amqqueue_test:all_tests() RABBITMQ_TEST_PATH=$(PACKAGE_DIR)/../../rabbitmq-test ABS_PACKAGE_DIR:=$(abspath $(PACKAGE_DIR)) @@ -13,13 +13,15 @@ TEST_CONFIG_PATH=$(TEST_EBIN_DIR)/test.config WITH_BROKER_TEST_CONFIG:=$(TEST_EBIN_DIR)/test +.PHONY: $(TEST_CONFIG_PATH) + ifeq ($(CAN_RUN_SSL),true) WITH_BROKER_TEST_SCRIPTS += $(PACKAGE_DIR)/test/src/test_ssl.py $(TEST_CONFIG_PATH): $(CERTS_DIR) $(ABS_PACKAGE_DIR)/test/src/ssl.config sed -e "s|%%CERTS_DIR%%|$(CERTS_DIR)|g" < $(ABS_PACKAGE_DIR)/test/src/ssl.config > $@ - @echo "Running SSL tests" $(WITH_BROKER_TEST_CONFIG) + @echo "\nRunning SSL tests\n" $(CERTS_DIR): mkdir -p $(CERTS_DIR) @@ -28,7 +30,7 @@ else $(TEST_CONFIG_PATH): $(ABS_PACKAGE_DIR)/test/src/non_ssl.config cp $(ABS_PACKAGE_DIR)/test/src/non_ssl.config $@ - @echo "NOT running SSL tests" $(WITH_BROKER_TEST_CONFIG) + @echo "\nNOT running SSL tests - looked in $(RABBITMQ_TEST_PATH) \n" endif diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src 2012-06-22 16:03:48.000000000 +0000 @@ -7,6 +7,8 @@ {env, [{default_user, [{login, "guest"}, {passcode, "guest"}]}, + {ssl_cert_login, false}, + {implicit_connect, false}, {tcp_listeners, [61613]}, {ssl_listeners, []}, {tcp_listen_options, [binary, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_client_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_client_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_client_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_client_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,59 +1,50 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_client_sup). -behaviour(supervisor2). -define(MAX_WAIT, 16#ffffffff). --export([start_link/2, init/1]). +-export([start_link/1, start_processor/2, init/1]). -start_link(Sock, Configuration) -> +start_link(Configuration) -> {ok, SupPid} = supervisor2:start_link(?MODULE, []), - {ok, ProcessorPid} = - supervisor2:start_child(SupPid, - {rabbit_stomp_processor, - {rabbit_stomp_processor, start_link, - [Sock, - rabbit_heartbeat:start_heartbeat_fun(SupPid), - Configuration]}, - intrinsic, ?MAX_WAIT, worker, - [rabbit_stomp_processor]}), + %% We want the reader to be transient since when it exits normally + %% the processor may have some work still to do (and the reader + %% tells the processor to exit). However, if the reader terminates + %% abnormally then we want to take everything down. + %% + %% The *processor* however is intrinsic, so when it exits, the + %% supervisor goes too. {ok, ReaderPid} = supervisor2:start_child(SupPid, {rabbit_stomp_reader, {rabbit_stomp_reader, - start_link, [ProcessorPid]}, - temporary, ?MAX_WAIT, worker, + start_link, [SupPid, Configuration]}, + transient, ?MAX_WAIT, worker, [rabbit_stomp_reader]}), {ok, SupPid, ReaderPid}. +start_processor(SupPid, Args) -> + supervisor2:start_child(SupPid, + {rabbit_stomp_processor, + {rabbit_stomp_processor, start_link, [Args]}, + intrinsic, ?MAX_WAIT, worker, + [rabbit_stomp_processor]}). + init([]) -> {ok, {{one_for_all, 0, 1}, []}}. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,33 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp). -include("rabbit_stomp.hrl"). @@ -39,41 +25,31 @@ #stomp_configuration{ default_login = undefined, default_passcode = undefined, - implicit_connect = false}). + implicit_connect = false, + ssl_cert_login = false}). start(normal, []) -> Config = parse_configuration(), Listeners = parse_listener_configuration(), - io:format("starting ~s (binding to ~p) ...", - ["STOMP Adapter", Listeners]), - {ok, SupPid} = rabbit_stomp_sup:start_link(Listeners, Config), - io:format("done~n"), - {ok, SupPid}. + rabbit_stomp_sup:start_link(Listeners, Config). stop(_State) -> ok. parse_listener_configuration() -> - case application:get_env(tcp_listeners) of - undefined -> - throw({error, {stomp_configuration_not_found}}); - {ok, Listeners} -> - case application:get_env(ssl_listeners) of - undefined -> {Listeners, []}; - {ok, SslListeners} -> {Listeners, SslListeners} - end - end. + {ok, Listeners} = application:get_env(tcp_listeners), + {ok, SslListeners} = application:get_env(ssl_listeners), + {Listeners, SslListeners}. parse_configuration() -> - Configuration = - case application:get_env(default_user) of - undefined -> - ?DEFAULT_CONFIGURATION; - {ok, UserConfig} -> - parse_default_user(UserConfig, ?DEFAULT_CONFIGURATION) - end, - report_configuration(Configuration), - Configuration. + {ok, UserConfig} = application:get_env(default_user), + Conf0 = parse_default_user(UserConfig, ?DEFAULT_CONFIGURATION), + {ok, SSLLogin} = application:get_env(ssl_cert_login), + {ok, ImplicitConnect} = application:get_env(implicit_connect), + Conf = Conf0#stomp_configuration{ssl_cert_login = SSLLogin, + implicit_connect = ImplicitConnect}, + report_configuration(Conf), + Conf. parse_default_user([], Configuration) -> Configuration; @@ -83,29 +59,29 @@ parse_default_user([{passcode, Passcode} | Rest], Configuration) -> parse_default_user(Rest, Configuration#stomp_configuration{ default_passcode = Passcode}); -parse_default_user([implicit_connect | Rest], Configuration) -> - parse_default_user(Rest, Configuration#stomp_configuration{ - implicit_connect = true}); parse_default_user([Unknown | Rest], Configuration) -> - error_logger:error_msg("Invalid default_user configuration option: ~p~n", - [Unknown]), + rabbit_log:warning("rabbit_stomp: ignoring invalid default_user " + "configuration option: ~p~n", [Unknown]), parse_default_user(Rest, Configuration). report_configuration(#stomp_configuration{ default_login = Login, - implicit_connect = ImplicitConnect}) -> + implicit_connect = ImplicitConnect, + ssl_cert_login = SSLCertLogin}) -> case Login of - undefined -> - ok; - _ -> - error_logger:info_msg("Default user '~s' enabled~n", [Login]) + undefined -> ok; + _ -> rabbit_log:info("rabbit_stomp: default user '~s' " + "enabled~n", [Login]) end, case ImplicitConnect of - true -> error_logger:info_msg("Implicit connect enabled~n"); + true -> rabbit_log:info("rabbit_stomp: implicit connect enabled~n"); false -> ok end, - ok. - + case SSLCertLogin of + true -> rabbit_log:info("rabbit_stomp: ssl_cert_login enabled~n"); + false -> ok + end, + ok. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% stomp_frame implements the STOMP framing protocol "version 1.0", as diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,37 +1,23 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% The Original Code is RabbitMQ. +%% The Original Code is RabbitMQ. %% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_processor). -behaviour(gen_server2). --export([start_link/3, process_frame/2, flush_and_die/1]). +-export([start_link/1, process_frame/2, flush_and_die/1]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]). @@ -41,10 +27,10 @@ -include("rabbit_stomp_prefixes.hrl"). -include("rabbit_stomp_headers.hrl"). --record(state, {socket, session_id, channel, - connection, subscriptions, version, - start_heartbeat_fun, pending_receipts, - config, reply_queues, frame_transformer}). +-record(state, {session_id, channel, connection, subscriptions, + version, start_heartbeat_fun, pending_receipts, + config, dest_queues, reply_queues, frame_transformer, + adapter_info, send_fun, ssl_login_name}). -record(subscription, {dest_hdr, channel, multi_ack, description}). @@ -54,12 +40,14 @@ %%---------------------------------------------------------------------------- %% Public API %%---------------------------------------------------------------------------- -start_link(Sock, StartHeartbeatFun, Configuration) -> - gen_server2:start_link(?MODULE, [Sock, StartHeartbeatFun, Configuration], - []). +start_link(Args) -> + gen_server2:start_link(?MODULE, Args, []). +process_frame(Pid, Frame = #stomp_frame{command = "SEND"}) -> + credit_flow:send(Pid), + gen_server2:cast(Pid, {"SEND", Frame, self()}); process_frame(Pid, Frame = #stomp_frame{command = Command}) -> - gen_server2:cast(Pid, {Command, Frame}). + gen_server2:cast(Pid, {Command, Frame, noflow}). flush_and_die(Pid) -> gen_server2:cast(Pid, flush_and_die). @@ -68,11 +56,10 @@ %% Basic gen_server2 callbacks %%---------------------------------------------------------------------------- -init([Sock, StartHeartbeatFun, Configuration]) -> +init([SendFun, AdapterInfo, StartHeartbeatFun, SSLLoginName, Configuration]) -> process_flag(trap_exit, true), {ok, #state { - socket = Sock, session_id = none, channel = none, connection = none, @@ -81,8 +68,12 @@ start_heartbeat_fun = StartHeartbeatFun, pending_receipts = undefined, config = Configuration, + dest_queues = sets:new(), reply_queues = dict:new(), - frame_transformer = undefined}, + frame_transformer = undefined, + adapter_info = AdapterInfo, + send_fun = SendFun, + ssl_login_name = SSLLoginName}, hibernate, {backoff, 1000, 1000, 10000} }. @@ -93,18 +84,21 @@ handle_cast(flush_and_die, State) -> {stop, normal, close_connection(State)}; -handle_cast({"STOMP", Frame}, State) -> +handle_cast({"STOMP", Frame, noflow}, State) -> process_connect(no_implicit, Frame, State); -handle_cast({"CONNECT", Frame}, State) -> +handle_cast({"CONNECT", Frame, noflow}, State) -> process_connect(no_implicit, Frame, State); handle_cast(Request, State = #state{channel = none, config = #stomp_configuration{ implicit_connect = true}}) -> - {noreply, State1, _} = + {noreply, State1 = #state{channel = Ch}, _} = process_connect(implicit, #stomp_frame{headers = []}, State), - handle_cast(Request, State1); + case Ch of + none -> {stop, normal, State1}; + _ -> handle_cast(Request, State1) + end; handle_cast(_Request, State = #state{channel = none, config = #stomp_configuration{ @@ -115,7 +109,12 @@ State), hibernate}; -handle_cast({Command, Frame}, State = #state{frame_transformer = FT}) -> +handle_cast({Command, Frame, FlowPid}, + State = #state{frame_transformer = FT}) -> + case FlowPid of + noflow -> ok; + _ -> credit_flow:ack(FlowPid) + end, Frame1 = FT(Frame), process_request( fun(StateN) -> @@ -139,8 +138,19 @@ handle_info({Delivery = #'basic.deliver'{}, #amqp_msg{props = Props, payload = Payload}}, State) -> {noreply, send_delivery(Delivery, Props, Payload, State), hibernate}; +handle_info({'EXIT', Conn, + {shutdown, {server_initiated_close, Code, Explanation}}}, + State = #state{connection = Conn}) -> + amqp_death(Code, Explanation, State); +handle_info({'EXIT', Conn, Reason}, State = #state{connection = Conn}) -> + send_error("AMQP connection died", "Reason: ~p", [Reason], State), + {stop, {conn_died, Reason}, State}; handle_info({inet_reply, _, ok}, State) -> {noreply, State, hibernate}; +handle_info({bump_credit, Msg}, State) -> + credit_flow:handle_bump_msg(Msg), + {noreply, State, hibernate}; + handle_info({inet_reply, _, Status}, State) -> {stop, Status, State}. @@ -171,39 +181,28 @@ {stop, R, NewState} end. -process_connect(Implicit, - Frame, - State = #state{ - channel = none, - socket = Sock, - config = #stomp_configuration{ - default_login = DefaultLogin, - default_passcode = DefaultPasscode}}) -> +process_connect(Implicit, Frame, + State = #state{channel = none, + config = Config, + ssl_login_name = SSLLoginName, + adapter_info = AdapterInfo}) -> process_request( fun(StateN) -> case negotiate_version(Frame) of {ok, Version} -> FT = frame_transformer(Version), Frame1 = FT(Frame), + {Username, Creds} = creds(Frame1, SSLLoginName, Config), {ok, DefaultVHost} = application:get_env(rabbit, default_vhost), + {ProtoName, _} = AdapterInfo#adapter_info.protocol, Res = do_login( - rabbit_stomp_frame:header(Frame1, - ?HEADER_LOGIN, - DefaultLogin), - rabbit_stomp_frame:header(Frame1, - ?HEADER_PASSCODE, - DefaultPasscode), - rabbit_stomp_frame:header(Frame1, - ?HEADER_HOST, - binary_to_list( - DefaultVHost)), - rabbit_stomp_frame:header(Frame1, - ?HEADER_HEART_BEAT, - "0,0"), - adapter_info(Sock, Version), - Version, - StateN#state{frame_transformer = FT}), + Username, Creds, + login_header(Frame1, ?HEADER_HOST, DefaultVHost), + login_header(Frame1, ?HEADER_HEART_BEAT, "0,0"), + AdapterInfo#adapter_info{ + protocol = {ProtoName, Version}}, Version, + StateN#state{frame_transformer = FT}), case {Res, Implicit} of {{ok, _, StateN1}, implicit} -> ok(StateN1); _ -> Res @@ -218,6 +217,26 @@ fun(StateM) -> StateM end, State). +creds(Frame, SSLLoginName, + #stomp_configuration{default_login = DefLogin, + default_passcode = DefPasscode}) -> + PasswordCreds = {login_header(Frame, ?HEADER_LOGIN, DefLogin), + [{password, login_header( + Frame, ?HEADER_PASSCODE, DefPasscode)}]}, + case {rabbit_stomp_frame:header(Frame, ?HEADER_LOGIN), SSLLoginName} of + {not_found, none} -> PasswordCreds; + {not_found, SSLName} -> {SSLName, []}; + _ -> PasswordCreds + end. + +login_header(Frame, Key, Default) when is_binary(Default) -> + login_header(Frame, Key, binary_to_list(Default)); +login_header(Frame, Key, Default) -> + case rabbit_stomp_frame:header(Frame, Key, Default) of + undefined -> undefined; + Hdr -> list_to_binary(Hdr) + end. + %%---------------------------------------------------------------------------- %% Frame Transformation %%---------------------------------------------------------------------------- @@ -257,8 +276,8 @@ handle_frame("SEND", Frame, State) -> without_headers(?HEADERS_NOT_ON_SEND, "SEND", Frame, State, - fun (Command, Frame, State) -> - with_destination("SEND", Frame, State, fun do_send/4) + fun (_Command, Frame1, State1) -> + with_destination("SEND", Frame1, State1, fun do_send/4) end); handle_frame("ACK", Frame, State) -> @@ -321,6 +340,12 @@ %% Internal helpers for processing frames callbacks %%---------------------------------------------------------------------------- +cancel_subscription({error, invalid_prefix}, _Frame, State) -> + error("Invalid id", + "UNSUBSCRIBE 'id' may not start with ~s~n", + [?TEMP_QUEUE_ID_PREFIX], + State); + cancel_subscription({error, _}, _Frame, State) -> error("Missing destination or id", "UNSUBSCRIBE must include a 'destination' or 'id' header\n", @@ -423,90 +448,54 @@ do_login(undefined, _, _, _, _, _, State) -> error("Bad CONNECT", "Missing login or passcode header(s)\n", State); - -do_login(Username0, Password0, VirtualHost0, Heartbeat, AdapterInfo, - Version, State) -> - Username = list_to_binary(Username0), - Password = list_to_binary(Password0), - VirtualHost = list_to_binary(VirtualHost0), - case rabbit_access_control:check_user_pass_login(Username, Password) of +do_login(Username, Creds, VirtualHost, Heartbeat, AdapterInfo, Version, + State) -> + case rabbit_access_control:check_user_login(Username, Creds) of {ok, _User} -> case amqp_connection:start( #amqp_params_direct{username = Username, virtual_host = VirtualHost, adapter_info = AdapterInfo}) of {ok, Connection} -> + link(Connection), {ok, Channel} = amqp_connection:open_channel(Connection), - SessionId = rabbit_guid:string_guid("session"), + SessionId = + rabbit_guid:string(rabbit_guid:gen_secure(), "session"), {{SendTimeout, ReceiveTimeout}, State1} = ensure_heartbeats(Heartbeat, State), ok("CONNECTED", [{?HEADER_SESSION, SessionId}, {?HEADER_HEART_BEAT, io_lib:format("~B,~B", [SendTimeout, ReceiveTimeout])}, + {?HEADER_SERVER, server_header()}, {?HEADER_VERSION, Version}], "", State1#state{session_id = SessionId, channel = Channel, connection = Connection}); {error, auth_failure} -> + rabbit_log:error("STOMP login failed - auth_failure " + "(user vanished)~n"), error("Bad CONNECT", "Authentication failure\n", State); {error, access_refused} -> + rabbit_log:warning("STOMP login failed - access_refused " + "(vhost access not allowed)~n"), error("Bad CONNECT", "Authentication failure\n", State) end; - {refused, _Msg, _Args} -> + {refused, Msg, Args} -> + rabbit_log:warning("STOMP login failed: " ++ Msg ++ "\n", Args), error("Bad CONNECT", "Authentication failure\n", State) end. -adapter_info(Sock, Version) -> - {Addr, Port} = case rabbit_net:sockname(Sock) of - {ok, Res} -> Res; - _ -> {unknown, unknown} - end, - {PeerAddr, PeerPort} = case rabbit_net:peername(Sock) of - {ok, Res2} -> Res2; - _ -> {unknown, unknown} - end, - #adapter_info{protocol = {'STOMP', Version}, - address = Addr, - port = Port, - peer_address = PeerAddr, - peer_port = PeerPort, - additional_info = maybe_ssl_info(Sock)}. - -maybe_ssl_info(Sock) -> - case rabbit_net:is_ssl(Sock) of - true -> [{ssl, true}] ++ ssl_info(Sock) ++ ssl_cert_info(Sock); - false -> [{ssl, false}] - end. - -ssl_info(Sock) -> - {Protocol, KeyExchange, Cipher, Hash} = - case rabbit_net:ssl_info(Sock) of - {ok, {P, {K, C, H}}} -> {P, K, C, H}; - {ok, {P, {K, C, H, _}}} -> {P, K, C, H}; - _ -> {unknown, unknown, unknown, unknown} - end, - [{ssl_protocol, Protocol}, - {ssl_key_exchange, KeyExchange}, - {ssl_cipher, Cipher}, - {ssl_hash, Hash}]. - -ssl_cert_info(Sock) -> - case rabbit_net:peercert(Sock) of - {ok, Cert} -> - [{peer_cert_issuer, list_to_binary( - rabbit_ssl:peer_cert_issuer(Cert))}, - {peer_cert_subject, list_to_binary( - rabbit_ssl:peer_cert_subject(Cert))}, - {peer_cert_validity, list_to_binary( - rabbit_ssl:peer_cert_validity(Cert))}]; - _ -> - [] - end. +server_header() -> + Props = rabbit_reader:server_properties(?PROTOCOL), + {_, Product} = rabbit_misc:table_lookup(Props, <<"product">>), + {_, Version} = rabbit_misc:table_lookup(Props, <<"version">>), + rabbit_misc:format("~s/~s", [Product, Version]). do_subscribe(Destination, DestHdr, Frame, State = #state{subscriptions = Subs, + dest_queues = DestQs, connection = Connection, channel = MainChannel}) -> Prefetch = @@ -526,7 +515,8 @@ {AckMode, IsMulti} = rabbit_stomp_util:ack_mode(Frame), - {ok, Queue} = ensure_queue(subscribe, Destination, Frame, Channel), + {ok, Queue, DestQs1} = ensure_queue(subscribe, Destination, Frame, Channel, + DestQs), {ok, ConsumerTag, Description} = rabbit_stomp_util:consumer_tag(Frame), @@ -547,14 +537,16 @@ channel = Channel, multi_ack = IsMulti, description = Description}, - Subs)}). + Subs), + dest_queues = DestQs1}). do_send(Destination, _DestHdr, Frame = #stomp_frame{body_iolist = BodyFragments}, - State = #state{channel = Channel}) -> - {ok, _Q} = ensure_queue(send, Destination, Frame, Channel), + State = #state{channel = Channel, dest_queues = DestQs}) -> + {ok, _Q, DestQs1} = ensure_queue(send, Destination, Frame, Channel, DestQs), - {Frame1, State1} = ensure_reply_to(Frame, State), + {Frame1, State1} = + ensure_reply_to(Frame, State#state{dest_queues = DestQs1}), Props = rabbit_stomp_util:message_properties(Frame1), @@ -600,11 +592,11 @@ State = #state{session_id = SessionId, subscriptions = Subs}) -> case dict:find(ConsumerTag, Subs) of - {ok, #subscription{dest_hdr = Destination}} -> + {ok, #subscription{}} -> send_frame( "MESSAGE", - rabbit_stomp_util:message_headers(Destination, SessionId, - Delivery, Properties), + rabbit_stomp_util:message_headers(SessionId, Delivery, + Properties), Body, State); error -> @@ -625,8 +617,9 @@ State = #state{channel = Channel}) -> send_method(Method, Channel, Properties, BodyFragments, State). -send_method(Method, Channel, Properties, BodyFragments, State) -> - amqp_channel:call( +send_method(Method = #'basic.publish'{}, Channel, Properties, BodyFragments, + State) -> + amqp_channel:cast_flow( Channel, Method, #amqp_msg{props = Properties, payload = list_to_binary(BodyFragments)}), @@ -673,12 +666,14 @@ #'queue.declare'{auto_delete = true, exclusive = true}), - #'basic.consume_ok'{consumer_tag = ConsumerTag} = + ConsumerTag = rabbit_stomp_util:consumer_tag_reply_to(TempQueueId), + #'basic.consume_ok'{} = amqp_channel:subscribe(Channel, #'basic.consume'{ - queue = Queue, - no_ack = true, - nowait = false}, + queue = Queue, + consumer_tag = ConsumerTag, + no_ack = true, + nowait = false}, self()), Destination = reply_to_destination(Queue), @@ -847,18 +842,19 @@ %%-------------------------------------------------------------------- ensure_heartbeats(Heartbeats, - State = #state{socket = Sock, start_heartbeat_fun = SHF}) -> + State = #state{start_heartbeat_fun = SHF, + send_fun = RawSendFun}) -> [CX, CY] = [list_to_integer(X) || X <- re:split(Heartbeats, ",", [{return, list}])], - SendFun = fun() -> catch rabbit_net:send(Sock, <<$\n>>) end, + SendFun = fun() -> RawSendFun(sync, <<$\n>>) end, Pid = self(), ReceiveFun = fun() -> gen_server2:cast(Pid, client_timeout) end, {SendTimeout, ReceiveTimeout} = {millis_to_seconds(CY), millis_to_seconds(CX)}, - SHF(Sock, SendTimeout, SendFun, ReceiveTimeout, ReceiveFun), + SHF(SendTimeout, SendFun, ReceiveTimeout, ReceiveFun), {{SendTimeout * 1000 , ReceiveTimeout * 1000}, State}. @@ -870,24 +866,29 @@ %% Queue and Binding Setup %%---------------------------------------------------------------------------- -ensure_queue(subscribe, {exchange, _}, _Frame, Channel) -> +ensure_queue(subscribe, {exchange, _}, _Frame, Channel, DestQs) -> %% Create anonymous, exclusive queue for SUBSCRIBE on /exchange destinations #'queue.declare_ok'{queue = Queue} = amqp_channel:call(Channel, #'queue.declare'{auto_delete = true, exclusive = true}), - {ok, Queue}; -ensure_queue(send, {exchange, _}, _Frame, _Channel) -> + {ok, Queue, DestQs}; +ensure_queue(send, {exchange, _}, _Frame, _Channel, DestQs) -> %% Don't create queues on SEND for /exchange destinations - {ok, undefined}; -ensure_queue(_, {queue, Name}, _Frame, Channel) -> - %% Always create named queue for /queue destinations + {ok, undefined, DestQs}; +ensure_queue(_, {queue, Name}, _Frame, Channel, DestQs) -> + %% Always create named queue for /queue destinations the first + %% time we encounter it Queue = list_to_binary(Name), - amqp_channel:cast(Channel, - #'queue.declare'{durable = true, - queue = Queue, - nowait = true}), - {ok, Queue}; -ensure_queue(subscribe, {topic, Name}, Frame, Channel) -> + DestQs1 = case sets:is_element(Queue, DestQs) of + true -> DestQs; + false -> amqp_channel:cast(Channel, + #'queue.declare'{durable = true, + queue = Queue, + nowait = true}), + sets:add_element(Queue, DestQs) + end, + {ok, Queue, DestQs1}; +ensure_queue(subscribe, {topic, Name}, Frame, Channel, DestQs) -> %% Create queue for SUBSCRIBE on /topic destinations Queues are %% anonymous, auto_delete and exclusive for transient %% subscriptions. Durable subscriptions get shared, named, durable @@ -905,13 +906,13 @@ #'queue.declare_ok'{queue = Queue} = amqp_channel:call(Channel, Method), - {ok, Queue}; -ensure_queue(send, {topic, _}, _Frame, _Channel) -> + {ok, Queue, DestQs}; +ensure_queue(send, {topic, _}, _Frame, _Channel, DestQs) -> %% Don't create queues on SEND for /topic destinations - {ok, undefined}; -ensure_queue(_, {Type, Name}, _Frame, _Channel) + {ok, undefined, DestQs}; +ensure_queue(_, {Type, Name}, _Frame, _Channel, DestQs) when Type =:= reply_queue orelse Type =:= amqqueue -> - {ok, list_to_binary(Name)}. + {ok, list_to_binary(Name), DestQs}. ensure_queue_binding(QueueBin, {"", Queue}, _Channel) -> %% i.e., we should only be asked to bind to the default exchange a @@ -940,10 +941,9 @@ amqp_death(ReplyCode, Explanation, State) -> ErrorName = ?PROTOCOL:amqp_exception(ReplyCode), - {stop, amqp_death, - send_error(atom_to_list(ErrorName), - format_detail("~s~n", [Explanation]), - State)}. + ErrorDesc = rabbit_misc:format("~s~n", [Explanation]), + log_error(ErrorName, ErrorDesc, none), + {stop, normal, send_error(atom_to_list(ErrorName), ErrorDesc, State)}. error(Message, Detail, State) -> priv_error(Message, Detail, none, State). @@ -952,19 +952,20 @@ priv_error(Message, Format, Args, none, State). priv_error(Message, Detail, ServerPrivateDetail, State) -> - error_logger:error_msg("STOMP error frame sent:~n" ++ - "Message: ~p~n" ++ - "Detail: ~p~n" ++ - "Server private detail: ~p~n", - [Message, Detail, ServerPrivateDetail]), + log_error(Message, Detail, ServerPrivateDetail), {error, Message, Detail, State}. priv_error(Message, Format, Args, ServerPrivateDetail, State) -> - priv_error(Message, format_detail(Format, Args), - ServerPrivateDetail, State). + priv_error(Message, rabbit_misc:format(Format, Args), ServerPrivateDetail, + State). + +log_error(Message, Detail, ServerPrivateDetail) -> + rabbit_log:error("STOMP error frame sent:~n" + "Message: ~p~n" + "Detail: ~p~n" + "Server private detail: ~p~n", + [Message, Detail, ServerPrivateDetail]). -format_detail(Format, Args) -> - lists:flatten(io_lib:format(Format, Args)). %%---------------------------------------------------------------------------- %% Frame sending utilities %%---------------------------------------------------------------------------- @@ -974,11 +975,8 @@ body_iolist = BodyFragments}, State). -send_frame(Frame, State = #state{socket = Sock}) -> - %% We ignore certain errors here, as we will be receiving an - %% asynchronous notification of the same (or a related) fault - %% shortly anyway. See bug 21365. - catch rabbit_net:port_command(Sock, rabbit_stomp_frame:serialize(Frame)), +send_frame(Frame, State = #state{send_fun = SendFun}) -> + SendFun(async, rabbit_stomp_frame:serialize(Frame)), State. send_error(Message, Detail, State) -> @@ -988,7 +986,7 @@ Detail, State). send_error(Message, Format, Args, State) -> - send_error(Message, format_detail(Format, Args), State). + send_error(Message, rabbit_misc:format(Format, Args), State). %%---------------------------------------------------------------------------- %% Skeleton gen_server2 callbacks @@ -998,4 +996,3 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. - diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_reader.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_reader.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_reader.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_reader.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,85 +1,88 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_reader). --export([start_link/1]). --export([init/1]). --export([conserve_memory/2]). +-export([start_link/2]). +-export([init/2]). +-export([conserve_resources/2]). +-include("rabbit_stomp.hrl"). -include("rabbit_stomp_frame.hrl"). +-include_lib("amqp_client/include/amqp_client.hrl"). + +-record(reader_state, {socket, parse_state, processor, state, iterations, + conserve_resources, recv_outstanding}). + +%%---------------------------------------------------------------------------- --record(reader_state, {socket, parse_state, processor, state, iterations}). +start_link(SupPid, Configuration) -> + {ok, proc_lib:spawn_link(?MODULE, init, [SupPid, Configuration])}. -start_link(ProcessorPid) -> - {ok, proc_lib:spawn_link(?MODULE, init, [ProcessorPid])}. +log(Level, Fmt, Args) -> rabbit_log:log(connection, Level, Fmt, Args). -init(ProcessorPid) -> +init(SupPid, Configuration) -> receive - {go, Sock} -> - {ok, {PeerAddress, PeerPort}} = rabbit_net:peername(Sock), - PeerAddressS = inet_parse:ntoa(PeerAddress), - error_logger:info_msg("starting STOMP connection ~p from ~s:~p~n", - [self(), PeerAddressS, PeerPort]), + {go, Sock0, SockTransform} -> + {ok, Sock} = SockTransform(Sock0), + {ok, ProcessorPid} = start_processor(SupPid, Configuration, Sock), + {ok, ConnStr} = rabbit_net:connection_string(Sock, inbound), + log(info, "accepting STOMP connection ~p (~s)~n", + [self(), ConnStr]), ParseState = rabbit_stomp_frame:initial_state(), try mainloop( - register_memory_alarm( - #reader_state{socket = Sock, - parse_state = ParseState, - processor = ProcessorPid, - state = running, - iterations = 0}), 0) + control_throttle( + register_resource_alarm( + #reader_state{socket = Sock, + parse_state = ParseState, + processor = ProcessorPid, + state = running, + iterations = 0, + conserve_resources = false, + recv_outstanding = false})), 0), + log(info, "closing STOMP connection ~p (~s)~n", + [self(), ConnStr]) + catch + Ex -> log(error, "closing STOMP connection ~p (~s):~n~p~n", + [self(), ConnStr, Ex]) after - rabbit_stomp_processor:flush_and_die(ProcessorPid), - error_logger:info_msg("ending STOMP connection ~p from ~s:~p~n", - [self(), PeerAddressS, PeerPort]) - end + rabbit_stomp_processor:flush_and_die(ProcessorPid) + end, + + done end. -mainloop(State = #reader_state{socket = Sock}, ByteCount) -> - run_socket(State, ByteCount), +mainloop(State0 = #reader_state{socket = Sock}, ByteCount) -> + State = run_socket(State0, ByteCount), receive {inet_async, Sock, _Ref, {ok, Data}} -> - process_received_bytes(Data, State); - {inet_async, Sock, _Ref, {error, closed}} -> - error_logger:info_msg("Socket ~p closed by client~n", [Sock]), - ok; - {inet_async, Sock, _Ref, {error, Reason}} -> - error_logger:error_msg("Socket ~p closed abruptly with " - "error code ~p~n", - [Sock, Reason]), + process_received_bytes(Data, State#reader_state{recv_outstanding = false}); + {inet_async, _Sock, _Ref, {error, closed}} -> ok; - {conserve_memory, Conserve} -> - mainloop(internal_conserve_memory(Conserve, State), ByteCount) + {inet_async, _Sock, _Ref, {error, Reason}} -> + throw({inet_error, Reason}); + {conserve_resources, Conserve} -> + mainloop( + control_throttle( + State#reader_state{conserve_resources = Conserve}), ByteCount); + {bump_credit, Msg} -> + credit_flow:handle_bump_msg(Msg), + mainloop(control_throttle(State), ByteCount) end. process_received_bytes([], State) -> @@ -96,33 +99,128 @@ rabbit_stomp_processor:process_frame(Processor, Frame), PS = rabbit_stomp_frame:initial_state(), process_received_bytes(Rest, - State#reader_state{ - parse_state = PS, - state = next_state(S, Frame)}) + control_throttle( + State#reader_state{ + parse_state = PS, + state = next_state(S, Frame)})) end. -conserve_memory(Pid, Conserve) -> - Pid ! {conserve_memory, Conserve}, +conserve_resources(Pid, Conserve) -> + Pid ! {conserve_resources, Conserve}, ok. -register_memory_alarm(State) -> - internal_conserve_memory( - rabbit_alarm:register(self(), {?MODULE, conserve_memory, []}), State). - -internal_conserve_memory(true, State = #reader_state{state = running}) -> - State#reader_state{state = blocking}; -internal_conserve_memory(false, State) -> - State#reader_state{state = running}; -internal_conserve_memory(_Conserve, State) -> - State. +register_resource_alarm(State) -> + rabbit_alarm:register(self(), {?MODULE, conserve_resources, []}), State. + +control_throttle(State = #reader_state{state = CS, + conserve_resources = Mem}) -> + case {CS, Mem orelse credit_flow:blocked()} of + {running, true} -> State#reader_state{state = blocking}; + {blocking, false} -> State#reader_state{state = running}; + {blocked, false} -> State#reader_state{state = running}; + {_, _} -> State + end. next_state(blocking, #stomp_frame{command = "SEND"}) -> blocked; next_state(S, _) -> S. -run_socket(#reader_state{state = blocked}, _ByteCount) -> - ok; -run_socket(#reader_state{socket = Sock}, ByteCount) -> +run_socket(State = #reader_state{state = blocked}, _ByteCount) -> + State; +run_socket(State = #reader_state{recv_outstanding = true}, _ByteCount) -> + State; +run_socket(State = #reader_state{socket = Sock}, ByteCount) -> rabbit_net:async_recv(Sock, ByteCount, infinity), - ok. + State#reader_state{recv_outstanding = true}. + +%%---------------------------------------------------------------------------- + +start_processor(SupPid, Configuration, Sock) -> + SendFun = fun (sync, IoData) -> + %% no messages emitted + catch rabbit_net:send(Sock, IoData); + (async, IoData) -> + %% {inet_reply, _, _} will appear soon + %% We ignore certain errors here, as we will be + %% receiving an asynchronous notification of the + %% same (or a related) fault shortly anyway. See + %% bug 21365. + catch rabbit_net:port_command(Sock, IoData) + end, + + StartHeartbeatFun = + fun (SendTimeout, SendFin, ReceiveTimeout, ReceiveFun) -> + SHF = rabbit_heartbeat:start_heartbeat_fun(SupPid), + SHF(Sock, SendTimeout, SendFin, ReceiveTimeout, ReceiveFun) + end, + + rabbit_stomp_client_sup:start_processor( + SupPid, [SendFun, adapter_info(Sock), StartHeartbeatFun, + ssl_login_name(Sock, Configuration), Configuration]). + + +adapter_info(Sock) -> + {Addr, Port} = case rabbit_net:sockname(Sock) of + {ok, Res} -> Res; + _ -> {unknown, unknown} + end, + {PeerAddr, PeerPort} = case rabbit_net:peername(Sock) of + {ok, Res2} -> Res2; + _ -> {unknown, unknown} + end, + Name = case rabbit_net:connection_string(Sock, inbound) of + {ok, Res3} -> Res3; + _ -> unknown + end, + #adapter_info{protocol = {'STOMP', 0}, + name = list_to_binary(Name), + address = Addr, + port = Port, + peer_address = PeerAddr, + peer_port = PeerPort, + additional_info = maybe_ssl_info(Sock)}. + +maybe_ssl_info(Sock) -> + case rabbit_net:is_ssl(Sock) of + true -> [{ssl, true}] ++ ssl_info(Sock) ++ ssl_cert_info(Sock); + false -> [{ssl, false}] + end. + +ssl_info(Sock) -> + {Protocol, KeyExchange, Cipher, Hash} = + case rabbit_net:ssl_info(Sock) of + {ok, {P, {K, C, H}}} -> {P, K, C, H}; + {ok, {P, {K, C, H, _}}} -> {P, K, C, H}; + _ -> {unknown, unknown, unknown, unknown} + end, + [{ssl_protocol, Protocol}, + {ssl_key_exchange, KeyExchange}, + {ssl_cipher, Cipher}, + {ssl_hash, Hash}]. + +ssl_cert_info(Sock) -> + case rabbit_net:peercert(Sock) of + {ok, Cert} -> + [{peer_cert_issuer, list_to_binary( + rabbit_ssl:peer_cert_issuer(Cert))}, + {peer_cert_subject, list_to_binary( + rabbit_ssl:peer_cert_subject(Cert))}, + {peer_cert_validity, list_to_binary( + rabbit_ssl:peer_cert_validity(Cert))}]; + _ -> + [] + end. + +ssl_login_name(_Sock, #stomp_configuration{ssl_cert_login = false}) -> + none; +ssl_login_name(Sock, #stomp_configuration{ssl_cert_login = true}) -> + case rabbit_net:peercert(Sock) of + {ok, C} -> case rabbit_ssl:peer_cert_auth_name(C) of + unsafe -> none; + not_found -> none; + Name -> Name + end; + {error, no_peercert} -> none; + nossl -> none + end. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,40 +1,25 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ. -%% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_sup). -behaviour(supervisor). -export([start_link/2, init/1]). --export([listener_started/3, listener_stopped/3, - start_client/2, start_ssl_client/3]). +-export([start_client/2, start_ssl_client/3]). start_link(Listeners, Configuration) -> supervisor:start_link({local, ?MODULE}, ?MODULE, @@ -62,46 +47,34 @@ listener_specs(Fun, Args, Listeners) -> [Fun([Address | Args]) || Listener <- Listeners, - Address <- rabbit_networking:check_tcp_listener_address( - rabbit_stomp_listener_sup, Listener)]. + Address <- rabbit_networking:tcp_listener_addresses(Listener)]. tcp_listener_spec([Address, SocketOpts, Configuration]) -> - listener_spec(Address, SocketOpts, stomp, - {?MODULE, start_client, [Configuration]}, - "STOMP TCP Listener"). + rabbit_networking:tcp_listener_spec( + rabbit_stomp_listener_sup, Address, SocketOpts, + stomp, "STOMP TCP Listener", + {?MODULE, start_client, [Configuration]}). ssl_listener_spec([Address, SocketOpts, SslOpts, Configuration]) -> - listener_spec(Address, SocketOpts, 'stomp/ssl', - {?MODULE, start_ssl_client, [Configuration, SslOpts]}, - "STOMP SSL Listener"). - -listener_spec({IPAddress, Port, Family, Name}, - SocketOpts, Protocol, OnConnect, Label) -> - {Name, - {tcp_listener_sup, start_link, - [IPAddress, Port, - [Family | SocketOpts], - {?MODULE, listener_started, [Protocol]}, - {?MODULE, listener_stopped, [Protocol]}, - OnConnect, Label]}, - transient, infinity, supervisor, [tcp_listener_sup]}. + rabbit_networking:tcp_listener_spec( + rabbit_stomp_listener_sup, Address, SocketOpts, + 'stomp/ssl', "STOMP SSL Listener", + {?MODULE, start_ssl_client, [Configuration, SslOpts]}). + +start_client(Configuration, Sock, SockTransform) -> + {ok, _Child, Reader} = supervisor:start_child(rabbit_stomp_client_sup_sup, + [Configuration]), + ok = rabbit_net:controlling_process(Sock, Reader), + Reader ! {go, Sock, SockTransform}, -listener_started(Protocol, IPAddress, Port) -> - rabbit_networking:tcp_listener_started(Protocol, IPAddress, Port). + %% see comment in rabbit_networking:start_client/2 + gen_event:which_handlers(error_logger), -listener_stopped(Protocol, IPAddress, Port) -> - rabbit_networking:tcp_listener_stopped(Protocol, IPAddress, Port). + Reader. start_client(Configuration, Sock) -> - {ok, SupPid, ReaderPid} = - supervisor:start_child(rabbit_stomp_client_sup_sup, - [Sock, Configuration]), - ok = rabbit_net:controlling_process(Sock, ReaderPid), - ReaderPid ! {go, Sock}, - SupPid. + start_client(Configuration, Sock, fun (S) -> {ok, S} end). start_ssl_client(Configuration, SslOpts, Sock) -> Transform = rabbit_networking:ssl_transform_fun(SslOpts), - {ok, SslSock} = Transform(Sock), - start_client(Configuration, SslSock). - + start_client(Configuration, Sock, Transform). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,32 +1,17 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% The Original Code is RabbitMQ. +%% The Original Code is RabbitMQ. %% -%% The Initial Developers of the Original Code are LShift Ltd, -%% Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, -%% Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd -%% are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial -%% Technologies LLC, and Rabbit Technologies Ltd. -%% -%% Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift -%% Ltd. Portions created by Cohesive Financial Technologies LLC are -%% Copyright (C) 2007-2009 Cohesive Financial Technologies -%% LLC. Portions created by Rabbit Technologies Ltd are Copyright -%% (C) 2007-2009 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_stomp_util). @@ -34,7 +19,8 @@ -export([parse_destination/1, parse_routing_information/1, parse_message_id/1, durable_subscription_queue/2]). -export([longstr_field/2]). --export([ack_mode/1, consumer_tag/1, message_headers/4, message_properties/1]). +-export([ack_mode/1, consumer_tag_reply_to/1, consumer_tag/1, message_headers/3, + message_properties/1]). -export([negotiate_version/2]). -export([trim_headers/1]). -export([valid_dest_prefixes/0]). @@ -44,18 +30,27 @@ -include("rabbit_stomp_prefixes.hrl"). -include("rabbit_stomp_headers.hrl"). +-define(INTERNAL_TAG_PREFIX, "T_"). +-define(QUEUE_TAG_PREFIX, "Q_"). + %%-------------------------------------------------------------------- %% Frame and Header Parsing %%-------------------------------------------------------------------- +consumer_tag_reply_to(QueueId) -> + internal_tag(?TEMP_QUEUE_ID_PREFIX ++ QueueId). + consumer_tag(Frame) -> case rabbit_stomp_frame:header(Frame, ?HEADER_ID) of - {ok, Str} -> - {ok, list_to_binary("T_" ++ Str), "id='" ++ Str ++ "'"}; + {ok, Id} -> + case lists:prefix(?TEMP_QUEUE_ID_PREFIX, Id) of + false -> {ok, internal_tag(Id), "id='" ++ Id ++ "'"}; + true -> {error, invalid_prefix} + end; not_found -> case rabbit_stomp_frame:header(Frame, ?HEADER_DESTINATION) of {ok, DestHdr} -> - {ok, list_to_binary("Q_" ++ DestHdr), + {ok, queue_tag(DestHdr), "destination='" ++ DestHdr ++ "'"}; not_found -> {error, missing_destination_header} @@ -91,11 +86,15 @@ headers = [longstr_field(K, V) || {K, V} <- Headers, user_header(K)]}. -message_headers(Destination, SessionId, +message_headers(SessionId, #'basic.deliver'{consumer_tag = ConsumerTag, - delivery_tag = DeliveryTag}, - Props = #'P_basic'{headers = Headers}) -> - Basic = [{?HEADER_DESTINATION, Destination}, + delivery_tag = DeliveryTag, + exchange = ExchangeBin, + routing_key = RoutingKeyBin}, + Props = #'P_basic'{headers = Headers}) -> + Basic = [{?HEADER_DESTINATION, + format_destination(binary_to_list(ExchangeBin), + binary_to_list(RoutingKeyBin))}, {?HEADER_MESSAGE_ID, create_message_id(ConsumerTag, SessionId, DeliveryTag)}], @@ -105,7 +104,7 @@ maybe_header(Header, element(Index, Props), Acc) end, case ConsumerTag of - <<"T_", Id/binary>> -> + <> -> [{"subscription", binary_to_list(Id)} | Basic]; _ -> Basic @@ -211,6 +210,25 @@ trim_headers(Frame = #stomp_frame{headers = Hdrs}) -> Frame#stomp_frame{headers = [{K, string:strip(V, left)} || {K, V} <- Hdrs]}. +internal_tag(Base) -> + list_to_binary(?INTERNAL_TAG_PREFIX ++ Base). + +queue_tag(Base) -> + list_to_binary(?QUEUE_TAG_PREFIX ++ Base). + +%%-------------------------------------------------------------------- +%% Destination Formatting +%%-------------------------------------------------------------------- + +format_destination("", RoutingKey) -> + ?QUEUE_PREFIX ++ "/" ++ escape(RoutingKey); +format_destination("amq.topic", RoutingKey) -> + ?TOPIC_PREFIX ++ "/" ++ escape(RoutingKey); +format_destination(Exchange, "") -> + ?EXCHANGE_PREFIX ++ "/" ++ escape(Exchange); +format_destination(Exchange, RoutingKey) -> + ?EXCHANGE_PREFIX ++ "/" ++ escape(Exchange) ++ "/" ++ escape(RoutingKey). + %%-------------------------------------------------------------------- %% Destination Parsing %%-------------------------------------------------------------------- @@ -251,8 +269,13 @@ valid_dest_prefixes() -> ?VALID_DEST_PREFIXES. durable_subscription_queue(Destination, SubscriptionId) -> - <<(list_to_binary("stomp.dsub." ++ Destination ++ "."))/binary, - (erlang:md5(SubscriptionId))/binary>>. + %% We need a queue name that a) can be derived from the + %% Destination and SubscriptionId, and b) meets the constraints on + %% AMQP queue names. It doesn't need to be secure; we use md5 here + %% simply as a convenient means to bound the length. + rabbit_guid:binary( + erlang:md5(term_to_binary({Destination, SubscriptionId})), + "stomp.dsub"). %% ---- Destination parsing helpers ---- @@ -285,10 +308,23 @@ take_prefix([Char | Prefix], [Char | List]) -> take_prefix(Prefix, List); take_prefix([], List) -> {ok, List}; -take_prefix(_Prefix, List) -> not_found. +take_prefix(_Prefix, _List) -> not_found. unescape(Str) -> unescape(Str, []). unescape("%2F" ++ Str, Acc) -> unescape(Str, [$/ | Acc]); unescape([C | Str], Acc) -> unescape(Str, [C | Acc]); unescape([], Acc) -> lists:reverse(Acc). + +escape(Str) -> escape(Str, []). + +escape([$/ | Str], Acc) -> escape(Str, "F2%" ++ Acc); %% $/ == '2F'x +escape([$% | Str], Acc) -> escape(Str, "52%" ++ Acc); %% $% == '25'x +escape([X | Str], Acc) when X < 32 orelse X > 127 -> + escape(Str, revhex(X) ++ "%" ++ Acc); +escape([C | Str], Acc) -> escape(Str, [C | Acc]); +escape([], Acc) -> lists:reverse(Acc). + +revhex(I) -> hexdig(I) ++ hexdig(I bsr 4). + +hexdig(I) -> erlang:integer_to_list(I band 15, 16). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/connect_options.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/connect_options.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/connect_options.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/connect_options.py 2012-06-22 16:03:48.000000000 +0000 @@ -1,18 +1,20 @@ import unittest import stomp import base +import test_util class TestConnectOptions(base.BaseTest): def test_implicit_connect(self): ''' Implicit connect with receipt on first command ''' self.conn.disconnect() + test_util.enable_implicit_connect() listener = base.WaitableListener() - new_conn = stomp.Connection(user="", passcode="") + new_conn = stomp.Connection() new_conn.set_listener('', listener) new_conn.start() # not going to issue connect - new_conn.subscribe(destination="/topic/implicit", receipt='implicit') + new_conn.subscribe(destination="/topic/implicit", id='sub_implicit', receipt='implicit') try: self.assertTrue(listener.await(5)) @@ -21,14 +23,20 @@ self.assertEquals('implicit', listener.receipts[0]['headers']['receipt-id']) finally: new_conn.disconnect() + test_util.disable_implicit_connect() def test_default_user(self): ''' Default user connection ''' self.conn.disconnect() - new_conn = stomp.Connection(user="", passcode="") + test_util.enable_default_user() + listener = base.WaitableListener() + new_conn = stomp.Connection() + new_conn.set_listener('', listener) new_conn.start() new_conn.connect() try: + self.assertFalse(listener.await(3)) # no error back self.assertTrue(new_conn.is_connected()) finally: - new_conn.disconnect() \ No newline at end of file + new_conn.disconnect() + test_util.disable_default_user() diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/destinations.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/destinations.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/destinations.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/destinations.py 2012-06-22 16:03:48.000000000 +0000 @@ -37,7 +37,10 @@ self.assertFalse(self.conn.is_connected()) def __test_exchange_send_rec(self, exchange, route = None): - dest = "/exchange/" + exchange + if exchange != "amq.topic": + dest = "/exchange/" + exchange + else: + dest = "/topic" if route != None: dest += "/" + route diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/non_ssl.config rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/non_ssl.config --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/non_ssl.config 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/non_ssl.config 2012-06-22 16:03:48.000000000 +0000 @@ -1,7 +1,6 @@ -[ - {rabbitmq_stomp, [ - {default_user, - [{login,"guest"}, - {passcode, "guest"}, - implicit_connect]}]} +[{rabbitmq_stomp, [{default_user, [{login, "guest"}, + {passcode, "guest"} + ]}, + {implicit_connect, true} + ]} ]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/parsing.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/parsing.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/parsing.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/parsing.py 2012-06-22 16:03:48.000000000 +0000 @@ -19,6 +19,7 @@ resp = ('CONNECTED\n' 'session:(.*)\n' 'heart-beat:0,0\n' + 'server:RabbitMQ/(.*)\n' 'version:1.0\n' '\n\x00') def w(m): @@ -186,7 +187,7 @@ resp=('MESSAGE\n' 'content-type:text/plain\n' 'subscription:(.*)\n' - 'destination:/exchange/amq.topic/da9d4779\n' + 'destination:/topic/da9d4779\n' 'message-id:(.*)\n' 'content-length:8\n' '\n' @@ -217,7 +218,7 @@ resp=('MESSAGE\n' 'content-type:text/plain\n' 'subscription:(.*)\n' - 'destination:/exchange/amq.topic/test_huge_message\n' + 'destination:/topic/test_huge_message\n' 'message-id:(.*)\n' 'content-length:%i\n' '\n' @@ -240,6 +241,7 @@ def test_message_with_embedded_nulls(self): ''' Test sending/receiving message with embedded nulls. ''' dest='destination:/exchange/amq.topic/test_embed_nulls_message\n' + resp_dest='destination:/topic/test_embed_nulls_message\n' subscribe=( 'SUBSCRIBE\n' 'id:xxx\n' +dest+ @@ -265,13 +267,13 @@ headresp=('MESSAGE\n' # 8 'content-type:text/plain\n' # 24 'subscription:(.*)\n' # 14 + subscription - +dest+ # 57 + +resp_dest+ # 44 'message-id:(.*)\n' # 12 + message-id 'content-length:%i\n' # 16 + 4==len('1024') '\n' # 1 '(.*)$' # prefix of body+null (potentially) % len(message) ) - headlen = 8 + 24 + 14 + (3) + 57 + 12 + (48) + 16 + (4) + 1 + (1) + headlen = 8 + 24 + 14 + (3) + 44 + 12 + (48) + 16 + (4) + 1 + (1) headbuf = self.recv_atleast(headlen) self.assertFalse(len(headbuf) == 0) @@ -292,7 +294,9 @@ @connect(['cd']) def test_message_in_packets(self): ''' Test sending/receiving message in packets. ''' - dest='destination:/exchange/amq.topic/test_embed_nulls_message\n' + base_dest='topic/test_embed_nulls_message\n' + dest='destination:/exchange/amq.' + base_dest + resp_dest='destination:/'+ base_dest subscribe=( 'SUBSCRIBE\n' 'id:xxx\n' +dest+ @@ -322,13 +326,13 @@ headresp=('MESSAGE\n' # 8 'content-type:text/plain\n' # 24 'subscription:(.*)\n' # 14 + subscription - +dest+ # 57 + +resp_dest+ # 44 'message-id:(.*)\n' # 12 + message-id 'content-length:%i\n' # 16 + 4==len('1024') '\n' # 1 '(.*)$' # prefix of body+null (potentially) % len(message) ) - headlen = 8 + 24 + 14 + (3) + 57 + 12 + (48) + 16 + (4) + 1 + (1) + headlen = 8 + 24 + 14 + (3) + 44 + 12 + (48) + 16 + (4) + 1 + (1) headbuf = self.recv_atleast(headlen) self.assertFalse(len(headbuf) == 0) diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_amqqueue_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_amqqueue_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_amqqueue_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_amqqueue_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,23 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ Management Console. -%% -%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. -%% -%% Copyright (C) 2011 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_amqqueue_test). -export([all_tests/0]). @@ -36,32 +32,35 @@ run_test(TestFun) -> {ok, Connection} = amqp_connection:start(#amqp_params_direct{}), {ok, Channel} = amqp_connection:open_channel(Connection), - {ok, Sock} = stomp_connect(), + {ok, Client} = rabbit_stomp_client:connect(), - Result = (catch TestFun(Channel, Sock)), + Result = (catch TestFun(Channel, Client)), - stomp_disconnect(Sock), + rabbit_stomp_client:disconnect(Client), amqp_channel:close(Channel), amqp_connection:close(Connection), Result. -test_subscribe_error(_Channel, Sock) -> +test_subscribe_error(_Channel, Client) -> %% SUBSCRIBE to missing queue - stomp_send(Sock, "SUBSCRIBE", [{"destination", ?DESTINATION}]), - #stomp_frame{command = "ERROR", headers = Hdrs} = stomp_recv(Sock), + rabbit_stomp_client:send( + Client, "SUBSCRIBE", [{"destination", ?DESTINATION}]), + {#stomp_frame{command = "ERROR", + headers = Hdrs}, _} = rabbit_stomp_client:recv(Client), "not_found" = proplists:get_value("message", Hdrs), ok. -test_subscribe(Channel, Sock) -> +test_subscribe(Channel, Client) -> #'queue.declare_ok'{} = amqp_channel:call(Channel, #'queue.declare'{queue = ?QUEUE, auto_delete = true}), %% subscribe and wait for receipt - stomp_send(Sock, "SUBSCRIBE", [{"destination", ?DESTINATION}, - {"receipt", "foo"}]), - #stomp_frame{command = "RECEIPT"} = stomp_recv(Sock), - + rabbit_stomp_client:send(Client, "SUBSCRIBE", + [{"destination", ?DESTINATION}, + {"receipt", "foo"}]), + {#stomp_frame{command = "RECEIPT"}, Client1} = + rabbit_stomp_client:recv(Client), %% send from amqp Method = #'basic.publish'{ @@ -71,55 +70,27 @@ amqp_channel:call(Channel, Method, #amqp_msg{props = #'P_basic'{}, payload = <<"hello">>}), - #stomp_frame{command = "MESSAGE", - body_iolist = [<<"hello">>]} = stomp_recv(Sock), - + {#stomp_frame{command = "MESSAGE", + body_iolist = [<<"hello">>]}, _Client2} = + rabbit_stomp_client:recv(Client1), ok. -test_send(Channel, Sock) -> +test_send(Channel, Client) -> #'queue.declare_ok'{} = amqp_channel:call(Channel, #'queue.declare'{queue = ?QUEUE, auto_delete = true}), %% subscribe and wait for receipt - stomp_send(Sock, "SUBSCRIBE", [{"destination", ?DESTINATION}, - {"receipt", "foo"}]), - #stomp_frame{command = "RECEIPT"} = stomp_recv(Sock), - + rabbit_stomp_client:send( + Client, "SUBSCRIBE", [{"destination", ?DESTINATION}, {"receipt", "foo"}]), + {#stomp_frame{command = "RECEIPT"}, Client1} = + rabbit_stomp_client:recv(Client), %% send from stomp - stomp_send(Sock, "SEND", [{"destination", ?DESTINATION}], ["hello"]), - - #stomp_frame{command = "MESSAGE", - body_iolist = [<<"hello">>]} = stomp_recv(Sock), + rabbit_stomp_client:send( + Client1, "SEND", [{"destination", ?DESTINATION}], ["hello"]), + {#stomp_frame{command = "MESSAGE", + body_iolist = [<<"hello">>]}, _Client2} = + rabbit_stomp_client:recv(Client1), ok. - -stomp_connect() -> - {ok, Sock} = gen_tcp:connect(localhost, 61613, [{active, false}, binary]), - stomp_send(Sock, "CONNECT"), - #stomp_frame{command = "CONNECTED"} = stomp_recv(Sock), - {ok, Sock}. - -stomp_disconnect(Sock) -> - stomp_send(Sock, "DISCONNECT"). - -stomp_send(Sock, Command) -> - stomp_send(Sock, Command, []). - -stomp_send(Sock, Command, Headers) -> - stomp_send(Sock, Command, Headers, []). - -stomp_send(Sock, Command, Headers, Body) -> - gen_tcp:send(Sock, rabbit_stomp_frame:serialize( - #stomp_frame{command = list_to_binary(Command), - headers = Headers, - body_iolist = Body})). - -stomp_recv(Sock) -> - {ok, Payload} = gen_tcp:recv(Sock, 0), - {ok, Frame, _Rest} = - rabbit_stomp_frame:parse(Payload, - rabbit_stomp_frame:initial_state()), - Frame. - diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,75 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Console. +%% +%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. +%% +%% Copyright (C) 2011 Rabbit Technologies Ltd. +%% +%% All Rights Reserved. +%% +%% Contributor(s): ______________________________________. +%% + +%% The stupidest client imaginable, just for testing. + +-module(rabbit_stomp_client). + +-export([connect/0, disconnect/1, send/2, send/3, send/4, recv/1]). + +-include("rabbit_stomp_frame.hrl"). + +connect() -> + {ok, Sock} = gen_tcp:connect(localhost, 61613, [{active, false}, binary]), + Client0 = recv_state(Sock), + send(Client0, "CONNECT", [{"login", "guest"}, {"passcode", "guest"}]), + {#stomp_frame{command = "CONNECTED"}, Client1} = recv(Client0), + {ok, Client1}. + +disconnect(Client = {Sock, _}) -> + send(Client, "DISCONNECT"), + gen_tcp:close(Sock). + +send(Client, Command) -> + send(Client, Command, []). + +send(Client, Command, Headers) -> + send(Client, Command, Headers, []). + +send({Sock, _}, Command, Headers, Body) -> + Frame = rabbit_stomp_frame:serialize( + #stomp_frame{command = list_to_binary(Command), + headers = Headers, + body_iolist = Body}), + gen_tcp:send(Sock, Frame). + +recv_state(Sock) -> + {Sock, []}. + +recv({_Sock, []} = Client) -> + recv(Client, rabbit_stomp_frame:initial_state(), 0); +recv({Sock, [Frame | Frames]}) -> + {Frame, {Sock, Frames}}. + +recv(Client = {Sock, _}, FrameState, Length) -> + {ok, Payload} = gen_tcp:recv(Sock, Length), + parse(Payload, Client, FrameState, Length). + +parse(Payload, Client = {Sock, FramesRev}, FrameState, Length) -> + case rabbit_stomp_frame:parse(Payload, FrameState) of + {ok, Frame, <<>>} -> + recv({Sock, lists:reverse([Frame | FramesRev])}); + {ok, Frame, Rest} -> + parse(Rest, {Sock, [Frame | FramesRev]}, + rabbit_stomp_frame:initial_state(), Length); + {more, NewState, NewLength} -> + recv(Client, NewState, NewLength) + end. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_publish_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_publish_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_publish_test.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_publish_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,88 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Console. +%% +%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. +%% +%% Copyright (C) 2011 Rabbit Technologies Ltd. +%% +%% All Rights Reserved. +%% +%% Contributor(s): ______________________________________. +%% +-module(rabbit_stomp_publish_test). + +-export([run/0]). + +-include("rabbit_stomp_frame.hrl"). + +-define(DESTINATION, "/queue/test"). + +-define(MICROS_PER_UPDATE, 5000000). +-define(MICROS_PER_UPDATE_MSG, 100000). +-define(MICROS_PER_SECOND, 1000000). + +%% A very simple publish-and-consume-as-fast-as-you-can test. + +run() -> + [put(K, 0) || K <- [sent, recd, last_sent, last_recd]], + put(last_ts, erlang:now()), + {ok, Pub} = rabbit_stomp_client:connect(), + {ok, Recv} = rabbit_stomp_client:connect(), + Self = self(), + spawn(fun() -> publish(Self, Pub, 0, erlang:now()) end), + rabbit_stomp_client:send( + Recv, "SUBSCRIBE", [{"destination", ?DESTINATION}]), + spawn(fun() -> recv(Self, Recv, 0, erlang:now()) end), + report(). + +report() -> + receive + {sent, C} -> put(sent, C); + {recd, C} -> put(recd, C) + end, + Diff = timer:now_diff(erlang:now(), get(last_ts)), + case Diff > ?MICROS_PER_UPDATE of + true -> S = get(sent) - get(last_sent), + R = get(recd) - get(last_recd), + put(last_sent, get(sent)), + put(last_recd, get(recd)), + put(last_ts, erlang:now()), + io:format("Send ~p msg/s | Recv ~p msg/s~n", + [trunc(S * ?MICROS_PER_SECOND / Diff), + trunc(R * ?MICROS_PER_SECOND / Diff)]); + false -> ok + end, + report(). + +publish(Owner, Client, Count, TS) -> + rabbit_stomp_client:send( + Client, "SEND", [{"destination", ?DESTINATION}], + [integer_to_list(Count)]), + Diff = timer:now_diff(erlang:now(), TS), + case Diff > ?MICROS_PER_UPDATE_MSG of + true -> Owner ! {sent, Count + 1}, + publish(Owner, Client, Count + 1, erlang:now()); + false -> publish(Owner, Client, Count + 1, TS) + end. + +recv(Owner, Client0, Count, TS) -> + {#stomp_frame{body_iolist = Body}, Client1} = + rabbit_stomp_client:recv(Client0), + BodyInt = list_to_integer(binary_to_list(iolist_to_binary(Body))), + Count = BodyInt, + Diff = timer:now_diff(erlang:now(), TS), + case Diff > ?MICROS_PER_UPDATE_MSG of + true -> Owner ! {recd, Count + 1}, + recv(Owner, Client1, Count + 1, erlang:now()); + false -> recv(Owner, Client1, Count + 1, TS) + end. + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,41 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(rabbit_stomp_test). +-export([all_tests/0]). +-import(rabbit_misc, [pget/2]). + +-include_lib("amqp_client/include/amqp_client.hrl"). +-include("rabbit_stomp_frame.hrl"). +-define(DESTINATION, "/queue/bulk-test"). + +all_tests() -> + test_messages_not_dropped_on_disconnect(), + ok. + +test_messages_not_dropped_on_disconnect() -> + {ok, Client} = rabbit_stomp_client:connect(), + [rabbit_stomp_client:send( + Client, "SEND", [{"destination", ?DESTINATION}], + [integer_to_list(Count)]) || Count <- lists:seq(1, 1000)], + rabbit_stomp_client:disconnect(Client), + QName = rabbit_misc:r(<<"/">>, queue, <<"bulk-test">>), + timer:sleep(1000), + rabbit_amqqueue:with( + QName, fun(Q) -> + 1000 = pget(messages, rabbit_amqqueue:info(Q, [messages])) + end), + ok. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,23 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% The Original Code is RabbitMQ. %% -%% The Original Code is RabbitMQ Management Console. -%% -%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. -%% -%% Copyright (C) 2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_test_frame). -include_lib("eunit/include/eunit.hrl"). @@ -116,7 +112,7 @@ {ok, Val} = rabbit_stomp_frame:header(Frame, "header"), ?assertEqual(":\n\\", Val), Serialized = lists:flatten(rabbit_stomp_frame:serialize(Frame)), - ?assertEqual(Content, lists:flatten(io_lib:format("~s", [Serialized]))). + ?assertEqual(Content, rabbit_misc:format("~s", [Serialized])). parse(Content) -> parse(Content, rabbit_stomp_frame:initial_state()). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_util.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_util.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_util.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_util.erl 2012-06-22 16:03:48.000000000 +0000 @@ -1,23 +1,19 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. %% -%% The Original Code is RabbitMQ Management Console. +%% The Original Code is RabbitMQ. %% -%% The Initial Developers of the Original Code are Rabbit Technologies Ltd. -%% -%% Copyright (C) 2010 Rabbit Technologies Ltd. -%% -%% All Rights Reserved. -%% -%% Contributor(s): ______________________________________. +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% + -module(rabbit_stomp_test_util). -include_lib("eunit/include/eunit.hrl"). @@ -65,7 +61,9 @@ Delivery = #'basic.deliver'{ consumer_tag = <<"Q_123">>, - delivery_tag = 123}, + delivery_tag = 123, + exchange = <<"">>, + routing_key = <<"foo">>}, Properties = #'P_basic'{ headers = [{<<"str">>, longstr, <<"foo">>}, @@ -78,8 +76,8 @@ reply_to = <<"something">>, message_id = <<"M123">>}, - Headers = rabbit_stomp_util:message_headers(Destination, SessionId, - Delivery, Properties), + Headers = rabbit_stomp_util:message_headers(SessionId, Delivery, + Properties), Expected = [ {"destination", Destination}, @@ -103,12 +101,14 @@ Delivery = #'basic.deliver'{ consumer_tag = <<"Q_123">>, - delivery_tag = 123}, + delivery_tag = 123, + exchange = <<"">>, + routing_key = <<"foo">>}, Properties = #'P_basic'{}, - Headers = rabbit_stomp_util:message_headers(Destination, SessionId, - Delivery, Properties), + Headers = rabbit_stomp_util:message_headers(SessionId, Delivery, + Properties), Expected = [ {"destination", Destination}, {"message-id", [<<"Q_123">>, "@@", SessionId, "@@", "123"]}, diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/ssl.config rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/ssl.config --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/ssl.config 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/ssl.config 2012-06-22 16:03:48.000000000 +0000 @@ -1,16 +1,12 @@ -[ - {rabbitmq_stomp, [ - {default_user, - [{login, "guest"}, - {passcode, "guest"}, - implicit_connect]}, - {ssl_listeners, [61614]} - ]}, - {rabbit, [ - {ssl_options, [{cacertfile,"%%CERTS_DIR%%/testca/cacert.pem"}, - {certfile,"%%CERTS_DIR%%/server/cert.pem"}, - {keyfile,"%%CERTS_DIR%%/server/key.pem"}, - {verify,verify_peer}, - {fail_if_no_peer_cert,false}]} - ]} +[{rabbitmq_stomp, [{default_user, []}, + {ssl_cert_login, true}, + {ssl_listeners, [61614]} + ]}, + {rabbit, [{ssl_options, [{cacertfile,"%%CERTS_DIR%%/testca/cacert.pem"}, + {certfile,"%%CERTS_DIR%%/server/cert.pem"}, + {keyfile,"%%CERTS_DIR%%/server/key.pem"}, + {verify,verify_peer}, + {fail_if_no_peer_cert,true} + ]} + ]} ]. diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/ssl_lifecycle.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/ssl_lifecycle.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/ssl_lifecycle.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/ssl_lifecycle.py 2012-06-22 16:03:48.000000000 +0000 @@ -4,13 +4,13 @@ import stomp import base +ssl_key_file = os.path.abspath("test/certs/client/key.pem") +ssl_cert_file = os.path.abspath("test/certs/client/cert.pem") +ssl_ca_certs = os.path.abspath("test/certs/testca/cacert.pem") + class TestSslClient(unittest.TestCase): def __ssl_connect(self): - ssl_key_file = os.path.abspath("test/certs/client/key.pem") - ssl_cert_file = os.path.abspath("test/certs/client/cert.pem") - ssl_ca_certs = os.path.abspath("test/certs/testca/cacert.pem") - conn = stomp.Connection(user="guest", passcode="guest", host_and_ports = [ ('localhost', 61614) ], use_ssl = True, ssl_key_file = ssl_key_file, @@ -21,13 +21,32 @@ conn.connect() return conn + def __ssl_auth_connect(self): + conn = stomp.Connection(host_and_ports = [ ('localhost', 61614) ], + use_ssl = True, ssl_key_file = ssl_key_file, + ssl_cert_file = ssl_cert_file, + ssl_ca_certs = ssl_ca_certs) + conn.start() + conn.connect() + return conn + def test_ssl_connect(self): conn = self.__ssl_connect() conn.stop() + def test_ssl_auth_connect(self): + conn = self.__ssl_auth_connect() + conn.stop() + def test_ssl_send_receive(self): conn = self.__ssl_connect() + self.__test_conn(conn) + + def test_ssl_auth_send_receive(self): + conn = self.__ssl_auth_connect() + self.__test_conn(conn) + def __test_conn(self, conn): try: listener = base.WaitableListener() diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/test_ssl.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/test_ssl.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/test_ssl.py 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/test_ssl.py 2012-06-22 16:03:48.000000000 +0000 @@ -1,8 +1,10 @@ #!/usr/bin/env python import test_runner +import test_util if __name__ == '__main__': modules = ['ssl_lifecycle'] + test_util.ensure_ssl_auth_user() test_runner.run_unittests(modules) diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/test_util.py rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/test_util.py --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-stomp/test/src/test_util.py 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-stomp/test/src/test_util.py 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,42 @@ +import subprocess +import socket +import sys +import os +import os.path + +def ensure_ssl_auth_user(): + user = 'O=client,CN=%s' % socket.gethostname() + rabbitmqctl(['stop_app']) + rabbitmqctl(['reset']) + rabbitmqctl(['start_app']) + rabbitmqctl(['add_user', user, 'foo']) + rabbitmqctl(['clear_password', user]) + rabbitmqctl(['set_permissions', user, '.*', '.*', '.*']) + +def enable_implicit_connect(): + switch_config(implicit_connect='true', default_user='[{login, "guest"}, {passcode, "guest"}]') + +def disable_implicit_connect(): + switch_config(implicit_connect='false', default_user='[]') + +def enable_default_user(): + switch_config(default_user='[{login, "guest"}, {passcode, "guest"}]') + +def disable_default_user(): + switch_config(default_user='[]') + +def switch_config(implicit_connect='', default_user=''): + cmd = 'application:stop(rabbitmq_stomp),' + if implicit_connect: + cmd += 'application:set_env(rabbitmq_stomp,implicit_connect,' + implicit_connect + '),' + if default_user: + cmd += 'application:set_env(rabbitmq_stomp,default_user,' + default_user + '),' + cmd += 'application:start(rabbitmq_stomp).' + rabbitmqctl(['eval', cmd]) + +def rabbitmqctl(args): + ctl = os.path.normpath(os.path.join(os.getcwd(), sys.argv[0], '../../../../rabbitmq-server/scripts/rabbitmqctl')) + cmdline = [ctl, '-n', 'rabbit-test'] + cmdline.extend(args) + subprocess.check_call(cmdline) + diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_app.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_app.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_app.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_app.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_app). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_consumer). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_consumer_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_consumer_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_files.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_files.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_files.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_files.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_files). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_mgmt.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_mgmt.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_mgmt.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_mgmt.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_mgmt). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_sup.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_sup.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_sup). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_traces.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_traces.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_traces.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_traces.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_traces). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_files.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_files.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_files.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_files.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_wm_files). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_traces.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_traces.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_traces.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/src/rabbit_tracing_wm_traces.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_wm_traces). diff -Nru rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/test/src/rabbit_tracing_test.erl rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/test/src/rabbit_tracing_test.erl --- rabbitmq-server-2.7.1/plugins-src/rabbitmq-tracing/test/src/rabbit_tracing_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/plugins-src/rabbitmq-tracing/test/src/rabbit_tracing_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tracing_test). diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmqctl rabbitmq-server-2.8.4/scripts/rabbitmqctl --- rabbitmq-server-2.7.1/scripts/rabbitmqctl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmqctl 2012-06-22 16:03:48.000000000 +0000 @@ -12,14 +12,20 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## +# Get default settings with user overrides for (RABBITMQ_) +# Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env +##--- Set environment vars RABBITMQ_ to defaults if not set + [ "x" = "x$RABBITMQ_NODENAME" ] && RABBITMQ_NODENAME=${NODENAME} [ "x" = "x$RABBITMQ_CTL_ERL_ARGS" ] && RABBITMQ_CTL_ERL_ARGS=${CTL_ERL_ARGS} +##--- End of overridden variables + exec erl \ -pa "${RABBITMQ_HOME}/ebin" \ -noinput \ diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmqctl.bat rabbitmq-server-2.8.4/scripts/rabbitmqctl.bat --- rabbitmq-server-2.7.1/scripts/rabbitmqctl.bat 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmqctl.bat 2012-06-22 16:03:48.000000000 +0000 @@ -12,7 +12,7 @@ REM The Original Code is RabbitMQ. REM REM The Initial Developer of the Original Code is VMware, Inc. -REM Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +REM Copyright (c) 2007-2012 VMware, Inc. All rights reserved. REM setlocal diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-defaults rabbitmq-server-2.8.4/scripts/rabbitmq-defaults --- rabbitmq-server-2.7.1/scripts/rabbitmq-defaults 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-defaults 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,30 @@ +#!/bin/sh +## The contents of this file are subject to the Mozilla Public License +## Version 1.1 (the "License"); you may not use this file except in +## compliance with the License. You may obtain a copy of the License +## at http://www.mozilla.org/MPL/ +## +## Software distributed under the License is distributed on an "AS IS" +## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +## the License for the specific language governing rights and +## limitations under the License. +## +## The Original Code is RabbitMQ. +## +## The Initial Developer of the Original Code is VMware, Inc. +## Copyright (c) 2012 VMware, Inc. All rights reserved. +## + +### next line potentially updated in package install steps +SYS_PREFIX= + +## Set default values + +CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq +LOG_BASE=${SYS_PREFIX}/var/log/rabbitmq +MNESIA_BASE=${SYS_PREFIX}/var/lib/rabbitmq/mnesia +ENABLED_PLUGINS_FILE=${SYS_PREFIX}/etc/rabbitmq/enabled_plugins + +PLUGINS_DIR="${RABBITMQ_HOME}/plugins" + +CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-echopid.bat rabbitmq-server-2.8.4/scripts/rabbitmq-echopid.bat --- rabbitmq-server-2.7.1/scripts/rabbitmq-echopid.bat 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-echopid.bat 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,49 @@ +@echo off + +REM Usage: rabbitmq-echopid.bat +REM +REM sname of the erlang node to connect to (required) + +setlocal + +if "%1"=="" goto fail + +:: set timeout vars :: +set TIMEOUT=10 +set TIMER=1 + +:: check that wmic exists :: +set WMIC_PATH=%SYSTEMROOT%\System32\Wbem\wmic.exe +if not exist "%WMIC_PATH%" ( + goto fail +) + +:getpid +for /f "usebackq tokens=* skip=1" %%P IN (`%%WMIC_PATH%% process where "name='erl.exe' and commandline like '%%-sname %1%%'" get processid 2^>nul`) do ( + set PID=%%P + goto echopid +) + +:echopid +:: check for pid not found :: +if "%PID%" == "" ( + PING 127.0.0.1 -n 2 > nul + set /a TIMER+=1 + if %TIMEOUT%==%TIMER% goto fail + goto getpid +) + +:: show pid :: +echo %PID% + +:: all done :: +:ok +endlocal +EXIT /B 0 + +:: something went wrong :: +:fail +endlocal +EXIT /B 1 + + diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-env rabbitmq-server-2.8.4/scripts/rabbitmq-env --- rabbitmq-server-2.7.1/scripts/rabbitmq-env 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-env 2012-06-22 16:03:48.000000000 +0000 @@ -12,10 +12,11 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## -# Determine where this script is really located +# Determine where this script is really located (if this script is +# invoked from another script, this is the location of the caller) SCRIPT_PATH="$0" while [ -h "$SCRIPT_PATH" ] ; do FULL_PATH=`readlink -f $SCRIPT_PATH 2>/dev/null` @@ -36,10 +37,19 @@ [ "x" = "x$HOSTNAME" ] && HOSTNAME=`env hostname` NODENAME=rabbit@${HOSTNAME%%.*} -# Load configuration from the rabbitmq.conf file +## Set defaults +. ${SCRIPT_DIR}/rabbitmq-defaults + +## Common defaults +SERVER_ERL_ARGS="+K true +A30 +P 1048576 \ + -kernel inet_default_connect_options [{nodelay,true}]" + +# warn about old rabbitmq.conf file, if no new one if [ -f /etc/rabbitmq/rabbitmq.conf ] && \ - [ ! -f /etc/rabbitmq/rabbitmq-env.conf ] ; then + [ ! -f ${CONF_ENV_FILE} ] ; then echo -n "WARNING: ignoring /etc/rabbitmq/rabbitmq.conf -- " - echo "location has moved to /etc/rabbitmq/rabbitmq-env.conf" + echo "location has moved to ${CONF_ENV_FILE}" fi -[ -f /etc/rabbitmq/rabbitmq-env.conf ] && . /etc/rabbitmq/rabbitmq-env.conf + +## Get configuration variables from the configure environment file +[ -f ${CONF_ENV_FILE} ] && . ${CONF_ENV_FILE} diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-plugins rabbitmq-server-2.8.4/scripts/rabbitmq-plugins --- rabbitmq-server-2.7.1/scripts/rabbitmq-plugins 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-plugins 2012-06-22 16:03:48.000000000 +0000 @@ -12,16 +12,19 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## +# Get default settings with user overrides for (RABBITMQ_) +# Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env -ENABLED_PLUGINS_FILE=/etc/rabbitmq/enabled_plugins +##--- Set environment vars RABBITMQ_ to defaults if not set [ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=${ENABLED_PLUGINS_FILE} +[ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR=${PLUGINS_DIR} -[ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR="${RABBITMQ_HOME}/plugins" +##--- End of overridden variables exec erl \ -pa "${RABBITMQ_HOME}/ebin" \ diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-plugins.bat rabbitmq-server-2.8.4/scripts/rabbitmq-plugins.bat --- rabbitmq-server-2.7.1/scripts/rabbitmq-plugins.bat 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-plugins.bat 2012-06-22 16:03:48.000000000 +0000 @@ -12,7 +12,7 @@ REM The Original Code is RabbitMQ. REM REM The Initial Developer of the Original Code is VMware, Inc. -REM Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +REM Copyright (c) 2007-2012 VMware, Inc. All rights reserved. REM setlocal @@ -43,7 +43,9 @@ set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins ) -set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins +if "!RABBITMQ_PLUGINS_DIR!"=="" ( + set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins +) "!ERLANG_HOME!\bin\erl.exe" -pa "!TDP0!..\ebin" -noinput -hidden -sname rabbitmq-plugins!RANDOM! -s rabbit_plugins -enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" -plugins_dist_dir "!RABBITMQ_PLUGINS_DIR:\=/!" -extra !STAR! diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-server rabbitmq-server-2.8.4/scripts/rabbitmq-server --- rabbitmq-server-2.7.1/scripts/rabbitmq-server 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-server 2012-06-22 16:03:48.000000000 +0000 @@ -12,33 +12,23 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is VMware, Inc. -## Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +## Copyright (c) 2007-2012 VMware, Inc. All rights reserved. ## -SERVER_ERL_ARGS="+K true +A30 +P 1048576 \ --kernel inet_default_connect_options [{nodelay,true}]" -CONFIG_FILE=/etc/rabbitmq/rabbitmq -LOG_BASE=/var/log/rabbitmq -MNESIA_BASE=/var/lib/rabbitmq/mnesia -SERVER_START_ARGS= -ENABLED_PLUGINS_FILE=/etc/rabbitmq/enabled_plugins - +# Get default settings with user overrides for (RABBITMQ_) +# Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env +##--- Set environment vars RABBITMQ_ to defaults if not set + DEFAULT_NODE_IP_ADDRESS=auto DEFAULT_NODE_PORT=5672 -[ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" != "x$NODE_IP_ADDRESS" ] && RABBITMQ_NODE_IP_ADDRESS=${NODE_IP_ADDRESS} -[ "x" = "x$RABBITMQ_NODE_PORT" ] && [ "x" != "x$NODE_PORT" ] && RABBITMQ_NODE_PORT=${NODE_PORT} -if [ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] -then - if [ "x" != "x$RABBITMQ_NODE_PORT" ] - then RABBITMQ_NODE_IP_ADDRESS=${DEFAULT_NODE_IP_ADDRESS} - fi -else - if [ "x" = "x$RABBITMQ_NODE_PORT" ] - then RABBITMQ_NODE_PORT=${DEFAULT_NODE_PORT} - fi -fi +[ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_NODE_IP_ADDRESS=${NODE_IP_ADDRESS} +[ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_PORT=${NODE_PORT} + +[ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" != "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_IP_ADDRESS=${DEFAULT_NODE_IP_ADDRESS} +[ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_PORT=${DEFAULT_NODE_PORT} + [ "x" = "x$RABBITMQ_NODENAME" ] && RABBITMQ_NODENAME=${NODENAME} [ "x" = "x$RABBITMQ_SERVER_ERL_ARGS" ] && RABBITMQ_SERVER_ERL_ARGS=${SERVER_ERL_ARGS} [ "x" = "x$RABBITMQ_CONFIG_FILE" ] && RABBITMQ_CONFIG_FILE=${CONFIG_FILE} @@ -48,13 +38,16 @@ [ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${MNESIA_DIR} [ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME} + +[ "x" = "x$RABBITMQ_PID_FILE" ] && RABBITMQ_PID_FILE=${PID_FILE} [ "x" = "x$RABBITMQ_PID_FILE" ] && RABBITMQ_PID_FILE=${RABBITMQ_MNESIA_DIR}.pid [ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${PLUGINS_EXPAND_DIR} [ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-plugins-expand [ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=${ENABLED_PLUGINS_FILE} -[ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR="${RABBITMQ_HOME}/plugins" + +[ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR=${PLUGINS_DIR} ## Log rotation [ "x" = "x$RABBITMQ_LOGS" ] && RABBITMQ_LOGS=${LOGS} @@ -62,6 +55,8 @@ [ "x" = "x$RABBITMQ_SASL_LOGS" ] && RABBITMQ_SASL_LOGS=${SASL_LOGS} [ "x" = "x$RABBITMQ_SASL_LOGS" ] && RABBITMQ_SASL_LOGS="${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}-sasl.log" +##--- End of overridden variables + RABBITMQ_START_RABBIT= [ "x" = "x$RABBITMQ_ALLOW_INPUT" ] && RABBITMQ_START_RABBIT='-noinput' @@ -117,7 +112,7 @@ -sasl sasl_error_logger false \ -rabbit error_logger '{file,"'${RABBITMQ_LOGS}'"}' \ -rabbit sasl_error_logger '{file,"'${RABBITMQ_SASL_LOGS}'"}' \ - -os_mon start_cpu_sup true \ + -os_mon start_cpu_sup false \ -os_mon start_disksup false \ -os_mon start_memsup false \ -mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \ diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-server.bat rabbitmq-server-2.8.4/scripts/rabbitmq-server.bat --- rabbitmq-server-2.7.1/scripts/rabbitmq-server.bat 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-server.bat 2012-06-22 16:03:48.000000000 +0000 @@ -12,7 +12,7 @@ REM The Original Code is RabbitMQ. REM REM The Initial Developer of the Original Code is VMware, Inc. -REM Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +REM Copyright (c) 2007-2012 VMware, Inc. All rights reserved. REM setlocal @@ -86,7 +86,10 @@ set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins ) -set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins +if "!RABBITMQ_PLUGINS_DIR!"=="" ( + set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins +) + set RABBITMQ_EBIN_ROOT=!TDP0!..\ebin "!ERLANG_HOME!\bin\erl.exe" ^ @@ -139,7 +142,7 @@ -sasl sasl_error_logger false ^ -rabbit error_logger {file,\""!LOGS:\=/!"\"} ^ -rabbit sasl_error_logger {file,\""!SASL_LOGS:\=/!"\"} ^ --os_mon start_cpu_sup true ^ +-os_mon start_cpu_sup false ^ -os_mon start_disksup false ^ -os_mon start_memsup false ^ -mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^ diff -Nru rabbitmq-server-2.7.1/scripts/rabbitmq-service.bat rabbitmq-server-2.8.4/scripts/rabbitmq-service.bat --- rabbitmq-server-2.7.1/scripts/rabbitmq-service.bat 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/scripts/rabbitmq-service.bat 2012-06-22 16:03:48.000000000 +0000 @@ -12,7 +12,7 @@ REM The Original Code is RabbitMQ. REM REM The Initial Developer of the Original Code is VMware, Inc. -REM Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +REM Copyright (c) 2007-2012 VMware, Inc. All rights reserved. REM setlocal @@ -204,7 +204,7 @@ -sasl sasl_error_logger false ^ -rabbit error_logger {file,\""!LOGS:\=/!"\"} ^ -rabbit sasl_error_logger {file,\""!SASL_LOGS:\=/!"\"} ^ --os_mon start_cpu_sup true ^ +-os_mon start_cpu_sup false ^ -os_mon start_disksup false ^ -os_mon start_memsup false ^ -mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^ diff -Nru rabbitmq-server-2.7.1/src/credit_flow.erl rabbitmq-server-2.8.4/src/credit_flow.erl --- rabbitmq-server-2.7.1/src/credit_flow.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/credit_flow.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,128 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(credit_flow). + +%% Credit flow is controlled by a credit specification - a +%% {InitialCredit, MoreCreditAfter} tuple. For the message sender, +%% credit starts at InitialCredit and is decremented with every +%% message sent. The message receiver grants more credit to the sender +%% by sending it a {bump_credit, ...} control message after receiving +%% MoreCreditAfter messages. The sender should pass this message in to +%% handle_bump_msg/1. The sender should block when it goes below 0 +%% (check by invoking blocked/0). If a process is both a sender and a +%% receiver it will not grant any more credit to its senders when it +%% is itself blocked - thus the only processes that need to check +%% blocked/0 are ones that read from network sockets. + +-define(DEFAULT_CREDIT, {200, 50}). + +-export([send/1, send/2, ack/1, ack/2, handle_bump_msg/1, blocked/0]). +-export([peer_down/1]). + +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-opaque(bump_msg() :: {pid(), non_neg_integer()}). +-type(credit_spec() :: {non_neg_integer(), non_neg_integer()}). + +-spec(send/1 :: (pid()) -> 'ok'). +-spec(send/2 :: (pid(), credit_spec()) -> 'ok'). +-spec(ack/1 :: (pid()) -> 'ok'). +-spec(ack/2 :: (pid(), credit_spec()) -> 'ok'). +-spec(handle_bump_msg/1 :: (bump_msg()) -> 'ok'). +-spec(blocked/0 :: () -> boolean()). +-spec(peer_down/1 :: (pid()) -> 'ok'). + +-endif. + +%%---------------------------------------------------------------------------- + +%% There are two "flows" here; of messages and of credit, going in +%% opposite directions. The variable names "From" and "To" refer to +%% the flow of credit, but the function names refer to the flow of +%% messages. This is the clearest I can make it (since the function +%% names form the API and want to make sense externally, while the +%% variable names are used in credit bookkeeping and want to make +%% sense internally). + +%% For any given pair of processes, ack/2 and send/2 must always be +%% called with the same credit_spec(). + +send(From) -> send(From, ?DEFAULT_CREDIT). + +send(From, {InitialCredit, _MoreCreditAfter}) -> + update({credit_from, From}, InitialCredit, + fun (1) -> block(From), + 0; + (C) -> C - 1 + end). + +ack(To) -> ack(To, ?DEFAULT_CREDIT). + +ack(To, {_InitialCredit, MoreCreditAfter}) -> + update({credit_to, To}, MoreCreditAfter, + fun (1) -> grant(To, MoreCreditAfter), + MoreCreditAfter; + (C) -> C - 1 + end). + +handle_bump_msg({From, MoreCredit}) -> + update({credit_from, From}, 0, + fun (C) when C =< 0 andalso C + MoreCredit > 0 -> unblock(From), + C + MoreCredit; + (C) -> C + MoreCredit + end). + +blocked() -> get(credit_blocked, []) =/= []. + +peer_down(Peer) -> + %% In theory we could also remove it from credit_deferred here, but it + %% doesn't really matter; at some point later we will drain + %% credit_deferred and thus send messages into the void... + unblock(Peer), + erase({credit_from, Peer}), + erase({credit_to, Peer}), + ok. + +%% -------------------------------------------------------------------------- + +grant(To, Quantity) -> + Msg = {bump_credit, {self(), Quantity}}, + case blocked() of + false -> To ! Msg; + true -> update(credit_deferred, [], + fun (Deferred) -> [{To, Msg} | Deferred] end) + end. + +block(From) -> update(credit_blocked, [], fun (Blocks) -> [From | Blocks] end). + +unblock(From) -> + update(credit_blocked, [], fun (Blocks) -> Blocks -- [From] end), + case blocked() of + false -> [To ! Msg || {To, Msg} <- get(credit_deferred, [])], + erase(credit_deferred); + true -> ok + end. + +get(Key, Default) -> + case get(Key) of + undefined -> Default; + Value -> Value + end. + +update(Key, Default, Fun) -> put(Key, Fun(get(Key, Default))), ok. diff -Nru rabbitmq-server-2.7.1/src/delegate.erl rabbitmq-server-2.8.4/src/delegate.erl --- rabbitmq-server-2.7.1/src/delegate.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/delegate.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(delegate). diff -Nru rabbitmq-server-2.7.1/src/delegate_sup.erl rabbitmq-server-2.8.4/src/delegate_sup.erl --- rabbitmq-server-2.7.1/src/delegate_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/delegate_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(delegate_sup). diff -Nru rabbitmq-server-2.7.1/src/dtree.erl rabbitmq-server-2.8.4/src/dtree.erl --- rabbitmq-server-2.7.1/src/dtree.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/dtree.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,163 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +%% A dual-index tree. +%% +%% Entries have the following shape: +%% +%% +----+--------------------+---+ +%% | PK | SK1, SK2, ..., SKN | V | +%% +----+--------------------+---+ +%% +%% i.e. a primary key, set of secondary keys, and a value. +%% +%% There can be only one entry per primary key, but secondary keys may +%% appear in multiple entries. +%% +%% The set of secondary keys must be non-empty. Or, to put it another +%% way, entries only exist while their secondary key set is non-empty. + +-module(dtree). + +-export([empty/0, insert/4, take/3, take/2, take_all/2, + is_defined/2, is_empty/1, smallest/1, size/1]). + +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-export_type([?MODULE/0]). + +-opaque(?MODULE() :: {gb_tree(), gb_tree()}). + +-type(pk() :: any()). +-type(sk() :: any()). +-type(val() :: any()). +-type(kv() :: {pk(), val()}). + +-spec(empty/0 :: () -> ?MODULE()). +-spec(insert/4 :: (pk(), [sk()], val(), ?MODULE()) -> ?MODULE()). +-spec(take/3 :: ([pk()], sk(), ?MODULE()) -> {[kv()], ?MODULE()}). +-spec(take/2 :: (sk(), ?MODULE()) -> {[kv()], ?MODULE()}). +-spec(take_all/2 :: (sk(), ?MODULE()) -> {[kv()], ?MODULE()}). +-spec(is_defined/2 :: (sk(), ?MODULE()) -> boolean()). +-spec(is_empty/1 :: (?MODULE()) -> boolean()). +-spec(smallest/1 :: (?MODULE()) -> kv()). +-spec(size/1 :: (?MODULE()) -> non_neg_integer()). + +-endif. + +%%---------------------------------------------------------------------------- + +empty() -> {gb_trees:empty(), gb_trees:empty()}. + +%% Insert an entry. Fails if there already is an entry with the given +%% primary key. +insert(PK, [], V, {P, S}) -> + %% dummy insert to force error if PK exists + gb_trees:insert(PK, {gb_sets:empty(), V}, P), + {P, S}; +insert(PK, SKs, V, {P, S}) -> + {gb_trees:insert(PK, {gb_sets:from_list(SKs), V}, P), + lists:foldl(fun (SK, S0) -> + case gb_trees:lookup(SK, S0) of + {value, PKS} -> PKS1 = gb_sets:insert(PK, PKS), + gb_trees:update(SK, PKS1, S0); + none -> PKS = gb_sets:singleton(PK), + gb_trees:insert(SK, PKS, S0) + end + end, S, SKs)}. + +%% Remove the given secondary key from the entries of the given +%% primary keys, returning the primary-key/value pairs of any entries +%% that were dropped as the result (i.e. due to their secondary key +%% set becoming empty). It is ok for the given primary keys and/or +%% secondary key to not exist. +take(PKs, SK, {P, S}) -> + case gb_trees:lookup(SK, S) of + none -> {[], {P, S}}; + {value, PKS} -> TakenPKS = gb_sets:from_list(PKs), + PKSInter = gb_sets:intersection(PKS, TakenPKS), + PKSDiff = gb_sets_difference (PKS, PKSInter), + {KVs, P1} = take2(PKSInter, SK, P), + {KVs, {P1, case gb_sets:is_empty(PKSDiff) of + true -> gb_trees:delete(SK, S); + false -> gb_trees:update(SK, PKSDiff, S) + end}} + end. + +%% Remove the given secondary key from all entries, returning the +%% primary-key/value pairs of any entries that were dropped as the +%% result (i.e. due to their secondary key set becoming empty). It is +%% ok for the given secondary key to not exist. +take(SK, {P, S}) -> + case gb_trees:lookup(SK, S) of + none -> {[], {P, S}}; + {value, PKS} -> {KVs, P1} = take2(PKS, SK, P), + {KVs, {P1, gb_trees:delete(SK, S)}} + end. + +%% Drop all entries which contain the given secondary key, returning +%% the primary-key/value pairs of these entries. It is ok for the +%% given secondary key to not exist. +take_all(SK, {P, S}) -> + case gb_trees:lookup(SK, S) of + none -> {[], {P, S}}; + {value, PKS} -> {KVs, SKS, P1} = take_all2(PKS, P), + {KVs, {P1, prune(SKS, PKS, S)}} + end. + +is_defined(SK, {_P, S}) -> gb_trees:is_defined(SK, S). + +is_empty({P, _S}) -> gb_trees:is_empty(P). + +smallest({P, _S}) -> {K, {_SKS, V}} = gb_trees:smallest(P), + {K, V}. + +size({P, _S}) -> gb_trees:size(P). + +%%---------------------------------------------------------------------------- + +take2(PKS, SK, P) -> + gb_sets:fold(fun (PK, {KVs, P0}) -> + {SKS, V} = gb_trees:get(PK, P0), + SKS1 = gb_sets:delete(SK, SKS), + case gb_sets:is_empty(SKS1) of + true -> KVs1 = [{PK, V} | KVs], + {KVs1, gb_trees:delete(PK, P0)}; + false -> {KVs, gb_trees:update(PK, {SKS1, V}, P0)} + end + end, {[], P}, PKS). + +take_all2(PKS, P) -> + gb_sets:fold(fun (PK, {KVs, SKS0, P0}) -> + {SKS, V} = gb_trees:get(PK, P0), + {[{PK, V} | KVs], gb_sets:union(SKS, SKS0), + gb_trees:delete(PK, P0)} + end, {[], gb_sets:empty(), P}, PKS). + +prune(SKS, PKS, S) -> + gb_sets:fold(fun (SK0, S0) -> + PKS1 = gb_trees:get(SK0, S0), + PKS2 = gb_sets_difference(PKS1, PKS), + case gb_sets:is_empty(PKS2) of + true -> gb_trees:delete(SK0, S0); + false -> gb_trees:update(SK0, PKS2, S0) + end + end, S, SKS). + +gb_sets_difference(S1, S2) -> + gb_sets:fold(fun gb_sets:delete_any/2, S1, S2). diff -Nru rabbitmq-server-2.7.1/src/file_handle_cache.erl rabbitmq-server-2.8.4/src/file_handle_cache.erl --- rabbitmq-server-2.7.1/src/file_handle_cache.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/file_handle_cache.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(file_handle_cache). @@ -125,8 +125,7 @@ %% requesting process is considered to 'own' one more %% descriptor. release/0 is the inverse operation and releases a %% previously obtained descriptor. transfer/1 transfers ownership of a -%% file descriptor between processes. It is non-blocking. Obtain is -%% used to obtain permission to accept file descriptors. Obtain has a +%% file descriptor between processes. It is non-blocking. Obtain has a %% lower limit, set by the ?OBTAIN_LIMIT/1 macro. File handles can use %% the entire limit, but will be evicted by obtain calls up to the %% point at which no more obtain calls can be satisfied by the obtains @@ -144,9 +143,9 @@ -behaviour(gen_server2). -export([register_callback/3]). --export([open/3, close/1, read/2, append/2, sync/1, position/2, truncate/1, - current_virtual_offset/1, current_raw_offset/1, flush/1, copy/3, - set_maximum_since_use/1, delete/1, clear/1]). +-export([open/3, close/1, read/2, append/2, needs_sync/1, sync/1, position/2, + truncate/1, current_virtual_offset/1, current_raw_offset/1, flush/1, + copy/3, set_maximum_since_use/1, delete/1, clear/1]). -export([obtain/0, release/0, transfer/1, set_limit/1, get_limit/0, info_keys/0, info/0, info/1]). -export([ulimit/0]). @@ -262,7 +261,7 @@ -endif. %%---------------------------------------------------------------------------- --define(INFO_KEYS, [obtain_count, obtain_limit]). +-define(INFO_KEYS, [total_limit, total_used, sockets_limit, sockets_used]). %%---------------------------------------------------------------------------- %% Public API @@ -374,6 +373,13 @@ end end). +needs_sync(Ref) -> + with_handles( + [Ref], + fun ([#handle { is_dirty = false, write_buffer = [] }]) -> false; + ([_Handle]) -> true + end). + position(Ref, NewOffset) -> with_flushed_handles( [Ref], @@ -790,8 +796,10 @@ infos(Items, State) -> [{Item, i(Item, State)} || Item <- Items]. -i(obtain_count, #fhc_state{obtain_count = Count}) -> Count; -i(obtain_limit, #fhc_state{obtain_limit = Limit}) -> Limit; +i(total_limit, #fhc_state{limit = Limit}) -> Limit; +i(total_used, #fhc_state{open_count = C1, obtain_count = C2}) -> C1 + C2; +i(sockets_limit, #fhc_state{obtain_limit = Limit}) -> Limit; +i(sockets_used, #fhc_state{obtain_count = Count}) -> Count; i(Item, _) -> throw({bad_argument, Item}). %%---------------------------------------------------------------------------- diff -Nru rabbitmq-server-2.7.1/src/gatherer.erl rabbitmq-server-2.8.4/src/gatherer.erl --- rabbitmq-server-2.7.1/src/gatherer.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/gatherer.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(gatherer). diff -Nru rabbitmq-server-2.7.1/src/gen_server2.erl rabbitmq-server-2.8.4/src/gen_server2.erl --- rabbitmq-server-2.7.1/src/gen_server2.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/gen_server2.erl 2012-06-22 16:03:48.000000000 +0000 @@ -31,13 +31,13 @@ %% handle_pre_hibernate/1 then the default action is to hibernate. %% %% 6) init can return a 4th arg, {backoff, InitialTimeout, -%% MinimumTimeout, DesiredHibernatePeriod} (all in -%% milliseconds). Then, on all callbacks which can return a timeout -%% (including init), timeout can be 'hibernate'. When this is the -%% case, the current timeout value will be used (initially, the -%% InitialTimeout supplied from init). After this timeout has -%% occurred, hibernation will occur as normal. Upon awaking, a new -%% current timeout value will be calculated. +%% MinimumTimeout, DesiredHibernatePeriod} (all in milliseconds, +%% 'infinity' does not make sense here). Then, on all callbacks which +%% can return a timeout (including init), timeout can be +%% 'hibernate'. When this is the case, the current timeout value will +%% be used (initially, the InitialTimeout supplied from init). After +%% this timeout has occurred, hibernation will occur as normal. Upon +%% awaking, a new current timeout value will be calculated. %% %% The purpose is that the gen_server2 takes care of adjusting the %% current timeout value such that the process will increase the @@ -73,7 +73,7 @@ %% but where the second argument is specifically the priority_queue %% which contains the prioritised message_queue. -%% All modifications are (C) 2009-2011 VMware, Inc. +%% All modifications are (C) 2009-2012 VMware, Inc. %% ``The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -135,9 +135,10 @@ %%% Reason = normal | shutdown | Term, terminate(State) is called %%% %%% terminate(Reason, State) Let the user module clean up +%%% Reason = normal | shutdown | {shutdown, Term} | Term %%% always called when server terminates %%% -%%% ==> ok +%%% ==> ok | Term %%% %%% handle_pre_hibernate(State) %%% @@ -182,8 +183,6 @@ multi_call/2, multi_call/3, multi_call/4, enter_loop/3, enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/1]). --export([behaviour_info/1]). - %% System exports -export([system_continue/3, system_terminate/4, @@ -200,12 +199,12 @@ timeout_state, queue, debug, prioritise_call, prioritise_cast, prioritise_info}). +-ifdef(use_specs). + %%%========================================================================= %%% Specs. These exist only to shut up dialyzer's warnings %%%========================================================================= --ifdef(use_specs). - -type(gs2_state() :: #gs2_state{}). -spec(handle_common_termination/3 :: @@ -214,18 +213,58 @@ -spec(pre_hibernate/1 :: (gs2_state()) -> no_return()). -spec(system_terminate/4 :: (_, _, _, gs2_state()) -> no_return()). --endif. +-type(millis() :: non_neg_integer()). %%%========================================================================= %%% API %%%========================================================================= +-callback init(Args :: term()) -> + {ok, State :: term()} | + {ok, State :: term(), timeout() | hibernate} | + {ok, State :: term(), timeout() | hibernate, + {backoff, millis(), millis(), millis()}} | + ignore | + {stop, Reason :: term()}. +-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: term()) -> + {reply, Reply :: term(), NewState :: term()} | + {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), + Reply :: term(), NewState :: term()}. +-callback handle_cast(Request :: term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_info(Info :: term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: term()) -> + ok | term(). +-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), + Extra :: term()) -> + {ok, NewState :: term()} | {error, Reason :: term()}. + +%% It's not possible to define "optional" -callbacks, so putting specs +%% for handle_pre_hibernate/1 and handle_post_hibernate/1 will result +%% in warnings (the same applied for the behaviour_info before). + +-else. + +-export([behaviour_info/1]). + behaviour_info(callbacks) -> [{init,1},{handle_call,3},{handle_cast,2},{handle_info,2}, {terminate,2},{code_change,3}]; behaviour_info(_Other) -> undefined. +-endif. + %%% ----------------------------------------------------------------- %%% Starts a generic server. %%% start(Mod, Args, Options) diff -Nru rabbitmq-server-2.7.1/src/gm.erl rabbitmq-server-2.8.4/src/gm.erl --- rabbitmq-server-2.7.1/src/gm.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/gm.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(gm). @@ -57,8 +57,8 @@ %% you wish to be passed into the callback module's functions. The %% joined/2 function will be called when we have joined the group, %% with the arguments passed to start_link and a list of the current -%% members of the group. See the comments in behaviour_info/1 below -%% for further details of the callback functions. +%% members of the group. See the callbacks specs and the comments +%% below for further details of the callback functions. %% %% leave/1 %% Provide the Pid. Removes the Pid from the group. The callback @@ -378,7 +378,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, prioritise_info/2]). +-ifndef(use_specs). -export([behaviour_info/1]). +-endif. -export([table_definitions/0]). @@ -431,56 +433,63 @@ -spec(confirmed_broadcast/2 :: (pid(), any()) -> 'ok'). -spec(group_members/1 :: (pid()) -> [pid()]). --endif. +%% The joined, members_changed and handle_msg callbacks can all +%% return any of the following terms: +%% +%% 'ok' - the callback function returns normally +%% +%% {'stop', Reason} - the callback indicates the member should +%% stop with reason Reason and should leave the group. +%% +%% {'become', Module, Args} - the callback indicates that the +%% callback module should be changed to Module and that the +%% callback functions should now be passed the arguments +%% Args. This allows the callback module to be dynamically +%% changed. + +%% Called when we've successfully joined the group. Supplied with +%% Args provided in start_link, plus current group members. +-callback joined(Args :: term(), Members :: [pid()]) -> + ok | {stop, Reason :: term()} | {become, Module :: atom(), Args :: any()}. + +%% Supplied with Args provided in start_link, the list of new +%% members and the list of members previously known to us that +%% have since died. Note that if a member joins and dies very +%% quickly, it's possible that we will never see that member +%% appear in either births or deaths. However we are guaranteed +%% that (1) we will see a member joining either in the births +%% here, or in the members passed to joined/2 before receiving +%% any messages from it; and (2) we will not see members die that +%% we have not seen born (or supplied in the members to +%% joined/2). +-callback members_changed(Args :: term(), Births :: [pid()], + Deaths :: [pid()]) -> + ok | {stop, Reason :: term()} | {become, Module :: atom(), Args :: any()}. + +%% Supplied with Args provided in start_link, the sender, and the +%% message. This does get called for messages injected by this +%% member, however, in such cases, there is no special +%% significance of this invocation: it does not indicate that the +%% message has made it to any other members, let alone all other +%% members. +-callback handle_msg(Args :: term(), From :: pid(), Message :: term()) -> + ok | {stop, Reason :: term()} | {become, Module :: atom(), Args :: any()}. + +%% Called on gm member termination as per rules in gen_server, +%% with the Args provided in start_link plus the termination +%% Reason. +-callback terminate(Args :: term(), Reason :: term()) -> + ok | term(). + +-else. behaviour_info(callbacks) -> - [ - %% The joined, members_changed and handle_msg callbacks can all - %% return any of the following terms: - %% - %% 'ok' - the callback function returns normally - %% - %% {'stop', Reason} - the callback indicates the member should - %% stop with reason Reason and should leave the group. - %% - %% {'become', Module, Args} - the callback indicates that the - %% callback module should be changed to Module and that the - %% callback functions should now be passed the arguments - %% Args. This allows the callback module to be dynamically - %% changed. - - %% Called when we've successfully joined the group. Supplied with - %% Args provided in start_link, plus current group members. - {joined, 2}, - - %% Supplied with Args provided in start_link, the list of new - %% members and the list of members previously known to us that - %% have since died. Note that if a member joins and dies very - %% quickly, it's possible that we will never see that member - %% appear in either births or deaths. However we are guaranteed - %% that (1) we will see a member joining either in the births - %% here, or in the members passed to joined/2 before receiving - %% any messages from it; and (2) we will not see members die that - %% we have not seen born (or supplied in the members to - %% joined/2). - {members_changed, 3}, - - %% Supplied with Args provided in start_link, the sender, and the - %% message. This does get called for messages injected by this - %% member, however, in such cases, there is no special - %% significance of this invocation: it does not indicate that the - %% message has made it to any other members, let alone all other - %% members. - {handle_msg, 3}, - - %% Called on gm member termination as per rules in gen_server, - %% with the Args provided in start_link plus the termination - %% Reason. - {terminate, 2} - ]; + [{joined, 2}, {members_changed, 3}, {handle_msg, 3}, {terminate, 2}]; behaviour_info(_Other) -> undefined. +-endif. + create_tables() -> create_tables([?TABLE]). @@ -524,7 +533,7 @@ group_name = GroupName, module = Module, view = undefined, - pub_count = 0, + pub_count = -1, members_state = undefined, callback_args = Args, confirms = queue:new(), @@ -566,33 +575,39 @@ members_state = MembersState, module = Module, callback_args = Args }) -> - Group = record_new_member_in_group( - GroupName, Self, NewMember, - fun (Group1) -> - View1 = group_to_view(Group1), - ok = send_right(NewMember, View1, - {catchup, Self, prepare_members_state( - MembersState)}) - end), + {MembersState1, Group} = + record_new_member_in_group( + GroupName, Self, NewMember, + fun (Group1) -> + View1 = group_to_view(Group1), + MembersState1 = remove_erased_members(MembersState, View1), + ok = send_right(NewMember, View1, + {catchup, Self, + prepare_members_state(MembersState1)}), + MembersState1 + end), View2 = group_to_view(Group), - State1 = check_neighbours(State #state { view = View2 }), + State1 = check_neighbours(State #state { view = View2, + members_state = MembersState1 }), Result = callback_view_changed(Args, Module, View, View2), handle_callback_result({Result, {ok, Group}, State1}). handle_cast({?TAG, ReqVer, Msg}, State = #state { view = View, + members_state = MembersState, group_name = GroupName, module = Module, callback_args = Args }) -> {Result, State1} = case needs_view_update(ReqVer, View) of - true -> - View1 = group_to_view(read_group(GroupName)), - {callback_view_changed(Args, Module, View, View1), - check_neighbours(State #state { view = View1 })}; - false -> - {ok, State} + true -> View1 = group_to_view(read_group(GroupName)), + MemberState1 = remove_erased_members(MembersState, View1), + {callback_view_changed(Args, Module, View, View1), + check_neighbours( + State #state { view = View1, + members_state = MemberState1 })}; + false -> {ok, State} end, handle_callback_result( if_callback_success( @@ -656,22 +671,21 @@ _ -> View1 = group_to_view(record_dead_member_in_group(Member, GroupName)), - State1 = State #state { view = View1 }, {Result, State2} = case alive_view_members(View1) of [Self] -> - maybe_erase_aliases( - State1 #state { + {Result1, State1} = maybe_erase_aliases(State, View1), + {Result1, State1 #state { members_state = blank_member_state(), - confirms = purge_confirms(Confirms) }); + confirms = purge_confirms(Confirms) }}; _ -> %% here we won't be pointing out any deaths: %% the concern is that there maybe births %% which we'd otherwise miss. {callback_view_changed(Args, Module, View, View1), - State1} + check_neighbours(State #state { view = View1 })} end, - handle_callback_result({Result, check_neighbours(State2)}) + handle_callback_result({Result, State2}) end. @@ -684,9 +698,13 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. -prioritise_info(flush, _State) -> 1; -prioritise_info({'DOWN', _MRef, process, _Pid, _Reason}, _State) -> 1; -prioritise_info(_ , _State) -> 0. +prioritise_info(flush, _State) -> + 1; +prioritise_info({'DOWN', _MRef, process, _Pid, _Reason}, + #state { members_state = MS }) when MS /= undefined -> + 1; +prioritise_info(_, _State) -> + 0. handle_msg(check_neighbours, State) -> @@ -786,8 +804,8 @@ State1 = State #state { members_state = MembersState1, confirms = Confirms1 }, Activity3 = activity_finalise(Activity1), - {Result, State2} = maybe_erase_aliases(State1), - ok = maybe_send_activity(Activity3, State2), + ok = maybe_send_activity(Activity3, State1), + {Result, State2} = maybe_erase_aliases(State1, View), if_callback_success( Result, fun activity_true/3, fun activity_false/3, Activity3, State2); @@ -820,13 +838,14 @@ confirms = Confirms, callback_args = Args, broadcast_buffer = Buffer }) -> + PubCount1 = PubCount + 1, Result = Module:handle_msg(Args, get_pid(Self), Msg), - Buffer1 = [{PubCount, Msg} | Buffer], + Buffer1 = [{PubCount1, Msg} | Buffer], Confirms1 = case From of none -> Confirms; - _ -> queue:in({PubCount, From}, Confirms) + _ -> queue:in({PubCount1, From}, Confirms) end, - State1 = State #state { pub_count = PubCount + 1, + State1 = State #state { pub_count = PubCount1, confirms = Confirms1, broadcast_buffer = Buffer1 }, case From =/= none of @@ -841,14 +860,17 @@ State; flush_broadcast_buffer(State = #state { self = Self, members_state = MembersState, - broadcast_buffer = Buffer }) -> + broadcast_buffer = Buffer, + pub_count = PubCount }) -> + [{PubCount, _Msg}|_] = Buffer, %% ASSERTION match on PubCount Pubs = lists:reverse(Buffer), Activity = activity_cons(Self, Pubs, [], activity_nil()), ok = maybe_send_activity(activity_finalise(Activity), State), MembersState1 = with_member( fun (Member = #member { pending_ack = PA }) -> PA1 = queue:join(PA, queue:from_list(Pubs)), - Member #member { pending_ack = PA1 } + Member #member { pending_ack = PA1, + last_pub = PubCount } end, Self, MembersState), State #state { members_state = MembersState1, broadcast_buffer = [] }. @@ -1043,7 +1065,7 @@ Group. record_new_member_in_group(GroupName, Left, NewMember, Fun) -> - {atomic, Group} = + {atomic, {Result, Group}} = mnesia:sync_transaction( fun () -> [#gm_group { members = Members, version = Ver } = Group1] = @@ -1053,11 +1075,11 @@ Members1 = Prefix ++ [Left, NewMember | Suffix], Group2 = Group1 #gm_group { members = Members1, version = Ver + 1 }, - ok = Fun(Group2), + Result = Fun(Group2), mnesia:write(Group2), - Group2 + {Result, Group2} end), - Group. + {Result, Group}. erase_members_in_group(Members, GroupName) -> DeadMembers = [{dead, Id} || Id <- Members], @@ -1080,10 +1102,10 @@ maybe_erase_aliases(State = #state { self = Self, group_name = GroupName, - view = View, + view = View0, members_state = MembersState, module = Module, - callback_args = Args }) -> + callback_args = Args }, View) -> #view_member { aliases = Aliases } = fetch_view_member(Self, View), {Erasable, MembersState1} = ?SETS:fold( @@ -1098,11 +1120,11 @@ end, {[], MembersState}, Aliases), State1 = State #state { members_state = MembersState1 }, case Erasable of - [] -> {ok, State1}; + [] -> {ok, State1 #state { view = View }}; _ -> View1 = group_to_view( erase_members_in_group(Erasable, GroupName)), - {callback_view_changed(Args, Module, View, View1), - State1 #state { view = View1 }} + {callback_view_changed(Args, Module, View0, View1), + check_neighbours(State1 #state { view = View1 })} end. can_erase_view_member(Self, Self, _LA, _LP) -> false; @@ -1248,6 +1270,12 @@ {error, not_found} -> ?VERSION_START end, self()}. +remove_erased_members(MembersState, View) -> + lists:foldl(fun (Id, MembersState1) -> + store_member(Id, find_member_or_blank(Id, MembersState), + MembersState1) + end, blank_member_state(), all_known_members(View)). + get_pid({_Version, Pid}) -> Pid. get_pids(Ids) -> [Pid || {_Version, Pid} <- Ids]. @@ -1278,16 +1306,30 @@ ok = gen_server2:cast(get_pid(Right), {?TAG, view_version(View), Msg}). callback(Args, Module, Activity) -> - lists:foldl( - fun ({Id, Pubs, _Acks}, ok) -> - lists:foldl(fun ({_PubNum, Pub}, ok) -> - Module:handle_msg(Args, get_pid(Id), Pub); - (_, Error) -> - Error - end, ok, Pubs); - (_, Error) -> - Error - end, ok, Activity). + Result = + lists:foldl( + fun ({Id, Pubs, _Acks}, {Args1, Module1, ok}) -> + lists:foldl(fun ({_PubNum, Pub}, Acc = {Args2, Module2, ok}) -> + case Module2:handle_msg( + Args2, get_pid(Id), Pub) of + ok -> + Acc; + {become, Module3, Args3} -> + {Args3, Module3, ok}; + {stop, _Reason} = Error -> + Error + end; + (_, Error = {stop, _Reason}) -> + Error + end, {Args1, Module1, ok}, Pubs); + (_, Error = {stop, _Reason}) -> + Error + end, {Args, Module, ok}, Activity), + case Result of + {Args, Module, ok} -> ok; + {Args1, Module1, ok} -> {become, Module1, Args1}; + {stop, _Reason} = Error -> Error + end. callback_view_changed(Args, Module, OldView, NewView) -> OldMembers = all_known_members(OldView), diff -Nru rabbitmq-server-2.7.1/src/gm_soak_test.erl rabbitmq-server-2.8.4/src/gm_soak_test.erl --- rabbitmq-server-2.7.1/src/gm_soak_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/gm_soak_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(gm_soak_test). diff -Nru rabbitmq-server-2.7.1/src/gm_speed_test.erl rabbitmq-server-2.8.4/src/gm_speed_test.erl --- rabbitmq-server-2.7.1/src/gm_speed_test.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/gm_speed_test.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(gm_speed_test). diff -Nru rabbitmq-server-2.7.1/src/gm_tests.erl rabbitmq-server-2.8.4/src/gm_tests.erl --- rabbitmq-server-2.7.1/src/gm_tests.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/gm_tests.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(gm_tests). diff -Nru rabbitmq-server-2.7.1/src/lqueue.erl rabbitmq-server-2.8.4/src/lqueue.erl --- rabbitmq-server-2.7.1/src/lqueue.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/lqueue.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(lqueue). diff -Nru rabbitmq-server-2.7.1/src/mirrored_supervisor.erl rabbitmq-server-2.8.4/src/mirrored_supervisor.erl --- rabbitmq-server-2.7.1/src/mirrored_supervisor.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/mirrored_supervisor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(mirrored_supervisor). @@ -120,8 +120,6 @@ delete_child/2, terminate_child/2, which_children/1, count_children/1, check_childspecs/1]). --export([behaviour_info/1]). - -behaviour(?GEN_SERVER). -behaviour(?SUPERVISOR). @@ -142,34 +140,24 @@ -ifdef(use_specs). --type child() :: pid() | 'undefined'. --type child_id() :: term(). --type mfargs() :: {M :: module(), F :: atom(), A :: [term()] | 'undefined'}. --type modules() :: [module()] | 'dynamic'. --type restart() :: 'permanent' | 'transient' | 'temporary'. --type shutdown() :: 'brutal_kill' | timeout(). --type worker() :: 'worker' | 'supervisor'. --type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}. --type sup_ref() :: (Name :: atom()) - | {Name :: atom(), Node :: node()} - | {'global', Name :: atom()} - | pid(). --type child_spec() :: {Id :: child_id(), - StartFunc :: mfargs(), - Restart :: restart(), - Shutdown :: shutdown(), - Type :: worker(), - Modules :: modules()}. +%%-------------------------------------------------------------------------- +%% Callback behaviour +%%-------------------------------------------------------------------------- + +-callback init(Args :: term()) -> + {ok, {{RestartStrategy :: supervisor2:strategy(), + MaxR :: non_neg_integer(), + MaxT :: non_neg_integer()}, + [ChildSpec :: supervisor2:child_spec()]}} + | ignore. + +%%-------------------------------------------------------------------------- +%% Specs +%%-------------------------------------------------------------------------- -type startlink_err() :: {'already_started', pid()} | 'shutdown' | term(). -type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}. --type startchild_err() :: 'already_present' - | {'already_started', Child :: child()} | term(). --type startchild_ret() :: {'ok', Child :: child()} - | {'ok', Child :: child(), Info :: term()} - | {'error', startchild_err()}. - -type group_name() :: any(). -spec start_link(GroupName, Module, Args) -> startlink_ret() when @@ -178,54 +166,26 @@ Args :: term(). -spec start_link(SupName, GroupName, Module, Args) -> startlink_ret() when - SupName :: sup_name(), + SupName :: supervisor2:sup_name(), GroupName :: group_name(), Module :: module(), Args :: term(). --spec start_child(SupRef, ChildSpec) -> startchild_ret() when - SupRef :: sup_ref(), - ChildSpec :: child_spec() | (List :: [term()]). - --spec restart_child(SupRef, Id) -> Result when - SupRef :: sup_ref(), - Id :: child_id(), - Result :: {'ok', Child :: child()} - | {'ok', Child :: child(), Info :: term()} - | {'error', Error}, - Error :: 'running' | 'not_found' | 'simple_one_for_one' | term(). - --spec delete_child(SupRef, Id) -> Result when - SupRef :: sup_ref(), - Id :: child_id(), - Result :: 'ok' | {'error', Error}, - Error :: 'running' | 'not_found' | 'simple_one_for_one'. - --spec terminate_child(SupRef, Id) -> Result when - SupRef :: sup_ref(), - Id :: pid() | child_id(), - Result :: 'ok' | {'error', Error}, - Error :: 'not_found' | 'simple_one_for_one'. - --spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when - SupRef :: sup_ref(), - Id :: child_id() | 'undefined', - Child :: child(), - Type :: worker(), - Modules :: modules(). - --spec check_childspecs(ChildSpecs) -> Result when - ChildSpecs :: [child_spec()], - Result :: 'ok' | {'error', Error :: term()}. - -spec start_internal(Group, ChildSpecs) -> Result when Group :: group_name(), - ChildSpecs :: [child_spec()], - Result :: startlink_ret(). + ChildSpecs :: [supervisor2:child_spec()], + Result :: supervisor2:startlink_ret(). -spec create_tables() -> Result when Result :: 'ok'. +-else. + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> [{init,1}]; +behaviour_info(_Other) -> undefined. + -endif. %%---------------------------------------------------------------------------- @@ -265,11 +225,8 @@ count_children(Sup) -> fold(count_children, Sup, fun add_proplists/2). check_childspecs(Specs) -> ?SUPERVISOR:check_childspecs(Specs). -behaviour_info(callbacks) -> [{init,1}]; -behaviour_info(_Other) -> undefined. - -call(Sup, Msg) -> - ?GEN_SERVER:call(child(Sup, mirroring), Msg, infinity). +call(Sup, Msg) -> ?GEN_SERVER:call(mirroring(Sup), Msg, infinity). +cast(Sup, Msg) -> ?GEN_SERVER:cast(mirroring(Sup), Msg). find_call(Sup, Id, Msg) -> Group = call(Sup, group), @@ -280,7 +237,7 @@ %% immediately after the tx - we can't be 100% here. So we may as %% well dirty_select. case mnesia:dirty_select(?TABLE, [{MatchHead, [], ['$1']}]) of - [Mirror] -> ?GEN_SERVER:call(Mirror, Msg, infinity); + [Mirror] -> call(Mirror, Msg); [] -> {error, not_found} end. @@ -289,13 +246,16 @@ lists:foldl(AggFun, [], [apply(?SUPERVISOR, FunAtom, [D]) || M <- ?PG2:get_members(Group), - D <- [?GEN_SERVER:call(M, delegate_supervisor, infinity)]]). + D <- [delegate(M)]]). child(Sup, Id) -> [Pid] = [Pid || {Id1, Pid, _, _} <- ?SUPERVISOR:which_children(Sup), Id1 =:= Id], Pid. +delegate(Sup) -> child(Sup, delegate). +mirroring(Sup) -> child(Sup, mirroring). + %%---------------------------------------------------------------------------- start_internal(Group, ChildSpecs) -> @@ -336,28 +296,29 @@ initial_childspecs = ChildSpecs}) -> process_flag(trap_exit, true), ?PG2:create(Group), - ok = ?PG2:join(Group, self()), - Rest = ?PG2:get_members(Group) -- [self()], + ok = ?PG2:join(Group, Overall), + Rest = ?PG2:get_members(Group) -- [Overall], case Rest of [] -> {atomic, _} = mnesia:transaction(fun() -> delete_all(Group) end); _ -> ok end, [begin - ?GEN_SERVER:cast(Pid, {ensure_monitoring, self()}), + ?GEN_SERVER:cast(mirroring(Pid), {ensure_monitoring, Overall}), erlang:monitor(process, Pid) end || Pid <- Rest], - Delegate = child(Overall, delegate), + Delegate = delegate(Overall), erlang:monitor(process, Delegate), State1 = State#state{overall = Overall, delegate = Delegate}, - case all_started([maybe_start(Group, Delegate, S) || S <- ChildSpecs]) of - true -> {reply, ok, State1}; - false -> {stop, shutdown, State1} + case errors([maybe_start(Group, Overall, Delegate, S) || S <- ChildSpecs]) of + [] -> {reply, ok, State1}; + Errors -> {stop, {shutdown, Errors}, State1} end; handle_call({start_child, ChildSpec}, _From, - State = #state{delegate = Delegate, + State = #state{overall = Overall, + delegate = Delegate, group = Group}) -> - {reply, case maybe_start(Group, Delegate, ChildSpec) of + {reply, case maybe_start(Group, Overall, Delegate, ChildSpec) of already_in_mnesia -> {error, already_present}; {already_in_mnesia, Pid} -> {error, {already_started, Pid}}; Else -> Else @@ -370,9 +331,6 @@ handle_call({msg, F, A}, _From, State = #state{delegate = Delegate}) -> {reply, apply(?SUPERVISOR, F, [Delegate | A]), State}; -handle_call(delegate_supervisor, _From, State = #state{delegate = Delegate}) -> - {reply, Delegate, State}; - handle_call(group, _From, State = #state{group = Group}) -> {reply, Group, State}; @@ -391,7 +349,7 @@ {stop, {unexpected_cast, Msg}, State}. handle_info({'DOWN', _Ref, process, Pid, Reason}, - State = #state{delegate = Pid, group = Group}) -> + State = #state{overall = Pid, group = Group}) -> %% Since the delegate is temporary, its death won't cause us to %% die. Since the overall supervisor kills processes in reverse %% order when shutting down "from above" and we started after the @@ -405,19 +363,20 @@ {stop, Reason, State}; handle_info({'DOWN', _Ref, process, Pid, _Reason}, - State = #state{delegate = Delegate, group = Group}) -> + State = #state{delegate = Delegate, group = Group, + overall = O}) -> %% TODO load balance this %% No guarantee pg2 will have received the DOWN before us. - Self = self(), R = case lists:sort(?PG2:get_members(Group)) -- [Pid] of - [Self | _] -> {atomic, ChildSpecs} = - mnesia:transaction(fun() -> update_all(Pid) end), - [start(Delegate, ChildSpec) || ChildSpec <- ChildSpecs]; - _ -> [] + [O | _] -> {atomic, ChildSpecs} = + mnesia:transaction( + fun() -> update_all(O, Pid) end), + [start(Delegate, ChildSpec) || ChildSpec <- ChildSpecs]; + _ -> [] end, - case all_started(R) of - true -> {noreply, State}; - false -> {stop, shutdown, State} + case errors(R) of + [] -> {noreply, State}; + Errors -> {stop, {shutdown, Errors}, State} end; handle_info(Info, State) -> @@ -432,13 +391,11 @@ %%---------------------------------------------------------------------------- tell_all_peers_to_die(Group, Reason) -> - [?GEN_SERVER:cast(P, {die, Reason}) || - P <- ?PG2:get_members(Group) -- [self()]]. + [cast(P, {die, Reason}) || P <- ?PG2:get_members(Group) -- [self()]]. -maybe_start(Group, Delegate, ChildSpec) -> - case mnesia:transaction(fun() -> - check_start(Group, Delegate, ChildSpec) - end) of +maybe_start(Group, Overall, Delegate, ChildSpec) -> + case mnesia:transaction( + fun() -> check_start(Group, Overall, Delegate, ChildSpec) end) of {atomic, start} -> start(Delegate, ChildSpec); {atomic, undefined} -> already_in_mnesia; {atomic, Pid} -> {already_in_mnesia, Pid}; @@ -446,31 +403,29 @@ {aborted, E} -> {error, E} end. -check_start(Group, Delegate, ChildSpec) -> +check_start(Group, Overall, Delegate, ChildSpec) -> case mnesia:wread({?TABLE, {Group, id(ChildSpec)}}) of - [] -> write(Group, ChildSpec), + [] -> write(Group, Overall, ChildSpec), start; [S] -> #mirrored_sup_childspec{key = {Group, Id}, mirroring_pid = Pid} = S, - case self() of + case Overall of Pid -> child(Delegate, Id); _ -> case supervisor(Pid) of - dead -> write(Group, ChildSpec), + dead -> write(Group, Overall, ChildSpec), start; Delegate0 -> child(Delegate0, Id) end end end. -supervisor(Pid) -> - with_exit_handler( - fun() -> dead end, - fun() -> gen_server:call(Pid, delegate_supervisor, infinity) end). +supervisor(Pid) -> with_exit_handler(fun() -> dead end, + fun() -> delegate(Pid) end). -write(Group, ChildSpec) -> +write(Group, Overall, ChildSpec) -> ok = mnesia:write( #mirrored_sup_childspec{key = {Group, id(ChildSpec)}, - mirroring_pid = self(), + mirroring_pid = Overall, childspec = ChildSpec}), ChildSpec. @@ -496,12 +451,12 @@ id({Id, _, _, _, _, _}) -> Id. -update_all(OldPid) -> - MatchHead = #mirrored_sup_childspec{mirroring_pid = OldPid, +update_all(Overall, OldOverall) -> + MatchHead = #mirrored_sup_childspec{mirroring_pid = OldOverall, key = '$1', childspec = '$2', _ = '_'}, - [write(Group, C) || + [write(Group, Overall, C) || [{Group, _Id}, C] <- mnesia:select(?TABLE, [{MatchHead, [], ['$$']}])]. delete_all(Group) -> @@ -511,12 +466,11 @@ [delete(Group, id(C)) || C <- mnesia:select(?TABLE, [{MatchHead, [], ['$1']}])]. -all_started(Results) -> [] =:= [R || R = {error, _} <- Results]. +errors(Results) -> [E || {error, E} <- Results]. %%---------------------------------------------------------------------------- -create_tables() -> - create_tables([?TABLE_DEF]). +create_tables() -> create_tables([?TABLE_DEF]). create_tables([]) -> ok; diff -Nru rabbitmq-server-2.7.1/src/mirrored_supervisor_tests.erl rabbitmq-server-2.8.4/src/mirrored_supervisor_tests.erl --- rabbitmq-server-2.7.1/src/mirrored_supervisor_tests.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/mirrored_supervisor_tests.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(mirrored_supervisor_tests). @@ -157,7 +157,7 @@ with_sups(fun([Evil, _]) -> ?MS:start_child(Evil, childspec(worker)), try - call(worker, ping), + call(worker, ping, 10000, 100), exit(worker_should_not_have_migrated) catch exit:{timeout_waiting_for_server, _, _} -> ok @@ -268,7 +268,7 @@ get_group(Group) -> {Group, get(counter)}. -call(Id, Msg) -> call(Id, Msg, 1000, 100). +call(Id, Msg) -> call(Id, Msg, 5*24*60*60*1000, 100). call(Id, Msg, 0, _Decr) -> exit({timeout_waiting_for_server, {Id, Msg}, erlang:get_stacktrace()}); @@ -285,7 +285,7 @@ kill(Pid, Waits) -> erlang:monitor(process, Pid), [erlang:monitor(process, P) || P <- Waits], - exit(Pid, kill), + exit(Pid, bang), kill_wait(Pid), [kill_wait(P) || P <- Waits]. diff -Nru rabbitmq-server-2.7.1/src/mnesia_sync.erl rabbitmq-server-2.8.4/src/mnesia_sync.erl --- rabbitmq-server-2.7.1/src/mnesia_sync.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/mnesia_sync.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,77 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(mnesia_sync). + +%% mnesia:sync_transaction/3 fails to guarantee that the log is flushed to disk +%% at commit. This module is an attempt to minimise the risk of data loss by +%% performing a coalesced log fsync. Unfortunately this is performed regardless +%% of whether or not the log was appended to. + +-behaviour(gen_server). + +-export([sync/0]). + +-export([start_link/0, init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, {waiting, disc_node}). + +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-spec(sync/0 :: () -> 'ok'). + +-endif. + +%%---------------------------------------------------------------------------- + +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +sync() -> + gen_server:call(?SERVER, sync, infinity). + +%%---------------------------------------------------------------------------- + +init([]) -> + {ok, #state{disc_node = mnesia:system_info(use_dir), waiting = []}}. + +handle_call(sync, _From, #state{disc_node = false} = State) -> + {reply, ok, State}; +handle_call(sync, From, #state{waiting = Waiting} = State) -> + {noreply, State#state{waiting = [From | Waiting]}, 0}; +handle_call(Request, _From, State) -> + {stop, {unhandled_call, Request}, State}. + +handle_cast(Request, State) -> + {stop, {unhandled_cast, Request}, State}. + +handle_info(timeout, #state{waiting = Waiting} = State) -> + ok = disk_log:sync(latest_log), + [gen_server:reply(From, ok) || From <- Waiting], + {noreply, State#state{waiting = []}}; +handle_info(Message, State) -> + {stop, {unhandled_info, Message}, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. diff -Nru rabbitmq-server-2.7.1/src/pg_local.erl rabbitmq-server-2.8.4/src/pg_local.erl --- rabbitmq-server-2.7.1/src/pg_local.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/pg_local.erl 2012-06-22 16:03:48.000000000 +0000 @@ -13,7 +13,7 @@ %% versions of Erlang/OTP. The remaining type specs have been %% removed. -%% All modifications are (C) 2010-2011 VMware, Inc. +%% All modifications are (C) 2010-2012 VMware, Inc. %% %CopyrightBegin% %% diff -Nru rabbitmq-server-2.7.1/src/pmon.erl rabbitmq-server-2.8.4/src/pmon.erl --- rabbitmq-server-2.7.1/src/pmon.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/pmon.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,64 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. +%% + +-module(pmon). + +-export([new/0, monitor/2, monitor_all/2, demonitor/2, is_monitored/2, erase/2, + monitored/1, is_empty/1]). + +-ifdef(use_specs). + +%%---------------------------------------------------------------------------- + +-export_type([?MODULE/0]). + +-opaque(?MODULE() :: dict()). + +-spec(new/0 :: () -> ?MODULE()). +-spec(monitor/2 :: (pid(), ?MODULE()) -> ?MODULE()). +-spec(monitor_all/2 :: ([pid()], ?MODULE()) -> ?MODULE()). +-spec(demonitor/2 :: (pid(), ?MODULE()) -> ?MODULE()). +-spec(is_monitored/2 :: (pid(), ?MODULE()) -> boolean()). +-spec(erase/2 :: (pid(), ?MODULE()) -> ?MODULE()). +-spec(monitored/1 :: (?MODULE()) -> [pid()]). +-spec(is_empty/1 :: (?MODULE()) -> boolean()). + +-endif. + +new() -> dict:new(). + +monitor(Pid, M) -> + case dict:is_key(Pid, M) of + true -> M; + false -> dict:store(Pid, erlang:monitor(process, Pid), M) + end. + +monitor_all(Pids, M) -> lists:foldl(fun monitor/2, M, Pids). + +demonitor(Pid, M) -> + case dict:find(Pid, M) of + {ok, MRef} -> erlang:demonitor(MRef), + dict:erase(Pid, M); + error -> M + end. + +is_monitored(Pid, M) -> dict:is_key(Pid, M). + +erase(Pid, M) -> dict:erase(Pid, M). + +monitored(M) -> dict:fetch_keys(M). + +is_empty(M) -> dict:size(M) == 0. diff -Nru rabbitmq-server-2.7.1/src/priority_queue.erl rabbitmq-server-2.8.4/src/priority_queue.erl --- rabbitmq-server-2.7.1/src/priority_queue.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/priority_queue.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% Priority queues have essentially the same interface as ordinary diff -Nru rabbitmq-server-2.7.1/src/rabbit_access_control.erl rabbitmq-server-2.8.4/src/rabbit_access_control.erl --- rabbitmq-server-2.7.1/src/rabbit_access_control.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_access_control.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_access_control). @@ -66,7 +66,6 @@ check_vhost_access(User = #user{ username = Username, auth_backend = Module }, VHostPath) -> - ?LOGDEBUG("Checking VHost access for ~p to ~p~n", [Username, VHostPath]), check_access( fun() -> rabbit_vhost:exists(VHostPath) andalso diff -Nru rabbitmq-server-2.7.1/src/rabbit_alarm.erl rabbitmq-server-2.8.4/src/rabbit_alarm.erl --- rabbitmq-server-2.7.1/src/rabbit_alarm.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_alarm.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_alarm). @@ -23,7 +23,7 @@ -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). --export([remote_conserve_memory/2]). %% Internal use only +-export([remote_conserve_resources/3]). %% Internal use only -record(alarms, {alertees, alarmed_nodes}). @@ -31,10 +31,9 @@ -ifdef(use_specs). --type(mfa_tuple() :: {atom(), atom(), list()}). -spec(start/0 :: () -> 'ok'). -spec(stop/0 :: () -> 'ok'). --spec(register/2 :: (pid(), mfa_tuple()) -> boolean()). +-spec(register/2 :: (pid(), rabbit_types:mfargs()) -> boolean()). -spec(on_node_up/1 :: (node()) -> 'ok'). -spec(on_node_down/1 :: (node()) -> 'ok'). @@ -46,6 +45,9 @@ ok = alarm_handler:add_alarm_handler(?MODULE, []), {ok, MemoryWatermark} = application:get_env(vm_memory_high_watermark), rabbit_sup:start_restartable_child(vm_memory_monitor, [MemoryWatermark]), + + {ok, DiskLimit} = application:get_env(disk_free_limit), + rabbit_sup:start_restartable_child(rabbit_disk_monitor, [DiskLimit]), ok. stop() -> @@ -62,41 +64,41 @@ %% Can't use alarm_handler:{set,clear}_alarm because that doesn't %% permit notifying a remote node. -remote_conserve_memory(Pid, true) -> +remote_conserve_resources(Pid, Source, true) -> gen_event:notify({alarm_handler, node(Pid)}, - {set_alarm, {{vm_memory_high_watermark, node()}, []}}); -remote_conserve_memory(Pid, false) -> + {set_alarm, {{resource_limit, Source, node()}, []}}); +remote_conserve_resources(Pid, Source, false) -> gen_event:notify({alarm_handler, node(Pid)}, - {clear_alarm, {vm_memory_high_watermark, node()}}). + {clear_alarm, {resource_limit, Source, node()}}). %%---------------------------------------------------------------------------- init([]) -> {ok, #alarms{alertees = dict:new(), - alarmed_nodes = sets:new()}}. + alarmed_nodes = dict:new()}}. handle_call({register, Pid, HighMemMFA}, State) -> - {ok, 0 < sets:size(State#alarms.alarmed_nodes), + {ok, 0 < dict:size(State#alarms.alarmed_nodes), internal_register(Pid, HighMemMFA, State)}; handle_call(_Request, State) -> {ok, not_understood, State}. -handle_event({set_alarm, {{vm_memory_high_watermark, Node}, []}}, State) -> - {ok, maybe_alert(fun sets:add_element/2, Node, State)}; +handle_event({set_alarm, {{resource_limit, Source, Node}, []}}, State) -> + {ok, maybe_alert(fun dict:append/3, Node, Source, State)}; -handle_event({clear_alarm, {vm_memory_high_watermark, Node}}, State) -> - {ok, maybe_alert(fun sets:del_element/2, Node, State)}; +handle_event({clear_alarm, {resource_limit, Source, Node}}, State) -> + {ok, maybe_alert(fun dict_unappend/3, Node, Source, State)}; handle_event({node_up, Node}, State) -> %% Must do this via notify and not call to avoid possible deadlock. ok = gen_event:notify( {alarm_handler, Node}, - {register, self(), {?MODULE, remote_conserve_memory, []}}), + {register, self(), {?MODULE, remote_conserve_resources, []}}), {ok, State}; handle_event({node_down, Node}, State) -> - {ok, maybe_alert(fun sets:del_element/2, Node, State)}; + {ok, maybe_alert(fun dict_unappend_all/3, Node, [], State)}; handle_event({register, Pid, HighMemMFA}, State) -> {ok, internal_register(Pid, HighMemMFA, State)}; @@ -119,34 +121,58 @@ %%---------------------------------------------------------------------------- -maybe_alert(SetFun, Node, State = #alarms{alarmed_nodes = AN, - alertees = Alertees}) -> - AN1 = SetFun(Node, AN), - BeforeSz = sets:size(AN), - AfterSz = sets:size(AN1), +dict_unappend_all(Key, _Val, Dict) -> + dict:erase(Key, Dict). + +dict_unappend(Key, Val, Dict) -> + case lists:delete(Val, dict:fetch(Key, Dict)) of + [] -> dict:erase(Key, Dict); + X -> dict:store(Key, X, Dict) + end. + +count_dict_values(Val, Dict) -> + dict:fold(fun (_Node, List, Count) -> + Count + case lists:member(Val, List) of + true -> 1; + false -> 0 + end + end, 0, Dict). + +maybe_alert(UpdateFun, Node, Source, + State = #alarms{alarmed_nodes = AN, + alertees = Alertees}) -> + AN1 = UpdateFun(Node, Source, AN), + BeforeSz = count_dict_values(Source, AN), + AfterSz = count_dict_values(Source, AN1), + %% If we have changed our alarm state, inform the remotes. IsLocal = Node =:= node(), - if IsLocal andalso BeforeSz < AfterSz -> ok = alert_remote(true, Alertees); - IsLocal andalso BeforeSz > AfterSz -> ok = alert_remote(false, Alertees); - true -> ok + if IsLocal andalso BeforeSz < AfterSz -> + ok = alert_remote(true, Alertees, Source); + IsLocal andalso BeforeSz > AfterSz -> + ok = alert_remote(false, Alertees, Source); + true -> + ok end, %% If the overall alarm state has changed, inform the locals. - case {BeforeSz, AfterSz} of - {0, 1} -> ok = alert_local(true, Alertees); - {1, 0} -> ok = alert_local(false, Alertees); + case {dict:size(AN), dict:size(AN1)} of + {0, 1} -> ok = alert_local(true, Alertees, Source); + {1, 0} -> ok = alert_local(false, Alertees, Source); {_, _} -> ok end, State#alarms{alarmed_nodes = AN1}. -alert_local(Alert, Alertees) -> alert(Alert, Alertees, fun erlang:'=:='/2). +alert_local(Alert, Alertees, Source) -> + alert(Alertees, Source, Alert, fun erlang:'=:='/2). -alert_remote(Alert, Alertees) -> alert(Alert, Alertees, fun erlang:'=/='/2). +alert_remote(Alert, Alertees, Source) -> + alert(Alertees, Source, Alert, fun erlang:'=/='/2). -alert(Alert, Alertees, NodeComparator) -> +alert(Alertees, Source, Alert, NodeComparator) -> Node = node(), dict:fold(fun (Pid, {M, F, A}, ok) -> case NodeComparator(Node, node(Pid)) of - true -> apply(M, F, A ++ [Pid, Alert]); + true -> apply(M, F, A ++ [Pid, Source, Alert]); false -> ok end end, ok, Alertees). @@ -154,9 +180,9 @@ internal_register(Pid, {M, F, A} = HighMemMFA, State = #alarms{alertees = Alertees}) -> _MRef = erlang:monitor(process, Pid), - case sets:is_element(node(), State#alarms.alarmed_nodes) of - true -> ok = apply(M, F, A ++ [Pid, true]); - false -> ok + case dict:find(node(), State#alarms.alarmed_nodes) of + {ok, Sources} -> [apply(M, F, A ++ [Pid, R, true]) || R <- Sources]; + error -> ok end, NewAlertees = dict:store(Pid, HighMemMFA, Alertees), State#alarms{alertees = NewAlertees}. diff -Nru rabbitmq-server-2.7.1/src/rabbit_amqqueue.erl rabbitmq-server-2.8.4/src/rabbit_amqqueue.erl --- rabbitmq-server-2.7.1/src/rabbit_amqqueue.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_amqqueue.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_amqqueue). @@ -20,19 +20,19 @@ -export([pseudo_queue/2]). -export([lookup/1, with/2, with_or_die/2, assert_equivalence/5, check_exclusive_access/2, with_exclusive_access_or_die/3, - stat/1, deliver/2, requeue/3, ack/3, reject/4]). + stat/1, deliver/2, deliver_flow/2, requeue/3, ack/3, reject/4]). -export([list/0, list/1, info_keys/0, info/1, info/2, info_all/1, info_all/2]). -export([force_event_refresh/0]). -export([consumers/1, consumers_all/1, consumer_info_keys/0]). -export([basic_get/3, basic_consume/7, basic_cancel/4]). --export([notify_sent/2, unblock/2, flush_all/2]). +-export([notify_sent/2, notify_sent_queue_down/1, unblock/2, flush_all/2]). -export([notify_down_all/2, limit_all/3]). -export([on_node_down/1]). -export([store_queue/1]). %% internal --export([internal_declare/2, internal_delete/1, run_backing_queue/3, +-export([internal_declare/2, internal_delete/2, run_backing_queue/3, set_ram_duration_target/2, set_maximum_since_use/2]). -include("rabbit.hrl"). @@ -40,21 +40,25 @@ -define(INTEGER_ARG_TYPES, [byte, short, signedint, long]). +-define(MORE_CONSUMER_CREDIT_AFTER, 50). + +-define(FAILOVER_WAIT_MILLIS, 100). + %%---------------------------------------------------------------------------- -ifdef(use_specs). --export_type([name/0, qmsg/0]). +-export_type([name/0, qmsg/0, routing_result/0]). -type(name() :: rabbit_types:r('queue')). - +-type(qpids() :: [pid()]). -type(qlen() :: rabbit_types:ok(non_neg_integer())). -type(qfun(A) :: fun ((rabbit_types:amqqueue()) -> A | no_return())). -type(qmsg() :: {name(), pid(), msg_id(), boolean(), rabbit_types:message()}). -type(msg_id() :: non_neg_integer()). -type(ok_or_errors() :: 'ok' | {'error', [{'error' | 'exit' | 'throw', any()}]}). - +-type(routing_result() :: 'routed' | 'unroutable' | 'not_delivered'). -type(queue_or_not_found() :: rabbit_types:amqqueue() | 'not_found'). -spec(start/0 :: () -> [name()]). @@ -69,7 +73,8 @@ -> queue_or_not_found() | rabbit_misc:thunk(queue_or_not_found())). -spec(lookup/1 :: (name()) -> rabbit_types:ok(rabbit_types:amqqueue()) | - rabbit_types:error('not_found')). + rabbit_types:error('not_found'); + ([name()]) -> [rabbit_types:amqqueue()]). -spec(with/2 :: (name(), qfun(A)) -> A | rabbit_types:error('not_found')). -spec(with_or_die/2 :: (name(), qfun(A)) -> A | rabbit_types:channel_exit()). @@ -104,7 +109,7 @@ -spec(stat/1 :: (rabbit_types:amqqueue()) -> {'ok', non_neg_integer(), non_neg_integer()}). --spec(delete_immediately/1 :: (rabbit_types:amqqueue()) -> 'ok'). +-spec(delete_immediately/1 :: (qpids()) -> 'ok'). -spec(delete/3 :: (rabbit_types:amqqueue(), 'false', 'false') -> qlen(); @@ -117,12 +122,15 @@ rabbit_types:error('in_use') | rabbit_types:error('not_empty')). -spec(purge/1 :: (rabbit_types:amqqueue()) -> qlen()). --spec(deliver/2 :: (pid(), rabbit_types:delivery()) -> boolean()). +-spec(deliver/2 :: ([rabbit_types:amqqueue()], rabbit_types:delivery()) -> + {routing_result(), qpids()}). +-spec(deliver_flow/2 :: ([rabbit_types:amqqueue()], rabbit_types:delivery()) -> + {routing_result(), qpids()}). -spec(requeue/3 :: (pid(), [msg_id()], pid()) -> 'ok'). -spec(ack/3 :: (pid(), [msg_id()], pid()) -> 'ok'). -spec(reject/4 :: (pid(), [msg_id()], boolean(), pid()) -> 'ok'). --spec(notify_down_all/2 :: ([pid()], pid()) -> ok_or_errors()). --spec(limit_all/3 :: ([pid()], pid(), rabbit_limiter:token()) -> +-spec(notify_down_all/2 :: (qpids(), pid()) -> ok_or_errors()). +-spec(limit_all/3 :: (qpids(), pid(), rabbit_limiter:token()) -> ok_or_errors()). -spec(basic_get/3 :: (rabbit_types:amqqueue(), pid(), boolean()) -> {'ok', non_neg_integer(), qmsg()} | 'empty'). @@ -133,13 +141,14 @@ -spec(basic_cancel/4 :: (rabbit_types:amqqueue(), pid(), rabbit_types:ctag(), any()) -> 'ok'). -spec(notify_sent/2 :: (pid(), pid()) -> 'ok'). +-spec(notify_sent_queue_down/1 :: (pid()) -> 'ok'). -spec(unblock/2 :: (pid(), pid()) -> 'ok'). --spec(flush_all/2 :: ([pid()], pid()) -> 'ok'). --spec(internal_delete/1 :: - (name()) -> rabbit_types:ok_or_error('not_found') | - rabbit_types:connection_exit() | - fun (() -> rabbit_types:ok_or_error('not_found') | - rabbit_types:connection_exit())). +-spec(flush_all/2 :: (qpids(), pid()) -> 'ok'). +-spec(internal_delete/2 :: + (name(), pid()) -> rabbit_types:ok_or_error('not_found') | + rabbit_types:connection_exit() | + fun (() -> rabbit_types:ok_or_error('not_found') | + rabbit_types:connection_exit())). -spec(run_backing_queue/3 :: (pid(), atom(), (fun ((atom(), A) -> {[rabbit_types:msg_id()], A}))) -> 'ok'). @@ -157,6 +166,9 @@ [queue_name, channel_pid, consumer_tag, ack_required]). start() -> + %% Clear out remnants of old incarnation, in case we restarted + %% faster than other nodes handled DOWN messages from us. + on_node_down(node()), DurableQueues = find_durable_queues(), {ok, BQ} = application:get_env(rabbit, backing_queue_module), ok = BQ:start([QName || #amqqueue{name = QName} <- DurableQueues]), @@ -222,7 +234,7 @@ [ExistingQ = #amqqueue{pid = QPid}] -> case rabbit_misc:is_process_alive(QPid) of true -> rabbit_misc:const(ExistingQ); - false -> TailFun = internal_delete(QueueName), + false -> TailFun = internal_delete(QueueName, QPid), fun () -> TailFun(), ExistingQ end end end @@ -264,6 +276,10 @@ key = RoutingKey, args = []}). +lookup(Names) when is_list(Names) -> + %% Normally we'd call mnesia:dirty_read/1 here, but that is quite + %% expensive for reasons explained in rabbit_misc:dirty_read/1. + lists:append([ets:lookup(rabbit_queue, Name) || Name <- Names]); lookup(Name) -> rabbit_misc:dirty_read({rabbit_queue, Name}). @@ -317,33 +333,60 @@ [<<"x-expires">>, <<"x-message-ttl">>, <<"x-ha-policy">>]). check_declare_arguments(QueueName, Args) -> - [case Fun(rabbit_misc:table_lookup(Args, Key), Args) of - ok -> ok; - {error, Error} -> rabbit_misc:protocol_error( - precondition_failed, - "invalid arg '~s' for ~s: ~255p", - [Key, rabbit_misc:rs(QueueName), Error]) - end || {Key, Fun} <- - [{<<"x-expires">>, fun check_integer_argument/2}, - {<<"x-message-ttl">>, fun check_integer_argument/2}, - {<<"x-ha-policy">>, fun check_ha_policy_argument/2}]], + Checks = [{<<"x-expires">>, fun check_positive_int_arg/2}, + {<<"x-message-ttl">>, fun check_non_neg_int_arg/2}, + {<<"x-ha-policy">>, fun check_ha_policy_arg/2}, + {<<"x-dead-letter-exchange">>, fun check_string_arg/2}, + {<<"x-dead-letter-routing-key">>, fun check_dlxrk_arg/2}], + [case rabbit_misc:table_lookup(Args, Key) of + undefined -> ok; + TypeVal -> case Fun(TypeVal, Args) of + ok -> ok; + {error, Error} -> rabbit_misc:protocol_error( + precondition_failed, + "invalid arg '~s' for ~s: ~255p", + [Key, rabbit_misc:rs(QueueName), + Error]) + end + end || {Key, Fun} <- Checks], ok. -check_integer_argument(undefined, _Args) -> +check_string_arg({longstr, _}, _Args) -> ok; -check_integer_argument({Type, Val}, _Args) when Val > 0 -> +check_string_arg({Type, _}, _) -> + {error, {unacceptable_type, Type}}. + +check_int_arg({Type, _}, _) -> case lists:member(Type, ?INTEGER_ARG_TYPES) of true -> ok; false -> {error, {unacceptable_type, Type}} + end. + +check_positive_int_arg({Type, Val}, Args) -> + case check_int_arg({Type, Val}, Args) of + ok when Val > 0 -> ok; + ok -> {error, {value_zero_or_less, Val}}; + Error -> Error + end. + +check_non_neg_int_arg({Type, Val}, Args) -> + case check_int_arg({Type, Val}, Args) of + ok when Val >= 0 -> ok; + ok -> {error, {value_less_than_zero, Val}}; + Error -> Error + end. + +check_dlxrk_arg({longstr, _}, Args) -> + case rabbit_misc:table_lookup(Args, <<"x-dead-letter-exchange">>) of + undefined -> {error, routing_key_but_no_dlx_defined}; + _ -> ok end; -check_integer_argument({_Type, Val}, _Args) -> - {error, {value_zero_or_less, Val}}. +check_dlxrk_arg({Type, _}, _Args) -> + {error, {unacceptable_type, Type}}. -check_ha_policy_argument(undefined, _Args) -> +check_ha_policy_arg({longstr, <<"all">>}, _Args) -> ok; -check_ha_policy_argument({longstr, <<"all">>}, _Args) -> - ok; -check_ha_policy_argument({longstr, <<"nodes">>}, Args) -> +check_ha_policy_arg({longstr, <<"nodes">>}, Args) -> case rabbit_misc:table_lookup(Args, <<"x-ha-policy-params">>) of undefined -> {error, {require, 'x-ha-policy-params'}}; @@ -359,9 +402,9 @@ {Type, _} -> {error, {ha_nodes_policy_params_not_array_of_longstr, Type}} end; -check_ha_policy_argument({longstr, Policy}, _Args) -> +check_ha_policy_arg({longstr, Policy}, _Args) -> {error, {invalid_ha_policy, Policy}}; -check_ha_policy_argument({Type, _}, _Args) -> +check_ha_policy_arg({Type, _}, _Args) -> {error, {unacceptable_type, Type}}. list() -> @@ -389,9 +432,26 @@ info_all(VHostPath, Items) -> map(VHostPath, fun (Q) -> info(Q, Items) end). +%% We need to account for the idea that queues may be mid-promotion +%% during force_event_refresh (since it's likely we're doing this in +%% the first place since a node failed). Therefore we keep poking at +%% the list of queues until we were able to talk to a live process or +%% the queue no longer exists. force_event_refresh() -> - [gen_server2:cast(Q#amqqueue.pid, force_event_refresh) || Q <- list()], - ok. + force_event_refresh([Q#amqqueue.name || Q <- list()]). + +force_event_refresh(QNames) -> + Qs = [Q || Q <- list(), lists:member(Q#amqqueue.name, QNames)], + {_, Bad} = rabbit_misc:multi_call( + [Q#amqqueue.pid || Q <- Qs], force_event_refresh), + FailedPids = [Pid || {Pid, _Reason} <- Bad], + Failed = [Name || #amqqueue{name = Name, pid = Pid} <- Qs, + lists:member(Pid, FailedPids)], + case Failed of + [] -> ok; + _ -> timer:sleep(?FAILOVER_WAIT_MILLIS), + force_event_refresh(Failed) + end. consumers(#amqqueue{ pid = QPid }) -> delegate_call(QPid, consumers). @@ -411,22 +471,18 @@ stat(#amqqueue{pid = QPid}) -> delegate_call(QPid, stat). -delete_immediately(#amqqueue{ pid = QPid }) -> - gen_server2:cast(QPid, delete_immediately). +delete_immediately(QPids) -> + [gen_server2:cast(QPid, delete_immediately) || QPid <- QPids], + ok. delete(#amqqueue{ pid = QPid }, IfUnused, IfEmpty) -> delegate_call(QPid, {delete, IfUnused, IfEmpty}). purge(#amqqueue{ pid = QPid }) -> delegate_call(QPid, purge). -deliver(QPid, Delivery = #delivery{immediate = true}) -> - gen_server2:call(QPid, {deliver_immediately, Delivery}, infinity); -deliver(QPid, Delivery = #delivery{mandatory = true}) -> - gen_server2:call(QPid, {deliver, Delivery}, infinity), - true; -deliver(QPid, Delivery) -> - gen_server2:cast(QPid, {deliver, Delivery}), - true. +deliver(Qs, Delivery) -> deliver(Qs, Delivery, noflow). + +deliver_flow(Qs, Delivery) -> deliver(Qs, Delivery, flow). requeue(QPid, MsgIds, ChPid) -> delegate_call(QPid, {requeue, MsgIds, ChPid}). @@ -458,7 +514,21 @@ ok = delegate_call(QPid, {basic_cancel, ChPid, ConsumerTag, OkMsg}). notify_sent(QPid, ChPid) -> - gen_server2:cast(QPid, {notify_sent, ChPid}). + Key = {consumer_credit_to, QPid}, + put(Key, case get(Key) of + 1 -> gen_server2:cast( + QPid, {notify_sent, ChPid, + ?MORE_CONSUMER_CREDIT_AFTER}), + ?MORE_CONSUMER_CREDIT_AFTER; + undefined -> erlang:monitor(process, QPid), + ?MORE_CONSUMER_CREDIT_AFTER - 1; + C -> C - 1 + end), + ok. + +notify_sent_queue_down(QPid) -> + erase({consumer_credit_to, QPid}), + ok. unblock(QPid, ChPid) -> delegate_cast(QPid, {unblock, ChPid}). @@ -474,13 +544,19 @@ %% after the transaction. rabbit_binding:remove_for_destination(QueueName). -internal_delete(QueueName) -> +internal_delete(QueueName, QPid) -> rabbit_misc:execute_mnesia_tx_with_tail( fun () -> case mnesia:wread({rabbit_queue, QueueName}) of [] -> rabbit_misc:const({error, not_found}); [_] -> Deletions = internal_delete1(QueueName), - rabbit_binding:process_deletions(Deletions) + T = rabbit_binding:process_deletions(Deletions), + fun() -> + ok = T(), + ok = rabbit_event:notify(queue_deleted, + [{pid, QPid}, + {name, QueueName}]) + end end end). @@ -495,14 +571,26 @@ on_node_down(Node) -> rabbit_misc:execute_mnesia_tx_with_tail( - fun () -> Dels = qlc:e(qlc:q([delete_queue(QueueName) || - #amqqueue{name = QueueName, pid = Pid, - slave_pids = []} - <- mnesia:table(rabbit_queue), - node(Pid) == Node])), - rabbit_binding:process_deletions( - lists:foldl(fun rabbit_binding:combine_deletions/2, - rabbit_binding:new_deletions(), Dels)) + fun () -> QsDels = + qlc:e(qlc:q([{{QName, Pid}, delete_queue(QName)} || + #amqqueue{name = QName, pid = Pid, + slave_pids = []} + <- mnesia:table(rabbit_queue), + node(Pid) == Node andalso + not is_process_alive(Pid)])), + {Qs, Dels} = lists:unzip(QsDels), + T = rabbit_binding:process_deletions( + lists:foldl(fun rabbit_binding:combine_deletions/2, + rabbit_binding:new_deletions(), Dels)), + fun () -> + T(), + lists:foreach( + fun({QName, QPid}) -> + ok = rabbit_event:notify(queue_deleted, + [{pid, QPid}, + {name, QName}]) + end, Qs) + end end). delete_queue(QueueName) -> @@ -518,6 +606,49 @@ slave_pids = [], mirror_nodes = undefined}. +deliver([], #delivery{mandatory = false, immediate = false}, _Flow) -> + %% /dev/null optimisation + {routed, []}; + +deliver(Qs, Delivery = #delivery{mandatory = false, immediate = false}, Flow) -> + %% optimisation: when Mandatory = false and Immediate = false, + %% rabbit_amqqueue:deliver will deliver the message to the queue + %% process asynchronously, and return true, which means all the + %% QPids will always be returned. It is therefore safe to use a + %% fire-and-forget cast here and return the QPids - the semantics + %% is preserved. This scales much better than the non-immediate + %% case below. + QPids = qpids(Qs), + case Flow of + flow -> [credit_flow:send(QPid) || QPid <- QPids]; + noflow -> ok + end, + delegate:invoke_no_result( + QPids, fun (QPid) -> + gen_server2:cast(QPid, {deliver, Delivery, Flow}) + end), + {routed, QPids}; + +deliver(Qs, Delivery = #delivery{mandatory = Mandatory, immediate = Immediate}, + _Flow) -> + QPids = qpids(Qs), + {Success, _} = + delegate:invoke( + QPids, fun (QPid) -> + gen_server2:call(QPid, {deliver, Delivery}, infinity) + end), + case {Mandatory, Immediate, + lists:foldl(fun ({QPid, true}, {_, H}) -> {true, [QPid | H]}; + ({_, false}, {_, H}) -> {true, H} + end, {false, []}, Success)} of + {true, _ , {false, []}} -> {unroutable, []}; + {_ , true, {_ , []}} -> {not_delivered, []}; + {_ , _ , {_ , R}} -> {routed, R} + end. + +qpids(Qs) -> lists:append([[QPid | SPids] || + #amqqueue{pid = QPid, slave_pids = SPids} <- Qs]). + safe_delegate_call_ok(F, Pids) -> case delegate:invoke(Pids, fun (Pid) -> rabbit_misc:with_exit_handler( diff -Nru rabbitmq-server-2.7.1/src/rabbit_amqqueue_process.erl rabbitmq-server-2.8.4/src/rabbit_amqqueue_process.erl --- rabbitmq-server-2.7.1/src/rabbit_amqqueue_process.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_amqqueue_process.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_amqqueue_process). @@ -20,16 +20,13 @@ -behaviour(gen_server2). --define(UNSENT_MESSAGE_LIMIT, 100). +-define(UNSENT_MESSAGE_LIMIT, 200). -define(SYNC_INTERVAL, 25). %% milliseconds -define(RAM_DURATION_UPDATE_INTERVAL, 5000). --define(BASE_MESSAGE_PROPERTIES, - #message_properties{expiry = undefined, needs_confirming = false}). - -export([start_link/1, info_keys/0]). --export([init_with_backing_queue_state/7]). +-export([init_with_backing_queue_state/8]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2, handle_pre_hibernate/1, prioritise_call/3, @@ -49,7 +46,14 @@ stats_timer, msg_id_to_channel, ttl, - ttl_timer_ref + ttl_timer_ref, + senders, + publish_seqno, + unconfirmed, + delayed_stop, + queue_monitors, + dlx, + dlx_routing_key }). -record(consumer, {tag, ack_required}). @@ -71,9 +75,9 @@ -spec(start_link/1 :: (rabbit_types:amqqueue()) -> rabbit_types:ok_pid_or_error()). -spec(info_keys/0 :: () -> rabbit_types:info_keys()). --spec(init_with_backing_queue_state/7 :: +-spec(init_with_backing_queue_state/8 :: (rabbit_types:amqqueue(), atom(), tuple(), any(), [any()], - [rabbit_types:delivery()], dict()) -> #q{}). + [rabbit_types:delivery()], pmon:pmon(), dict()) -> #q{}). -endif. @@ -115,7 +119,6 @@ %%---------------------------------------------------------------------------- init(Q) -> - ?LOGDEBUG("Queue starting - ~p~n", [Q]), process_flag(trap_exit, true), State = #q{q = Q#amqqueue{pid = self()}, @@ -129,13 +132,19 @@ rate_timer_ref = undefined, expiry_timer_ref = undefined, ttl = undefined, + senders = pmon:new(), + dlx = undefined, + dlx_routing_key = undefined, + publish_seqno = 1, + unconfirmed = dtree:empty(), + delayed_stop = undefined, + queue_monitors = pmon:new(), msg_id_to_channel = gb_trees:empty()}, {ok, rabbit_event:init_stats_timer(State, #q.stats_timer), hibernate, {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. init_with_backing_queue_state(Q = #amqqueue{exclusive_owner = Owner}, BQ, BQS, - RateTRef, AckTags, Deliveries, MTC) -> - ?LOGDEBUG("Queue starting - ~p~n", [Q]), + RateTRef, AckTags, Deliveries, Senders, MTC) -> case Owner of none -> ok; _ -> erlang:monitor(process, Owner) @@ -151,6 +160,11 @@ rate_timer_ref = RateTRef, expiry_timer_ref = undefined, ttl = undefined, + senders = Senders, + publish_seqno = 1, + unconfirmed = dtree:empty(), + delayed_stop = undefined, + queue_monitors = pmon:new(), msg_id_to_channel = MTC}, State1 = requeue_and_run(AckTags, process_args( rabbit_event:init_stats_timer( @@ -166,16 +180,13 @@ terminate(Reason, State = #q{q = #amqqueue{name = QName}, backing_queue = BQ}) -> %% FIXME: How do we cancel active subscriptions? - terminate_shutdown(fun (BQS) -> - rabbit_event:notify( - queue_deleted, [{pid, self()}, - {name, QName}]), - BQS1 = BQ:delete_and_terminate(Reason, BQS), - %% don't care if the internal delete - %% doesn't return 'ok'. - rabbit_amqqueue:internal_delete(qname(State)), - BQS1 - end, State). + terminate_shutdown( + fun (BQS) -> + BQS1 = BQ:delete_and_terminate(Reason, BQS), + %% don't care if the internal delete doesn't return 'ok'. + rabbit_amqqueue:internal_delete(QName, self()), + BQS1 + end, State). code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -212,18 +223,28 @@ end). process_args(State = #q{q = #amqqueue{arguments = Arguments}}) -> - lists:foldl(fun({Arg, Fun}, State1) -> - case rabbit_misc:table_lookup(Arguments, Arg) of - {_Type, Val} -> Fun(Val, State1); - undefined -> State1 - end - end, State, [{<<"x-expires">>, fun init_expires/2}, - {<<"x-message-ttl">>, fun init_ttl/2}]). + lists:foldl( + fun({Arg, Fun}, State1) -> + case rabbit_misc:table_lookup(Arguments, Arg) of + {_Type, Val} -> Fun(Val, State1); + undefined -> State1 + end + end, State, + [{<<"x-expires">>, fun init_expires/2}, + {<<"x-message-ttl">>, fun init_ttl/2}, + {<<"x-dead-letter-exchange">>, fun init_dlx/2}, + {<<"x-dead-letter-routing-key">>, fun init_dlx_routing_key/2}]). init_expires(Expires, State) -> ensure_expiry_timer(State#q{expires = Expires}). init_ttl(TTL, State) -> drop_expired_messages(State#q{ttl = TTL}). +init_dlx(DLX, State = #q{q = #amqqueue{name = QName}}) -> + State#q{dlx = rabbit_misc:r(QName, exchange, DLX)}. + +init_dlx_routing_key(RoutingKey, State) -> + State#q{dlx_routing_key = RoutingKey}. + terminate_shutdown(Fun, State) -> State1 = #q{backing_queue_state = BQS} = stop_sync_timer(stop_rate_timer(State)), @@ -252,9 +273,9 @@ confirm_messages(MsgIds, State#q{ backing_queue_state = BQS1}))), case BQ:needs_timeout(BQS1) of - false -> {stop_sync_timer(State1), hibernate}; - idle -> {stop_sync_timer(State1), 0 }; - timed -> {ensure_sync_timer(State1), 0 } + false -> {stop_sync_timer(State1), hibernate }; + idle -> {stop_sync_timer(State1), ?SYNC_INTERVAL}; + timed -> {ensure_sync_timer(State1), 0 } end. backing_queue_module(#amqqueue{arguments = Args}) -> @@ -306,12 +327,10 @@ State; ensure_expiry_timer(State = #q{expires = Expires}) -> case is_unused(State) of - true -> - NewState = stop_expiry_timer(State), - TRef = erlang:send_after(Expires, self(), maybe_expire), - NewState#q{expiry_timer_ref = TRef}; - false -> - State + true -> NewState = stop_expiry_timer(State), + TRef = erlang:send_after(Expires, self(), maybe_expire), + NewState#q{expiry_timer_ref = TRef}; + false -> State end. ensure_stats_timer(State) -> @@ -390,34 +409,32 @@ {_, _} -> ok end. -deliver_msgs_to_consumers(Funs = {PredFun, DeliverFun}, FunAcc, +deliver_msgs_to_consumers(_DeliverFun, true, State) -> + {true, State}; +deliver_msgs_to_consumers(DeliverFun, false, State = #q{active_consumers = ActiveConsumers}) -> - case PredFun(FunAcc, State) of - false -> {FunAcc, State}; - true -> case queue:out(ActiveConsumers) of - {empty, _} -> - {FunAcc, State}; - {{value, QEntry}, Tail} -> - {FunAcc1, State1} = - deliver_msg_to_consumer( + case queue:out(ActiveConsumers) of + {empty, _} -> + {false, State}; + {{value, QEntry}, Tail} -> + {Stop, State1} = deliver_msg_to_consumer( DeliverFun, QEntry, - FunAcc, State#q{active_consumers = Tail}), - deliver_msgs_to_consumers(Funs, FunAcc1, State1) - end + State#q{active_consumers = Tail}), + deliver_msgs_to_consumers(DeliverFun, Stop, State1) end. -deliver_msg_to_consumer(DeliverFun, E = {ChPid, Consumer}, FunAcc, State) -> +deliver_msg_to_consumer(DeliverFun, E = {ChPid, Consumer}, State) -> C = ch_record(ChPid), case is_ch_blocked(C) of true -> block_consumer(C, E), - {FunAcc, State}; + {false, State}; false -> case rabbit_limiter:can_send(C#cr.limiter, self(), Consumer#consumer.ack_required) of false -> block_consumer(C#cr{is_limit_active = true}, E), - {FunAcc, State}; + {false, State}; true -> AC1 = queue:in(E, State#q.active_consumers), deliver_msg_to_consumer( - DeliverFun, Consumer, C, FunAcc, + DeliverFun, Consumer, C, State#q{active_consumers = AC1}) end end. @@ -428,9 +445,9 @@ C = #cr{ch_pid = ChPid, acktags = ChAckTags, unsent_message_count = Count}, - FunAcc, State = #q{q = #amqqueue{name = QName}}) -> - {{Message, IsDelivered, AckTag}, FunAcc1, State1} = - DeliverFun(AckRequired, FunAcc, State), + State = #q{q = #amqqueue{name = QName}}) -> + {{Message, IsDelivered, AckTag}, Stop, State1} = + DeliverFun(AckRequired, State), rabbit_channel:deliver(ChPid, ConsumerTag, AckRequired, {QName, self(), AckTag, IsDelivered, Message}), ChAckTags1 = case AckRequired of @@ -439,11 +456,9 @@ end, update_ch_record(C#cr{acktags = ChAckTags1, unsent_message_count = Count + 1}), - {FunAcc1, State1}. + {Stop, State1}. -deliver_from_queue_pred(IsEmpty, _State) -> not IsEmpty. - -deliver_from_queue_deliver(AckRequired, false, State) -> +deliver_from_queue_deliver(AckRequired, State) -> {{Message, IsDelivered, AckTag, Remaining}, State1} = fetch(AckRequired, State), {{Message, IsDelivered, AckTag}, 0 == Remaining, State1}. @@ -455,100 +470,96 @@ lists:foldl( fun(MsgId, {CMs, MTC0}) -> case gb_trees:lookup(MsgId, MTC0) of - {value, {ChPid, MsgSeqNo}} -> - {rabbit_misc:gb_trees_cons(ChPid, MsgSeqNo, CMs), + {value, {SenderPid, MsgSeqNo}} -> + {rabbit_misc:gb_trees_cons(SenderPid, + MsgSeqNo, CMs), gb_trees:delete(MsgId, MTC0)}; none -> {CMs, MTC0} end end, {gb_trees:empty(), MTC}, MsgIds), - rabbit_misc:gb_trees_foreach(fun rabbit_channel:confirm/2, CMs), + rabbit_misc:gb_trees_foreach(fun rabbit_misc:confirm_to_sender/2, CMs), State#q{msg_id_to_channel = MTC1}. should_confirm_message(#delivery{msg_seq_no = undefined}, _State) -> never; -should_confirm_message(#delivery{sender = ChPid, +should_confirm_message(#delivery{sender = SenderPid, msg_seq_no = MsgSeqNo, message = #basic_message { is_persistent = true, id = MsgId}}, #q{q = #amqqueue{durable = true}}) -> - {eventually, ChPid, MsgSeqNo, MsgId}; -should_confirm_message(_Delivery, _State) -> - immediately. + {eventually, SenderPid, MsgSeqNo, MsgId}; +should_confirm_message(#delivery{sender = SenderPid, + msg_seq_no = MsgSeqNo}, + _State) -> + {immediately, SenderPid, MsgSeqNo}. needs_confirming({eventually, _, _, _}) -> true; needs_confirming(_) -> false. -maybe_record_confirm_message({eventually, ChPid, MsgSeqNo, MsgId}, +maybe_record_confirm_message({eventually, SenderPid, MsgSeqNo, MsgId}, State = #q{msg_id_to_channel = MTC}) -> - State#q{msg_id_to_channel = gb_trees:insert(MsgId, {ChPid, MsgSeqNo}, MTC)}; + State#q{msg_id_to_channel = + gb_trees:insert(MsgId, {SenderPid, MsgSeqNo}, MTC)}; +maybe_record_confirm_message({immediately, SenderPid, MsgSeqNo}, State) -> + rabbit_misc:confirm_to_sender(SenderPid, [MsgSeqNo]), + State; maybe_record_confirm_message(_Confirm, State) -> State. run_message_queue(State) -> - Funs = {fun deliver_from_queue_pred/2, - fun deliver_from_queue_deliver/3}, State1 = #q{backing_queue = BQ, backing_queue_state = BQS} = drop_expired_messages(State), - IsEmpty = BQ:is_empty(BQS), - {_IsEmpty1, State2} = deliver_msgs_to_consumers(Funs, IsEmpty, State1), + {_IsEmpty1, State2} = deliver_msgs_to_consumers( + fun deliver_from_queue_deliver/2, + BQ:is_empty(BQS), State1), State2. -attempt_delivery(Delivery = #delivery{sender = ChPid, - message = Message, - msg_seq_no = MsgSeqNo}, +attempt_delivery(#delivery{sender = SenderPid, message = Message}, Confirm, State = #q{backing_queue = BQ, backing_queue_state = BQS}) -> - Confirm = should_confirm_message(Delivery, State), - case Confirm of - immediately -> rabbit_channel:confirm(ChPid, [MsgSeqNo]); - _ -> ok - end, case BQ:is_duplicate(Message, BQS) of {false, BQS1} -> - PredFun = fun (IsEmpty, _State) -> not IsEmpty end, - DeliverFun = - fun (AckRequired, false, - State1 = #q{backing_queue_state = BQS2}) -> - %% we don't need an expiry here because - %% messages are not being enqueued, so we use - %% an empty message_properties. - {AckTag, BQS3} = - BQ:publish_delivered( - AckRequired, Message, - (?BASE_MESSAGE_PROPERTIES)#message_properties{ - needs_confirming = needs_confirming(Confirm)}, - ChPid, BQS2), - {{Message, false, AckTag}, true, - State1#q{backing_queue_state = BQS3}} - end, - {Delivered, State2} = - deliver_msgs_to_consumers({ PredFun, DeliverFun }, false, - State#q{backing_queue_state = BQS1}), - {Delivered, Confirm, State2}; + deliver_msgs_to_consumers( + fun (AckRequired, State1 = #q{backing_queue_state = BQS2}) -> + Props = message_properties(Confirm, State1), + {AckTag, BQS3} = BQ:publish_delivered( + AckRequired, Message, Props, + SenderPid, BQS2), + {{Message, false, AckTag}, true, + State1#q{backing_queue_state = BQS3}} + end, false, State#q{backing_queue_state = BQS1}); {Duplicate, BQS1} -> %% if the message has previously been seen by the BQ then %% it must have been seen under the same circumstances as %% now: i.e. if it is now a deliver_immediately then it %% must have been before. - Delivered = case Duplicate of - published -> true; - discarded -> false - end, - {Delivered, Confirm, State#q{backing_queue_state = BQS1}} - end. - -deliver_or_enqueue(Delivery = #delivery{message = Message, - sender = ChPid}, State) -> - {Delivered, Confirm, State1} = attempt_delivery(Delivery, State), - State2 = #q{backing_queue = BQ, backing_queue_state = BQS} = - maybe_record_confirm_message(Confirm, State1), - case Delivered of - true -> State2; - false -> Props = (message_properties(State)) #message_properties{ - needs_confirming = needs_confirming(Confirm)}, - BQS1 = BQ:publish(Message, Props, ChPid, BQS), - ensure_ttl_timer(State2#q{backing_queue_state = BQS1}) + {case Duplicate of + published -> true; + discarded -> false + end, + State#q{backing_queue_state = BQS1}} + end. + +deliver_or_enqueue(Delivery = #delivery{message = Message, + msg_seq_no = MsgSeqNo, + sender = SenderPid}, State) -> + Confirm = should_confirm_message(Delivery, State), + case attempt_delivery(Delivery, Confirm, State) of + {true, State1} -> + maybe_record_confirm_message(Confirm, State1); + %% the next two are optimisations + {false, State1 = #q{ttl = 0, dlx = undefined}} when Confirm == never -> + discard_delivery(Delivery, State1); + {false, State1 = #q{ttl = 0, dlx = undefined}} -> + rabbit_misc:confirm_to_sender(SenderPid, [MsgSeqNo]), + discard_delivery(Delivery, State1); + {false, State1} -> + State2 = #q{backing_queue = BQ, backing_queue_state = BQS} = + maybe_record_confirm_message(Confirm, State1), + Props = message_properties(Confirm, State2), + BQS1 = BQ:publish(Message, Props, SenderPid, BQS), + ensure_ttl_timer(State2#q{backing_queue_state = BQS1}) end. requeue_and_run(AckTags, State = #q{backing_queue = BQ}) -> @@ -597,10 +608,16 @@ should_auto_delete(#q{has_had_consumers = false}) -> false; should_auto_delete(State) -> is_unused(State). -handle_ch_down(DownPid, State = #q{exclusive_consumer = Holder}) -> +handle_ch_down(DownPid, State = #q{exclusive_consumer = Holder, + senders = Senders}) -> + Senders1 = case pmon:is_monitored(DownPid, Senders) of + false -> Senders; + true -> credit_flow:peer_down(DownPid), + pmon:demonitor(DownPid, Senders) + end, case lookup_ch(DownPid) of not_found -> - {ok, State}; + {ok, State#q{senders = Senders1}}; C = #cr{ch_pid = ChPid, acktags = ChAckTags, blocked_consumers = Blocked} -> @@ -612,7 +629,8 @@ Other -> Other end, active_consumers = remove_consumers( - ChPid, State#q.active_consumers)}, + ChPid, State#q.active_consumers), + senders = Senders1}, case should_auto_delete(State1) of true -> {stop, State1}; false -> {ok, requeue_and_run(sets:to_list(ChAckTags), @@ -662,14 +680,15 @@ Fun(State) end. -discard_delivery(#delivery{sender = ChPid, +discard_delivery(#delivery{sender = SenderPid, message = Message}, State = #q{backing_queue = BQ, backing_queue_state = BQS}) -> - State#q{backing_queue_state = BQ:discard(Message, ChPid, BQS)}. + State#q{backing_queue_state = BQ:discard(Message, SenderPid, BQS)}. -message_properties(#q{ttl=TTL}) -> - #message_properties{expiry = calculate_msg_expiry(TTL)}. +message_properties(Confirm, #q{ttl = TTL}) -> + #message_properties{expiry = calculate_msg_expiry(TTL), + needs_confirming = needs_confirming(Confirm)}. calculate_msg_expiry(undefined) -> undefined; calculate_msg_expiry(TTL) -> now_micros() + (TTL * 1000). @@ -677,11 +696,18 @@ drop_expired_messages(State = #q{ttl = undefined}) -> State; drop_expired_messages(State = #q{backing_queue_state = BQS, - backing_queue = BQ}) -> + backing_queue = BQ }) -> Now = now_micros(), - BQS1 = BQ:dropwhile( - fun (#message_properties{expiry = Expiry}) -> Now > Expiry end, - BQS), + DLXFun = dead_letter_fun(expired, State), + ExpirePred = fun (#message_properties{expiry = Expiry}) -> Now > Expiry end, + case DLXFun of + undefined -> {undefined, BQS1} = BQ:dropwhile(ExpirePred, false, BQS), + BQS1; + _ -> {Msgs, BQS1} = BQ:dropwhile(ExpirePred, true, BQS), + lists:foreach( + fun({Msg, AckTag}) -> DLXFun(Msg, AckTag) end, Msgs), + BQS1 + end, ensure_ttl_timer(State#q{backing_queue_state = BQS1}). ensure_ttl_timer(State = #q{backing_queue = BQ, @@ -697,6 +723,156 @@ ensure_ttl_timer(State) -> State. +ack_if_no_dlx(AckTags, State = #q{dlx = undefined, + backing_queue = BQ, + backing_queue_state = BQS }) -> + {_Guids, BQS1} = BQ:ack(AckTags, BQS), + State#q{backing_queue_state = BQS1}; +ack_if_no_dlx(_AckTags, State) -> + State. + +dead_letter_fun(_Reason, #q{dlx = undefined}) -> + undefined; +dead_letter_fun(Reason, _State) -> + fun(Msg, AckTag) -> + gen_server2:cast(self(), {dead_letter, {Msg, AckTag}, Reason}) + end. + +dead_letter_publish(Msg, Reason, State = #q{publish_seqno = MsgSeqNo}) -> + DLMsg = #basic_message{exchange_name = XName} = + make_dead_letter_msg(Reason, Msg, State), + case rabbit_exchange:lookup(XName) of + {ok, X} -> + Delivery = rabbit_basic:delivery(false, false, DLMsg, MsgSeqNo), + {Queues, Cycles} = detect_dead_letter_cycles( + DLMsg, rabbit_exchange:route(X, Delivery)), + lists:foreach(fun log_cycle_once/1, Cycles), + QPids = rabbit_amqqueue:lookup(Queues), + {_, DeliveredQPids} = rabbit_amqqueue:deliver(QPids, Delivery), + DeliveredQPids; + {error, not_found} -> + [] + end. + +dead_letter_msg(Msg, AckTag, Reason, State = #q{publish_seqno = MsgSeqNo, + unconfirmed = UC}) -> + QPids = dead_letter_publish(Msg, Reason, State), + State1 = State#q{queue_monitors = pmon:monitor_all( + QPids, State#q.queue_monitors), + publish_seqno = MsgSeqNo + 1}, + case QPids of + [] -> cleanup_after_confirm([AckTag], State1); + _ -> UC1 = dtree:insert(MsgSeqNo, QPids, AckTag, UC), + noreply(State1#q{unconfirmed = UC1}) + end. + +handle_queue_down(QPid, Reason, State = #q{queue_monitors = QMons, + unconfirmed = UC}) -> + case pmon:is_monitored(QPid, QMons) of + false -> noreply(State); + true -> case rabbit_misc:is_abnormal_termination(Reason) of + true -> {Lost, _UC1} = dtree:take_all(QPid, UC), + QNameS = rabbit_misc:rs(qname(State)), + rabbit_log:warning("DLQ ~p for ~s died with " + "~p unconfirmed messages~n", + [QPid, QNameS, length(Lost)]); + false -> ok + end, + {MsgSeqNoAckTags, UC1} = dtree:take(QPid, UC), + cleanup_after_confirm( + [AckTag || {_MsgSeqNo, AckTag} <- MsgSeqNoAckTags], + State#q{queue_monitors = pmon:erase(QPid, QMons), + unconfirmed = UC1}) + end. + +stop_later(Reason, State) -> + stop_later(Reason, undefined, noreply, State). + +stop_later(Reason, From, Reply, State = #q{unconfirmed = UC}) -> + case {dtree:is_empty(UC), Reply} of + {true, noreply} -> + {stop, Reason, State}; + {true, _} -> + {stop, Reason, Reply, State}; + {false, _} -> + noreply(State#q{delayed_stop = {Reason, {From, Reply}}}) + end. + +cleanup_after_confirm(AckTags, State = #q{delayed_stop = DS, + unconfirmed = UC, + backing_queue = BQ, + backing_queue_state = BQS}) -> + {_Guids, BQS1} = BQ:ack(AckTags, BQS), + State1 = State#q{backing_queue_state = BQS1}, + case dtree:is_empty(UC) andalso DS =/= undefined of + true -> case DS of + {_, {_, noreply}} -> ok; + {_, {From, Reply}} -> gen_server2:reply(From, Reply) + end, + {Reason, _} = DS, + {stop, Reason, State1}; + false -> noreply(State1) + end. + +detect_dead_letter_cycles(#basic_message{content = Content}, Queues) -> + #content{properties = #'P_basic'{headers = Headers}} = + rabbit_binary_parser:ensure_content_decoded(Content), + NoCycles = {Queues, []}, + case Headers of + undefined -> + NoCycles; + _ -> + case rabbit_misc:table_lookup(Headers, <<"x-death">>) of + {array, DeathTables} -> + OldQueues = [rabbit_misc:table_lookup(D, <<"queue">>) || + {table, D} <- DeathTables], + OldQueues1 = [QName || {longstr, QName} <- OldQueues], + OldQueuesSet = ordsets:from_list(OldQueues1), + {Cycling, NotCycling} = + lists:partition( + fun(Queue) -> + ordsets:is_element(Queue#resource.name, + OldQueuesSet) + end, Queues), + {NotCycling, [[QName | OldQueues1] || + #resource{name = QName} <- Cycling]}; + _ -> + NoCycles + end + end. + +make_dead_letter_msg(Reason, + Msg = #basic_message{content = Content, + exchange_name = Exchange, + routing_keys = RoutingKeys}, + State = #q{dlx = DLX, dlx_routing_key = DlxRoutingKey}) -> + {DeathRoutingKeys, HeadersFun1} = + case DlxRoutingKey of + undefined -> {RoutingKeys, fun (H) -> H end}; + _ -> {[DlxRoutingKey], + fun (H) -> lists:keydelete(<<"CC">>, 1, H) end} + end, + ReasonBin = list_to_binary(atom_to_list(Reason)), + #resource{name = QName} = qname(State), + TimeSec = rabbit_misc:now_ms() div 1000, + HeadersFun2 = + fun (Headers) -> + %% The first routing key is the one specified in the + %% basic.publish; all others are CC or BCC keys. + RKs = [hd(RoutingKeys) | rabbit_basic:header_routes(Headers)], + RKs1 = [{longstr, Key} || Key <- RKs], + Info = [{<<"reason">>, longstr, ReasonBin}, + {<<"queue">>, longstr, QName}, + {<<"time">>, timestamp, TimeSec}, + {<<"exchange">>, longstr, Exchange#resource.name}, + {<<"routing-keys">>, array, RKs1}], + HeadersFun1(rabbit_basic:append_table_header(<<"x-death">>, + Info, Headers)) + end, + Content1 = rabbit_basic:map_headers(HeadersFun2, Content), + Msg#basic_message{exchange_name = DLX, id = rabbit_guid:gen(), + routing_keys = DeathRoutingKeys, content = Content1}. + now_micros() -> timer:now_diff(now(), {0,0,0}). infos(Items, State) -> @@ -713,15 +889,12 @@ || Item <- (Items1 -- [synchronised_slave_pids])]. slaves_status(#q{q = #amqqueue{name = Name}}) -> - {ok, #amqqueue{mirror_nodes = MNodes, slave_pids = SPids}} = - rabbit_amqqueue:lookup(Name), - case MNodes of - undefined -> + case rabbit_amqqueue:lookup(Name) of + {ok, #amqqueue{mirror_nodes = undefined}} -> [{slave_pids, ''}, {synchronised_slave_pids, ''}]; - _ -> + {ok, #amqqueue{slave_pids = SPids}} -> {Results, _Bad} = - delegate:invoke( - SPids, fun (Pid) -> rabbit_mirror_queue_slave:info(Pid) end), + delegate:invoke(SPids, fun rabbit_mirror_queue_slave:info/1), {SPids1, SSPids} = lists:foldl( fun ({Pid, Infos}, {SPidsN, SSPidsN}) -> @@ -765,11 +938,9 @@ {memory, M} = process_info(self(), memory), M; i(slave_pids, #q{q = #amqqueue{name = Name}}) -> - {ok, #amqqueue{mirror_nodes = MNodes, - slave_pids = SPids}} = rabbit_amqqueue:lookup(Name), - case MNodes of - undefined -> []; - _ -> SPids + case rabbit_amqqueue:lookup(Name) of + {ok, #amqqueue{mirror_nodes = undefined}} -> []; + {ok, #amqqueue{slave_pids = SPids}} -> SPids end; i(backing_queue_status, #q{backing_queue_state = BQS, backing_queue = BQ}) -> BQ:status(BQS); @@ -813,8 +984,6 @@ info -> 9; {info, _Items} -> 9; consumers -> 9; - {basic_consume, _, _, _, _, _, _} -> 7; - {basic_cancel, _, _, _} -> 7; stat -> 7; _ -> 0 end. @@ -824,10 +993,6 @@ delete_immediately -> 8; {set_ram_duration_target, _Duration} -> 8; {set_maximum_since_use, _Age} -> 8; - {ack, _AckTags, _ChPid} -> 7; - {reject, _AckTags, _Requeue, _ChPid} -> 7; - {notify_sent, _ChPid} -> 7; - {unblock, _ChPid} -> 7; {run_backing_queue, _Mod, _Fun} -> 6; _ -> 0 end. @@ -843,6 +1008,9 @@ _ -> 0 end. +handle_call(_, _, State = #q{delayed_stop = DS}) when DS =/= undefined -> + noreply(State); + handle_call({init, Recover}, From, State = #q{q = #amqqueue{exclusive_owner = none}}) -> declare(Recover, From, State); @@ -877,9 +1045,7 @@ handle_call(consumers, _From, State) -> reply(consumers(State), State); -handle_call({deliver_immediately, Delivery}, _From, State) -> - %% Synchronous, "immediate" delivery mode - %% +handle_call({deliver, Delivery = #delivery{immediate = true}}, _From, State) -> %% FIXME: Is this correct semantics? %% %% I'm worried in particular about the case where an exchange has @@ -891,26 +1057,26 @@ %% just all ready-to-consume queues get the message, with unready %% queues discarding the message? %% - {Delivered, Confirm, State1} = attempt_delivery(Delivery, State), + Confirm = should_confirm_message(Delivery, State), + {Delivered, State1} = attempt_delivery(Delivery, Confirm, State), reply(Delivered, case Delivered of true -> maybe_record_confirm_message(Confirm, State1); false -> discard_delivery(Delivery, State1) end); -handle_call({deliver, Delivery}, From, State) -> - %% Synchronous, "mandatory" delivery mode. Reply asap. +handle_call({deliver, Delivery = #delivery{mandatory = true}}, From, State) -> gen_server2:reply(From, true), noreply(deliver_or_enqueue(Delivery, State)); -handle_call({notify_down, ChPid}, _From, State) -> +handle_call({notify_down, ChPid}, From, State) -> %% we want to do this synchronously, so that auto_deleted queues %% are no longer visible by the time we send a response to the %% client. The queue is ultimately deleted in terminate/2; if we %% return stop with a reply, terminate/2 will be called by %% gen_server2 *before* the reply is sent. case handle_ch_down(ChPid, State) of - {ok, NewState} -> reply(ok, NewState); - {stop, NewState} -> {stop, normal, ok, NewState} + {ok, State1} -> reply(ok, State1); + {stop, State1} -> stop_later(normal, From, ok, State1) end; handle_call({basic_get, ChPid, NoAck}, _From, @@ -965,7 +1131,7 @@ reply(ok, State2) end; -handle_call({basic_cancel, ChPid, ConsumerTag, OkMsg}, _From, +handle_call({basic_cancel, ChPid, ConsumerTag, OkMsg}, From, State = #q{exclusive_consumer = Holder}) -> ok = maybe_send_reply(ChPid, OkMsg), case lookup_ch(ChPid) of @@ -985,7 +1151,7 @@ State#q.active_consumers)}, case should_auto_delete(State1) of false -> reply(ok, ensure_expiry_timer(State1)); - true -> {stop, normal, ok, State1} + true -> stop_later(normal, From, ok, State1) end end; @@ -994,20 +1160,18 @@ drop_expired_messages(ensure_expiry_timer(State)), reply({ok, BQ:len(BQS), active_consumer_count()}, State1); -handle_call({delete, IfUnused, IfEmpty}, _From, +handle_call({delete, IfUnused, IfEmpty}, From, State = #q{backing_queue_state = BQS, backing_queue = BQ}) -> IsEmpty = BQ:is_empty(BQS), IsUnused = is_unused(State), if - IfEmpty and not(IsEmpty) -> - reply({error, not_empty}, State); - IfUnused and not(IsUnused) -> - reply({error, in_use}, State); - true -> - {stop, normal, {ok, BQ:len(BQS)}, State} + IfEmpty and not(IsEmpty) -> reply({error, not_empty}, State); + IfUnused and not(IsUnused) -> reply({error, in_use}, State); + true -> stop_later(normal, From, + {ok, BQ:len(BQS)}, State) end; -handle_call(purge, _From, State = #q{backing_queue = BQ, +handle_call(purge, _From, State = #q{backing_queue = BQ, backing_queue_state = BQS}) -> {Count, BQS1} = BQ:purge(BQS), reply({ok, Count}, State#q{backing_queue_state = BQS1}); @@ -1016,14 +1180,45 @@ gen_server2:reply(From, ok), noreply(subtract_acks( ChPid, AckTags, State, - fun (State1) -> requeue_and_run(AckTags, State1) end)). + fun (State1) -> requeue_and_run(AckTags, State1) end)); + +handle_call(force_event_refresh, _From, + State = #q{exclusive_consumer = Exclusive}) -> + rabbit_event:notify(queue_created, infos(?CREATION_EVENT_KEYS, State)), + case Exclusive of + none -> [emit_consumer_created(Ch, CTag, false, AckRequired) || + {Ch, CTag, AckRequired} <- consumers(State)]; + {Ch, CTag} -> [{Ch, CTag, AckRequired}] = consumers(State), + emit_consumer_created(Ch, CTag, true, AckRequired) + end, + reply(ok, State). + +handle_cast({confirm, MsgSeqNos, QPid}, State = #q{unconfirmed = UC}) -> + {MsgSeqNoAckTags, UC1} = dtree:take(MsgSeqNos, QPid, UC), + State1 = case dtree:is_defined(QPid, UC1) of + false -> QMons = State#q.queue_monitors, + State#q{queue_monitors = pmon:demonitor(QPid, QMons)}; + true -> State + end, + cleanup_after_confirm([AckTag || {_MsgSeqNo, AckTag} <- MsgSeqNoAckTags], + State1#q{unconfirmed = UC1}); + +handle_cast(_, State = #q{delayed_stop = DS}) when DS =/= undefined -> + noreply(State); handle_cast({run_backing_queue, Mod, Fun}, State) -> noreply(run_backing_queue(Mod, Fun, State)); -handle_cast({deliver, Delivery}, State) -> +handle_cast({deliver, Delivery = #delivery{sender = Sender}, Flow}, + State = #q{senders = Senders}) -> %% Asynchronous, non-"mandatory", non-"immediate" deliver mode. - noreply(deliver_or_enqueue(Delivery, State)); + Senders1 = case Flow of + flow -> credit_flow:ack(Sender), + pmon:monitor(Sender, Senders); + noflow -> Senders + end, + State1 = State#q{senders = Senders1}, + noreply(deliver_or_enqueue(Delivery, State1)); handle_cast({ack, AckTags, ChPid}, State) -> noreply(subtract_acks( @@ -1037,28 +1232,31 @@ handle_cast({reject, AckTags, Requeue, ChPid}, State) -> noreply(subtract_acks( ChPid, AckTags, State, - fun (State1 = #q{backing_queue = BQ, - backing_queue_state = BQS}) -> - case Requeue of - true -> requeue_and_run(AckTags, State1); - false -> {_Guids, BQS1} = BQ:ack(AckTags, BQS), - State1#q{backing_queue_state = BQS1} - end + case Requeue of + true -> fun (State1) -> requeue_and_run(AckTags, State1) end; + false -> fun (State1 = #q{backing_queue = BQ, + backing_queue_state = BQS}) -> + Fun = dead_letter_fun(rejected, State1), + BQS1 = BQ:fold(Fun, BQS, AckTags), + ack_if_no_dlx( + AckTags, + State1#q{backing_queue_state = BQS1}) + end end)); handle_cast(delete_immediately, State) -> - {stop, normal, State}; + stop_later(normal, State); handle_cast({unblock, ChPid}, State) -> noreply( possibly_unblock(State, ChPid, fun (C) -> C#cr{is_limit_active = false} end)); -handle_cast({notify_sent, ChPid}, State) -> +handle_cast({notify_sent, ChPid, Credit}, State) -> noreply( possibly_unblock(State, ChPid, fun (C = #cr{unsent_message_count = Count}) -> - C#cr{unsent_message_count = Count - 1} + C#cr{unsent_message_count = Count - Credit} end)); handle_cast({limit, ChPid, Limiter}, State) -> @@ -1090,20 +1288,21 @@ ok = file_handle_cache:set_maximum_since_use(Age), noreply(State); -handle_cast(force_event_refresh, State = #q{exclusive_consumer = Exclusive}) -> - rabbit_event:notify(queue_created, infos(?CREATION_EVENT_KEYS, State)), - case Exclusive of - none -> [emit_consumer_created(Ch, CTag, false, AckRequired) || - {Ch, CTag, AckRequired} <- consumers(State)]; - {Ch, CTag} -> [{Ch, CTag, AckRequired}] = consumers(State), - emit_consumer_created(Ch, CTag, true, AckRequired) - end, - noreply(State). +handle_cast({dead_letter, {Msg, AckTag}, Reason}, State) -> + dead_letter_msg(Msg, AckTag, Reason, State). + +%% We need to not ignore this as we need to remove outstanding +%% confirms due to queue death. +handle_info({'DOWN', _MonitorRef, process, DownPid, Reason}, + State = #q{delayed_stop = DS}) when DS =/= undefined -> + handle_queue_down(DownPid, Reason, State); + +handle_info(_, State = #q{delayed_stop = DS}) when DS =/= undefined -> + noreply(State); handle_info(maybe_expire, State) -> case is_unused(State) of - true -> ?LOGDEBUG("Queue lease expired for ~p~n", [State#q.q]), - {stop, normal, State}; + true -> stop_later(normal, State); false -> noreply(ensure_expiry_timer(State)) end; @@ -1125,11 +1324,12 @@ %% match what people expect (see bug 21824). However we need this %% monitor-and-async- delete in case the connection goes away %% unexpectedly. - {stop, normal, State}; -handle_info({'DOWN', _MonitorRef, process, DownPid, _Reason}, State) -> + stop_later(normal, State); + +handle_info({'DOWN', _MonitorRef, process, DownPid, Reason}, State) -> case handle_ch_down(DownPid, State) of - {ok, NewState} -> noreply(NewState); - {stop, NewState} -> {stop, normal, NewState} + {ok, State1} -> handle_queue_down(DownPid, Reason, State1); + {stop, State1} -> stop_later(normal, State1) end; handle_info(update_ram_duration, State = #q{backing_queue = BQ, @@ -1150,8 +1350,11 @@ handle_info({'EXIT', _Pid, Reason}, State) -> {stop, Reason, State}; +handle_info({bump_credit, Msg}, State) -> + credit_flow:handle_bump_msg(Msg), + noreply(State); + handle_info(Info, State) -> - ?LOGDEBUG("Info in queue: ~p~n", [Info]), {stop, {unhandled_info, Info}, State}. handle_pre_hibernate(State = #q{backing_queue_state = undefined}) -> @@ -1171,3 +1374,14 @@ {hibernate, stop_rate_timer(State1)}. format_message_queue(Opt, MQ) -> rabbit_misc:format_message_queue(Opt, MQ). + +log_cycle_once(Queues) -> + Key = {queue_cycle, Queues}, + case get(Key) of + true -> ok; + undefined -> rabbit_log:warning( + "Message dropped. Dead-letter queues cycle detected" ++ + ": ~p~nThis cycle will NOT be reported again.~n", + [Queues]), + put(Key, true) + end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_amqqueue_sup.erl rabbitmq-server-2.8.4/src/rabbit_amqqueue_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_amqqueue_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_amqqueue_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_amqqueue_sup). diff -Nru rabbitmq-server-2.7.1/src/rabbit_auth_backend.erl rabbitmq-server-2.8.4/src/rabbit_auth_backend.erl --- rabbitmq-server-2.7.1/src/rabbit_auth_backend.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_auth_backend.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,47 +11,62 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend). +-ifdef(use_specs). + +%% A description proplist as with auth mechanisms, +%% exchanges. Currently unused. +-callback description() -> [proplist:property()]. + +%% Check a user can log in, given a username and a proplist of +%% authentication information (e.g. [{password, Password}]). +%% +%% Possible responses: +%% {ok, User} +%% Authentication succeeded, and here's the user record. +%% {error, Error} +%% Something went wrong. Log and die. +%% {refused, Msg, Args} +%% Client failed authentication. Log and die. +-callback check_user_login(rabbit_types:username(), [term()]) -> + {'ok', rabbit_types:user()} | + {'refused', string(), [any()]} | + {'error', any()}. + +%% Given #user and vhost, can a user log in to a vhost? +%% Possible responses: +%% true +%% false +%% {error, Error} +%% Something went wrong. Log and die. +-callback check_vhost_access(rabbit_types:user(), rabbit_types:vhost()) -> + boolean() | {'error', any()}. + + +%% Given #user, resource and permission, can a user access a resource? +%% +%% Possible responses: +%% true +%% false +%% {error, Error} +%% Something went wrong. Log and die. +-callback check_resource_access(rabbit_types:user(), + rabbit_types:r(atom()), + rabbit_access_control:permission_atom()) -> + boolean() | {'error', any()}. + +-else. + -export([behaviour_info/1]). behaviour_info(callbacks) -> - [ - %% A description proplist as with auth mechanisms, - %% exchanges. Currently unused. - {description, 0}, - - %% Check a user can log in, given a username and a proplist of - %% authentication information (e.g. [{password, Password}]). - %% - %% Possible responses: - %% {ok, User} - %% Authentication succeeded, and here's the user record. - %% {error, Error} - %% Something went wrong. Log and die. - %% {refused, Msg, Args} - %% Client failed authentication. Log and die. - {check_user_login, 2}, - - %% Given #user and vhost, can a user log in to a vhost? - %% Possible responses: - %% true - %% false - %% {error, Error} - %% Something went wrong. Log and die. - {check_vhost_access, 2}, - - %% Given #user, resource and permission, can a user access a resource? - %% - %% Possible responses: - %% true - %% false - %% {error, Error} - %% Something went wrong. Log and die. - {check_resource_access, 3} - ]; + [{description, 0}, {check_user_login, 2}, {check_vhost_access, 2}, + {check_resource_access, 3}]; behaviour_info(_Other) -> undefined. + +-endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_auth_backend_internal.erl rabbitmq-server-2.8.4/src/rabbit_auth_backend_internal.erl --- rabbitmq-server-2.7.1/src/rabbit_auth_backend_internal.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_auth_backend_internal.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_backend_internal). @@ -32,8 +32,6 @@ vhost_perms_info_keys/0, user_perms_info_keys/0, user_vhost_perms_info_keys/0]). --include("rabbit_auth_backend_spec.hrl"). - -ifdef(use_specs). -type(regexp() :: binary()). diff -Nru rabbitmq-server-2.7.1/src/rabbit_auth_mechanism_amqplain.erl rabbitmq-server-2.8.4/src/rabbit_auth_mechanism_amqplain.erl --- rabbitmq-server-2.7.1/src/rabbit_auth_mechanism_amqplain.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_auth_mechanism_amqplain.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_amqplain). @@ -21,8 +21,6 @@ -export([description/0, should_offer/1, init/1, handle_response/2]). --include("rabbit_auth_mechanism_spec.hrl"). - -rabbit_boot_step({?MODULE, [{description, "auth mechanism amqplain"}, {mfa, {rabbit_registry, register, diff -Nru rabbitmq-server-2.7.1/src/rabbit_auth_mechanism_cr_demo.erl rabbitmq-server-2.8.4/src/rabbit_auth_mechanism_cr_demo.erl --- rabbitmq-server-2.7.1/src/rabbit_auth_mechanism_cr_demo.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_auth_mechanism_cr_demo.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_cr_demo). @@ -21,8 +21,6 @@ -export([description/0, should_offer/1, init/1, handle_response/2]). --include("rabbit_auth_mechanism_spec.hrl"). - -rabbit_boot_step({?MODULE, [{description, "auth mechanism cr-demo"}, {mfa, {rabbit_registry, register, diff -Nru rabbitmq-server-2.7.1/src/rabbit_auth_mechanism.erl rabbitmq-server-2.8.4/src/rabbit_auth_mechanism.erl --- rabbitmq-server-2.7.1/src/rabbit_auth_mechanism.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_auth_mechanism.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,36 +11,46 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_mechanism). +-ifdef(use_specs). + +%% A description. +-callback description() -> [proplist:property()]. + +%% If this mechanism is enabled, should it be offered for a given socket? +%% (primarily so EXTERNAL can be SSL-only) +-callback should_offer(rabbit_net:socket()) -> boolean(). + +%% Called before authentication starts. Should create a state +%% object to be passed through all the stages of authentication. +-callback init(rabbit_net:socket()) -> any(). + +%% Handle a stage of authentication. Possible responses: +%% {ok, User} +%% Authentication succeeded, and here's the user record. +%% {challenge, Challenge, NextState} +%% Another round is needed. Here's the state I want next time. +%% {protocol_error, Msg, Args} +%% Client got the protocol wrong. Log and die. +%% {refused, Msg, Args} +%% Client failed authentication. Log and die. +-callback handle_response(binary(), any()) -> + {'ok', rabbit_types:user()} | + {'challenge', binary(), any()} | + {'protocol_error', string(), [any()]} | + {'refused', string(), [any()]}. + +-else. + -export([behaviour_info/1]). behaviour_info(callbacks) -> - [ - %% A description. - {description, 0}, - - %% If this mechanism is enabled, should it be offered for a given socket? - %% (primarily so EXTERNAL can be SSL-only) - {should_offer, 1}, - - %% Called before authentication starts. Should create a state - %% object to be passed through all the stages of authentication. - {init, 1}, - - %% Handle a stage of authentication. Possible responses: - %% {ok, User} - %% Authentication succeeded, and here's the user record. - %% {challenge, Challenge, NextState} - %% Another round is needed. Here's the state I want next time. - %% {protocol_error, Msg, Args} - %% Client got the protocol wrong. Log and die. - %% {refused, Msg, Args} - %% Client failed authentication. Log and die. - {handle_response, 2} - ]; + [{description, 0}, {should_offer, 1}, {init, 1}, {handle_response, 2}]; behaviour_info(_Other) -> undefined. + +-endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_auth_mechanism_plain.erl rabbitmq-server-2.8.4/src/rabbit_auth_mechanism_plain.erl --- rabbitmq-server-2.7.1/src/rabbit_auth_mechanism_plain.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_auth_mechanism_plain.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_plain). @@ -21,8 +21,6 @@ -export([description/0, should_offer/1, init/1, handle_response/2]). --include("rabbit_auth_mechanism_spec.hrl"). - -rabbit_boot_step({?MODULE, [{description, "auth mechanism plain"}, {mfa, {rabbit_registry, register, diff -Nru rabbitmq-server-2.7.1/src/rabbit_backing_queue.erl rabbitmq-server-2.8.4/src/rabbit_backing_queue.erl --- rabbitmq-server-2.7.1/src/rabbit_backing_queue.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_backing_queue.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,161 +11,208 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_backing_queue). +-ifdef(use_specs). + +%% We can't specify a per-queue ack/state with callback signatures +-type(ack() :: any()). +-type(state() :: any()). + +-type(fetch_result(Ack) :: + ('empty' | + %% Message, IsDelivered, AckTag, Remaining_Len + {rabbit_types:basic_message(), boolean(), Ack, non_neg_integer()})). +-type(is_durable() :: boolean()). +-type(attempt_recovery() :: boolean()). +-type(purged_msg_count() :: non_neg_integer()). +-type(confirm_required() :: boolean()). +-type(async_callback() :: fun ((atom(), fun ((atom(), state()) -> state())) -> 'ok')). +-type(duration() :: ('undefined' | 'infinity' | number())). + +-type(msg_fun() :: fun((rabbit_types:basic_message(), ack()) -> 'ok') | + 'undefined'). +-type(msg_pred() :: fun ((rabbit_types:message_properties()) -> boolean())). + +%% Called on startup with a list of durable queue names. The queues +%% aren't being started at this point, but this call allows the +%% backing queue to perform any checking necessary for the consistency +%% of those queues, or initialise any other shared resources. +-callback start([rabbit_amqqueue:name()]) -> 'ok'. + +%% Called to tear down any state/resources. NB: Implementations should +%% not depend on this function being called on shutdown and instead +%% should hook into the rabbit supervision hierarchy. +-callback stop() -> 'ok'. + +%% Initialise the backing queue and its state. +%% +%% Takes +%% 1. the amqqueue record +%% 2. a boolean indicating whether the queue is an existing queue that +%% should be recovered +%% 3. an asynchronous callback which accepts a function of type +%% backing-queue-state to backing-queue-state. This callback +%% function can be safely invoked from any process, which makes it +%% useful for passing messages back into the backing queue, +%% especially as the backing queue does not have control of its own +%% mailbox. +-callback init(rabbit_types:amqqueue(), attempt_recovery(), + async_callback()) -> state(). + +%% Called on queue shutdown when queue isn't being deleted. +-callback terminate(any(), state()) -> state(). + +%% Called when the queue is terminating and needs to delete all its +%% content. +-callback delete_and_terminate(any(), state()) -> state(). + +%% Remove all messages in the queue, but not messages which have been +%% fetched and are pending acks. +-callback purge(state()) -> {purged_msg_count(), state()}. + +%% Publish a message. +-callback publish(rabbit_types:basic_message(), + rabbit_types:message_properties(), pid(), state()) -> + state(). + +%% Called for messages which have already been passed straight +%% out to a client. The queue will be empty for these calls +%% (i.e. saves the round trip through the backing queue). +-callback publish_delivered(true, rabbit_types:basic_message(), + rabbit_types:message_properties(), pid(), state()) + -> {ack(), state()}; + (false, rabbit_types:basic_message(), + rabbit_types:message_properties(), pid(), state()) + -> {undefined, state()}. + +%% Return ids of messages which have been confirmed since the last +%% invocation of this function (or initialisation). +%% +%% Message ids should only appear in the result of drain_confirmed +%% under the following circumstances: +%% +%% 1. The message appears in a call to publish_delivered/4 and the +%% first argument (ack_required) is false; or +%% 2. The message is fetched from the queue with fetch/2 and the first +%% argument (ack_required) is false; or +%% 3. The message is acked (ack/2 is called for the message); or +%% 4. The message is fully fsync'd to disk in such a way that the +%% recovery of the message is guaranteed in the event of a crash of +%% this rabbit node (excluding hardware failure). +%% +%% In addition to the above conditions, a message id may only appear +%% in the result of drain_confirmed if +%% #message_properties.needs_confirming = true when the msg was +%% published (through whichever means) to the backing queue. +%% +%% It is legal for the same message id to appear in the results of +%% multiple calls to drain_confirmed, which means that the backing +%% queue is not required to keep track of which messages it has +%% already confirmed. The confirm will be issued to the publisher the +%% first time the message id appears in the result of +%% drain_confirmed. All subsequent appearances of that message id will +%% be ignored. +-callback drain_confirmed(state()) -> {[rabbit_guid:guid()], state()}. + +%% Drop messages from the head of the queue while the supplied predicate returns +%% true. Also accepts a boolean parameter that determines whether the messages +%% necessitate an ack or not. If they do, the function returns a list of +%% messages with the respective acktags. +-callback dropwhile(msg_pred(), true, state()) + -> {[{rabbit_types:basic_message(), ack()}], state()}; + (msg_pred(), false, state()) + -> {undefined, state()}. + +%% Produce the next message. +-callback fetch(true, state()) -> {fetch_result(ack()), state()}; + (false, state()) -> {fetch_result(undefined), state()}. + +%% Acktags supplied are for messages which can now be forgotten +%% about. Must return 1 msg_id per Ack, in the same order as Acks. +-callback ack([ack()], state()) -> {[rabbit_guid:guid()], state()}. + +%% Acktags supplied are for messages which should be processed. The +%% provided callback function is called with each message. +-callback fold(msg_fun(), state(), [ack()]) -> state(). + +%% Reinsert messages into the queue which have already been delivered +%% and were pending acknowledgement. +-callback requeue([ack()], state()) -> {[rabbit_guid:guid()], state()}. + +%% How long is my queue? +-callback len(state()) -> non_neg_integer(). + +%% Is my queue empty? +-callback is_empty(state()) -> boolean(). + +%% For the next three functions, the assumption is that you're +%% monitoring something like the ingress and egress rates of the +%% queue. The RAM duration is thus the length of time represented by +%% the messages held in RAM given the current rates. If you want to +%% ignore all of this stuff, then do so, and return 0 in +%% ram_duration/1. + +%% The target is to have no more messages in RAM than indicated by the +%% duration and the current queue rates. +-callback set_ram_duration_target(duration(), state()) -> state(). + +%% Optionally recalculate the duration internally (likely to be just +%% update your internal rates), and report how many seconds the +%% messages in RAM represent given the current rates of the queue. +-callback ram_duration(state()) -> {duration(), state()}. + +%% Should 'timeout' be called as soon as the queue process can manage +%% (either on an empty mailbox, or when a timer fires)? +-callback needs_timeout(state()) -> 'false' | 'timed' | 'idle'. + +%% Called (eventually) after needs_timeout returns 'idle' or 'timed'. +%% Note this may be called more than once for each 'idle' or 'timed' +%% returned from needs_timeout +-callback timeout(state()) -> state(). + +%% Called immediately before the queue hibernates. +-callback handle_pre_hibernate(state()) -> state(). + +%% Exists for debugging purposes, to be able to expose state via +%% rabbitmqctl list_queues backing_queue_status +-callback status(state()) -> [{atom(), any()}]. + +%% Passed a function to be invoked with the relevant backing queue's +%% state. Useful for when the backing queue or other components need +%% to pass functions into the backing queue. +-callback invoke(atom(), fun ((atom(), A) -> A), state()) -> state(). + +%% Called prior to a publish or publish_delivered call. Allows the BQ +%% to signal that it's already seen this message (and in what capacity +%% - i.e. was it published previously or discarded previously) and +%% thus the message should be dropped. +-callback is_duplicate(rabbit_types:basic_message(), state()) + -> {'false'|'published'|'discarded', state()}. + +%% Called to inform the BQ about messages which have reached the +%% queue, but are not going to be further passed to BQ for some +%% reason. Note that this is may be invoked for messages for which +%% BQ:is_duplicate/2 has already returned {'published' | 'discarded', +%% BQS}. +-callback discard(rabbit_types:basic_message(), pid(), state()) -> state(). + +-else. + -export([behaviour_info/1]). behaviour_info(callbacks) -> - [ - %% Called on startup with a list of durable queue names. The - %% queues aren't being started at this point, but this call - %% allows the backing queue to perform any checking necessary for - %% the consistency of those queues, or initialise any other - %% shared resources. - {start, 1}, - - %% Called to tear down any state/resources. NB: Implementations - %% should not depend on this function being called on shutdown - %% and instead should hook into the rabbit supervision hierarchy. - {stop, 0}, - - %% Initialise the backing queue and its state. - %% - %% Takes - %% 1. the amqqueue record - %% 2. a boolean indicating whether the queue is an existing queue - %% that should be recovered - %% 3. an asynchronous callback which accepts a function of type - %% backing-queue-state to backing-queue-state. This callback - %% function can be safely invoked from any process, which - %% makes it useful for passing messages back into the backing - %% queue, especially as the backing queue does not have - %% control of its own mailbox. - {init, 3}, - - %% Called on queue shutdown when queue isn't being deleted. - {terminate, 2}, - - %% Called when the queue is terminating and needs to delete all - %% its content. - {delete_and_terminate, 2}, - - %% Remove all messages in the queue, but not messages which have - %% been fetched and are pending acks. - {purge, 1}, - - %% Publish a message. - {publish, 4}, - - %% Called for messages which have already been passed straight - %% out to a client. The queue will be empty for these calls - %% (i.e. saves the round trip through the backing queue). - {publish_delivered, 5}, - - %% Return ids of messages which have been confirmed since - %% the last invocation of this function (or initialisation). - %% - %% Message ids should only appear in the result of - %% drain_confirmed under the following circumstances: - %% - %% 1. The message appears in a call to publish_delivered/4 and - %% the first argument (ack_required) is false; or - %% 2. The message is fetched from the queue with fetch/2 and the - %% first argument (ack_required) is false; or - %% 3. The message is acked (ack/2 is called for the message); or - %% 4. The message is fully fsync'd to disk in such a way that the - %% recovery of the message is guaranteed in the event of a - %% crash of this rabbit node (excluding hardware failure). - %% - %% In addition to the above conditions, a message id may only - %% appear in the result of drain_confirmed if - %% #message_properties.needs_confirming = true when the msg was - %% published (through whichever means) to the backing queue. - %% - %% It is legal for the same message id to appear in the results - %% of multiple calls to drain_confirmed, which means that the - %% backing queue is not required to keep track of which messages - %% it has already confirmed. The confirm will be issued to the - %% publisher the first time the message id appears in the result - %% of drain_confirmed. All subsequent appearances of that message - %% id will be ignored. - {drain_confirmed, 1}, - - %% Drop messages from the head of the queue while the supplied - %% predicate returns true. - {dropwhile, 2}, - - %% Produce the next message. - {fetch, 2}, - - %% Acktags supplied are for messages which can now be forgotten - %% about. Must return 1 msg_id per Ack, in the same order as Acks. - {ack, 2}, - - %% Reinsert messages into the queue which have already been - %% delivered and were pending acknowledgement. - {requeue, 2}, - - %% How long is my queue? - {len, 1}, - - %% Is my queue empty? - {is_empty, 1}, - - %% For the next three functions, the assumption is that you're - %% monitoring something like the ingress and egress rates of the - %% queue. The RAM duration is thus the length of time represented - %% by the messages held in RAM given the current rates. If you - %% want to ignore all of this stuff, then do so, and return 0 in - %% ram_duration/1. - - %% The target is to have no more messages in RAM than indicated - %% by the duration and the current queue rates. - {set_ram_duration_target, 2}, - - %% Optionally recalculate the duration internally (likely to be - %% just update your internal rates), and report how many seconds - %% the messages in RAM represent given the current rates of the - %% queue. - {ram_duration, 1}, - - %% Should 'timeout' be called as soon as the queue process - %% can manage (either on an empty mailbox, or when a timer - %% fires)? - {needs_timeout, 1}, - - %% Called (eventually) after needs_timeout returns 'idle' or - %% 'timed'. Note this may be called more than once for each - %% 'idle' or 'timed' returned from needs_timeout. - {timeout, 1}, - - %% Called immediately before the queue hibernates. - {handle_pre_hibernate, 1}, - - %% Exists for debugging purposes, to be able to expose state via - %% rabbitmqctl list_queues backing_queue_status - {status, 1}, - - %% Passed a function to be invoked with the relevant backing - %% queue's state. Useful for when the backing queue or other - %% components need to pass functions into the backing queue. - {invoke, 3}, - - %% Called prior to a publish or publish_delivered call. Allows - %% the BQ to signal that it's already seen this message (and in - %% what capacity - i.e. was it published previously or discarded - %% previously) and thus the message should be dropped. - {is_duplicate, 2}, - - %% Called to inform the BQ about messages which have reached the - %% queue, but are not going to be further passed to BQ for some - %% reason. Note that this is may be invoked for messages for - %% which BQ:is_duplicate/2 has already returned {'published' | - %% 'discarded', BQS}. - {discard, 3} - ]; + [{start, 1}, {stop, 0}, {init, 3}, {terminate, 2}, + {delete_and_terminate, 2}, {purge, 1}, {publish, 4}, + {publish_delivered, 5}, {drain_confirmed, 1}, {dropwhile, 3}, + {fetch, 2}, {ack, 2}, {fold, 3}, {requeue, 2}, {len, 1}, + {is_empty, 1}, {set_ram_duration_target, 2}, {ram_duration, 1}, + {needs_timeout, 1}, {timeout, 1}, {handle_pre_hibernate, 1}, + {status, 1}, {invoke, 3}, {is_duplicate, 2}, {discard, 3}]; behaviour_info(_Other) -> undefined. + +-endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_backing_queue_qc.erl rabbitmq-server-2.8.4/src/rabbit_backing_queue_qc.erl --- rabbitmq-server-2.7.1/src/rabbit_backing_queue_qc.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_backing_queue_qc.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_backing_queue_qc). @@ -141,7 +141,7 @@ {call, ?BQMOD, drain_confirmed, [BQ]}. qc_dropwhile(#state{bqstate = BQ}) -> - {call, ?BQMOD, dropwhile, [fun dropfun/1, BQ]}. + {call, ?BQMOD, dropwhile, [fun dropfun/1, false, BQ]}. qc_is_empty(#state{bqstate = BQ}) -> {call, ?BQMOD, is_empty, [BQ]}. @@ -267,10 +267,11 @@ BQ1 = {call, erlang, element, [2, Res]}, S#state{bqstate = BQ1}; -next_state(S, BQ1, {call, ?BQMOD, dropwhile, _Args}) -> +next_state(S, Res, {call, ?BQMOD, dropwhile, _Args}) -> + BQ = {call, erlang, element, [2, Res]}, #state{messages = Messages} = S, Msgs1 = drop_messages(Messages), - S#state{bqstate = BQ1, len = gb_trees:size(Msgs1), messages = Msgs1}; + S#state{bqstate = BQ, len = gb_trees:size(Msgs1), messages = Msgs1}; next_state(S, _Res, {call, ?BQMOD, is_empty, _Args}) -> S; diff -Nru rabbitmq-server-2.7.1/src/rabbit_basic.erl rabbitmq-server-2.8.4/src/rabbit_basic.erl --- rabbitmq-server-2.7.1/src/rabbit_basic.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_basic.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_basic). @@ -19,7 +19,8 @@ -include("rabbit_framing.hrl"). -export([publish/4, publish/6, publish/1, - message/3, message/4, properties/1, delivery/4]). + message/3, message/4, properties/1, append_table_header/3, + extract_headers/1, map_headers/2, delivery/4, header_routes/1]). -export([build_content/2, from_content/1]). %%---------------------------------------------------------------------------- @@ -29,8 +30,9 @@ -type(properties_input() :: (rabbit_framing:amqp_property_record() | [{atom(), any()}])). -type(publish_result() :: - ({ok, rabbit_router:routing_result(), [pid()]} + ({ok, rabbit_amqqueue:routing_result(), [pid()]} | rabbit_types:error('not_found'))). +-type(headers() :: rabbit_framing:amqp_table() | 'undefined'). -type(exchange_input() :: (rabbit_types:exchange() | rabbit_exchange:name())). -type(body_input() :: (binary() | [binary()])). @@ -55,6 +57,17 @@ rabbit_types:ok_or_error2(rabbit_types:message(), any())). -spec(properties/1 :: (properties_input()) -> rabbit_framing:amqp_property_record()). + +-spec(append_table_header/3 :: + (binary(), rabbit_framing:amqp_table(), headers()) -> headers()). + +-spec(extract_headers/1 :: (rabbit_types:content()) -> headers()). + +-spec(map_headers/2 :: (fun((headers()) -> headers()), rabbit_types:content()) + -> rabbit_types:content()). + +-spec(header_routes/1 :: + (undefined | rabbit_framing:amqp_table()) -> [string()]). -spec(build_content/2 :: (rabbit_framing:amqp_property_record(), binary() | [binary()]) -> rabbit_types:content()). -spec(from_content/1 :: (rabbit_types:content()) -> @@ -88,8 +101,8 @@ end. publish(X, Delivery) -> - {RoutingRes, DeliveredQPids} = - rabbit_router:deliver(rabbit_exchange:route(X, Delivery), Delivery), + Qs = rabbit_amqqueue:lookup(rabbit_exchange:route(X, Delivery)), + {RoutingRes, DeliveredQPids} = rabbit_amqqueue:deliver(Qs, Delivery), {ok, RoutingRes, DeliveredQPids}. delivery(Mandatory, Immediate, Message, MsgSeqNo) -> @@ -139,7 +152,7 @@ {ok, #basic_message{ exchange_name = XName, content = strip_header(DecodedContent, ?DELETED_HEADER), - id = rabbit_guid:guid(), + id = rabbit_guid:gen(), is_persistent = is_message_persistent(DecodedContent), routing_keys = [RoutingKey | header_routes(Props#'P_basic'.headers)]}} @@ -166,11 +179,32 @@ end end, #'P_basic'{}, P). +append_table_header(Name, Info, undefined) -> + append_table_header(Name, Info, []); +append_table_header(Name, Info, Headers) -> + Prior = case rabbit_misc:table_lookup(Headers, Name) of + undefined -> []; + {array, Existing} -> Existing + end, + rabbit_misc:set_table_value(Headers, Name, array, [{table, Info} | Prior]). + +extract_headers(Content) -> + #content{properties = #'P_basic'{headers = Headers}} = + rabbit_binary_parser:ensure_content_decoded(Content), + Headers. + +map_headers(F, Content) -> + Content1 = rabbit_binary_parser:ensure_content_decoded(Content), + #content{properties = #'P_basic'{headers = Headers} = Props} = Content1, + Headers1 = F(Headers), + rabbit_binary_generator:clear_encoded_content( + Content1#content{properties = Props#'P_basic'{headers = Headers1}}). + indexof(L, Element) -> indexof(L, Element, 1). -indexof([], _Element, _N) -> 0; -indexof([Element | _Rest], Element, N) -> N; -indexof([_ | Rest], Element, N) -> indexof(Rest, Element, N + 1). +indexof([], _Element, _N) -> 0; +indexof([Element | _Rest], Element, N) -> N; +indexof([_ | Rest], Element, N) -> indexof(Rest, Element, N + 1). is_message_persistent(#content{properties = #'P_basic'{ delivery_mode = Mode}}) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_binary_generator.erl rabbitmq-server-2.8.4/src/rabbit_binary_generator.erl --- rabbitmq-server-2.7.1/src/rabbit_binary_generator.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_binary_generator.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_binary_generator). diff -Nru rabbitmq-server-2.7.1/src/rabbit_binary_parser.erl rabbitmq-server-2.8.4/src/rabbit_binary_parser.erl --- rabbitmq-server-2.7.1/src/rabbit_binary_parser.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_binary_parser.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_binary_parser). diff -Nru rabbitmq-server-2.7.1/src/rabbit_binding.erl rabbitmq-server-2.8.4/src/rabbit_binding.erl --- rabbitmq-server-2.7.1/src/rabbit_binding.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_binding.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_binding). @@ -354,8 +354,8 @@ %% For bulk operations we lock the tables we are operating on in order %% to reduce the time complexity. Without the table locks we end up -%% with num_tables*num_bulk_bindings row-level locks. Takiing each -%% lock takes time proportional to the number of existing locks, thus +%% with num_tables*num_bulk_bindings row-level locks. Taking each lock +%% takes time proportional to the number of existing locks, thus %% resulting in O(num_bulk_bindings^2) complexity. %% %% The locks need to be write locks since ultimately we end up diff -Nru rabbitmq-server-2.7.1/src/rabbit_channel.erl rabbitmq-server-2.8.4/src/rabbit_channel.erl --- rabbitmq-server-2.7.1/src/rabbit_channel.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_channel.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_channel). @@ -20,8 +20,8 @@ -behaviour(gen_server2). --export([start_link/10, do/2, do/3, flush/1, shutdown/1]). --export([send_command/2, deliver/4, flushed/2, confirm/2]). +-export([start_link/11, do/2, do/3, do_flow/3, flush/1, shutdown/1]). +-export([send_command/2, deliver/4, flushed/2]). -export([list/0, info_keys/0, info/1, info/2, info_all/0, info_all/1]). -export([refresh_config_local/0, ready_for_close/1]). -export([force_event_refresh/0]). @@ -33,12 +33,12 @@ -export([list_local/0]). -record(ch, {state, protocol, channel, reader_pid, writer_pid, conn_pid, - limiter, tx_status, next_tag, - unacked_message_q, uncommitted_message_q, uncommitted_acks, - user, virtual_host, most_recently_declared_queue, queue_monitors, - consumer_mapping, blocking, queue_consumers, queue_collector_pid, - stats_timer, confirm_enabled, publish_seqno, unconfirmed_mq, - unconfirmed_qm, confirmed, capabilities, trace_state}). + conn_name, limiter, tx_status, next_tag, unacked_message_q, + uncommitted_message_q, uncommitted_acks, uncommitted_nacks, user, + virtual_host, most_recently_declared_queue, queue_monitors, + consumer_mapping, blocking, queue_consumers, delivering_queues, + queue_collector_pid, stats_timer, confirm_enabled, publish_seqno, + unconfirmed, confirmed, capabilities, trace_state}). -define(MAX_PERMISSION_CACHE_SIZE, 12). @@ -56,6 +56,7 @@ -define(CREATION_EVENT_KEYS, [pid, + name, connection, number, user, @@ -71,13 +72,16 @@ -type(channel_number() :: non_neg_integer()). --spec(start_link/10 :: - (channel_number(), pid(), pid(), pid(), rabbit_types:protocol(), - rabbit_types:user(), rabbit_types:vhost(), rabbit_framing:amqp_table(), +-spec(start_link/11 :: + (channel_number(), pid(), pid(), pid(), string(), + rabbit_types:protocol(), rabbit_types:user(), rabbit_types:vhost(), + rabbit_framing:amqp_table(), pid(), rabbit_limiter:token()) -> rabbit_types:ok_pid_or_error()). -spec(do/2 :: (pid(), rabbit_framing:amqp_method_record()) -> 'ok'). -spec(do/3 :: (pid(), rabbit_framing:amqp_method_record(), rabbit_types:maybe(rabbit_types:content())) -> 'ok'). +-spec(do_flow/3 :: (pid(), rabbit_framing:amqp_method_record(), + rabbit_types:maybe(rabbit_types:content())) -> 'ok'). -spec(flush/1 :: (pid()) -> 'ok'). -spec(shutdown/1 :: (pid()) -> 'ok'). -spec(send_command/2 :: (pid(), rabbit_framing:amqp_method_record()) -> 'ok'). @@ -85,7 +89,6 @@ (pid(), rabbit_types:ctag(), boolean(), rabbit_amqqueue:qmsg()) -> 'ok'). -spec(flushed/2 :: (pid(), pid()) -> 'ok'). --spec(confirm/2 ::(pid(), [non_neg_integer()]) -> 'ok'). -spec(list/0 :: () -> [pid()]). -spec(list_local/0 :: () -> [pid()]). -spec(info_keys/0 :: () -> rabbit_types:info_keys()). @@ -101,17 +104,21 @@ %%---------------------------------------------------------------------------- -start_link(Channel, ReaderPid, WriterPid, ConnPid, Protocol, User, VHost, - Capabilities, CollectorPid, Limiter) -> +start_link(Channel, ReaderPid, WriterPid, ConnPid, ConnName, Protocol, User, + VHost, Capabilities, CollectorPid, Limiter) -> gen_server2:start_link( - ?MODULE, [Channel, ReaderPid, WriterPid, ConnPid, Protocol, User, - VHost, Capabilities, CollectorPid, Limiter], []). + ?MODULE, [Channel, ReaderPid, WriterPid, ConnPid, ConnName, Protocol, + User, VHost, Capabilities, CollectorPid, Limiter], []). do(Pid, Method) -> do(Pid, Method, none). do(Pid, Method, Content) -> - gen_server2:cast(Pid, {method, Method, Content}). + gen_server2:cast(Pid, {method, Method, Content, noflow}). + +do_flow(Pid, Method, Content) -> + credit_flow:send(Pid), + gen_server2:cast(Pid, {method, Method, Content, flow}). flush(Pid) -> gen_server2:call(Pid, flush, infinity). @@ -128,9 +135,6 @@ flushed(Pid, QPid) -> gen_server2:cast(Pid, {flushed, QPid}). -confirm(Pid, MsgSeqNos) -> - gen_server2:cast(Pid, {confirm, MsgSeqNos, self()}). - list() -> rabbit_misc:append_rpc_all_nodes(rabbit_mnesia:running_clustered_nodes(), rabbit_channel, list_local, []). @@ -169,7 +173,7 @@ %%--------------------------------------------------------------------------- -init([Channel, ReaderPid, WriterPid, ConnPid, Protocol, User, VHost, +init([Channel, ReaderPid, WriterPid, ConnPid, ConnName, Protocol, User, VHost, Capabilities, CollectorPid, Limiter]) -> process_flag(trap_exit, true), ok = pg_local:join(rabbit_channels, self()), @@ -179,24 +183,26 @@ reader_pid = ReaderPid, writer_pid = WriterPid, conn_pid = ConnPid, + conn_name = ConnName, limiter = Limiter, tx_status = none, next_tag = 1, unacked_message_q = queue:new(), uncommitted_message_q = queue:new(), uncommitted_acks = [], + uncommitted_nacks = [], user = User, virtual_host = VHost, most_recently_declared_queue = <<>>, - queue_monitors = dict:new(), + queue_monitors = pmon:new(), consumer_mapping = dict:new(), blocking = sets:new(), queue_consumers = dict:new(), + delivering_queues = sets:new(), queue_collector_pid = CollectorPid, confirm_enabled = false, publish_seqno = 1, - unconfirmed_mq = gb_trees:empty(), - unconfirmed_qm = gb_trees:empty(), + unconfirmed = dtree:empty(), confirmed = [], capabilities = Capabilities, trace_state = rabbit_trace:init(VHost)}, @@ -244,7 +250,12 @@ handle_call(_Request, _From, State) -> noreply(State). -handle_cast({method, Method, Content}, State) -> +handle_cast({method, Method, Content, Flow}, + State = #ch{reader_pid = Reader}) -> + case Flow of + flow -> credit_flow:ack(Reader); + noflow -> ok + end, try handle_method(Method, Content, State) of {reply, Reply, NewState} -> ok = rabbit_writer:send_command(NewState#ch.writer_pid, Reply), @@ -284,29 +295,19 @@ handle_cast({deliver, ConsumerTag, AckRequired, Msg = {_QName, QPid, _MsgId, Redelivered, #basic_message{exchange_name = ExchangeName, - routing_keys = [RoutingKey | _CcRoutes], - content = Content}}}, - State = #ch{writer_pid = WriterPid, - next_tag = DeliveryTag, - trace_state = TraceState}) -> - State1 = lock_message(AckRequired, - ack_record(DeliveryTag, ConsumerTag, Msg), - State), - - M = #'basic.deliver'{consumer_tag = ConsumerTag, - delivery_tag = DeliveryTag, - redelivered = Redelivered, - exchange = ExchangeName#resource.name, - routing_key = RoutingKey}, - rabbit_writer:send_command_and_notify(WriterPid, QPid, self(), M, Content), - State2 = maybe_incr_stats([{QPid, 1}], case AckRequired of - true -> deliver; - false -> deliver_no_ack - end, State1), - State3 = maybe_incr_redeliver_stats(Redelivered, QPid, State2), - rabbit_trace:tap_trace_out(Msg, TraceState), - noreply(State3#ch{next_tag = DeliveryTag + 1}); - + routing_keys = [RoutingKey | _CcRoutes], + content = Content}}}, + State = #ch{writer_pid = WriterPid, + next_tag = DeliveryTag}) -> + ok = rabbit_writer:send_command_and_notify( + WriterPid, QPid, self(), + #'basic.deliver'{consumer_tag = ConsumerTag, + delivery_tag = DeliveryTag, + redelivered = Redelivered, + exchange = ExchangeName#resource.name, + routing_key = RoutingKey}, + Content), + noreply(record_sent(ConsumerTag, AckRequired, Msg, State)); handle_cast(force_event_refresh, State) -> rabbit_event:notify(channel_created, infos(?CREATION_EVENT_KEYS, State)), @@ -315,6 +316,10 @@ State1 = #ch{confirmed = C} = confirm(MsgSeqNos, From, State), noreply([send_confirms], State1, case C of [] -> hibernate; _ -> 0 end). +handle_info({bump_credit, Msg}, State) -> + credit_flow:handle_bump_msg(Msg), + noreply(State); + handle_info(timeout, State) -> noreply(State); @@ -327,9 +332,11 @@ State1 = handle_publishing_queue_down(QPid, Reason, State), State2 = queue_blocked(QPid, State1), State3 = handle_consuming_queue_down(QPid, State2), + State4 = handle_delivering_queue_down(QPid, State3), + credit_flow:peer_down(QPid), erase_queue_stats(QPid), - noreply(State3#ch{queue_monitors = - dict:erase(QPid, State3#ch.queue_monitors)}); + noreply(State3#ch{queue_monitors = pmon:erase( + QPid, State4#ch.queue_monitors)}); handle_info({'EXIT', _Pid, Reason}, State) -> {stop, Reason, State}. @@ -527,7 +534,7 @@ #'channel.flow_ok'{active = false}); _ -> ok end, - demonitor_queue(QPid, State#ch{blocking = Blocking1}) + State#ch{blocking = Blocking1} end. record_confirm(undefined, _, State) -> @@ -542,46 +549,9 @@ confirm([], _QPid, State) -> State; -confirm(MsgSeqNos, QPid, State) -> - {MXs, State1} = process_confirms(MsgSeqNos, QPid, false, State), - record_confirms(MXs, State1). - -process_confirms(MsgSeqNos, QPid, Nack, State) -> - lists:foldl( - fun(MsgSeqNo, {_MXs, _State = #ch{unconfirmed_mq = UMQ0}} = Acc) -> - case gb_trees:lookup(MsgSeqNo, UMQ0) of - {value, XQ} -> remove_unconfirmed(MsgSeqNo, QPid, XQ, - Acc, Nack); - none -> Acc - end - end, {[], State}, MsgSeqNos). - -remove_unconfirmed(MsgSeqNo, QPid, {XName, Qs}, - {MXs, State = #ch{unconfirmed_mq = UMQ, - unconfirmed_qm = UQM}}, - Nack) -> - State1 = case gb_trees:lookup(QPid, UQM) of - {value, MsgSeqNos} -> - MsgSeqNos1 = gb_sets:delete(MsgSeqNo, MsgSeqNos), - case gb_sets:is_empty(MsgSeqNos1) of - true -> UQM1 = gb_trees:delete(QPid, UQM), - demonitor_queue( - QPid, State#ch{unconfirmed_qm = UQM1}); - false -> UQM1 = gb_trees:update(QPid, MsgSeqNos1, UQM), - State#ch{unconfirmed_qm = UQM1} - end; - none -> - State - end, - Qs1 = gb_sets:del_element(QPid, Qs), - %% If QPid somehow died initiating a nack, clear the message from - %% internal data-structures. Also, cleanup empty entries. - case (Nack orelse gb_sets:is_empty(Qs1)) of - true -> UMQ1 = gb_trees:delete(MsgSeqNo, UMQ), - {[{MsgSeqNo, XName} | MXs], State1#ch{unconfirmed_mq = UMQ1}}; - false -> UMQ1 = gb_trees:update(MsgSeqNo, {XName, Qs1}, UMQ), - {MXs, State1#ch{unconfirmed_mq = UMQ1}} - end. +confirm(MsgSeqNos, QPid, State = #ch{unconfirmed = UC}) -> + {MXs, UC1} = dtree:take(MsgSeqNos, QPid, UC), + record_confirms(MXs, State#ch{unconfirmed = UC1}). handle_method(#'channel.open'{}, _, State = #ch{state = starting}) -> {reply, #'channel.open_ok'{}, State#ch{state = running}}; @@ -672,17 +642,17 @@ State1 = State#ch{unacked_message_q = Remaining}, {noreply, case TxStatus of - none -> ack(Acked, State1); + none -> ack(Acked, State1), + State1; in_progress -> State1#ch{uncommitted_acks = Acked ++ State1#ch.uncommitted_acks} end}; handle_method(#'basic.get'{queue = QueueNameBin, no_ack = NoAck}, - _, State = #ch{writer_pid = WriterPid, - conn_pid = ConnPid, - next_tag = DeliveryTag, - trace_state = TraceState}) -> + _, State = #ch{writer_pid = WriterPid, + conn_pid = ConnPid, + next_tag = DeliveryTag}) -> QueueName = expand_queue_name_shortcut(QueueNameBin, State), check_read_permitted(QueueName, State), case rabbit_amqqueue:with_exclusive_access_or_die( @@ -691,26 +661,18 @@ {ok, MessageCount, Msg = {_QName, QPid, _MsgId, Redelivered, #basic_message{exchange_name = ExchangeName, - routing_keys = [RoutingKey | _CcRoutes], - content = Content}}} -> - State1 = lock_message(not(NoAck), - ack_record(DeliveryTag, none, Msg), - State), - State2 = maybe_incr_stats([{QPid, 1}], case NoAck of - true -> get_no_ack; - false -> get - end, State1), - State3 = maybe_incr_redeliver_stats(Redelivered, QPid, State2), - rabbit_trace:tap_trace_out(Msg, TraceState), + routing_keys = [RoutingKey | _CcRoutes], + content = Content}}} -> ok = rabbit_writer:send_command( WriterPid, - #'basic.get_ok'{delivery_tag = DeliveryTag, - redelivered = Redelivered, - exchange = ExchangeName#resource.name, - routing_key = RoutingKey, + #'basic.get_ok'{delivery_tag = DeliveryTag, + redelivered = Redelivered, + exchange = ExchangeName#resource.name, + routing_key = RoutingKey, message_count = MessageCount}, Content), - {noreply, State3#ch{next_tag = DeliveryTag + 1}}; + State1 = monitor_delivering_queue(NoAck, QPid, State), + {noreply, record_sent(none, not(NoAck), Msg, State1)}; empty -> {reply, #'basic.get_empty'{}, State} end; @@ -730,7 +692,8 @@ check_read_permitted(QueueName, State), ActualConsumerTag = case ConsumerTag of - <<>> -> rabbit_guid:binstring_guid("amq.ctag"); + <<>> -> rabbit_guid:binary(rabbit_guid:gen_secure(), + "amq.ctag"); Other -> Other end, @@ -747,10 +710,10 @@ consumer_tag = ActualConsumerTag})), Q} end) of - {ok, Q} -> - State1 = State#ch{consumer_mapping = - dict:store(ActualConsumerTag, Q, - ConsumerMapping)}, + {ok, Q = #amqqueue{pid = QPid}} -> + CM1 = dict:store(ActualConsumerTag, Q, ConsumerMapping), + State1 = monitor_delivering_queue( + NoAck, QPid, State#ch{consumer_mapping = CM1}), {noreply, case NoWait of true -> consumer_monitor(ActualConsumerTag, State1); @@ -787,9 +750,8 @@ false -> dict:store(QPid, CTags1, QCons) end end, - NewState = demonitor_queue( - Q, State#ch{consumer_mapping = ConsumerMapping1, - queue_consumers = QCons1}), + NewState = State#ch{consumer_mapping = ConsumerMapping1, + queue_consumers = QCons1}, %% In order to ensure that no more messages are sent to %% the consumer after the cancel_ok has been sent, we get %% the queue process to send the cancel_ok on our @@ -799,9 +761,7 @@ fun () -> {error, not_found} end, fun () -> rabbit_amqqueue:basic_cancel( - Q, self(), ConsumerTag, - ok_msg(NoWait, #'basic.cancel_ok'{ - consumer_tag = ConsumerTag})) + Q, self(), ConsumerTag, ok_msg(NoWait, OkMsg)) end) of ok -> {noreply, NewState}; @@ -960,7 +920,8 @@ false -> none end, ActualNameBin = case QueueNameBin of - <<>> -> rabbit_guid:binstring_guid("amq.gen"); + <<>> -> rabbit_guid:binary(rabbit_guid:gen_secure(), + "amq.gen"); Other -> check_name('queue', Other) end, QueueName = rabbit_misc:r(VHostPath, queue, ActualNameBin), @@ -977,7 +938,7 @@ {error, not_found} -> case rabbit_amqqueue:declare(QueueName, Durable, AutoDelete, Args, Owner) of - {new, Q = #amqqueue{}} -> + {new, #amqqueue{pid = QPid}} -> %% We need to notify the reader within the channel %% process so that we can be sure there are no %% outstanding exclusive queues being declared as @@ -985,7 +946,7 @@ ok = case Owner of none -> ok; _ -> rabbit_queue_collector:register( - CollectorPid, Q) + CollectorPid, QPid) end, return_queue_declare_ok(QueueName, NoWait, 0, 0, State); {existing, _Q} -> @@ -1068,19 +1029,26 @@ rabbit_misc:protocol_error( precondition_failed, "channel is not transactional", []); -handle_method(#'tx.commit'{}, _, State = #ch{uncommitted_message_q = TMQ, - uncommitted_acks = TAL}) -> - State1 = new_tx(ack(TAL, rabbit_misc:queue_fold(fun deliver_to_queues/2, - State, TMQ))), - {noreply, maybe_complete_tx(State1#ch{tx_status = committing})}; +handle_method(#'tx.commit'{}, _, + State = #ch{uncommitted_message_q = TMQ, + uncommitted_acks = TAL, + uncommitted_nacks = TNL, + limiter = Limiter}) -> + State1 = rabbit_misc:queue_fold(fun deliver_to_queues/2, State, TMQ), + ack(TAL, State1), + lists:foreach( + fun({Requeue, Acked}) -> reject(Requeue, Acked, Limiter) end, TNL), + {noreply, maybe_complete_tx(new_tx(State1#ch{tx_status = committing}))}; handle_method(#'tx.rollback'{}, _, #ch{tx_status = none}) -> rabbit_misc:protocol_error( precondition_failed, "channel is not transactional", []); handle_method(#'tx.rollback'{}, _, State = #ch{unacked_message_q = UAMQ, - uncommitted_acks = TAL}) -> - UAMQ1 = queue:from_list(lists:usort(TAL ++ queue:to_list(UAMQ))), + uncommitted_acks = TAL, + uncommitted_nacks = TNL}) -> + TNL1 = lists:append([L || {_, L} <- TNL]), + UAMQ1 = queue:from_list(lists:usort(TAL ++ TNL1 ++ queue:to_list(UAMQ))), {reply, #'tx.rollback_ok'{}, new_tx(State#ch{unacked_message_q = UAMQ1})}; handle_method(#'confirm.select'{}, _, #ch{tx_status = in_progress}) -> @@ -1111,10 +1079,7 @@ ok = rabbit_limiter:block(Limiter1), case consumer_queues(Consumers) of [] -> {reply, #'channel.flow_ok'{active = false}, State1}; - QPids -> State2 = lists:foldl(fun monitor_queue/2, - State1#ch{blocking = - sets:from_list(QPids)}, - QPids), + QPids -> State2 = State1#ch{blocking = sets:from_list(QPids)}, ok = rabbit_amqqueue:flush_all(QPids, self()), {noreply, State2} end; @@ -1127,6 +1092,7 @@ consumer_monitor(ConsumerTag, State = #ch{consumer_mapping = ConsumerMapping, + queue_monitors = QMons, queue_consumers = QCons, capabilities = Capabilities}) -> case rabbit_misc:table_lookup( @@ -1139,59 +1105,27 @@ end, gb_sets:singleton(ConsumerTag), QCons), - monitor_queue(QPid, State#ch{queue_consumers = QCons1}); + State#ch{queue_monitors = pmon:monitor(QPid, QMons), + queue_consumers = QCons1}; _ -> State end. -monitor_queue(QPid, State = #ch{queue_monitors = QMons}) -> - case (not dict:is_key(QPid, QMons) andalso - queue_monitor_needed(QPid, State)) of - true -> MRef = erlang:monitor(process, QPid), - State#ch{queue_monitors = dict:store(QPid, MRef, QMons)}; - false -> State - end. - -demonitor_queue(QPid, State = #ch{queue_monitors = QMons}) -> - case (dict:is_key(QPid, QMons) andalso - not queue_monitor_needed(QPid, State)) of - true -> true = erlang:demonitor(dict:fetch(QPid, QMons)), - State#ch{queue_monitors = dict:erase(QPid, QMons)}; - false -> State +monitor_delivering_queue(true, _QPid, State) -> + State; +monitor_delivering_queue(false, QPid, State = #ch{queue_monitors = QMons, + delivering_queues = DQ}) -> + State#ch{queue_monitors = pmon:monitor(QPid, QMons), + delivering_queues = sets:add_element(QPid, DQ)}. + +handle_publishing_queue_down(QPid, Reason, State = #ch{unconfirmed = UC}) -> + case rabbit_misc:is_abnormal_termination(Reason) of + true -> {MXs, UC1} = dtree:take_all(QPid, UC), + send_nacks(MXs, State#ch{unconfirmed = UC1}); + false -> {MXs, UC1} = dtree:take(QPid, UC), + record_confirms(MXs, State#ch{unconfirmed = UC1}) end. -queue_monitor_needed(QPid, #ch{queue_consumers = QCons, - blocking = Blocking, - unconfirmed_qm = UQM} = State) -> - StatsEnabled = rabbit_event:stats_level( - State, #ch.stats_timer) =:= fine, - ConsumerMonitored = dict:is_key(QPid, QCons), - QueueBlocked = sets:is_element(QPid, Blocking), - ConfirmMonitored = gb_trees:is_defined(QPid, UQM), - StatsEnabled or ConsumerMonitored or QueueBlocked or ConfirmMonitored. - -handle_publishing_queue_down(QPid, Reason, State = #ch{unconfirmed_qm = UQM}) -> - MsgSeqNos = case gb_trees:lookup(QPid, UQM) of - {value, MsgSet} -> gb_sets:to_list(MsgSet); - none -> [] - end, - %% We remove the MsgSeqNos from UQM before calling - %% process_confirms to prevent each MsgSeqNo being removed from - %% the set one by one which which would be inefficient - State1 = State#ch{unconfirmed_qm = gb_trees:delete_any(QPid, UQM)}, - {Nack, SendFun} = - case Reason of - Reason when Reason =:= noproc; Reason =:= noconnection; - Reason =:= normal; Reason =:= shutdown -> - {false, fun record_confirms/2}; - {shutdown, _} -> - {false, fun record_confirms/2}; - _ -> - {true, fun send_nacks/2} - end, - {MXs, State2} = process_confirms(MsgSeqNos, QPid, Nack, State1), - SendFun(MXs, State2). - handle_consuming_queue_down(QPid, State = #ch{consumer_mapping = ConsumerMapping, queue_consumers = QCons, @@ -1210,6 +1144,9 @@ State#ch{consumer_mapping = ConsumerMapping1, queue_consumers = dict:erase(QPid, QCons)}. +handle_delivering_queue_down(QPid, State = #ch{delivering_queues = DQ}) -> + State#ch{delivering_queues = sets:del_element(QPid, DQ)}. + binding_action(Fun, ExchangeNameBin, DestinationType, DestinationNameBin, RoutingKey, Arguments, ReturnMethod, NoWait, State = #ch{virtual_host = VHostPath, @@ -1266,18 +1203,46 @@ routing_key = RoutingKey}, Content). -reject(DeliveryTag, Requeue, Multiple, State = #ch{unacked_message_q = UAMQ}) -> +reject(DeliveryTag, Requeue, Multiple, + State = #ch{unacked_message_q = UAMQ, tx_status = TxStatus}) -> {Acked, Remaining} = collect_acks(UAMQ, DeliveryTag, Multiple), + State1 = State#ch{unacked_message_q = Remaining}, + {noreply, + case TxStatus of + none -> + reject(Requeue, Acked, State1#ch.limiter), + State1; + in_progress -> + State1#ch{uncommitted_nacks = + [{Requeue, Acked} | State1#ch.uncommitted_nacks]} + end}. + +reject(Requeue, Acked, Limiter) -> ok = fold_per_queue( fun (QPid, MsgIds, ok) -> rabbit_amqqueue:reject(QPid, MsgIds, Requeue, self()) end, ok, Acked), - ok = notify_limiter(State#ch.limiter, Acked), - {noreply, State#ch{unacked_message_q = Remaining}}. + ok = notify_limiter(Limiter, Acked). -ack_record(DeliveryTag, ConsumerTag, - _MsgStruct = {_QName, QPid, MsgId, _Redelivered, _Msg}) -> - {DeliveryTag, ConsumerTag, {QPid, MsgId}}. +record_sent(ConsumerTag, AckRequired, + Msg = {_QName, QPid, MsgId, Redelivered, _Message}, + State = #ch{unacked_message_q = UAMQ, + next_tag = DeliveryTag, + trace_state = TraceState}) -> + maybe_incr_stats([{QPid, 1}], case {ConsumerTag, AckRequired} of + {none, true} -> get; + {none, false} -> get_no_ack; + {_ , true} -> deliver; + {_ , false} -> deliver_no_ack + end, State), + maybe_incr_redeliver_stats(Redelivered, QPid, State), + rabbit_trace:tap_trace_out(Msg, TraceState), + UAMQ1 = case AckRequired of + true -> queue:in({DeliveryTag, ConsumerTag, {QPid, MsgId}}, + UAMQ); + false -> UAMQ + end, + State#ch{unacked_message_q = UAMQ1, next_tag = DeliveryTag + 1}. collect_acks(Q, 0, true) -> {queue:to_list(Q), queue:new()}; @@ -1312,13 +1277,16 @@ maybe_incr_stats(QIncs, ack, State). new_tx(State) -> State#ch{uncommitted_message_q = queue:new(), - uncommitted_acks = []}. + uncommitted_acks = [], + uncommitted_nacks = []}. notify_queues(State = #ch{state = closing}) -> {ok, State}; -notify_queues(State = #ch{consumer_mapping = Consumers}) -> - {rabbit_amqqueue:notify_down_all(consumer_queues(Consumers), self()), - State#ch{state = closing}}. +notify_queues(State = #ch{consumer_mapping = Consumers, + delivering_queues = DQ }) -> + QPids = sets:to_list( + sets:union(sets:from_list(consumer_queues(Consumers)), DQ)), + {rabbit_amqqueue:notify_down_all(QPids, self()), State#ch{state = closing}}. fold_per_queue(_F, Acc, []) -> Acc; @@ -1362,56 +1330,42 @@ exchange_name = XName}, msg_seq_no = MsgSeqNo}, QNames}, State) -> - {RoutingRes, DeliveredQPids} = rabbit_router:deliver(QNames, Delivery), - State1 = process_routing_result(RoutingRes, DeliveredQPids, - XName, MsgSeqNo, Message, State), + {RoutingRes, DeliveredQPids} = + rabbit_amqqueue:deliver_flow(rabbit_amqqueue:lookup(QNames), Delivery), + State1 = State#ch{queue_monitors = + pmon:monitor_all(DeliveredQPids, + State#ch.queue_monitors)}, + State2 = process_routing_result(RoutingRes, DeliveredQPids, + XName, MsgSeqNo, Message, State1), maybe_incr_stats([{XName, 1} | [{{QPid, XName}, 1} || - QPid <- DeliveredQPids]], publish, State1). + QPid <- DeliveredQPids]], publish, State2), + State2. process_routing_result(unroutable, _, XName, MsgSeqNo, Msg, State) -> ok = basic_return(Msg, State, no_route), - record_confirm(MsgSeqNo, XName, - maybe_incr_stats([{Msg#basic_message.exchange_name, 1}], - return_unroutable, State)); + maybe_incr_stats([{Msg#basic_message.exchange_name, 1}], + return_unroutable, State), + record_confirm(MsgSeqNo, XName, State); process_routing_result(not_delivered, _, XName, MsgSeqNo, Msg, State) -> ok = basic_return(Msg, State, no_consumers), - record_confirm(MsgSeqNo, XName, - maybe_incr_stats([{XName, 1}], return_not_delivered, State)); + maybe_incr_stats([{XName, 1}], return_not_delivered, State), + record_confirm(MsgSeqNo, XName, State); process_routing_result(routed, [], XName, MsgSeqNo, _, State) -> record_confirm(MsgSeqNo, XName, State); process_routing_result(routed, _, _, undefined, _, State) -> State; process_routing_result(routed, QPids, XName, MsgSeqNo, _, State) -> - #ch{unconfirmed_mq = UMQ} = State, - UMQ1 = gb_trees:insert(MsgSeqNo, {XName, gb_sets:from_list(QPids)}, UMQ), - SingletonSet = gb_sets:singleton(MsgSeqNo), - lists:foldl( - fun (QPid, State0 = #ch{unconfirmed_qm = UQM}) -> - case gb_trees:lookup(QPid, UQM) of - {value, MsgSeqNos} -> - MsgSeqNos1 = gb_sets:insert(MsgSeqNo, MsgSeqNos), - UQM1 = gb_trees:update(QPid, MsgSeqNos1, UQM), - State0#ch{unconfirmed_qm = UQM1}; - none -> - UQM1 = gb_trees:insert(QPid, SingletonSet, UQM), - monitor_queue(QPid, State0#ch{unconfirmed_qm = UQM1}) - end - end, State#ch{unconfirmed_mq = UMQ1}, QPids). - -lock_message(true, MsgStruct, State = #ch{unacked_message_q = UAMQ}) -> - State#ch{unacked_message_q = queue:in(MsgStruct, UAMQ)}; -lock_message(false, _MsgStruct, State) -> - State. + State#ch{unconfirmed = dtree:insert(MsgSeqNo, QPids, XName, + State#ch.unconfirmed)}. send_nacks([], State) -> State; send_nacks(MXs, State = #ch{tx_status = none}) -> - MsgSeqNos = [ MsgSeqNo || {MsgSeqNo, _} <- MXs ], - coalesce_and_send(MsgSeqNos, + coalesce_and_send([MsgSeqNo || {MsgSeqNo, _} <- MXs], fun(MsgSeqNo, Multiple) -> #'basic.nack'{delivery_tag = MsgSeqNo, - multiple = Multiple} + multiple = Multiple} end, State); send_nacks(_, State) -> maybe_complete_tx(State#ch{tx_status = failed}). @@ -1419,13 +1373,12 @@ send_confirms(State = #ch{tx_status = none, confirmed = []}) -> State; send_confirms(State = #ch{tx_status = none, confirmed = C}) -> - {MsgSeqNos, State1} = - lists:foldl(fun ({MsgSeqNo, ExchangeName}, {MSNs, State0}) -> - {[MsgSeqNo | MSNs], - maybe_incr_stats([{ExchangeName, 1}], confirm, - State0)} - end, {[], State}, lists:append(C)), - send_confirms(MsgSeqNos, State1 #ch{confirmed = []}); + MsgSeqNos = + lists:foldl(fun ({MsgSeqNo, XName}, MSNs) -> + maybe_incr_stats([{XName, 1}], confirm, State), + [MsgSeqNo | MSNs] + end, [], lists:append(C)), + send_confirms(MsgSeqNos, State#ch{confirmed = []}); send_confirms(State) -> maybe_complete_tx(State). @@ -1442,11 +1395,11 @@ end, State). coalesce_and_send(MsgSeqNos, MkMsgFun, - State = #ch{writer_pid = WriterPid, unconfirmed_mq = UMQ}) -> + State = #ch{writer_pid = WriterPid, unconfirmed = UC}) -> SMsgSeqNos = lists:usort(MsgSeqNos), - CutOff = case gb_trees:is_empty(UMQ) of + CutOff = case dtree:is_empty(UC) of true -> lists:last(SMsgSeqNos) + 1; - false -> {SeqNo, _XQ} = gb_trees:smallest(UMQ), SeqNo + false -> {SeqNo, _XName} = dtree:smallest(UC), SeqNo end, {Ms, Ss} = lists:splitwith(fun(X) -> X < CutOff end, SMsgSeqNos), case Ms of @@ -1460,8 +1413,8 @@ maybe_complete_tx(State = #ch{tx_status = in_progress}) -> State; -maybe_complete_tx(State = #ch{unconfirmed_mq = UMQ}) -> - case gb_trees:is_empty(UMQ) of +maybe_complete_tx(State = #ch{unconfirmed = UC}) -> + case dtree:is_empty(UC) of false -> State; true -> complete_tx(State#ch{confirmed = []}) end. @@ -1486,10 +1439,11 @@ i(vhost, #ch{virtual_host = VHost}) -> VHost; i(transactional, #ch{tx_status = TE}) -> TE =/= none; i(confirm, #ch{confirm_enabled = CE}) -> CE; +i(name, State) -> name(State); i(consumer_count, #ch{consumer_mapping = ConsumerMapping}) -> dict:size(ConsumerMapping); -i(messages_unconfirmed, #ch{unconfirmed_mq = UMQ}) -> - gb_trees:size(UMQ); +i(messages_unconfirmed, #ch{unconfirmed = UC}) -> + dtree:size(UC); i(messages_unacknowledged, #ch{unacked_message_q = UAMQ}) -> queue:len(UAMQ); i(messages_uncommitted, #ch{uncommitted_message_q = TMQ}) -> @@ -1503,28 +1457,26 @@ i(Item, _) -> throw({bad_argument, Item}). +name(#ch{conn_name = ConnName, channel = Channel}) -> + list_to_binary(rabbit_misc:format("~s (~p)", [ConnName, Channel])). + maybe_incr_redeliver_stats(true, QPid, State) -> maybe_incr_stats([{QPid, 1}], redeliver, State); -maybe_incr_redeliver_stats(_, _, State) -> - State. +maybe_incr_redeliver_stats(_, _, _State) -> + ok. maybe_incr_stats(QXIncs, Measure, State) -> case rabbit_event:stats_level(State, #ch.stats_timer) of - fine -> lists:foldl(fun ({QX, Inc}, State0) -> - incr_stats(QX, Inc, Measure, State0) - end, State, QXIncs); - _ -> State + fine -> [incr_stats(QX, Inc, Measure) || {QX, Inc} <- QXIncs]; + _ -> ok end. -incr_stats({QPid, _} = QX, Inc, Measure, State) -> - update_measures(queue_exchange_stats, QX, Inc, Measure), - monitor_queue(QPid, State); -incr_stats(QPid, Inc, Measure, State) when is_pid(QPid) -> - update_measures(queue_stats, QPid, Inc, Measure), - monitor_queue(QPid, State); -incr_stats(X, Inc, Measure, State) -> - update_measures(exchange_stats, X, Inc, Measure), - State. +incr_stats({_, _} = QX, Inc, Measure) -> + update_measures(queue_exchange_stats, QX, Inc, Measure); +incr_stats(QPid, Inc, Measure) when is_pid(QPid) -> + update_measures(queue_stats, QPid, Inc, Measure); +incr_stats(X, Inc, Measure) -> + update_measures(exchange_stats, X, Inc, Measure). update_measures(Type, QX, Inc, Measure) -> Measures = case get({Type, QX}) of diff -Nru rabbitmq-server-2.7.1/src/rabbit_channel_sup.erl rabbitmq-server-2.8.4/src/rabbit_channel_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_channel_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_channel_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_channel_sup). @@ -32,10 +32,10 @@ -type(start_link_args() :: {'tcp', rabbit_net:socket(), rabbit_channel:channel_number(), - non_neg_integer(), pid(), rabbit_types:protocol(), rabbit_types:user(), - rabbit_types:vhost(), rabbit_framing:amqp_table(), + non_neg_integer(), pid(), string(), rabbit_types:protocol(), + rabbit_types:user(), rabbit_types:vhost(), rabbit_framing:amqp_table(), pid()} | - {'direct', rabbit_channel:channel_number(), pid(), + {'direct', rabbit_channel:channel_number(), pid(), string(), rabbit_types:protocol(), rabbit_types:user(), rabbit_types:vhost(), rabbit_framing:amqp_table(), pid()}). @@ -45,8 +45,8 @@ %%---------------------------------------------------------------------------- -start_link({tcp, Sock, Channel, FrameMax, ReaderPid, Protocol, User, VHost, - Capabilities, Collector}) -> +start_link({tcp, Sock, Channel, FrameMax, ReaderPid, ConnName, Protocol, User, + VHost, Capabilities, Collector}) -> {ok, SupPid} = supervisor2:start_link(?MODULE, {tcp, Sock, Channel, FrameMax, ReaderPid, Protocol}), @@ -56,14 +56,14 @@ supervisor2:start_child( SupPid, {channel, {rabbit_channel, start_link, - [Channel, ReaderPid, WriterPid, ReaderPid, Protocol, - User, VHost, Capabilities, Collector, + [Channel, ReaderPid, WriterPid, ReaderPid, ConnName, + Protocol, User, VHost, Capabilities, Collector, rabbit_limiter:make_token(LimiterPid)]}, intrinsic, ?MAX_WAIT, worker, [rabbit_channel]}), {ok, AState} = rabbit_command_assembler:init(Protocol), {ok, SupPid, {ChannelPid, AState}}; -start_link({direct, Channel, ClientChannelPid, ConnPid, Protocol, User, VHost, - Capabilities, Collector}) -> +start_link({direct, Channel, ClientChannelPid, ConnPid, ConnName, Protocol, + User, VHost, Capabilities, Collector}) -> {ok, SupPid} = supervisor2:start_link(?MODULE, direct), [LimiterPid] = supervisor2:find_child(SupPid, limiter), {ok, ChannelPid} = @@ -71,7 +71,7 @@ SupPid, {channel, {rabbit_channel, start_link, [Channel, ClientChannelPid, ClientChannelPid, ConnPid, - Protocol, User, VHost, Capabilities, Collector, + ConnName, Protocol, User, VHost, Capabilities, Collector, rabbit_limiter:make_token(LimiterPid)]}, intrinsic, ?MAX_WAIT, worker, [rabbit_channel]}), {ok, SupPid, {ChannelPid, none}}. diff -Nru rabbitmq-server-2.7.1/src/rabbit_channel_sup_sup.erl rabbitmq-server-2.8.4/src/rabbit_channel_sup_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_channel_sup_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_channel_sup_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_channel_sup_sup). diff -Nru rabbitmq-server-2.7.1/src/rabbit_client_sup.erl rabbitmq-server-2.8.4/src/rabbit_client_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_client_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_client_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_client_sup). @@ -28,8 +28,9 @@ -ifdef(use_specs). --spec(start_link/1 :: (mfa()) -> rabbit_types:ok_pid_or_error()). --spec(start_link/2 :: ({'local', atom()}, mfa()) -> +-spec(start_link/1 :: (rabbit_types:mfargs()) -> + rabbit_types:ok_pid_or_error()). +-spec(start_link/2 :: ({'local', atom()}, rabbit_types:mfargs()) -> rabbit_types:ok_pid_or_error()). -endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_command_assembler.erl rabbitmq-server-2.8.4/src/rabbit_command_assembler.erl --- rabbitmq-server-2.7.1/src/rabbit_command_assembler.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_command_assembler.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_command_assembler). diff -Nru rabbitmq-server-2.7.1/src/rabbit_connection_sup.erl rabbitmq-server-2.8.4/src/rabbit_connection_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_connection_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_connection_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_connection_sup). diff -Nru rabbitmq-server-2.7.1/src/rabbit_control.erl rabbitmq-server-2.8.4/src/rabbit_control.erl --- rabbitmq-server-2.7.1/src/rabbit_control.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_control.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,13 +11,13 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_control). -include("rabbit.hrl"). --export([start/0, stop/0, action/5, diagnostics/1]). +-export([start/0, stop/0, action/5]). -define(RPC_TIMEOUT, infinity). -define(EXTERNAL_CHECK_INTERVAL, 1000). @@ -49,7 +49,6 @@ (atom(), node(), [string()], [{string(), any()}], fun ((string(), [any()]) -> 'ok')) -> 'ok'). --spec(diagnostics/1 :: (node()) -> [{string(), [any()]}]). -spec(usage/0 :: () -> no_return()). -endif. @@ -67,7 +66,7 @@ CmdArgsAndOpts -> CmdArgsAndOpts end, Opts1 = [case K of - ?NODE_OPT -> {?NODE_OPT, rabbit_misc:makenode(V)}; + ?NODE_OPT -> {?NODE_OPT, rabbit_nodes:make(V)}; _ -> {K, V} end || {K, V} <- Opts], Command = list_to_atom(Command0), @@ -79,6 +78,12 @@ io:format(Format ++ " ...~n", Args1) end end, + PrintInvalidCommandError = + fun () -> + print_error("invalid command '~s'", + [string:join([atom_to_list(Command) | Args], " ")]) + end, + %% The reason we don't use a try/catch here is that rpc:call turns %% thrown errors into normal return values case catch action(Command, Node, Args, Opts, Inform) of @@ -88,9 +93,11 @@ false -> io:format("...done.~n") end, rabbit_misc:quit(0); - {'EXIT', {function_clause, [{?MODULE, action, _} | _]}} -> - print_error("invalid command '~s'", - [string:join([atom_to_list(Command) | Args], " ")]), + {'EXIT', {function_clause, [{?MODULE, action, _} | _]}} -> %% < R15 + PrintInvalidCommandError(), + usage(); + {'EXIT', {function_clause, [{?MODULE, action, _, _} | _]}} -> %% >= R15 + PrintInvalidCommandError(), usage(); {'EXIT', {badarg, _}} -> print_error("invalid parameter: ~p", [Args]), @@ -135,26 +142,7 @@ print_error(Format, Args) -> fmt_stderr("Error: " ++ Format, Args). print_badrpc_diagnostics(Node) -> - [fmt_stderr(Fmt, Args) || {Fmt, Args} <- diagnostics(Node)]. - -diagnostics(Node) -> - {_NodeName, NodeHost} = rabbit_misc:nodeparts(Node), - [{"diagnostics:", []}, - case net_adm:names(NodeHost) of - {error, EpmdReason} -> - {"- unable to connect to epmd on ~s: ~w", - [NodeHost, EpmdReason]}; - {ok, NamePorts} -> - {"- nodes and their ports on ~s: ~p", - [NodeHost, [{list_to_atom(Name), Port} || - {Name, Port} <- NamePorts]]} - end, - {"- current node: ~w", [node()]}, - case init:get_argument(home) of - {ok, [[Home]]} -> {"- current node home dir: ~s", [Home]}; - Other -> {"- no current node home dir: ~p", [Other]} - end, - {"- current node cookie hash: ~s", [rabbit_misc:cookie_hash()]}]. + fmt_stderr(rabbit_nodes:diagnostics([Node]), []). stop() -> ok. @@ -206,7 +194,11 @@ action(wait, Node, [PidFile], _Opts, Inform) -> Inform("Waiting for ~p", [Node]), - wait_for_application(Node, PidFile, Inform); + wait_for_application(Node, PidFile, rabbit, Inform); + +action(wait, Node, [PidFile, App], _Opts, Inform) -> + Inform("Waiting for ~p on ~p", [App, Node]), + wait_for_application(Node, PidFile, list_to_atom(App), Inform); action(status, Node, [], _Opts, Inform) -> Inform("Status of node ~p", [Node]), @@ -224,33 +216,33 @@ Inform("Reopening logs for node ~p", [Node]), call(Node, {rabbit, rotate_logs, [""]}); action(rotate_logs, Node, Args = [Suffix], _Opts, Inform) -> - Inform("Rotating logs to files with suffix ~p", [Suffix]), + Inform("Rotating logs to files with suffix \"~s\"", [Suffix]), call(Node, {rabbit, rotate_logs, Args}); action(close_connection, Node, [PidStr, Explanation], _Opts, Inform) -> - Inform("Closing connection ~s", [PidStr]), + Inform("Closing connection \"~s\"", [PidStr]), rpc_call(Node, rabbit_networking, close_connection, [rabbit_misc:string_to_pid(PidStr), Explanation]); action(add_user, Node, Args = [Username, _Password], _Opts, Inform) -> - Inform("Creating user ~p", [Username]), + Inform("Creating user \"~s\"", [Username]), call(Node, {rabbit_auth_backend_internal, add_user, Args}); action(delete_user, Node, Args = [_Username], _Opts, Inform) -> - Inform("Deleting user ~p", Args), + Inform("Deleting user \"~s\"", Args), call(Node, {rabbit_auth_backend_internal, delete_user, Args}); action(change_password, Node, Args = [Username, _Newpassword], _Opts, Inform) -> - Inform("Changing password for user ~p", [Username]), + Inform("Changing password for user \"~s\"", [Username]), call(Node, {rabbit_auth_backend_internal, change_password, Args}); action(clear_password, Node, Args = [Username], _Opts, Inform) -> - Inform("Clearing password for user ~p", [Username]), + Inform("Clearing password for user \"~s\"", [Username]), call(Node, {rabbit_auth_backend_internal, clear_password, Args}); action(set_user_tags, Node, [Username | TagsStr], _Opts, Inform) -> Tags = [list_to_atom(T) || T <- TagsStr], - Inform("Setting tags for user ~p to ~p", [Username, Tags]), + Inform("Setting tags for user \"~s\" to ~p", [Username, Tags]), rpc_call(Node, rabbit_auth_backend_internal, set_tags, [list_to_binary(Username), Tags]); @@ -261,11 +253,11 @@ rabbit_auth_backend_internal:user_info_keys()); action(add_vhost, Node, Args = [_VHostPath], _Opts, Inform) -> - Inform("Creating vhost ~p", Args), + Inform("Creating vhost \"~s\"", Args), call(Node, {rabbit_vhost, add, Args}); action(delete_vhost, Node, Args = [_VHostPath], _Opts, Inform) -> - Inform("Deleting vhost ~p", Args), + Inform("Deleting vhost \"~s\"", Args), call(Node, {rabbit_vhost, delete, Args}); action(list_vhosts, Node, Args, _Opts, Inform) -> @@ -327,12 +319,12 @@ action(trace_on, Node, [], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), - Inform("Starting tracing for vhost ~p", [VHost]), + Inform("Starting tracing for vhost \"~s\"", [VHost]), rpc_call(Node, rabbit_trace, start, [list_to_binary(VHost)]); action(trace_off, Node, [], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), - Inform("Stopping tracing for vhost ~p", [VHost]), + Inform("Stopping tracing for vhost \"~s\"", [VHost]), rpc_call(Node, rabbit_trace, stop, [list_to_binary(VHost)]); action(set_vm_memory_high_watermark, Node, [Arg], _Opts, Inform) -> @@ -340,24 +332,26 @@ 0 -> Arg ++ ".0"; _ -> Arg end), - Inform("Setting memory threshhold on ~p to ~p", [Node, Frac]), + Inform("Setting memory threshold on ~p to ~p", [Node, Frac]), rpc_call(Node, vm_memory_monitor, set_vm_memory_high_watermark, [Frac]); action(set_permissions, Node, [Username, CPerm, WPerm, RPerm], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), - Inform("Setting permissions for user ~p in vhost ~p", [Username, VHost]), + Inform("Setting permissions for user \"~s\" in vhost \"~s\"", + [Username, VHost]), call(Node, {rabbit_auth_backend_internal, set_permissions, [Username, VHost, CPerm, WPerm, RPerm]}); action(clear_permissions, Node, [Username], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), - Inform("Clearing permissions for user ~p in vhost ~p", [Username, VHost]), + Inform("Clearing permissions for user \"~s\" in vhost \"~s\"", + [Username, VHost]), call(Node, {rabbit_auth_backend_internal, clear_permissions, [Username, VHost]}); action(list_permissions, Node, [], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), - Inform("Listing permissions in vhost ~p", [VHost]), + Inform("Listing permissions in vhost \"~s\"", [VHost]), display_info_list(call(Node, {rabbit_auth_backend_internal, list_vhost_permissions, [VHost]}), rabbit_auth_backend_internal:vhost_perms_info_keys()); @@ -391,17 +385,17 @@ %%---------------------------------------------------------------------------- -wait_for_application(Node, PidFile, Inform) -> +wait_for_application(Node, PidFile, Application, Inform) -> Pid = read_pid_file(PidFile, true), Inform("pid is ~s", [Pid]), - wait_for_application(Node, Pid). + wait_for_application(Node, Pid, Application). -wait_for_application(Node, Pid) -> +wait_for_application(Node, Pid, Application) -> case process_up(Pid) of - true -> case rabbit:is_running(Node) of + true -> case rabbit_nodes:is_running(Node, Application) of true -> ok; false -> timer:sleep(?EXTERNAL_CHECK_INTERVAL), - wait_for_application(Node, Pid) + wait_for_application(Node, Pid, Application) end; false -> {error, process_not_running} end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_direct.erl rabbitmq-server-2.8.4/src/rabbit_direct.erl --- rabbitmq-server-2.7.1/src/rabbit_direct.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_direct.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,13 +11,13 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_direct). -export([boot/0, force_event_refresh/0, list/0, connect/5, - start_channel/8, disconnect/2]). + start_channel/9, disconnect/2]). %% Internal -export([list_local/0]). @@ -36,10 +36,10 @@ rabbit_event:event_props()) -> {'ok', {rabbit_types:user(), rabbit_framing:amqp_table()}}). --spec(start_channel/8 :: - (rabbit_channel:channel_number(), pid(), pid(), rabbit_types:protocol(), - rabbit_types:user(), rabbit_types:vhost(), rabbit_framing:amqp_table(), - pid()) -> {'ok', pid()}). +-spec(start_channel/9 :: + (rabbit_channel:channel_number(), pid(), pid(), string(), + rabbit_types:protocol(), rabbit_types:user(), rabbit_types:vhost(), + rabbit_framing:amqp_table(), pid()) -> {'ok', pid()}). -spec(disconnect/2 :: (pid(), rabbit_event:event_props()) -> 'ok'). @@ -92,13 +92,13 @@ {error, broker_not_found_on_node} end. -start_channel(Number, ClientChannelPid, ConnPid, Protocol, User, VHost, - Capabilities, Collector) -> +start_channel(Number, ClientChannelPid, ConnPid, ConnName, Protocol, User, + VHost, Capabilities, Collector) -> {ok, _, {ChannelPid, _}} = supervisor2:start_child( rabbit_direct_client_sup, - [{direct, Number, ClientChannelPid, ConnPid, Protocol, User, VHost, - Capabilities, Collector}]), + [{direct, Number, ClientChannelPid, ConnPid, ConnName, Protocol, + User, VHost, Capabilities, Collector}]), {ok, ChannelPid}. disconnect(Pid, Infos) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_disk_monitor.erl rabbitmq-server-2.8.4/src/rabbit_disk_monitor.erl --- rabbitmq-server-2.7.1/src/rabbit_disk_monitor.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_disk_monitor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,197 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(rabbit_disk_monitor). + +-behaviour(gen_server). + +-export([start_link/1]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-export([get_disk_free_limit/0, set_disk_free_limit/1, get_check_interval/0, + set_check_interval/1, get_disk_free/0]). + +-define(SERVER, ?MODULE). +-define(DEFAULT_DISK_CHECK_INTERVAL, 10000). + +-record(state, {dir, + limit, + timeout, + timer, + alarmed + }). + +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-type(disk_free_limit() :: (integer() | {'mem_relative', float()})). +-spec(start_link/1 :: (disk_free_limit()) -> rabbit_types:ok_pid_or_error()). +-spec(get_disk_free_limit/0 :: () -> integer()). +-spec(set_disk_free_limit/1 :: (disk_free_limit()) -> 'ok'). +-spec(get_check_interval/0 :: () -> integer()). +-spec(set_check_interval/1 :: (integer()) -> 'ok'). +-spec(get_disk_free/0 :: () -> (integer() | 'unknown')). + +-endif. + +%%---------------------------------------------------------------------------- +%% Public API +%%---------------------------------------------------------------------------- + +get_disk_free_limit() -> + gen_server:call(?MODULE, get_disk_free_limit, infinity). + +set_disk_free_limit(Limit) -> + gen_server:call(?MODULE, {set_disk_free_limit, Limit}, infinity). + +get_check_interval() -> + gen_server:call(?MODULE, get_check_interval, infinity). + +set_check_interval(Interval) -> + gen_server:call(?MODULE, {set_check_interval, Interval}, infinity). + +get_disk_free() -> + gen_server:call(?MODULE, get_disk_free, infinity). + +%%---------------------------------------------------------------------------- +%% gen_server callbacks +%%---------------------------------------------------------------------------- + +start_link(Args) -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [Args], []). + +init([Limit]) -> + TRef = start_timer(?DEFAULT_DISK_CHECK_INTERVAL), + Dir = dir(), + State = #state { dir = Dir, + timeout = ?DEFAULT_DISK_CHECK_INTERVAL, + timer = TRef, + alarmed = false}, + case {catch get_disk_free(Dir), + vm_memory_monitor:get_total_memory()} of + {N1, N2} when is_integer(N1), is_integer(N2) -> + {ok, set_disk_limits(State, Limit)}; + Err -> + rabbit_log:info("Disabling disk free space monitoring " + "on unsupported platform: ~p~n", [Err]), + {stop, unsupported_platform} + end. + +handle_call(get_disk_free_limit, _From, State) -> + {reply, interpret_limit(State#state.limit), State}; + +handle_call({set_disk_free_limit, Limit}, _From, State) -> + {reply, ok, set_disk_limits(State, Limit)}; + +handle_call(get_check_interval, _From, State) -> + {reply, State#state.timeout, State}; + +handle_call({set_check_interval, Timeout}, _From, State) -> + {ok, cancel} = timer:cancel(State#state.timer), + {reply, ok, State#state{timeout = Timeout, timer = start_timer(Timeout)}}; + +handle_call(get_disk_free, _From, State = #state { dir = Dir }) -> + {reply, get_disk_free(Dir), State}; + +handle_call(_Request, _From, State) -> + {noreply, State}. + +handle_cast(_Request, State) -> + {noreply, State}. + +handle_info(update, State) -> + {noreply, internal_update(State)}; + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------------- +%% Server Internals +%%---------------------------------------------------------------------------- + +% the partition / drive containing this directory will be monitored +dir() -> rabbit_mnesia:dir(). + +set_disk_limits(State, Limit) -> + State1 = State#state { limit = Limit }, + rabbit_log:info("Disk free limit set to ~pMB~n", + [trunc(interpret_limit(Limit) / 1048576)]), + internal_update(State1). + +internal_update(State = #state { limit = Limit, + dir = Dir, + alarmed = Alarmed}) -> + CurrentFreeBytes = get_disk_free(Dir), + LimitBytes = interpret_limit(Limit), + NewAlarmed = CurrentFreeBytes < LimitBytes, + case {Alarmed, NewAlarmed} of + {false, true} -> + emit_update_info("exceeded", CurrentFreeBytes, LimitBytes), + alarm_handler:set_alarm({{resource_limit, disk, node()}, []}); + {true, false} -> + emit_update_info("below limit", CurrentFreeBytes, LimitBytes), + alarm_handler:clear_alarm({resource_limit, disk, node()}); + _ -> + ok + end, + State #state {alarmed = NewAlarmed}. + +get_disk_free(Dir) -> + get_disk_free(Dir, os:type()). + +get_disk_free(Dir, {unix, Sun}) + when Sun =:= sunos; Sun =:= sunos4; Sun =:= solaris -> + parse_free_unix(rabbit_misc:os_cmd("/usr/bin/df -k " ++ Dir)); +get_disk_free(Dir, {unix, _}) -> + parse_free_unix(rabbit_misc:os_cmd("/bin/df -kP " ++ Dir)); +get_disk_free(Dir, {win32, _}) -> + parse_free_win32(os:cmd("dir /-C /W \"" ++ Dir ++ [$"])); +get_disk_free(_, _) -> + unknown. + +parse_free_unix(CommandResult) -> + [_, Stats | _] = string:tokens(CommandResult, "\n"), + [_FS, _Total, _Used, Free | _] = string:tokens(Stats, " \t"), + list_to_integer(Free) * 1024. + +parse_free_win32(CommandResult) -> + LastLine = lists:last(string:tokens(CommandResult, "\r\n")), + {match, [Free]} = re:run(lists:reverse(LastLine), "(\\d+)", + [{capture, all_but_first, list}]), + list_to_integer(lists:reverse(Free)). + +interpret_limit({mem_relative, R}) -> + round(R * vm_memory_monitor:get_total_memory()); +interpret_limit(L) -> + L. + +emit_update_info(State, CurrentFree, Limit) -> + rabbit_log:info( + "Disk free space limit now ~s. Free bytes:~p Limit:~p~n", + [State, CurrentFree, Limit]). + +start_timer(Timeout) -> + {ok, TRef} = timer:send_interval(Timeout, update), + TRef. diff -Nru rabbitmq-server-2.7.1/src/rabbit.erl rabbitmq-server-2.8.4/src/rabbit.erl --- rabbitmq-server-2.7.1/src/rabbit.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit). @@ -45,6 +45,12 @@ {requires, file_handle_cache}, {enables, external_infrastructure}]}). +-rabbit_boot_step({database_sync, + [{description, "database sync"}, + {mfa, {rabbit_sup, start_child, [mnesia_sync]}}, + {requires, database}, + {enables, external_infrastructure}]}). + -rabbit_boot_step({file_handle_cache, [{description, "file handle cache server"}, {mfa, {rabbit_sup, start_restartable_child, @@ -132,7 +138,7 @@ -rabbit_boot_step({recovery, [{description, "exchange, queue and binding recovery"}, {mfa, {rabbit, recover, []}}, - {requires, empty_db_check}, + {requires, core_initialized}, {enables, routing_ready}]}). -rabbit_boot_step({mirror_queue_slave_sup, @@ -158,8 +164,9 @@ {enables, networking}]}). -rabbit_boot_step({direct_client, - [{mfa, {rabbit_direct, boot, []}}, - {requires, log_relay}]}). + [{description, "direct client"}, + {mfa, {rabbit_direct, boot, []}}, + {requires, log_relay}]}). -rabbit_boot_step({networking, [{mfa, {rabbit_networking, boot, []}}, @@ -190,7 +197,7 @@ rabbit_queue_index, gen, dict, ordsets, file_handle_cache, rabbit_msg_store, array, rabbit_msg_store_ets_index, rabbit_msg_file, rabbit_exchange_type_fanout, rabbit_exchange_type_topic, mnesia, - mnesia_lib, rpc, mnesia_tm, qlc, sofs, proplists]). + mnesia_lib, rpc, mnesia_tm, qlc, sofs, proplists, credit_flow]). %% HiPE compilation uses multiple cores anyway, but some bits are %% IO-bound so we can go faster if we parallelise a bit more. In @@ -205,14 +212,13 @@ -type(file_suffix() :: binary()). %% this really should be an abstract type -type(log_location() :: 'tty' | 'undefined' | file:filename()). +-type(param() :: atom()). -spec(maybe_hipe_compile/0 :: () -> 'ok'). -spec(prepare/0 :: () -> 'ok'). -spec(start/0 :: () -> 'ok'). -spec(stop/0 :: () -> 'ok'). -spec(stop_and_halt/0 :: () -> no_return()). --spec(rotate_logs/1 :: (file_suffix()) -> rabbit_types:ok_or_error(any())). --spec(force_event_refresh/0 :: () -> 'ok'). -spec(status/0 :: () -> [{pid, integer()} | {running_applications, [{atom(), string(), string()}]} | @@ -221,12 +227,11 @@ {memory, any()}]). -spec(is_running/0 :: () -> boolean()). -spec(is_running/1 :: (node()) -> boolean()). --spec(environment/0 :: () -> [{atom() | term()}]). --spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()). +-spec(environment/0 :: () -> [{param() | term()}]). +-spec(rotate_logs/1 :: (file_suffix()) -> rabbit_types:ok_or_error(any())). +-spec(force_event_refresh/0 :: () -> 'ok'). --spec(maybe_insert_default_data/0 :: () -> 'ok'). --spec(boot_delegate/0 :: () -> 'ok'). --spec(recover/0 :: () -> 'ok'). +-spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()). -spec(start/2 :: ('normal',[]) -> {'error', @@ -236,6 +241,10 @@ {'ok',pid()}). -spec(stop/1 :: (_) -> 'ok'). +-spec(maybe_insert_default_data/0 :: () -> 'ok'). +-spec(boot_delegate/0 :: () -> 'ok'). +-spec(recover/0 :: () -> 'ok'). + -endif. %%---------------------------------------------------------------------------- @@ -308,25 +317,37 @@ ok. status() -> - [{pid, list_to_integer(os:getpid())}, - {running_applications, application:which_applications(infinity)}, - {os, os:type()}, - {erlang_version, erlang:system_info(system_version)}, - {memory, erlang:memory()}] ++ - rabbit_misc:filter_exit_map( - fun ({Key, {M, F, A}}) -> {Key, erlang:apply(M, F, A)} end, - [{vm_memory_high_watermark, {vm_memory_monitor, - get_vm_memory_high_watermark, []}}, - {vm_memory_limit, {vm_memory_monitor, - get_memory_limit, []}}]). + S1 = [{pid, list_to_integer(os:getpid())}, + {running_applications, application:which_applications(infinity)}, + {os, os:type()}, + {erlang_version, erlang:system_info(system_version)}, + {memory, erlang:memory()}], + S2 = rabbit_misc:filter_exit_map( + fun ({Key, {M, F, A}}) -> {Key, erlang:apply(M, F, A)} end, + [{vm_memory_high_watermark, {vm_memory_monitor, + get_vm_memory_high_watermark, []}}, + {vm_memory_limit, {vm_memory_monitor, + get_memory_limit, []}}, + {disk_free_limit, {rabbit_disk_monitor, + get_disk_free_limit, []}}, + {disk_free, {rabbit_disk_monitor, + get_disk_free, []}}]), + S3 = rabbit_misc:with_exit_handler( + fun () -> [] end, + fun () -> [{file_descriptors, file_handle_cache:info()}] end), + S4 = [{processes, [{limit, erlang:system_info(process_limit)}, + {used, erlang:system_info(process_count)}]}, + {run_queue, erlang:statistics(run_queue)}, + {uptime, begin + {T,_} = erlang:statistics(wall_clock), + T div 1000 + end}], + S1 ++ S2 ++ S3 ++ S4. is_running() -> is_running(node()). is_running(Node) -> - case rpc:call(Node, application, which_applications, [infinity]) of - {badrpc, _} -> false; - Apps -> proplists:is_defined(rabbit, Apps) - end. + rabbit_nodes:is_running(Node, rabbit). environment() -> lists:keysort( @@ -348,10 +369,8 @@ start(normal, []) -> case erts_version_check() of ok -> - ok = rabbit_mnesia:delete_previously_running_nodes(), {ok, SupPid} = rabbit_sup:start_link(), true = register(rabbit, self()), - print_banner(), [ok = run_boot_step(Step) || Step <- boot_steps()], io:format("~nbroker running~n"), @@ -430,8 +449,7 @@ [try apply(M,F,A) catch - _:Reason -> boot_error("FAILED~nReason: ~p~nStacktrace: ~p~n", - [Reason, erlang:get_stacktrace()]) + _:Reason -> boot_step_error(Reason, erlang:get_stacktrace()) end || {M,F,A} <- MFAs], io:format("done~n"), ok @@ -490,8 +508,27 @@ end]) end. +boot_step_error({error, {timeout_waiting_for_tables, _}}, _Stacktrace) -> + {Err, Nodes} = + case rabbit_mnesia:read_previously_running_nodes() of + [] -> {"Timeout contacting cluster nodes. Since RabbitMQ was" + " shut down forcefully~nit cannot determine which nodes" + " are timing out. Details on all nodes will~nfollow.~n", + rabbit_mnesia:all_clustered_nodes() -- [node()]}; + Ns -> {rabbit_misc:format( + "Timeout contacting cluster nodes: ~p.~n", [Ns]), + Ns} + end, + boot_error(Err ++ rabbit_nodes:diagnostics(Nodes) ++ "~n~n", []); + +boot_step_error(Reason, Stacktrace) -> + boot_error("Error description:~n ~p~n~n" + "Log files (may contain more information):~n ~s~n ~s~n~n" + "Stack trace:~n ~p~n~n", + [Reason, log_location(kernel), log_location(sasl), Stacktrace]). + boot_error(Format, Args) -> - io:format("BOOT ERROR: " ++ Format, Args), + io:format("~n~nBOOT FAILED~n===========~n~n" ++ Format, Args), error_logger:error_msg(Format, Args), timer:sleep(1000), exit({?MODULE, failure_during_boot}). @@ -645,7 +682,7 @@ {"app descriptor", app_location()}, {"home dir", home_dir()}, {"config file(s)", config_files()}, - {"cookie hash", rabbit_misc:cookie_hash()}, + {"cookie hash", rabbit_nodes:cookie_hash()}, {"log", log_location(kernel)}, {"sasl log", log_location(sasl)}, {"database dir", rabbit_mnesia:dir()}, @@ -678,6 +715,6 @@ case init:get_argument(config) of {ok, Files} -> [filename:absname( filename:rootname(File, ".config") ++ ".config") || - File <- Files]; + [File] <- Files]; error -> [] end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_error_logger.erl rabbitmq-server-2.8.4/src/rabbit_error_logger.erl --- rabbitmq-server-2.7.1/src/rabbit_error_logger.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_error_logger.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_error_logger). diff -Nru rabbitmq-server-2.7.1/src/rabbit_error_logger_file_h.erl rabbitmq-server-2.8.4/src/rabbit_error_logger_file_h.erl --- rabbitmq-server-2.7.1/src/rabbit_error_logger_file_h.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_error_logger_file_h.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_error_logger_file_h). diff -Nru rabbitmq-server-2.7.1/src/rabbit_event.erl rabbitmq-server-2.8.4/src/rabbit_event.erl --- rabbitmq-server-2.7.1/src/rabbit_event.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_event.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_event). diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange.erl rabbitmq-server-2.8.4/src/rabbit_exchange.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange). @@ -242,6 +242,11 @@ info_all(VHostPath, Items) -> map(VHostPath, fun (X) -> info(X, Items) end). +%% Optimisation +route(#exchange{name = #resource{name = <<"">>, virtual_host = VHost}}, + #delivery{message = #basic_message{routing_keys = RKs}}) -> + [rabbit_misc:r(VHost, queue, RK) || RK <- lists:usort(RKs)]; + route(X = #exchange{name = XName}, Delivery) -> route1(Delivery, {queue:from_list([X]), XName, []}). @@ -355,11 +360,21 @@ _ -> undefined end. +invalid_module(T) -> + rabbit_log:warning( + "Could not find exchange type ~s.~n", [T]), + put({xtype_to_module, T}, rabbit_exchange_type_invalid), + rabbit_exchange_type_invalid. + %% Used with atoms from records; e.g., the type is expected to exist. type_to_module(T) -> case get({xtype_to_module, T}) of - undefined -> {ok, Module} = rabbit_registry:lookup_module(exchange, T), - put({xtype_to_module, T}, Module), - Module; - Module -> Module + undefined -> + case rabbit_registry:lookup_module(exchange, T) of + {ok, Module} -> put({xtype_to_module, T}, Module), + Module; + {error, not_found} -> invalid_module(T) + end; + Module -> + Module end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange_type_direct.erl rabbitmq-server-2.8.4/src/rabbit_exchange_type_direct.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange_type_direct.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange_type_direct.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type_direct). @@ -22,7 +22,6 @@ -export([description/0, serialise_events/0, route/2]). -export([validate/1, create/2, delete/3, add_binding/3, remove_bindings/3, assert_args_equivalence/2]). --include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, [{description, "exchange type direct"}, diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange_type.erl rabbitmq-server-2.8.4/src/rabbit_exchange_type.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange_type.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange_type.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,44 +11,62 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type). --export([behaviour_info/1]). +-ifdef(use_specs). -behaviour_info(callbacks) -> - [ - {description, 0}, +-type(tx() :: 'transaction' | 'none'). +-type(serial() :: pos_integer() | tx()). + +-callback description() -> [proplist:property()]. + +%% Should Rabbit ensure that all binding events that are +%% delivered to an individual exchange can be serialised? (they +%% might still be delivered out of order, but there'll be a +%% serial number). +-callback serialise_events() -> boolean(). - %% Should Rabbit ensure that all binding events that are - %% delivered to an individual exchange can be serialised? (they - %% might still be delivered out of order, but there'll be a - %% serial number). - {serialise_events, 0}, +%% The no_return is there so that we can have an "invalid" exchange +%% type (see rabbit_exchange_type_invalid). +-callback route(rabbit_types:exchange(), rabbit_types:delivery()) -> + rabbit_router:match_result(). - {route, 2}, +%% called BEFORE declaration, to check args etc; may exit with #amqp_error{} +-callback validate(rabbit_types:exchange()) -> 'ok'. - %% called BEFORE declaration, to check args etc; may exit with #amqp_error{} - {validate, 1}, +%% called after declaration and recovery +-callback create(tx(), rabbit_types:exchange()) -> 'ok'. - %% called after declaration and recovery - {create, 2}, +%% called after exchange (auto)deletion. +-callback delete(tx(), rabbit_types:exchange(), [rabbit_types:binding()]) -> + 'ok'. - %% called after exchange (auto)deletion. - {delete, 3}, +%% called after a binding has been added or recovered +-callback add_binding(serial(), rabbit_types:exchange(), + rabbit_types:binding()) -> 'ok'. - %% called after a binding has been added or recovered - {add_binding, 3}, +%% called after bindings have been deleted. +-callback remove_bindings(serial(), rabbit_types:exchange(), + [rabbit_types:binding()]) -> 'ok'. - %% called after bindings have been deleted. - {remove_bindings, 3}, +%% called when comparing exchanges for equivalence - should return ok or +%% exit with #amqp_error{} +-callback assert_args_equivalence (rabbit_types:exchange(), + rabbit_framing:amqp_table()) -> + 'ok' | rabbit_types:connection_exit(). - %% called when comparing exchanges for equivalence - should return ok or - %% exit with #amqp_error{} - {assert_args_equivalence, 2} +-else. - ]; +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{description, 0}, {serialise_events, 0}, {route, 2}, {validate, 1}, + {create, 2}, {delete, 3}, {add_binding, 3}, {remove_bindings, 3}, + {assert_args_equivalence, 2}]; behaviour_info(_Other) -> undefined. + +-endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange_type_fanout.erl rabbitmq-server-2.8.4/src/rabbit_exchange_type_fanout.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange_type_fanout.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange_type_fanout.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type_fanout). @@ -22,7 +22,6 @@ -export([description/0, serialise_events/0, route/2]). -export([validate/1, create/2, delete/3, add_binding/3, remove_bindings/3, assert_args_equivalence/2]). --include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, [{description, "exchange type fanout"}, diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange_type_headers.erl rabbitmq-server-2.8.4/src/rabbit_exchange_type_headers.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange_type_headers.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange_type_headers.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type_headers). @@ -23,7 +23,6 @@ -export([description/0, serialise_events/0, route/2]). -export([validate/1, create/2, delete/3, add_binding/3, remove_bindings/3, assert_args_equivalence/2]). --include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, [{description, "exchange type headers"}, diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange_type_invalid.erl rabbitmq-server-2.8.4/src/rabbit_exchange_type_invalid.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange_type_invalid.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange_type_invalid.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,46 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(rabbit_exchange_type_invalid). +-include("rabbit.hrl"). + +-behaviour(rabbit_exchange_type). + +-export([description/0, serialise_events/0, route/2]). +-export([validate/1, create/2, delete/3, + add_binding/3, remove_bindings/3, assert_args_equivalence/2]). + +description() -> + [{name, <<"invalid">>}, + {description, + <<"Dummy exchange type, to be used when the intended one is not found.">> + }]. + +serialise_events() -> false. + +route(#exchange{name = Name, type = Type}, _) -> + rabbit_misc:protocol_error( + precondition_failed, + "Cannot route message through ~s: exchange type ~s not found", + [rabbit_misc:rs(Name), Type]). + +validate(_X) -> ok. +create(_Tx, _X) -> ok. +delete(_Tx, _X, _Bs) -> ok. +add_binding(_Tx, _X, _B) -> ok. +remove_bindings(_Tx, _X, _Bs) -> ok. +assert_args_equivalence(X, Args) -> + rabbit_exchange:assert_args_equivalence(X, Args). diff -Nru rabbitmq-server-2.7.1/src/rabbit_exchange_type_topic.erl rabbitmq-server-2.8.4/src/rabbit_exchange_type_topic.erl --- rabbitmq-server-2.7.1/src/rabbit_exchange_type_topic.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_exchange_type_topic.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_exchange_type_topic). @@ -23,7 +23,6 @@ -export([description/0, serialise_events/0, route/2]). -export([validate/1, create/2, delete/3, add_binding/3, remove_bindings/3, assert_args_equivalence/2]). --include("rabbit_exchange_type_spec.hrl"). -rabbit_boot_step({?MODULE, [{description, "exchange type topic"}, @@ -52,6 +51,7 @@ create(_Tx, _X) -> ok. delete(transaction, #exchange{name = X}, _Bs) -> + trie_remove_all_nodes(X), trie_remove_all_edges(X), trie_remove_all_bindings(X), ok; @@ -63,59 +63,26 @@ add_binding(none, _Exchange, _Binding) -> ok. -remove_bindings(transaction, #exchange{name = X}, Bs) -> - %% The remove process is split into two distinct phases. In the - %% first phase we gather the lists of bindings and edges to - %% delete, then in the second phase we process all the - %% deletions. This is to prevent interleaving of read/write - %% operations in mnesia that can adversely affect performance. - {ToDelete, Paths} = - lists:foldl( - fun(#binding{source = S, key = K, destination = D}, {Acc, PathAcc}) -> - Path = [{FinalNode, _} | _] = - follow_down_get_path(S, split_topic_key(K)), - {[{FinalNode, D} | Acc], - decrement_bindings(X, Path, maybe_add_path(X, Path, PathAcc))} - end, {[], gb_trees:empty()}, Bs), - - [trie_remove_binding(X, FinalNode, D) || {FinalNode, D} <- ToDelete], - [trie_remove_edge(X, Parent, Node, W) || - {Node, {Parent, W, {0, 0}}} <- gb_trees:to_list(Paths)], +remove_bindings(transaction, _X, Bs) -> + %% See rabbit_binding:lock_route_tables for the rationale for + %% taking table locks. + case Bs of + [_] -> ok; + _ -> [mnesia:lock({table, T}, write) || + T <- [rabbit_topic_trie_node, + rabbit_topic_trie_edge, + rabbit_topic_trie_binding]] + end, + [begin + Path = [{FinalNode, _} | _] = + follow_down_get_path(X, split_topic_key(K)), + trie_remove_binding(X, FinalNode, D), + remove_path_if_empty(X, Path) + end || #binding{source = X, key = K, destination = D} <- Bs], ok; remove_bindings(none, _X, _Bs) -> ok. -maybe_add_path(_X, [{root, none}], PathAcc) -> - PathAcc; -maybe_add_path(X, [{Node, W}, {Parent, _} | _], PathAcc) -> - case gb_trees:is_defined(Node, PathAcc) of - true -> PathAcc; - false -> gb_trees:insert(Node, {Parent, W, {trie_binding_count(X, Node), - trie_child_count(X, Node)}}, - PathAcc) - end. - -decrement_bindings(X, Path, PathAcc) -> - with_path_acc(X, fun({Bindings, Edges}) -> {Bindings - 1, Edges} end, - Path, PathAcc). - -decrement_edges(X, Path, PathAcc) -> - with_path_acc(X, fun({Bindings, Edges}) -> {Bindings, Edges - 1} end, - Path, PathAcc). - -with_path_acc(_X, _Fun, [{root, none}], PathAcc) -> - PathAcc; -with_path_acc(X, Fun, [{Node, _} | ParentPath], PathAcc) -> - {Parent, W, Counts} = gb_trees:get(Node, PathAcc), - NewCounts = Fun(Counts), - NewPathAcc = gb_trees:update(Node, {Parent, W, NewCounts}, PathAcc), - case NewCounts of - {0, 0} -> decrement_edges(X, ParentPath, - maybe_add_path(X, ParentPath, NewPathAcc)); - _ -> NewPathAcc - end. - - assert_args_equivalence(X, Args) -> rabbit_exchange:assert_args_equivalence(X, Args). @@ -183,6 +150,16 @@ error -> {error, Acc, Words} end. +remove_path_if_empty(_, [{root, none}]) -> + ok; +remove_path_if_empty(X, [{Node, W} | [{Parent, _} | _] = RestPath]) -> + case mnesia:read(rabbit_topic_trie_node, + #trie_node{exchange_name = X, node_id = Node}, write) of + [] -> trie_remove_edge(X, Parent, Node, W), + remove_path_if_empty(X, RestPath); + _ -> ok + end. + trie_child(X, Node, Word) -> case mnesia:read({rabbit_topic_trie_edge, #trie_edge{exchange_name = X, @@ -199,10 +176,30 @@ destination = '$1'}}, mnesia:select(rabbit_topic_trie_binding, [{MatchHead, [], ['$1']}]). +trie_update_node_counts(X, Node, Field, Delta) -> + E = case mnesia:read(rabbit_topic_trie_node, + #trie_node{exchange_name = X, + node_id = Node}, write) of + [] -> #topic_trie_node{trie_node = #trie_node{ + exchange_name = X, + node_id = Node}, + edge_count = 0, + binding_count = 0}; + [E0] -> E0 + end, + case setelement(Field, E, element(Field, E) + Delta) of + #topic_trie_node{edge_count = 0, binding_count = 0} -> + ok = mnesia:delete_object(rabbit_topic_trie_node, E, write); + EN -> + ok = mnesia:write(rabbit_topic_trie_node, EN, write) + end. + trie_add_edge(X, FromNode, ToNode, W) -> + trie_update_node_counts(X, FromNode, #topic_trie_node.edge_count, +1), trie_edge_op(X, FromNode, ToNode, W, fun mnesia:write/3). trie_remove_edge(X, FromNode, ToNode, W) -> + trie_update_node_counts(X, FromNode, #topic_trie_node.edge_count, -1), trie_edge_op(X, FromNode, ToNode, W, fun mnesia:delete_object/3). trie_edge_op(X, FromNode, ToNode, W, Op) -> @@ -214,9 +211,11 @@ write). trie_add_binding(X, Node, D) -> + trie_update_node_counts(X, Node, #topic_trie_node.binding_count, +1), trie_binding_op(X, Node, D, fun mnesia:write/3). trie_remove_binding(X, Node, D) -> + trie_update_node_counts(X, Node, #topic_trie_node.binding_count, -1), trie_binding_op(X, Node, D, fun mnesia:delete_object/3). trie_binding_op(X, Node, D, Op) -> @@ -227,23 +226,11 @@ destination = D}}, write). -trie_child_count(X, Node) -> - count(rabbit_topic_trie_edge, - #topic_trie_edge{trie_edge = #trie_edge{exchange_name = X, - node_id = Node, - _ = '_'}, - _ = '_'}). - -trie_binding_count(X, Node) -> - count(rabbit_topic_trie_binding, - #topic_trie_binding{ - trie_binding = #trie_binding{exchange_name = X, - node_id = Node, - _ = '_'}, - _ = '_'}). - -count(Table, Match) -> - length(mnesia:match_object(Table, Match, read)). +trie_remove_all_nodes(X) -> + remove_all(rabbit_topic_trie_node, + #topic_trie_node{trie_node = #trie_node{exchange_name = X, + _ = '_'}, + _ = '_'}). trie_remove_all_edges(X) -> remove_all(rabbit_topic_trie_edge, @@ -262,7 +249,7 @@ mnesia:match_object(Table, Pattern, write)). new_node_id() -> - rabbit_guid:guid(). + rabbit_guid:gen(). split_topic_key(Key) -> split_topic_key(Key, [], []). @@ -275,4 +262,3 @@ split_topic_key(Rest, [], [lists:reverse(RevWordAcc) | RevResAcc]); split_topic_key(<>, RevWordAcc, RevResAcc) -> split_topic_key(Rest, [C | RevWordAcc], RevResAcc). - diff -Nru rabbitmq-server-2.7.1/src/rabbit_file.erl rabbitmq-server-2.8.4/src/rabbit_file.erl --- rabbitmq-server-2.7.1/src/rabbit_file.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_file.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_file). @@ -102,9 +102,12 @@ with_fhc_handle(fun () -> prim_file:read_file_info(File) end). with_fhc_handle(Fun) -> - ok = file_handle_cache:obtain(), + with_fhc_handle(1, Fun). + +with_fhc_handle(N, Fun) -> + [ ok = file_handle_cache:obtain() || _ <- lists:seq(1, N)], try Fun() - after ok = file_handle_cache:release() + after [ ok = file_handle_cache:release() || _ <- lists:seq(1, N)] end. read_term_file(File) -> @@ -165,7 +168,7 @@ {error, Reason} end. - +%% TODO the semantics of this function are rather odd. But see bug 25021. append_file(File, Suffix) -> case read_file_info(File) of {ok, FInfo} -> append_file(File, FInfo#file_info.size, Suffix); @@ -183,9 +186,11 @@ end end); append_file(File, _, Suffix) -> - case with_fhc_handle(fun () -> prim_file:read_file(File) end) of - {ok, Data} -> write_file([File, Suffix], Data, [append]); - Error -> Error + case with_fhc_handle(2, fun () -> + file:copy(File, {[File, Suffix], [append]}) + end) of + {ok, _BytesCopied} -> ok; + Error -> Error end. ensure_parent_dirs_exist(Filename) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_framing.erl rabbitmq-server-2.8.4/src/rabbit_framing.erl --- rabbitmq-server-2.7.1/src/rabbit_framing.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_framing.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% TODO auto-generate diff -Nru rabbitmq-server-2.7.1/src/rabbit_guid.erl rabbitmq-server-2.8.4/src/rabbit_guid.erl --- rabbitmq-server-2.7.1/src/rabbit_guid.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_guid.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_guid). @@ -19,7 +19,8 @@ -behaviour(gen_server). -export([start_link/0]). --export([guid/0, string_guid/1, binstring_guid/1]). +-export([filename/0]). +-export([gen/0, gen_secure/0, string/2, binary/2]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -38,9 +39,11 @@ -type(guid() :: binary()). -spec(start_link/0 :: () -> rabbit_types:ok_pid_or_error()). --spec(guid/0 :: () -> guid()). --spec(string_guid/1 :: (any()) -> string()). --spec(binstring_guid/1 :: (any()) -> binary()). +-spec(filename/0 :: () -> string()). +-spec(gen/0 :: () -> guid()). +-spec(gen_secure/0 :: () -> guid()). +-spec(string/2 :: (guid(), any()) -> string()). +-spec(binary/2 :: (guid(), any()) -> binary()). -endif. @@ -50,8 +53,14 @@ gen_server:start_link({local, ?SERVER}, ?MODULE, [update_disk_serial()], []). +%% We use this to detect a (possibly rather old) Mnesia directory, +%% since it has existed since at least 1.7.0 (as far back as I cared +%% to go). +filename() -> + filename:join(rabbit_mnesia:dir(), ?SERIAL_FILENAME). + update_disk_serial() -> - Filename = filename:join(rabbit_mnesia:dir(), ?SERIAL_FILENAME), + Filename = filename(), Serial = case rabbit_file:read_term_file(Filename) of {ok, [Num]} -> Num; {error, enoent} -> 0; @@ -65,11 +74,8 @@ end, Serial. -%% generate a GUID. -%% -%% The id is only unique within a single cluster and as long as the -%% serial store hasn't been deleted. -guid() -> +%% Generate an un-hashed guid. +fresh() -> %% We don't use erlang:now() here because a) it may return %% duplicates when the system clock has been rewound prior to a %% restart, or ids were generated at a high rate (which causes @@ -78,29 +84,74 @@ %% %% A persisted serial number, the node, and a unique reference %% (per node incarnation) uniquely identifies a process in space - %% and time. We combine that with a process-local counter to give - %% us a GUID. - G = case get(guid) of - undefined -> Serial = gen_server:call(?SERVER, serial, infinity), - {{Serial, node(), make_ref()}, 0}; + %% and time. + Serial = gen_server:call(?SERVER, serial, infinity), + {Serial, node(), make_ref()}. + +advance_blocks({B1, B2, B3, B4}, I) -> + %% To produce a new set of blocks, we create a new 32bit block + %% hashing {B5, I}. The new hash is used as last block, and the + %% other three blocks are XORed with it. + %% + %% Doing this is convenient because it avoids cascading conflits, + %% while being very fast. The conflicts are avoided by propagating + %% the changes through all the blocks at each round by XORing, so + %% the only occasion in which a collision will take place is when + %% all 4 blocks are the same and the counter is the same. + %% + %% The range (2^32) is provided explicitly since phash uses 2^27 + %% by default. + B5 = erlang:phash2({B1, I}, 4294967296), + {{(B2 bxor B5), (B3 bxor B5), (B4 bxor B5), B5}, I+1}. + +blocks_to_binary({B1, B2, B3, B4}) -> <>. + +%% generate a GUID. This function should be used when performance is a +%% priority and predictability is not an issue. Otherwise use +%% gen_secure/0. +gen() -> + %% We hash a fresh GUID with md5, split it in 4 blocks, and each + %% time we need a new guid we rotate them producing a new hash + %% with the aid of the counter. Look at the comments in + %% advance_blocks/2 for details. + {BS, I} = case get(guid) of + undefined -> <> = + erlang:md5(term_to_binary(fresh())), + {{B1,B2,B3,B4}, 0}; + {BS0, I0} -> advance_blocks(BS0, I0) + end, + put(guid, {BS, I}), + blocks_to_binary(BS). + +%% generate a non-predictable GUID. +%% +%% The id is only unique within a single cluster and as long as the +%% serial store hasn't been deleted. +%% +%% If you are not concerned with predictability, gen/0 is faster. +gen_secure() -> + %% Here instead of hashing once we hash the GUID and the counter + %% each time, so that the GUID is not predictable. + G = case get(guid_secure) of + undefined -> {fresh(), 0}; {S, I} -> {S, I+1} end, - put(guid, G), + put(guid_secure, G), erlang:md5(term_to_binary(G)). %% generate a readable string representation of a GUID. %% %% employs base64url encoding, which is safer in more contexts than %% plain base64. -string_guid(Prefix) -> +string(G, Prefix) -> Prefix ++ "-" ++ lists:foldl(fun ($\+, Acc) -> [$\- | Acc]; ($\/, Acc) -> [$\_ | Acc]; ($\=, Acc) -> Acc; (Chr, Acc) -> [Chr | Acc] - end, [], base64:encode_to_string(guid())). + end, [], base64:encode_to_string(G)). -binstring_guid(Prefix) -> - list_to_binary(string_guid(Prefix)). +binary(G, Prefix) -> + list_to_binary(string(G, Prefix)). %%---------------------------------------------------------------------------- diff -Nru rabbitmq-server-2.7.1/src/rabbit_heartbeat.erl rabbitmq-server-2.8.4/src/rabbit_heartbeat.erl --- rabbitmq-server-2.7.1/src/rabbit_heartbeat.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_heartbeat.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_heartbeat). diff -Nru rabbitmq-server-2.7.1/src/rabbit_limiter.erl rabbitmq-server-2.8.4/src/rabbit_limiter.erl --- rabbitmq-server-2.7.1/src/rabbit_limiter.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_limiter.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_limiter). diff -Nru rabbitmq-server-2.7.1/src/rabbit_log.erl rabbitmq-server-2.8.4/src/rabbit_log.erl --- rabbitmq-server-2.7.1/src/rabbit_log.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_log.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_log). @@ -23,8 +23,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([debug/1, debug/2, message/4, info/1, info/2, - warning/1, warning/2, error/1, error/2]). +-export([log/3, log/4, info/1, info/2, warning/1, warning/2, error/1, error/2]). -define(SERVER, ?MODULE). @@ -32,9 +31,15 @@ -ifdef(use_specs). +-export_type([level/0]). + +-type(category() :: atom()). +-type(level() :: 'info' | 'warning' | 'error'). + -spec(start_link/0 :: () -> rabbit_types:ok_pid_or_error()). --spec(debug/1 :: (string()) -> 'ok'). --spec(debug/2 :: (string(), [any()]) -> 'ok'). + +-spec(log/3 :: (category(), level(), string()) -> 'ok'). +-spec(log/4 :: (category(), level(), string(), [any()]) -> 'ok'). -spec(info/1 :: (string()) -> 'ok'). -spec(info/2 :: (string(), [any()]) -> 'ok'). -spec(warning/1 :: (string()) -> 'ok'). @@ -42,84 +47,47 @@ -spec(error/1 :: (string()) -> 'ok'). -spec(error/2 :: (string(), [any()]) -> 'ok'). --spec(message/4 :: (_,_,_,_) -> 'ok'). - -endif. %%---------------------------------------------------------------------------- - start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). +log(Category, Level, Fmt) -> log(Category, Level, Fmt, []). -debug(Fmt) -> - gen_server:cast(?SERVER, {debug, Fmt}). - -debug(Fmt, Args) when is_list(Args) -> - gen_server:cast(?SERVER, {debug, Fmt, Args}). - -message(Direction, Channel, MethodRecord, Content) -> - gen_server:cast(?SERVER, - {message, Direction, Channel, MethodRecord, Content}). +log(Category, Level, Fmt, Args) when is_list(Args) -> + gen_server:cast(?SERVER, {log, Category, Level, Fmt, Args}). -info(Fmt) -> - gen_server:cast(?SERVER, {info, Fmt}). - -info(Fmt, Args) when is_list(Args) -> - gen_server:cast(?SERVER, {info, Fmt, Args}). - -warning(Fmt) -> - gen_server:cast(?SERVER, {warning, Fmt}). - -warning(Fmt, Args) when is_list(Args) -> - gen_server:cast(?SERVER, {warning, Fmt, Args}). - -error(Fmt) -> - gen_server:cast(?SERVER, {error, Fmt}). - -error(Fmt, Args) when is_list(Args) -> - gen_server:cast(?SERVER, {error, Fmt, Args}). +info(Fmt) -> log(default, info, Fmt). +info(Fmt, Args) -> log(default, info, Fmt, Args). +warning(Fmt) -> log(default, warning, Fmt). +warning(Fmt, Args) -> log(default, warning, Fmt, Args). +error(Fmt) -> log(default, error, Fmt). +error(Fmt, Args) -> log(default, error, Fmt, Args). %%-------------------------------------------------------------------- -init([]) -> {ok, none}. +init([]) -> + {ok, CatLevelList} = application:get_env(log_levels), + CatLevels = [{Cat, level(Level)} || {Cat, Level} <- CatLevelList], + {ok, orddict:from_list(CatLevels)}. handle_call(_Request, _From, State) -> {noreply, State}. -handle_cast({debug, Fmt}, State) -> - io:format("debug:: "), io:format(Fmt), - error_logger:info_msg("debug:: " ++ Fmt), - {noreply, State}; -handle_cast({debug, Fmt, Args}, State) -> - io:format("debug:: "), io:format(Fmt, Args), - error_logger:info_msg("debug:: " ++ Fmt, Args), - {noreply, State}; -handle_cast({message, Direction, Channel, MethodRecord, Content}, State) -> - io:format("~s ch~p ~p~n", - [case Direction of - in -> "-->"; - out -> "<--" end, - Channel, - {MethodRecord, Content}]), - {noreply, State}; -handle_cast({info, Fmt}, State) -> - error_logger:info_msg(Fmt), - {noreply, State}; -handle_cast({info, Fmt, Args}, State) -> - error_logger:info_msg(Fmt, Args), - {noreply, State}; -handle_cast({warning, Fmt}, State) -> - error_logger:warning_msg(Fmt), - {noreply, State}; -handle_cast({warning, Fmt, Args}, State) -> - error_logger:warning_msg(Fmt, Args), - {noreply, State}; -handle_cast({error, Fmt}, State) -> - error_logger:error_msg(Fmt), - {noreply, State}; -handle_cast({error, Fmt, Args}, State) -> - error_logger:error_msg(Fmt, Args), - {noreply, State}; +handle_cast({log, Category, Level, Fmt, Args}, CatLevels) -> + CatLevel = case orddict:find(Category, CatLevels) of + {ok, L} -> L; + error -> level(info) + end, + case level(Level) =< CatLevel of + false -> ok; + true -> (case Level of + info -> fun error_logger:info_msg/2; + warning -> fun error_logger:warning_msg/2; + error -> fun error_logger:error_msg/2 + end)(Fmt, Args) + end, + {noreply, CatLevels}; handle_cast(_Msg, State) -> {noreply, State}. @@ -132,3 +100,9 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. +%%-------------------------------------------------------------------- + +level(info) -> 3; +level(warning) -> 2; +level(error) -> 1; +level(none) -> 0. diff -Nru rabbitmq-server-2.7.1/src/rabbit_memory_monitor.erl rabbitmq-server-2.8.4/src/rabbit_memory_monitor.erl --- rabbitmq-server-2.7.1/src/rabbit_memory_monitor.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_memory_monitor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% @@ -178,11 +178,8 @@ %% Internal functions %%---------------------------------------------------------------------------- -zero_clamp(Sum) -> - case Sum < ?EPSILON of - true -> 0.0; - false -> Sum - end. +zero_clamp(Sum) when Sum < ?EPSILON -> 0.0; +zero_clamp(Sum) -> Sum. internal_deregister(Pid, Demonitor, State = #state { queue_duration_sum = Sum, @@ -240,26 +237,21 @@ fun (Proc = #process { reported = QueueDuration, sent = PrevSendDuration, callback = {M, F, A} }, true) -> - case (case {QueueDuration, PrevSendDuration} of - {infinity, infinity} -> - true; - {infinity, D} -> - DesiredDurationAvg1 < D; - {D, infinity} -> - DesiredDurationAvg1 < D; - {D1, D2} -> - DesiredDurationAvg1 < - lists:min([D1,D2]) - end) of - true -> - ok = erlang:apply( - M, F, A ++ [DesiredDurationAvg1]), - ets:insert( - Durations, - Proc #process {sent = DesiredDurationAvg1}); - false -> - true + case should_send(QueueDuration, PrevSendDuration, + DesiredDurationAvg1) of + true -> ok = erlang:apply( + M, F, A ++ [DesiredDurationAvg1]), + ets:insert( + Durations, + Proc #process { + sent = DesiredDurationAvg1}); + false -> true end end, true, Durations) end, State1. + +should_send(infinity, infinity, _) -> true; +should_send(infinity, D, DD) -> DD < D; +should_send(D, infinity, DD) -> DD < D; +should_send(D1, D2, DD) -> DD < lists:min([D1, D2]). diff -Nru rabbitmq-server-2.7.1/src/rabbit_mirror_queue_coordinator.erl rabbitmq-server-2.8.4/src/rabbit_mirror_queue_coordinator.erl --- rabbitmq-server-2.7.1/src/rabbit_mirror_queue_coordinator.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_mirror_queue_coordinator.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mirror_queue_coordinator). @@ -325,11 +325,10 @@ true = link(GM), GM end, - {ok, _TRef} = - timer:apply_interval(?ONE_SECOND, gm, broadcast, [GM1, heartbeat]), + ensure_gm_heartbeat(), {ok, #state { q = Q, gm = GM1, - monitors = dict:new(), + monitors = pmon:new(), death_fun = DeathFun, length_fun = LengthFun }, hibernate, @@ -354,25 +353,24 @@ ok = LengthFun(), noreply(State); -handle_cast({ensure_monitoring, Pids}, - State = #state { monitors = Monitors }) -> - Monitors1 = - lists:foldl(fun (Pid, MonitorsN) -> - case dict:is_key(Pid, MonitorsN) of - true -> MonitorsN; - false -> MRef = erlang:monitor(process, Pid), - dict:store(Pid, MRef, MonitorsN) - end - end, Monitors, Pids), - noreply(State #state { monitors = Monitors1 }). +handle_cast({ensure_monitoring, Pids}, State = #state { monitors = Mons }) -> + noreply(State #state { monitors = pmon:monitor_all(Pids, Mons) }); + +handle_cast({delete_and_terminate, Reason}, State) -> + {stop, Reason, State}. + +handle_info(send_gm_heartbeat, State = #state { gm = GM }) -> + gm:broadcast(GM, heartbeat), + ensure_gm_heartbeat(), + noreply(State); handle_info({'DOWN', _MonitorRef, process, Pid, _Reason}, - State = #state { monitors = Monitors, + State = #state { monitors = Mons, death_fun = DeathFun }) -> - noreply(case dict:is_key(Pid, Monitors) of + noreply(case pmon:is_monitored(Pid, Mons) of false -> State; true -> ok = DeathFun(Pid), - State #state { monitors = dict:erase(Pid, Monitors) } + State #state { monitors = pmon:erase(Pid, Mons) } end); handle_info(Msg, State) -> @@ -407,6 +405,9 @@ ok = gen_server2:cast(CPid, Msg); handle_msg([CPid], _From, {ensure_monitoring, _Pids} = Msg) -> ok = gen_server2:cast(CPid, Msg); +handle_msg([CPid], _From, {delete_and_terminate, Reason} = Msg) -> + ok = gen_server2:cast(CPid, Msg), + {stop, Reason}; handle_msg([_CPid], _From, _Msg) -> ok. @@ -419,3 +420,6 @@ reply(Reply, State) -> {reply, Reply, State, hibernate}. + +ensure_gm_heartbeat() -> + erlang:send_after(?ONE_SECOND, self(), send_gm_heartbeat). diff -Nru rabbitmq-server-2.7.1/src/rabbit_mirror_queue_master.erl rabbitmq-server-2.8.4/src/rabbit_mirror_queue_master.erl --- rabbitmq-server-2.7.1/src/rabbit_mirror_queue_master.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_mirror_queue_master.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,17 +11,17 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mirror_queue_master). -export([init/3, terminate/2, delete_and_terminate/2, purge/1, publish/4, publish_delivered/5, fetch/2, ack/2, - requeue/2, len/1, is_empty/1, drain_confirmed/1, dropwhile/2, + requeue/2, len/1, is_empty/1, drain_confirmed/1, dropwhile/3, set_ram_duration_target/2, ram_duration/1, needs_timeout/1, timeout/1, handle_pre_hibernate/1, - status/1, invoke/3, is_duplicate/2, discard/3]). + status/1, invoke/3, is_duplicate/2, discard/3, fold/3]). -export([start/1, stop/0]). @@ -59,10 +59,6 @@ known_senders :: set() }). --type(ack() :: non_neg_integer()). --type(state() :: master_state()). --include("rabbit_backing_queue_spec.hrl"). - -spec(promote_backing_queue_state/6 :: (pid(), atom(), any(), pid(), dict(), [pid()]) -> master_state()). -spec(sender_death_fun/0 :: () -> death_fun()). @@ -138,7 +134,7 @@ purge(State = #state { gm = GM, backing_queue = BQ, backing_queue_state = BQS }) -> - ok = gm:broadcast(GM, {set_length, 0}), + ok = gm:broadcast(GM, {set_length, 0, false}), {Count, BQS1} = BQ:purge(BQS), {Count, State #state { backing_queue_state = BQS1, set_delivered = 0 }}. @@ -172,17 +168,19 @@ ensure_monitoring(ChPid, State #state { backing_queue_state = BQS1, ack_msg_id = AM1 })}. -dropwhile(Fun, State = #state { gm = GM, - backing_queue = BQ, - backing_queue_state = BQS, - set_delivered = SetDelivered }) -> - Len = BQ:len(BQS), - BQS1 = BQ:dropwhile(Fun, BQS), - Dropped = Len - BQ:len(BQS1), +dropwhile(Pred, AckRequired, + State = #state{gm = GM, + backing_queue = BQ, + set_delivered = SetDelivered, + backing_queue_state = BQS }) -> + Len = BQ:len(BQS), + {Msgs, BQS1} = BQ:dropwhile(Pred, AckRequired, BQS), + Len1 = BQ:len(BQS1), + ok = gm:broadcast(GM, {set_length, Len1, AckRequired}), + Dropped = Len - Len1, SetDelivered1 = lists:max([0, SetDelivered - Dropped]), - ok = gm:broadcast(GM, {set_length, BQ:len(BQS1)}), - State #state { backing_queue_state = BQS1, - set_delivered = SetDelivered1 }. + {Msgs, State #state { backing_queue_state = BQS1, + set_delivered = SetDelivered1 } }. drain_confirmed(State = #state { backing_queue = BQ, backing_queue_state = BQS, @@ -240,14 +238,18 @@ backing_queue_state = BQS, ack_msg_id = AM }) -> {MsgIds, BQS1} = BQ:ack(AckTags, BQS), - AM1 = lists:foldl(fun dict:erase/2, AM, AckTags), case MsgIds of [] -> ok; _ -> ok = gm:broadcast(GM, {ack, MsgIds}) end, + AM1 = lists:foldl(fun dict:erase/2, AM, AckTags), {MsgIds, State #state { backing_queue_state = BQS1, ack_msg_id = AM1 }}. +fold(MsgFun, State = #state { backing_queue = BQ, + backing_queue_state = BQS }, AckTags) -> + State #state { backing_queue_state = BQ:fold(MsgFun, BQS, AckTags) }. + requeue(AckTags, State = #state { gm = GM, backing_queue = BQ, backing_queue_state = BQS }) -> @@ -280,8 +282,10 @@ backing_queue_state = BQS }) -> State #state { backing_queue_state = BQ:handle_pre_hibernate(BQS) }. -status(#state { backing_queue = BQ, backing_queue_state = BQS }) -> - BQ:status(BQS). +status(State = #state { backing_queue = BQ, backing_queue_state = BQS }) -> + BQ:status(BQS) ++ + [ {mirror_seen, dict:size(State #state.seen_status)}, + {mirror_senders, sets:size(State #state.known_senders)} ]. invoke(?MODULE, Fun, State) -> Fun(?MODULE, State); diff -Nru rabbitmq-server-2.7.1/src/rabbit_mirror_queue_misc.erl rabbitmq-server-2.8.4/src/rabbit_mirror_queue_misc.erl --- rabbitmq-server-2.7.1/src/rabbit_mirror_queue_misc.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_mirror_queue_misc.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mirror_queue_misc). @@ -134,14 +134,17 @@ Queue, fun (#amqqueue { name = Name, pid = QPid, slave_pids = SPids } = Q) -> case [Pid || Pid <- [QPid | SPids], node(Pid) =:= MirrorNode] of - [] -> Result = rabbit_mirror_queue_slave_sup:start_child( - MirrorNode, [Q]), - rabbit_log:info( - "Adding mirror of queue ~s on node ~p: ~p~n", - [rabbit_misc:rs(Name), MirrorNode, Result]), - case Result of - {ok, _Pid} -> ok; - _ -> Result + [] -> case rabbit_mirror_queue_slave_sup:start_child( + MirrorNode, [Q]) of + {ok, undefined} -> %% Already running + ok; + {ok, SPid} -> + rabbit_log:info( + "Adding mirror of ~s on node ~p: ~p~n", + [rabbit_misc:rs(Name), MirrorNode, SPid]), + ok; + Other -> + Other end; [_] -> {error, {queue_already_mirrored_on_node, MirrorNode}} end diff -Nru rabbitmq-server-2.7.1/src/rabbit_mirror_queue_slave.erl rabbitmq-server-2.8.4/src/rabbit_mirror_queue_slave.erl --- rabbitmq-server-2.7.1/src/rabbit_mirror_queue_slave.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_mirror_queue_slave.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mirror_queue_slave). @@ -90,7 +90,7 @@ }). start_link(Q) -> - gen_server2:start_link(?MODULE, [Q], []). + gen_server2:start_link(?MODULE, Q, []). set_maximum_since_use(QPid, Age) -> gen_server2:cast(QPid, {set_maximum_since_use, Age}). @@ -98,59 +98,64 @@ info(QPid) -> gen_server2:call(QPid, info, infinity). -init([#amqqueue { name = QueueName } = Q]) -> - process_flag(trap_exit, true), %% amqqueue_process traps exits too. - {ok, GM} = gm:start_link(QueueName, ?MODULE, [self()]), - receive {joined, GM} -> - ok - end, +init(#amqqueue { name = QueueName } = Q) -> Self = self(), Node = node(), - {ok, MPid} = - rabbit_misc:execute_mnesia_transaction( - fun () -> - [Q1 = #amqqueue { pid = QPid, slave_pids = MPids }] = - mnesia:read({rabbit_queue, QueueName}), - %% ASSERTION - [] = [Pid || Pid <- [QPid | MPids], node(Pid) =:= Node], - MPids1 = MPids ++ [Self], - ok = rabbit_amqqueue:store_queue( - Q1 #amqqueue { slave_pids = MPids1 }), - {ok, QPid} - end), - erlang:monitor(process, MPid), - ok = file_handle_cache:register_callback( - rabbit_amqqueue, set_maximum_since_use, [Self]), - ok = rabbit_memory_monitor:register( - Self, {rabbit_amqqueue, set_ram_duration_target, [Self]}), - {ok, BQ} = application:get_env(backing_queue_module), - BQS = bq_init(BQ, Q, false), - State = #state { q = Q, - gm = GM, - master_pid = MPid, - backing_queue = BQ, - backing_queue_state = BQS, - rate_timer_ref = undefined, - sync_timer_ref = undefined, - - sender_queues = dict:new(), - msg_id_ack = dict:new(), - ack_num = 0, + case rabbit_misc:execute_mnesia_transaction( + fun () -> + [Q1 = #amqqueue { pid = QPid, slave_pids = MPids }] = + mnesia:read({rabbit_queue, QueueName}), + case [Pid || Pid <- [QPid | MPids], node(Pid) =:= Node] of + [] -> MPids1 = MPids ++ [Self], + ok = rabbit_amqqueue:store_queue( + Q1 #amqqueue { slave_pids = MPids1 }), + {new, QPid}; + [SPid] -> true = rabbit_misc:is_process_alive(SPid), + existing + end + end) of + {new, MPid} -> + process_flag(trap_exit, true), %% amqqueue_process traps exits too. + {ok, GM} = gm:start_link(QueueName, ?MODULE, [self()]), + receive {joined, GM} -> + ok + end, + erlang:monitor(process, MPid), + ok = file_handle_cache:register_callback( + rabbit_amqqueue, set_maximum_since_use, [Self]), + ok = rabbit_memory_monitor:register( + Self, {rabbit_amqqueue, set_ram_duration_target, [Self]}), + {ok, BQ} = application:get_env(backing_queue_module), + BQS = bq_init(BQ, Q, false), + State = #state { q = Q, + gm = GM, + master_pid = MPid, + backing_queue = BQ, + backing_queue_state = BQS, + rate_timer_ref = undefined, + sync_timer_ref = undefined, + + sender_queues = dict:new(), + msg_id_ack = dict:new(), + ack_num = 0, - msg_id_status = dict:new(), - known_senders = dict:new(), + msg_id_status = dict:new(), + known_senders = pmon:new(), - synchronised = false + synchronised = false }, - rabbit_event:notify(queue_slave_created, - infos(?CREATION_EVENT_KEYS, State)), - ok = gm:broadcast(GM, request_length), - {ok, State, hibernate, - {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. - -handle_call({deliver_immediately, Delivery = #delivery {}}, From, State) -> - %% Synchronous, "immediate" delivery mode + rabbit_event:notify(queue_slave_created, + infos(?CREATION_EVENT_KEYS, State)), + ok = gm:broadcast(GM, request_length), + {ok, State, hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, + ?DESIRED_HIBERNATE}}; + existing -> + ignore + end. +handle_call({deliver, Delivery = #delivery { immediate = true }}, + From, State) -> %% It is safe to reply 'false' here even if a) we've not seen the %% msg via gm, or b) the master dies before we receive the msg via %% gm. In the case of (a), we will eventually receive the msg via @@ -166,8 +171,8 @@ gen_server2:reply(From, false), %% master may deliver it, not us noreply(maybe_enqueue_message(Delivery, false, State)); -handle_call({deliver, Delivery = #delivery {}}, From, State) -> - %% Synchronous, "mandatory" delivery mode +handle_call({deliver, Delivery = #delivery { mandatory = true }}, + From, State) -> gen_server2:reply(From, true), %% amqqueue throws away the result anyway noreply(maybe_enqueue_message(Delivery, true, State)); @@ -208,8 +213,12 @@ handle_cast({gm, Instruction}, State) -> handle_process_result(process_instruction(Instruction, State)); -handle_cast({deliver, Delivery = #delivery {}}, State) -> +handle_cast({deliver, Delivery = #delivery{sender = Sender}, Flow}, State) -> %% Asynchronous, non-"mandatory", non-"immediate" deliver mode. + case Flow of + flow -> credit_flow:ack(Sender); + noflow -> ok + end, noreply(maybe_enqueue_message(Delivery, true, State)); handle_cast({set_maximum_since_use, Age}, State) -> @@ -250,6 +259,10 @@ handle_info({'EXIT', _Pid, Reason}, State) -> {stop, Reason, State}; +handle_info({bump_credit, Msg}, State) -> + credit_flow:handle_bump_msg(Msg), + noreply(State); + handle_info(Msg, State) -> {stop, {unexpected_info, Msg}, State}. @@ -273,7 +286,7 @@ rate_timer_ref = RateTRef }) -> ok = gm:leave(GM), QueueState = rabbit_amqqueue_process:init_with_backing_queue_state( - Q, BQ, BQS, RateTRef, [], [], dict:new()), + Q, BQ, BQS, RateTRef, [], [], pmon:new(), dict:new()), rabbit_amqqueue_process:terminate(Reason, QueueState); terminate([_SPid], _Reason) -> %% gm case @@ -417,7 +430,7 @@ Acc end end, {gb_trees:empty(), MS}, MsgIds), - rabbit_misc:gb_trees_foreach(fun rabbit_channel:confirm/2, CMs), + rabbit_misc:gb_trees_foreach(fun rabbit_misc:confirm_to_sender/2, CMs), State #state { msg_id_status = MS1 }. handle_process_result({ok, State}) -> noreply(State); @@ -446,12 +459,8 @@ %% Everything that we're monitoring, we need to ensure our new %% coordinator is monitoring. - - MonitoringPids = [begin true = erlang:demonitor(MRef), - Pid - end || {Pid, MRef} <- dict:to_list(KS)], - ok = rabbit_mirror_queue_coordinator:ensure_monitoring( - CPid, MonitoringPids), + MPids = pmon:monitored(KS), + ok = rabbit_mirror_queue_coordinator:ensure_monitoring(CPid, MPids), %% We find all the messages that we've received from channels but %% not from gm, and if they're due to be enqueued on promotion @@ -524,7 +533,7 @@ Status =:= published orelse Status =:= confirmed]), MasterState = rabbit_mirror_queue_master:promote_backing_queue_state( - CPid, BQ, BQS, GM, SS, MonitoringPids), + CPid, BQ, BQS, GM, SS, MPids), MTC = lists:foldl(fun ({MsgId, {published, ChPid, MsgSeqNo}}, MTC0) -> gb_trees:insert(MsgId, {ChPid, MsgSeqNo}, MTC0); @@ -537,7 +546,7 @@ {Delivery, true} <- queue:to_list(PubQ)], QueueState = rabbit_amqqueue_process:init_with_backing_queue_state( Q1, rabbit_mirror_queue_master, MasterState, RateTRef, - AckTags, Deliveries, MTC), + AckTags, Deliveries, KS, MTC), {become, rabbit_amqqueue_process, QueueState, hibernate}. noreply(State) -> @@ -592,16 +601,13 @@ State #state { rate_timer_ref = undefined }. ensure_monitoring(ChPid, State = #state { known_senders = KS }) -> - case dict:is_key(ChPid, KS) of - true -> State; - false -> MRef = erlang:monitor(process, ChPid), - State #state { known_senders = dict:store(ChPid, MRef, KS) } - end. + State #state { known_senders = pmon:monitor(ChPid, KS) }. local_sender_death(ChPid, State = #state { known_senders = KS }) -> - ok = case dict:is_key(ChPid, KS) of + ok = case pmon:is_monitored(ChPid, KS) of false -> ok; - true -> confirm_sender_death(ChPid) + true -> credit_flow:peer_down(ChPid), + confirm_sender_death(ChPid) end, State. @@ -614,7 +620,7 @@ fun (?MODULE, State = #state { known_senders = KS, gm = GM }) -> %% We're running still as a slave - ok = case dict:is_key(Pid, KS) of + ok = case pmon:is_monitored(Pid, KS) of false -> ok; true -> gm:broadcast(GM, {ensure_monitoring, [Pid]}), confirm_sender_death(Pid) @@ -651,7 +657,7 @@ {ok, {confirmed, ChPid}} -> %% BQ has confirmed it but we didn't know what the %% msg_seq_no was at the time. We do now! - ok = rabbit_channel:confirm(ChPid, [MsgSeqNo]), + ok = rabbit_misc:confirm_to_sender(ChPid, [MsgSeqNo]), SQ1 = remove_from_pending_ch(MsgId, ChPid, SQ), State1 #state { sender_queues = SQ1, msg_id_status = dict:erase(MsgId, MS) }; @@ -668,7 +674,7 @@ msg_id_status = dict:store(MsgId, {published, ChPid, MsgSeqNo}, MS) }; immediately -> - ok = rabbit_channel:confirm(ChPid, [MsgSeqNo]), + ok = rabbit_misc:confirm_to_sender(ChPid, [MsgSeqNo]), SQ1 = remove_from_pending_ch(MsgId, ChPid, SQ), State1 #state { msg_id_status = dict:erase(MsgId, MS), sender_queues = SQ1 } @@ -730,7 +736,7 @@ {MQ2, PendingCh, dict:store(MsgId, {published, ChPid, MsgSeqNo}, MS)}; immediately -> - ok = rabbit_channel:confirm(ChPid, [MsgSeqNo]), + ok = rabbit_misc:confirm_to_sender(ChPid, [MsgSeqNo]), {MQ2, PendingCh, MS} end; {{value, {#delivery {}, _EnqueueOnPromotion}}, _MQ2} -> @@ -787,23 +793,27 @@ {ok, State1 #state { sender_queues = SQ1, msg_id_status = MS1, backing_queue_state = BQS1 }}; -process_instruction({set_length, Length}, +process_instruction({set_length, Length, AckRequired}, State = #state { backing_queue = BQ, backing_queue_state = BQS }) -> QLen = BQ:len(BQS), ToDrop = QLen - Length, - {ok, case ToDrop >= 0 of - true -> BQS1 = - lists:foldl( - fun (const, BQSN) -> - {{_Msg, _IsDelivered, _AckTag, _Remaining}, - BQSN1} = BQ:fetch(false, BQSN), - BQSN1 - end, BQS, lists:duplicate(ToDrop, const)), - set_synchronised( - true, State #state { backing_queue_state = BQS1 }); - false -> State - end}; + {ok, + case ToDrop >= 0 of + true -> + State1 = + lists:foldl( + fun (const, StateN = #state {backing_queue_state = BQSN}) -> + {{#basic_message{id = MsgId}, _IsDelivered, AckTag, + _Remaining}, BQSN1} = BQ:fetch(AckRequired, BQSN), + maybe_store_ack( + AckRequired, MsgId, AckTag, + StateN #state { backing_queue_state = BQSN1 }) + end, State, lists:duplicate(ToDrop, const)), + set_synchronised(true, State1); + false -> + State + end}; process_instruction({fetch, AckRequired, MsgId, Remaining}, State = #state { backing_queue = BQ, backing_queue_state = BQS }) -> @@ -852,21 +862,18 @@ State = #state { sender_queues = SQ, msg_id_status = MS, known_senders = KS }) -> - {ok, case dict:find(ChPid, KS) of - error -> - State; - {ok, MRef} -> - true = erlang:demonitor(MRef), - MS1 = case dict:find(ChPid, SQ) of - error -> - MS; - {ok, {_MQ, PendingCh}} -> - lists:foldl(fun dict:erase/2, MS, - sets:to_list(PendingCh)) - end, - State #state { sender_queues = dict:erase(ChPid, SQ), - msg_id_status = MS1, - known_senders = dict:erase(ChPid, KS) } + {ok, case pmon:is_monitored(ChPid, KS) of + false -> State; + true -> MS1 = case dict:find(ChPid, SQ) of + error -> + MS; + {ok, {_MQ, PendingCh}} -> + lists:foldl(fun dict:erase/2, MS, + sets:to_list(PendingCh)) + end, + State #state { sender_queues = dict:erase(ChPid, SQ), + msg_id_status = MS1, + known_senders = pmon:demonitor(ChPid, KS) } end}; process_instruction({length, Length}, State = #state { backing_queue = BQ, diff -Nru rabbitmq-server-2.7.1/src/rabbit_mirror_queue_slave_sup.erl rabbitmq-server-2.8.4/src/rabbit_mirror_queue_slave_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_mirror_queue_slave_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_mirror_queue_slave_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2010-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved. %% -module(rabbit_mirror_queue_slave_sup). diff -Nru rabbitmq-server-2.7.1/src/rabbit_misc.erl rabbitmq-server-2.8.4/src/rabbit_misc.erl --- rabbitmq-server-2.7.1/src/rabbit_misc.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_misc.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_misc). @@ -28,17 +28,19 @@ -export([enable_cover/0, report_cover/0]). -export([enable_cover/1, report_cover/1]). -export([start_cover/1]). +-export([confirm_to_sender/2]). -export([throw_on_error/2, with_exit_handler/2, filter_exit_map/2]). +-export([is_abnormal_termination/1]). -export([with_user/2, with_user_and_vhost/3]). -export([execute_mnesia_transaction/1]). -export([execute_mnesia_transaction/2]). -export([execute_mnesia_tx_with_tail/1]). -export([ensure_ok/2]). --export([makenode/1, nodeparts/1, cookie_hash/0, tcp_name/3]). +-export([tcp_name/3]). -export([upmap/2, map_in_order/2]). -export([table_filter/3]). -export([dirty_read_all/1, dirty_foreach_key/2, dirty_dump_log/1]). --export([format_stderr/2, with_local_io/1, local_info_msg/2]). +-export([format/2, format_stderr/2, with_local_io/1, local_info_msg/2]). -export([start_applications/1, stop_applications/1]). -export([unfold/2, ceil/1, queue_fold/3]). -export([sort_field_table/1]). @@ -55,7 +57,10 @@ -export([pget/2, pget/3, pget_or_die/2]). -export([format_message_queue/2]). -export([append_rpc_all_nodes/4]). +-export([multi_call/2]). -export([quit/1]). +-export([os_cmd/1]). +-export([gb_sets_difference/2]). %%---------------------------------------------------------------------------- @@ -108,7 +113,6 @@ (rabbit_framing:amqp_table(), binary(), rabbit_framing:amqp_field_type(), rabbit_framing:amqp_value()) -> rabbit_framing:amqp_table()). - -spec(r/2 :: (rabbit_types:vhost(), K) -> rabbit_types:r3(rabbit_types:vhost(), K, '_') when is_subtype(K, atom())). @@ -131,6 +135,7 @@ (atom(), thunk(rabbit_types:error(any()) | {ok, A} | A)) -> A). -spec(with_exit_handler/2 :: (thunk(A), thunk(A)) -> A). -spec(filter_exit_map/2 :: (fun ((A) -> B), [A]) -> [B]). +-spec(is_abnormal_termination/1 :: (any()) -> boolean()). -spec(with_user/2 :: (rabbit_types:username(), thunk(A)) -> A). -spec(with_user_and_vhost/3 :: (rabbit_types:username(), rabbit_types:vhost(), thunk(A)) @@ -141,9 +146,6 @@ -spec(execute_mnesia_tx_with_tail/1 :: (thunk(fun ((boolean()) -> B))) -> B | (fun ((boolean()) -> B))). -spec(ensure_ok/2 :: (ok_or_error(), atom()) -> 'ok'). --spec(makenode/1 :: ({string(), string()} | string()) -> node()). --spec(nodeparts/1 :: (node() | string()) -> {string(), string()}). --spec(cookie_hash/0 :: () -> string()). -spec(tcp_name/3 :: (atom(), inet:ip_address(), rabbit_networking:ip_port()) -> atom()). @@ -155,6 +157,7 @@ -spec(dirty_foreach_key/2 :: (fun ((any()) -> any()), atom()) -> 'ok' | 'aborted'). -spec(dirty_dump_log/1 :: (file:filename()) -> ok_or_error()). +-spec(format/2 :: (string(), [any()]) -> string()). -spec(format_stderr/2 :: (string(), [any()]) -> 'ok'). -spec(with_local_io/1 :: (fun (() -> A)) -> A). -spec(local_info_msg/2 :: (string(), [any()]) -> 'ok'). @@ -198,7 +201,11 @@ -spec(pget_or_die/2 :: (term(), [term()]) -> term() | no_return()). -spec(format_message_queue/2 :: (any(), priority_queue:q()) -> term()). -spec(append_rpc_all_nodes/4 :: ([node()], atom(), atom(), [any()]) -> [any()]). +-spec(multi_call/2 :: + ([pid()], any()) -> {[{pid(), any()}], [{pid(), any()}]}). -spec(quit/1 :: (integer() | string()) -> no_return()). +-spec(os_cmd/1 :: (string()) -> string()). +-spec(gb_sets_difference/2 :: (gb_set(), gb_set()) -> gb_set()). -endif. @@ -222,7 +229,7 @@ protocol_error(frame_error, "cannot decode ~w", [BinaryFields], MethodName). amqp_error(Name, ExplanationFormat, Params, Method) -> - Explanation = lists:flatten(io_lib:format(ExplanationFormat, Params)), + Explanation = format(ExplanationFormat, Params), #amqp_error{name = Name, explanation = Explanation, method = Method}. protocol_error(Name, ExplanationFormat, Params) -> @@ -276,8 +283,7 @@ true -> "~s"; false -> "~w" end, - lists:flatten(io_lib:format("the value '" ++ ValFmt ++ "' of type '~s'", - [Value, Type])). + format("the value '" ++ ValFmt ++ "' of type '~s'", [Value, Type]). %% Normally we'd call mnesia:dirty_read/1 here, but that is quite %% expensive due to general mnesia overheads (figuring out table types @@ -320,8 +326,7 @@ end. rs(#resource{virtual_host = VHostPath, kind = Kind, name = Name}) -> - lists:flatten(io_lib:format("~s '~s' in vhost '~s'", - [Kind, Name, VHostPath])). + format("~s '~s' in vhost '~s'", [Kind, Name, VHostPath]). enable_cover() -> enable_cover(["."]). @@ -337,7 +342,7 @@ end, ok, Dirs). start_cover(NodesS) -> - {ok, _} = cover:start([makenode(N) || N <- NodesS]), + {ok, _} = cover:start([rabbit_nodes:make(N) || N <- NodesS]), ok. report_cover() -> report_cover(["."]). @@ -376,6 +381,9 @@ end, Mod]). +confirm_to_sender(Pid, MsgSeqNos) -> + gen_server2:cast(Pid, {confirm, MsgSeqNos, self()}). + throw_on_error(E, Thunk) -> case Thunk() of {error, Reason} -> throw({E, Reason}); @@ -401,6 +409,12 @@ fun () -> Ref end, fun () -> F(I) end) || I <- L]). +is_abnormal_termination(Reason) + when Reason =:= noproc; Reason =:= noconnection; + Reason =:= normal; Reason =:= shutdown -> false; +is_abnormal_termination({shutdown, _}) -> false; +is_abnormal_termination(_) -> true. + with_user(Username, Thunk) -> fun () -> case mnesia:read({rabbit_user, Username}) of @@ -418,12 +432,25 @@ %% Making this a sync_transaction allows us to use dirty_read %% elsewhere and get a consistent result even when that read %% executes on a different node. - case worker_pool:submit({mnesia, sync_transaction, [TxFun]}) of - {atomic, Result} -> Result; - {aborted, Reason} -> throw({error, Reason}) + case worker_pool:submit( + fun () -> + case mnesia:is_transaction() of + false -> DiskLogBefore = mnesia_dumper:get_log_writes(), + Res = mnesia:sync_transaction(TxFun), + DiskLogAfter = mnesia_dumper:get_log_writes(), + case DiskLogAfter == DiskLogBefore of + true -> Res; + false -> {sync, Res} + end; + true -> mnesia:sync_transaction(TxFun) + end + end) of + {sync, {atomic, Result}} -> mnesia_sync:sync(), Result; + {sync, {aborted, Reason}} -> throw({error, Reason}); + {atomic, Result} -> Result; + {aborted, Reason} -> throw({error, Reason}) end. - %% Like execute_mnesia_transaction/1 with additional Pre- and Post- %% commit function execute_mnesia_transaction(TxFun, PrePostCommitFun) -> @@ -450,29 +477,10 @@ ensure_ok(ok, _) -> ok; ensure_ok({error, Reason}, ErrorTag) -> throw({error, {ErrorTag, Reason}}). -makenode({Prefix, Suffix}) -> - list_to_atom(lists:append([Prefix, "@", Suffix])); -makenode(NodeStr) -> - makenode(nodeparts(NodeStr)). - -nodeparts(Node) when is_atom(Node) -> - nodeparts(atom_to_list(Node)); -nodeparts(NodeStr) -> - case lists:splitwith(fun (E) -> E =/= $@ end, NodeStr) of - {Prefix, []} -> {_, Suffix} = nodeparts(node()), - {Prefix, Suffix}; - {Prefix, Suffix} -> {Prefix, tl(Suffix)} - end. - -cookie_hash() -> - base64:encode_to_string(erlang:md5(atom_to_list(erlang:get_cookie()))). - tcp_name(Prefix, IPAddress, Port) when is_atom(Prefix) andalso is_number(Port) -> list_to_atom( - lists:flatten( - io_lib:format("~w_~s:~w", - [Prefix, inet_parse:ntoa(IPAddress), Port]))). + format("~w_~s:~w", [Prefix, inet_parse:ntoa(IPAddress), Port])). %% This is a modified version of Luke Gorrie's pmap - %% http://lukego.livejournal.com/6753.html - that doesn't care about @@ -541,6 +549,8 @@ io:format("Bad Chunk, ~p: ~p~n", [BadBytes, Terms]), dirty_dump_log1(LH, disk_log:chunk(LH, K)). +format(Fmt, Args) -> lists:flatten(io_lib:format(Fmt, Args)). + format_stderr(Fmt, Args) -> case os:type() of {unix, _} -> @@ -636,7 +646,7 @@ <<131,103,100,NodeLen:16,NodeBin:NodeLen/binary,Id:32,Ser:32,Cre:8>> = term_to_binary(Pid), Node = binary_to_term(<<131,100,NodeLen:16,NodeBin:NodeLen/binary>>), - lists:flatten(io_lib:format("<~w.~B.~B.~B>", [Node, Cre, Id, Ser])). + format("<~w.~B.~B.~B>", [Node, Cre, Id, Ser]). %% inverse of above string_to_pid(Str) -> @@ -728,13 +738,14 @@ %% [{"-q",true},{"-p","/"}]} get_options(Defs, As) -> lists:foldl(fun(Def, {AsIn, RsIn}) -> - {AsOut, Value} = case Def of - {flag, Key} -> - get_flag(Key, AsIn); - {option, Key, Default} -> - get_option(Key, Default, AsIn) - end, - {AsOut, [{Key, Value} | RsIn]} + {K, {AsOut, V}} = + case Def of + {flag, Key} -> + {Key, get_flag(Key, AsIn)}; + {option, Key, Default} -> + {Key, get_option(Key, Default, AsIn)} + end, + {AsOut, [{K, V} | RsIn]} end, {As, []}, Defs). get_option(K, _Default, [K, V | As]) -> @@ -865,9 +876,44 @@ _ -> Res end || Res <- ResL]). +%% A simplified version of gen_server:multi_call/2 with a sane +%% API. This is not in gen_server2 as there is no useful +%% infrastructure there to share. +multi_call(Pids, Req) -> + MonitorPids = [start_multi_call(Pid, Req) || Pid <- Pids], + receive_multi_call(MonitorPids, [], []). + +start_multi_call(Pid, Req) when is_pid(Pid) -> + Mref = erlang:monitor(process, Pid), + Pid ! {'$gen_call', {self(), Mref}, Req}, + {Mref, Pid}. + +receive_multi_call([], Good, Bad) -> + {lists:reverse(Good), lists:reverse(Bad)}; +receive_multi_call([{Mref, Pid} | MonitorPids], Good, Bad) -> + receive + {Mref, Reply} -> + erlang:demonitor(Mref, [flush]), + receive_multi_call(MonitorPids, [{Pid, Reply} | Good], Bad); + {'DOWN', Mref, _, _, noconnection} -> + receive_multi_call(MonitorPids, Good, [{Pid, nodedown} | Bad]); + {'DOWN', Mref, _, _, Reason} -> + receive_multi_call(MonitorPids, Good, [{Pid, Reason} | Bad]) + end. + %% the slower shutdown on windows required to flush stdout quit(Status) -> case os:type() of {unix, _} -> halt(Status); {win32, _} -> init:stop(Status) end. + +os_cmd(Command) -> + Exec = hd(string:tokens(Command, " ")), + case os:find_executable(Exec) of + false -> throw({command_not_found, Exec}); + _ -> os:cmd(Command) + end. + +gb_sets_difference(S1, S2) -> + gb_sets:fold(fun gb_sets:delete_any/2, S1, S2). diff -Nru rabbitmq-server-2.7.1/src/rabbit_mnesia.erl rabbitmq-server-2.8.4/src/rabbit_mnesia.erl --- rabbitmq-server-2.7.1/src/rabbit_mnesia.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_mnesia.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% @@ -23,8 +23,8 @@ empty_ram_only_tables/0, copy_db/1, wait_for_tables/1, create_cluster_nodes_config/1, read_cluster_nodes_config/0, record_running_nodes/0, read_previously_running_nodes/0, - delete_previously_running_nodes/0, running_nodes_filename/0, - is_disc_node/0, on_node_down/1, on_node_up/1]). + running_nodes_filename/0, is_disc_node/0, on_node_down/1, + on_node_up/1]). -export([table_names/0]). @@ -64,7 +64,6 @@ -spec(read_cluster_nodes_config/0 :: () -> [node()]). -spec(record_running_nodes/0 :: () -> 'ok'). -spec(read_previously_running_nodes/0 :: () -> [node()]). --spec(delete_previously_running_nodes/0 :: () -> 'ok'). -spec(running_nodes_filename/0 :: () -> file:filename()). -spec(is_disc_node/0 :: () -> boolean()). -spec(on_node_up/1 :: (node()) -> 'ok'). @@ -98,12 +97,13 @@ init() -> ensure_mnesia_running(), ensure_mnesia_dir(), - ok = init_db(read_cluster_nodes_config(), true, - fun maybe_upgrade_local_or_record_desired/0), + Nodes = read_cluster_nodes_config(), + ok = init_db(Nodes, should_be_disc_node(Nodes)), %% We intuitively expect the global name server to be synced when %% Mnesia is up. In fact that's not guaranteed to be the case - let's %% make it so. ok = global:sync(), + ok = delete_previously_running_nodes(), ok. is_db_empty() -> @@ -174,8 +174,7 @@ %% Join the cluster start_mnesia(), try - ok = init_db(ClusterNodes, Force, - fun maybe_upgrade_local_or_record_desired/0), + ok = init_db(ClusterNodes, Force), ok = create_cluster_nodes_config(ClusterNodes) after stop_mnesia() @@ -268,6 +267,11 @@ {type, ordered_set}, {match, #reverse_route{reverse_binding = reverse_binding_match(), _='_'}}]}, + {rabbit_topic_trie_node, + [{record_name, topic_trie_node}, + {attributes, record_info(fields, topic_trie_node)}, + {type, ordered_set}, + {match, #topic_trie_node{trie_node = trie_node_match(), _='_'}}]}, {rabbit_topic_trie_edge, [{record_name, topic_trie_edge}, {attributes, record_info(fields, topic_trie_edge)}, @@ -314,12 +318,12 @@ _='_'}. binding_destination_match() -> resource_match('_'). +trie_node_match() -> + #trie_node{ exchange_name = exchange_name_match(), _='_'}. trie_edge_match() -> - #trie_edge{exchange_name = exchange_name_match(), - _='_'}. + #trie_edge{ exchange_name = exchange_name_match(), _='_'}. trie_binding_match() -> - #trie_binding{exchange_name = exchange_name_match(), - _='_'}. + #trie_binding{exchange_name = exchange_name_match(), _='_'}. exchange_name_match() -> resource_match(exchange). queue_name_match() -> @@ -496,6 +500,18 @@ FileName, Reason}}) end. +init_db(ClusterNodes, Force) -> + init_db( + ClusterNodes, Force, + fun () -> + case rabbit_upgrade:maybe_upgrade_local() of + ok -> ok; + %% If we're just starting up a new node we won't have a + %% version + starting_from_scratch -> ok = rabbit_version:record_desired() + end + end). + %% Take a cluster node config and create the right kind of node - a %% standalone disk node, or disk or ram node connected to the %% specified cluster nodes. If Force is false, don't allow @@ -504,20 +520,12 @@ UClusterNodes = lists:usort(ClusterNodes), ProperClusterNodes = UClusterNodes -- [node()], case mnesia:change_config(extra_db_nodes, ProperClusterNodes) of + {ok, []} when not Force andalso ProperClusterNodes =/= [] -> + throw({error, {failed_to_cluster_with, ProperClusterNodes, + "Mnesia could not connect to any disc nodes."}}); {ok, Nodes} -> - case Force of - false -> FailedClusterNodes = ProperClusterNodes -- Nodes, - case FailedClusterNodes of - [] -> ok; - _ -> throw({error, {failed_to_cluster_with, - FailedClusterNodes, - "Mnesia could not connect " - "to some nodes."}}) - end; - true -> ok - end, - WantDiscNode = should_be_disc_node(ClusterNodes), WasDiscNode = is_disc_node(), + WantDiscNode = should_be_disc_node(ClusterNodes), %% We create a new db (on disk, or in ram) in the first %% two cases and attempt to upgrade the in the other two case {Nodes, WasDiscNode, WantDiscNode} of @@ -567,14 +575,6 @@ throw({error, {unable_to_join_cluster, ClusterNodes, Reason}}) end. -maybe_upgrade_local_or_record_desired() -> - case rabbit_upgrade:maybe_upgrade_local() of - ok -> ok; - %% If we're just starting up a new node we won't have a - %% version - version_not_available -> ok = rabbit_version:record_desired() - end. - schema_ok_or_move() -> case check_schema_integrity() of ok -> @@ -622,10 +622,9 @@ stop_mnesia(), MnesiaDir = filename:dirname(dir() ++ "/"), {{Year, Month, Day}, {Hour, Minute, Second}} = erlang:universaltime(), - BackupDir = lists:flatten( - io_lib:format("~s_~w~2..0w~2..0w~2..0w~2..0w~2..0w", - [MnesiaDir, - Year, Month, Day, Hour, Minute, Second])), + BackupDir = rabbit_misc:format( + "~s_~w~2..0w~2..0w~2..0w~2..0w~2..0w", + [MnesiaDir, Year, Month, Day, Hour, Minute, Second]), case file:rename(MnesiaDir, BackupDir) of ok -> %% NB: we cannot use rabbit_log here since it may not have @@ -733,16 +732,18 @@ false -> ok end, Node = node(), + Nodes = all_clustered_nodes() -- [Node], case Force of true -> ok; false -> ensure_mnesia_dir(), start_mnesia(), - {Nodes, RunningNodes} = + RunningNodes = try - ok = init(), - {all_clustered_nodes() -- [Node], - running_clustered_nodes() -- [Node]} + %% Force=true here so that reset still works when clustered + %% with a node which is down + ok = init_db(read_cluster_nodes_config(), true), + running_clustered_nodes() -- [Node] after stop_mnesia() end, @@ -750,6 +751,10 @@ rabbit_misc:ensure_ok(mnesia:delete_schema([Node]), cannot_delete_schema) end, + %% We need to make sure that we don't end up in a distributed + %% Erlang system with nodes while not being in an Mnesia cluster + %% with them. We don't handle that well. + [erlang:disconnect_node(N) || N <- Nodes], ok = delete_cluster_nodes_config(), %% remove persisted messages and any other garbage we find ok = rabbit_file:recursive_delete(filelib:wildcard(dir() ++ "/*")), diff -Nru rabbitmq-server-2.7.1/src/rabbit_msg_file.erl rabbitmq-server-2.8.4/src/rabbit_msg_file.erl --- rabbitmq-server-2.7.1/src/rabbit_msg_file.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_msg_file.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_msg_file). diff -Nru rabbitmq-server-2.7.1/src/rabbit_msg_store.erl rabbitmq-server-2.8.4/src/rabbit_msg_store.erl --- rabbitmq-server-2.7.1/src/rabbit_msg_store.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_msg_store.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_msg_store). @@ -21,7 +21,7 @@ -export([start_link/4, successfully_recovered_state/1, client_init/4, client_terminate/1, client_delete_and_terminate/1, client_ref/1, close_all_indicated/1, - write/3, read/2, contains/2, remove/2]). + write/3, write_flow/3, read/2, contains/2, remove/2]). -export([set_maximum_since_use/2, has_readers/2, combine_files/3, delete_file/2]). %% internal @@ -152,6 +152,7 @@ -spec(close_all_indicated/1 :: (client_msstate()) -> rabbit_types:ok(client_msstate())). -spec(write/3 :: (rabbit_types:msg_id(), msg(), client_msstate()) -> 'ok'). +-spec(write_flow/3 :: (rabbit_types:msg_id(), msg(), client_msstate()) -> 'ok'). -spec(read/2 :: (rabbit_types:msg_id(), client_msstate()) -> {rabbit_types:ok(msg()) | 'not_found', client_msstate()}). -spec(contains/2 :: (rabbit_types:msg_id(), client_msstate()) -> boolean()). @@ -436,7 +437,8 @@ {IState, IModule, Dir, GCPid, FileHandlesEts, FileSummaryEts, CurFileCacheEts, FlyingEts} = gen_server2:call( - Server, {new_client_state, Ref, MsgOnDiskFun, CloseFDsFun}, infinity), + Server, {new_client_state, Ref, self(), MsgOnDiskFun, CloseFDsFun}, + infinity), #client_msstate { server = Server, client_ref = Ref, file_handle_cache = dict:new(), @@ -460,12 +462,11 @@ client_ref(#client_msstate { client_ref = Ref }) -> Ref. -write(MsgId, Msg, - CState = #client_msstate { cur_file_cache_ets = CurFileCacheEts, - client_ref = CRef }) -> - ok = client_update_flying(+1, MsgId, CState), - ok = update_msg_cache(CurFileCacheEts, MsgId, Msg), - ok = server_cast(CState, {write, CRef, MsgId}). +write_flow(MsgId, Msg, CState = #client_msstate { server = Server }) -> + credit_flow:send(whereis(Server), ?CREDIT_DISC_BOUND), + client_write(MsgId, Msg, flow, CState). + +write(MsgId, Msg, CState) -> client_write(MsgId, Msg, noflow, CState). read(MsgId, CState = #client_msstate { cur_file_cache_ets = CurFileCacheEts }) -> @@ -500,6 +501,13 @@ server_cast(#client_msstate { server = Server }, Msg) -> gen_server2:cast(Server, Msg). +client_write(MsgId, Msg, Flow, + CState = #client_msstate { cur_file_cache_ets = CurFileCacheEts, + client_ref = CRef }) -> + ok = client_update_flying(+1, MsgId, CState), + ok = update_msg_cache(CurFileCacheEts, MsgId, Msg), + ok = server_cast(CState, {write, CRef, MsgId, Flow}). + client_read1(#msg_location { msg_id = MsgId, file = File } = MsgLocation, Defer, CState = #client_msstate { file_summary_ets = FileSummaryEts }) -> case ets:lookup(FileSummaryEts, File) of @@ -666,7 +674,8 @@ recover_index_and_client_refs(IndexModule, FileSummaryRecovered, ClientRefs, Dir, Server), Clients = dict:from_list( - [{CRef, {undefined, undefined}} || CRef <- ClientRefs1]), + [{CRef, {undefined, undefined, undefined}} || + CRef <- ClientRefs1]), %% CleanShutdown => msg location index and file_summary both %% recovered correctly. true = case {FileSummaryRecovered, CleanShutdown} of @@ -731,10 +740,10 @@ prioritise_call(Msg, _From, _State) -> case Msg of - successfully_recovered_state -> 7; - {new_client_state, _Ref, _MODC, _CloseFDsFun} -> 7; - {read, _MsgId} -> 2; - _ -> 0 + successfully_recovered_state -> 7; + {new_client_state, _Ref, _Pid, _MODC, _CloseFDsFun} -> 7; + {read, _MsgId} -> 2; + _ -> 0 end. prioritise_cast(Msg, _State) -> @@ -755,7 +764,7 @@ handle_call(successfully_recovered_state, _From, State) -> reply(State #msstate.successfully_recovered, State); -handle_call({new_client_state, CRef, MsgOnDiskFun, CloseFDsFun}, _From, +handle_call({new_client_state, CRef, CPid, MsgOnDiskFun, CloseFDsFun}, _From, State = #msstate { dir = Dir, index_state = IndexState, index_module = IndexModule, @@ -765,7 +774,7 @@ flying_ets = FlyingEts, clients = Clients, gc_pid = GCPid }) -> - Clients1 = dict:store(CRef, {MsgOnDiskFun, CloseFDsFun}, Clients), + Clients1 = dict:store(CRef, {CPid, MsgOnDiskFun, CloseFDsFun}, Clients), reply({IndexState, IndexModule, Dir, GCPid, FileHandlesEts, FileSummaryEts, CurFileCacheEts, FlyingEts}, State #msstate { clients = Clients1 }); @@ -789,11 +798,19 @@ handle_cast({client_delete, CRef}, State = #msstate { clients = Clients }) -> + {CPid, _, _} = dict:fetch(CRef, Clients), + credit_flow:peer_down(CPid), State1 = State #msstate { clients = dict:erase(CRef, Clients) }, noreply(remove_message(CRef, CRef, clear_client(CRef, State1))); -handle_cast({write, CRef, MsgId}, - State = #msstate { cur_file_cache_ets = CurFileCacheEts }) -> +handle_cast({write, CRef, MsgId, Flow}, + State = #msstate { cur_file_cache_ets = CurFileCacheEts, + clients = Clients }) -> + case Flow of + flow -> {CPid, _, _} = dict:fetch(CRef, Clients), + credit_flow:ack(CPid, ?CREDIT_DISC_BOUND); + noflow -> ok + end, true = 0 =< ets:update_counter(CurFileCacheEts, MsgId, {3, -1}), case update_flying(-1, MsgId, CRef, State) of process -> @@ -1204,10 +1221,10 @@ State = #msstate { clients = Clients, cref_to_msg_ids = CTM }) -> case dict:fetch(CRef, Clients) of - {undefined, _CloseFDsFun} -> State; - {MsgOnDiskFun, _CloseFDsFun} -> CTM1 = Fun(MsgOnDiskFun, CTM), - State #msstate { - cref_to_msg_ids = CTM1 } + {_CPid, undefined, _CloseFDsFun} -> State; + {_CPid, MsgOnDiskFun, _CloseFDsFun} -> CTM1 = Fun(MsgOnDiskFun, CTM), + State #msstate { + cref_to_msg_ids = CTM1 } end. record_pending_confirm(CRef, MsgId, State) -> @@ -1223,7 +1240,8 @@ case dict:find(CRef, CTM) of {ok, Gs} -> MsgOnDiskFun(gb_sets:intersection(Gs, MsgIds), ActionTaken), - MsgIds1 = gb_sets:difference(Gs, MsgIds), + MsgIds1 = rabbit_misc:gb_sets_difference( + Gs, MsgIds), case gb_sets:is_empty(MsgIds1) of true -> dict:erase(CRef, CTM); false -> dict:store(CRef, MsgIds1, CTM) @@ -1294,8 +1312,10 @@ case (ets:update_element(FileHandlesEts, Key, {2, close}) andalso Invoke) of true -> case dict:fetch(Ref, ClientRefs) of - {_MsgOnDiskFun, undefined} -> ok; - {_MsgOnDiskFun, CloseFDsFun} -> ok = CloseFDsFun() + {_CPid, _MsgOnDiskFun, undefined} -> + ok; + {_CPid, _MsgOnDiskFun, CloseFDsFun} -> + ok = CloseFDsFun() end; false -> ok end diff -Nru rabbitmq-server-2.7.1/src/rabbit_msg_store_ets_index.erl rabbitmq-server-2.8.4/src/rabbit_msg_store_ets_index.erl --- rabbitmq-server-2.7.1/src/rabbit_msg_store_ets_index.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_msg_store_ets_index.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,11 +11,13 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_msg_store_ets_index). +-include("rabbit_msg_store.hrl"). + -behaviour(rabbit_msg_store_index). -export([new/1, recover/1, @@ -25,8 +27,6 @@ -define(MSG_LOC_NAME, rabbit_msg_store_ets_index). -define(FILENAME, "msg_store_index.ets"). --include("rabbit_msg_store_index.hrl"). - -record(state, { table, dir }). new(Dir) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_msg_store_gc.erl rabbitmq-server-2.8.4/src/rabbit_msg_store_gc.erl --- rabbitmq-server-2.7.1/src/rabbit_msg_store_gc.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_msg_store_gc.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_msg_store_gc). diff -Nru rabbitmq-server-2.7.1/src/rabbit_msg_store_index.erl rabbitmq-server-2.8.4/src/rabbit_msg_store_index.erl --- rabbitmq-server-2.7.1/src/rabbit_msg_store_index.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_msg_store_index.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,11 +11,36 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_msg_store_index). +-include("rabbit_msg_store.hrl"). + +-ifdef(use_specs). + +-type(dir() :: any()). +-type(index_state() :: any()). +-type(keyvalue() :: any()). +-type(fieldpos() :: non_neg_integer()). +-type(fieldvalue() :: any()). + +-callback new(dir()) -> index_state(). +-callback recover(dir()) -> rabbit_types:ok_or_error2(index_state(), any()). +-callback lookup(rabbit_types:msg_id(), index_state()) -> ('not_found' | keyvalue()). +-callback insert(keyvalue(), index_state()) -> 'ok'. +-callback update(keyvalue(), index_state()) -> 'ok'. +-callback update_fields(rabbit_types:msg_id(), ({fieldpos(), fieldvalue()} | + [{fieldpos(), fieldvalue()}]), + index_state()) -> 'ok'. +-callback delete(rabbit_types:msg_id(), index_state()) -> 'ok'. +-callback delete_object(keyvalue(), index_state()) -> 'ok'. +-callback delete_by_file(fieldvalue(), index_state()) -> 'ok'. +-callback terminate(index_state()) -> any(). + +-else. + -export([behaviour_info/1]). behaviour_info(callbacks) -> @@ -30,3 +55,5 @@ {terminate, 1}]; behaviour_info(_Other) -> undefined. + +-endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_net.erl rabbitmq-server-2.8.4/src/rabbit_net.erl --- rabbitmq-server-2.7.1/src/rabbit_net.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_net.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,15 +11,16 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_net). -include("rabbit.hrl"). -export([is_ssl/1, ssl_info/1, controlling_process/2, getstat/2, - recv/1, async_recv/3, port_command/2, setopts/2, send/2, close/1, - sockname/1, peername/1, peercert/1]). + recv/1, async_recv/3, port_command/2, getopts/2, setopts/2, send/2, + close/1, maybe_fast_close/1, sockname/1, peername/1, peercert/1, + connection_string/2]). %%--------------------------------------------------------------------------- @@ -33,6 +34,8 @@ -type(ok_val_or_error(A) :: rabbit_types:ok_or_error2(A, any())). -type(ok_or_any_error() :: rabbit_types:ok_or_error(any())). -type(socket() :: port() | #ssl_socket{}). +-type(opts() :: [{atom(), any()} | + {raw, non_neg_integer(), non_neg_integer(), binary()}]). -spec(is_ssl/1 :: (socket()) -> boolean()). -spec(ssl_info/1 :: (socket()) @@ -48,11 +51,15 @@ -spec(async_recv/3 :: (socket(), integer(), timeout()) -> rabbit_types:ok(any())). -spec(port_command/2 :: (socket(), iolist()) -> 'true'). --spec(setopts/2 :: (socket(), [{atom(), any()} | - {raw, non_neg_integer(), non_neg_integer(), - binary()}]) -> ok_or_any_error()). +-spec(getopts/2 :: (socket(), [atom() | {raw, + non_neg_integer(), + non_neg_integer(), + non_neg_integer() | binary()}]) + -> ok_val_or_error(opts())). +-spec(setopts/2 :: (socket(), opts()) -> ok_or_any_error()). -spec(send/2 :: (socket(), binary() | iolist()) -> ok_or_any_error()). -spec(close/1 :: (socket()) -> ok_or_any_error()). +-spec(maybe_fast_close/1 :: (socket()) -> ok_or_any_error()). -spec(sockname/1 :: (socket()) -> ok_val_or_error({inet:ip_address(), rabbit_networking:ip_port()})). @@ -62,6 +69,8 @@ -spec(peercert/1 :: (socket()) -> 'nossl' | ok_val_or_error(rabbit_ssl:certificate())). +-spec(connection_string/2 :: + (socket(), 'inbound' | 'outbound') -> ok_val_or_error(string())). -endif. @@ -122,6 +131,11 @@ port_command(Sock, Data) when is_port(Sock) -> erlang:port_command(Sock, Data). +getopts(Sock, Options) when ?IS_SSL(Sock) -> + ssl:getopts(Sock#ssl_socket.ssl, Options); +getopts(Sock, Options) when is_port(Sock) -> + inet:getopts(Sock, Options). + setopts(Sock, Options) when ?IS_SSL(Sock) -> ssl:setopts(Sock#ssl_socket.ssl, Options); setopts(Sock, Options) when is_port(Sock) -> @@ -133,6 +147,9 @@ close(Sock) when ?IS_SSL(Sock) -> ssl:close(Sock#ssl_socket.ssl); close(Sock) when is_port(Sock) -> gen_tcp:close(Sock). +maybe_fast_close(Sock) when ?IS_SSL(Sock) -> ok; +maybe_fast_close(Sock) when is_port(Sock) -> erlang:port_close(Sock), ok. + sockname(Sock) when ?IS_SSL(Sock) -> ssl:sockname(Sock#ssl_socket.ssl); sockname(Sock) when is_port(Sock) -> inet:sockname(Sock). @@ -141,3 +158,19 @@ peercert(Sock) when ?IS_SSL(Sock) -> ssl:peercert(Sock#ssl_socket.ssl); peercert(Sock) when is_port(Sock) -> nossl. + +connection_string(Sock, Direction) -> + {From, To} = case Direction of + inbound -> {fun peername/1, fun sockname/1}; + outbound -> {fun sockname/1, fun peername/1} + end, + case {From(Sock), To(Sock)} of + {{ok, {FromAddress, FromPort}}, {ok, {ToAddress, ToPort}}} -> + {ok, rabbit_misc:format("~s:~p -> ~s:~p", + [rabbit_misc:ntoab(FromAddress), FromPort, + rabbit_misc:ntoab(ToAddress), ToPort])}; + {{error, _Reason} = Error, _} -> + Error; + {_, {error, _Reason} = Error} -> + Error + end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_networking.erl rabbitmq-server-2.8.4/src/rabbit_networking.erl --- rabbitmq-server-2.7.1/src/rabbit_networking.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_networking.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_networking). @@ -24,7 +24,7 @@ close_connection/2, force_connection_event_refresh/0]). %%used by TCP-based transports, e.g. STOMP adapter --export([check_tcp_listener_address/2, +-export([tcp_listener_addresses/1, tcp_listener_spec/6, ensure_ssl/0, ssl_transform_fun/1]). -export([tcp_listener_started/3, tcp_listener_stopped/3, @@ -47,12 +47,16 @@ -export_type([ip_port/0, hostname/0]). -type(hostname() :: inet:hostname()). --type(ip_port() :: inet:ip_port()). +-type(ip_port() :: inet:port_number()). -type(family() :: atom()). -type(listener_config() :: ip_port() | {hostname(), ip_port()} | {hostname(), ip_port(), family()}). +-type(address() :: {inet:ip_address(), ip_port(), family()}). +-type(name_prefix() :: atom()). +-type(protocol() :: atom()). +-type(label() :: string()). -spec(start/0 :: () -> 'ok'). -spec(start_tcp_listener/1 :: (listener_config()) -> 'ok'). @@ -76,8 +80,10 @@ -spec(force_connection_event_refresh/0 :: () -> 'ok'). -spec(on_node_down/1 :: (node()) -> 'ok'). --spec(check_tcp_listener_address/2 :: (atom(), listener_config()) - -> [{inet:ip_address(), ip_port(), family(), atom()}]). +-spec(tcp_listener_addresses/1 :: (listener_config()) -> [address()]). +-spec(tcp_listener_spec/6 :: + (name_prefix(), address(), [gen_tcp:listen_option()], protocol(), + label(), rabbit_types:mfargs()) -> supervisor:child_spec()). -spec(ensure_ssl/0 :: () -> rabbit_types:infos()). -spec(ssl_transform_fun/1 :: (rabbit_types:infos()) @@ -140,39 +146,6 @@ transient, infinity, supervisor, [rabbit_client_sup]}), ok. -%% inet_parse:address takes care of ip string, like "0.0.0.0" -%% inet:getaddr returns immediately for ip tuple {0,0,0,0}, -%% and runs 'inet_gethost' port process for dns lookups. -%% On Windows inet:getaddr runs dns resolver for ip string, which may fail. - -getaddr(Host, Family) -> - case inet_parse:address(Host) of - {ok, IPAddress} -> [{IPAddress, resolve_family(IPAddress, Family)}]; - {error, _} -> gethostaddr(Host, Family) - end. - -gethostaddr(Host, auto) -> - Lookups = [{Family, inet:getaddr(Host, Family)} || Family <- [inet, inet6]], - case [{IP, Family} || {Family, {ok, IP}} <- Lookups] of - [] -> host_lookup_error(Host, Lookups); - IPs -> IPs - end; - -gethostaddr(Host, Family) -> - case inet:getaddr(Host, Family) of - {ok, IPAddress} -> [{IPAddress, Family}]; - {error, Reason} -> host_lookup_error(Host, Reason) - end. - -host_lookup_error(Host, Reason) -> - error_logger:error_msg("invalid host ~p - ~p~n", [Host, Reason]), - throw({error, {invalid_host, Host, Reason}}). - -resolve_family({_,_,_,_}, auto) -> inet; -resolve_family({_,_,_,_,_,_,_,_}, auto) -> inet6; -resolve_family(IP, auto) -> throw({error, {strange_family, IP}}); -resolve_family(_, F) -> F. - ensure_ssl() -> ok = rabbit_misc:start_applications([crypto, public_key, ssl]), {ok, SslOptsConfig} = application:get_env(rabbit, ssl_options), @@ -191,8 +164,6 @@ fun (Sock) -> case catch ssl:ssl_accept(Sock, SslOpts, ?SSL_TIMEOUT * 1000) of {ok, SslSock} -> - rabbit_log:info("upgraded TCP connection ~p to SSL~n", - [self()]), {ok, #ssl_socket{tcp = Sock, ssl = SslSock}}; {error, Reason} -> {error, {ssl_upgrade_error, Reason}}; @@ -201,31 +172,36 @@ end end. -check_tcp_listener_address(NamePrefix, Port) when is_integer(Port) -> - check_tcp_listener_address_auto(NamePrefix, Port); - -check_tcp_listener_address(NamePrefix, {"auto", Port}) -> +tcp_listener_addresses(Port) when is_integer(Port) -> + tcp_listener_addresses_auto(Port); +tcp_listener_addresses({"auto", Port}) -> %% Variant to prevent lots of hacking around in bash and batch files - check_tcp_listener_address_auto(NamePrefix, Port); - -check_tcp_listener_address(NamePrefix, {Host, Port}) -> + tcp_listener_addresses_auto(Port); +tcp_listener_addresses({Host, Port}) -> %% auto: determine family IPv4 / IPv6 after converting to IP address - check_tcp_listener_address(NamePrefix, {Host, Port, auto}); + tcp_listener_addresses({Host, Port, auto}); +tcp_listener_addresses({Host, Port, Family0}) + when is_integer(Port) andalso (Port >= 0) andalso (Port =< 65535) -> + [{IPAddress, Port, Family} || + {IPAddress, Family} <- getaddr(Host, Family0)]; +tcp_listener_addresses({_Host, Port, _Family0}) -> + error_logger:error_msg("invalid port ~p - not 0..65535~n", [Port]), + throw({error, {invalid_port, Port}}). -check_tcp_listener_address(NamePrefix, {Host, Port, Family0}) -> - if is_integer(Port) andalso (Port >= 0) andalso (Port =< 65535) -> ok; - true -> error_logger:error_msg("invalid port ~p - not 0..65535~n", - [Port]), - throw({error, {invalid_port, Port}}) - end, - [{IPAddress, Port, Family, - rabbit_misc:tcp_name(NamePrefix, IPAddress, Port)} || - {IPAddress, Family} <- getaddr(Host, Family0)]. - -check_tcp_listener_address_auto(NamePrefix, Port) -> - lists:append([check_tcp_listener_address(NamePrefix, Listener) || +tcp_listener_addresses_auto(Port) -> + lists:append([tcp_listener_addresses(Listener) || Listener <- port_to_listeners(Port)]). +tcp_listener_spec(NamePrefix, {IPAddress, Port, Family}, SocketOpts, + Protocol, Label, OnConnect) -> + {rabbit_misc:tcp_name(NamePrefix, IPAddress, Port), + {tcp_listener_sup, start_link, + [IPAddress, Port, [Family | SocketOpts], + {?MODULE, tcp_listener_started, [Protocol]}, + {?MODULE, tcp_listener_stopped, [Protocol]}, + OnConnect, Label]}, + transient, infinity, supervisor, [tcp_listener_sup]}. + start_tcp_listener(Listener) -> start_listener(Listener, amqp, "TCP Listener", {?MODULE, start_client, []}). @@ -235,27 +211,26 @@ {?MODULE, start_ssl_client, [SslOpts]}). start_listener(Listener, Protocol, Label, OnConnect) -> - [start_listener0(Spec, Protocol, Label, OnConnect) || - Spec <- check_tcp_listener_address(rabbit_tcp_listener_sup, Listener)], + [start_listener0(Address, Protocol, Label, OnConnect) || + Address <- tcp_listener_addresses(Listener)], ok. -start_listener0({IPAddress, Port, Family, Name}, Protocol, Label, OnConnect) -> - {ok,_} = supervisor:start_child( - rabbit_sup, - {Name, - {tcp_listener_sup, start_link, - [IPAddress, Port, [Family | tcp_opts()], - {?MODULE, tcp_listener_started, [Protocol]}, - {?MODULE, tcp_listener_stopped, [Protocol]}, - OnConnect, Label]}, - transient, infinity, supervisor, [tcp_listener_sup]}). +start_listener0(Address, Protocol, Label, OnConnect) -> + Spec = tcp_listener_spec(rabbit_tcp_listener_sup, Address, tcp_opts(), + Protocol, Label, OnConnect), + case supervisor:start_child(rabbit_sup, Spec) of + {ok, _} -> ok; + {error, {shutdown, _}} -> {IPAddress, Port, _Family} = Address, + exit({could_not_start_tcp_listener, + {rabbit_misc:ntoa(IPAddress), Port}}) + end. stop_tcp_listener(Listener) -> - [stop_tcp_listener0(Spec) || - Spec <- check_tcp_listener_address(rabbit_tcp_listener_sup, Listener)], + [stop_tcp_listener0(Address) || + Address <- tcp_listener_addresses(Listener)], ok. -stop_tcp_listener0({IPAddress, Port, _Family, Name}) -> +stop_tcp_listener0({IPAddress, Port, _Family}) -> Name = rabbit_misc:tcp_name(rabbit_tcp_listener_sup, IPAddress, Port), ok = supervisor:terminate_child(rabbit_sup, Name), ok = supervisor:delete_child(rabbit_sup, Name). @@ -294,6 +269,16 @@ {ok, _Child, Reader} = supervisor:start_child(rabbit_tcp_client_sup, []), ok = rabbit_net:controlling_process(Sock, Reader), Reader ! {go, Sock, SockTransform}, + + %% In the event that somebody floods us with connections, the + %% reader processes can spew log events at error_logger faster + %% than it can keep up, causing its mailbox to grow unbounded + %% until we eat all the memory available and crash. So here is a + %% meaningless synchronous call to the underlying gen_event + %% mechanism. When it returns the mailbox is drained, and we + %% return to our caller to accept more connetions. + gen_event:which_handlers(error_logger), + Reader. start_client(Sock) -> @@ -363,6 +348,38 @@ {ok, Opts} = application:get_env(rabbit, tcp_listen_options), Opts. +%% inet_parse:address takes care of ip string, like "0.0.0.0" +%% inet:getaddr returns immediately for ip tuple {0,0,0,0}, +%% and runs 'inet_gethost' port process for dns lookups. +%% On Windows inet:getaddr runs dns resolver for ip string, which may fail. +getaddr(Host, Family) -> + case inet_parse:address(Host) of + {ok, IPAddress} -> [{IPAddress, resolve_family(IPAddress, Family)}]; + {error, _} -> gethostaddr(Host, Family) + end. + +gethostaddr(Host, auto) -> + Lookups = [{Family, inet:getaddr(Host, Family)} || Family <- [inet, inet6]], + case [{IP, Family} || {Family, {ok, IP}} <- Lookups] of + [] -> host_lookup_error(Host, Lookups); + IPs -> IPs + end; + +gethostaddr(Host, Family) -> + case inet:getaddr(Host, Family) of + {ok, IPAddress} -> [{IPAddress, Family}]; + {error, Reason} -> host_lookup_error(Host, Reason) + end. + +host_lookup_error(Host, Reason) -> + error_logger:error_msg("invalid host ~p - ~p~n", [Host, Reason]), + throw({error, {invalid_host, Host, Reason}}). + +resolve_family({_,_,_,_}, auto) -> inet; +resolve_family({_,_,_,_,_,_,_,_}, auto) -> inet6; +resolve_family(IP, auto) -> throw({error, {strange_family, IP}}); +resolve_family(_, F) -> F. + %%-------------------------------------------------------------------- %% There are three kinds of machine (for our purposes). @@ -429,16 +446,19 @@ {ok, LSock4} -> gen_tcp:close(LSock4), single_stack; %% IPv6-only machine. Welcome to the future. - {error, eafnosupport} -> ipv6_only; + {error, eafnosupport} -> ipv6_only; %% Linux + {error, eprotonosupport}-> ipv6_only; %% FreeBSD %% Dual stack machine with something already %% on IPv4. {error, _} -> ipv6_status(TestPort + 1) end end; - {error, eafnosupport} -> - %% IPv4-only machine. Welcome to the 90s. + %% IPv4-only machine. Welcome to the 90s. + {error, eafnosupport} -> %% Linux + ipv4_only; + {error, eprotonosupport} -> %% FreeBSD ipv4_only; + %% Port in use {error, _} -> - %% Port in use ipv6_status(TestPort + 1) end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_node_monitor.erl rabbitmq-server-2.8.4/src/rabbit_node_monitor.erl --- rabbitmq-server-2.7.1/src/rabbit_node_monitor.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_node_monitor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_node_monitor). @@ -55,29 +55,32 @@ {_, Bad} -> rabbit_log:info("failed to contact nodes ~p~n", [Bad]) end, %% register other active rabbits with this rabbit - [ rabbit_node_monitor:rabbit_running_on(N) || N <- Nodes ], + [ rabbit_running_on(N) || N <- Nodes ], ok. %%-------------------------------------------------------------------- init([]) -> - {ok, no_state}. + {ok, ordsets:new()}. handle_call(_Request, _From, State) -> {noreply, State}. -handle_cast({rabbit_running_on, Node}, State) -> - rabbit_log:info("rabbit on ~p up~n", [Node]), - erlang:monitor(process, {rabbit, Node}), - ok = handle_live_rabbit(Node), - {noreply, State}; +handle_cast({rabbit_running_on, Node}, Nodes) -> + case ordsets:is_element(Node, Nodes) of + true -> {noreply, Nodes}; + false -> rabbit_log:info("rabbit on node ~p up~n", [Node]), + erlang:monitor(process, {rabbit, Node}), + ok = handle_live_rabbit(Node), + {noreply, ordsets:add_element(Node, Nodes)} + end; handle_cast(_Msg, State) -> {noreply, State}. -handle_info({'DOWN', _MRef, process, {rabbit, Node}, _Reason}, State) -> - rabbit_log:info("node ~p lost 'rabbit'~n", [Node]), +handle_info({'DOWN', _MRef, process, {rabbit, Node}, _Reason}, Nodes) -> + rabbit_log:info("rabbit on node ~p down~n", [Node]), ok = handle_dead_rabbit(Node), - {noreply, State}; + {noreply, ordsets:del_element(Node, Nodes)}; handle_info(_Info, State) -> {noreply, State}. diff -Nru rabbitmq-server-2.7.1/src/rabbit_nodes.erl rabbitmq-server-2.8.4/src/rabbit_nodes.erl --- rabbitmq-server-2.7.1/src/rabbit_nodes.erl 1970-01-01 00:00:00.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_nodes.erl 2012-06-22 16:03:48.000000000 +0000 @@ -0,0 +1,101 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is VMware, Inc. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. +%% + +-module(rabbit_nodes). + +-export([names/1, diagnostics/1, make/1, parts/1, cookie_hash/0, is_running/2]). + +-define(EPMD_TIMEOUT, 30000). + +%%---------------------------------------------------------------------------- +%% Specs +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-spec(names/1 :: (string()) -> rabbit_types:ok_or_error2( + [{string(), integer()}], term())). +-spec(diagnostics/1 :: ([node()]) -> string()). +-spec(make/1 :: ({string(), string()} | string()) -> node()). +-spec(parts/1 :: (node() | string()) -> {string(), string()}). +-spec(cookie_hash/0 :: () -> string()). +-spec(is_running/2 :: (node(), atom()) -> boolean()). + +-endif. + +%%---------------------------------------------------------------------------- + +names(Hostname) -> + Self = self(), + Ref = make_ref(), + {Pid, MRef} = spawn_monitor( + fun () -> Self ! {Ref, net_adm:names(Hostname)} end), + timer:exit_after(?EPMD_TIMEOUT, Pid, timeout), + receive + {Ref, Names} -> erlang:demonitor(MRef, [flush]), + Names; + {'DOWN', MRef, process, Pid, Reason} -> {error, Reason} + end. + +diagnostics(Nodes) -> + Hosts = lists:usort([element(2, parts(Node)) || Node <- Nodes]), + NodeDiags = [{"~nDIAGNOSTICS~n===========~n~n" + "nodes in question: ~p~n~n" + "hosts, their running nodes and ports:", [Nodes]}] ++ + [diagnostics_host(Host) || Host <- Hosts] ++ + diagnostics0(), + lists:flatten([io_lib:format(F ++ "~n", A) || NodeDiag <- NodeDiags, + {F, A} <- [NodeDiag]]). + +diagnostics0() -> + [{"~ncurrent node details:~n- node name: ~w", [node()]}, + case init:get_argument(home) of + {ok, [[Home]]} -> {"- home dir: ~s", [Home]}; + Other -> {"- no home dir: ~p", [Other]} + end, + {"- cookie hash: ~s", [cookie_hash()]}]. + +diagnostics_host(Host) -> + case names(Host) of + {error, EpmdReason} -> + {"- unable to connect to epmd on ~s: ~w", + [Host, EpmdReason]}; + {ok, NamePorts} -> + {"- ~s: ~p", + [Host, [{list_to_atom(Name), Port} || + {Name, Port} <- NamePorts]]} + end. + +make({Prefix, Suffix}) -> list_to_atom(lists:append([Prefix, "@", Suffix])); +make(NodeStr) -> make(parts(NodeStr)). + +parts(Node) when is_atom(Node) -> + parts(atom_to_list(Node)); +parts(NodeStr) -> + case lists:splitwith(fun (E) -> E =/= $@ end, NodeStr) of + {Prefix, []} -> {_, Suffix} = parts(node()), + {Prefix, Suffix}; + {Prefix, Suffix} -> {Prefix, tl(Suffix)} + end. + +cookie_hash() -> + base64:encode_to_string(erlang:md5(atom_to_list(erlang:get_cookie()))). + +is_running(Node, Application) -> + case rpc:call(Node, application, which_applications, [infinity]) of + {badrpc, _} -> false; + Apps -> proplists:is_defined(Application, Apps) + end. diff -Nru rabbitmq-server-2.7.1/src/rabbit_plugins.erl rabbitmq-server-2.8.4/src/rabbit_plugins.erl --- rabbitmq-server-2.7.1/src/rabbit_plugins.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_plugins.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved. %% -module(rabbit_plugins). @@ -55,17 +55,27 @@ CmdArgsAndOpts -> CmdArgsAndOpts end, Command = list_to_atom(Command0), + PrintInvalidCommandError = + fun () -> + print_error("invalid command '~s'", + [string:join([atom_to_list(Command) | Args], " ")]) + end, case catch action(Command, Args, Opts, PluginsFile, PluginsDir) of ok -> rabbit_misc:quit(0); {'EXIT', {function_clause, [{?MODULE, action, _} | _]}} -> - print_error("invalid command '~s'", - [string:join([atom_to_list(Command) | Args], " ")]), + PrintInvalidCommandError(), + usage(); + {'EXIT', {function_clause, [{?MODULE, action, _, _} | _]}} -> + PrintInvalidCommandError(), usage(); {error, Reason} -> print_error("~p", [Reason]), rabbit_misc:quit(2); + {error_string, Reason} -> + print_error("~s", [Reason]), + rabbit_misc:quit(2); Other -> print_error("~p", [Other]), rabbit_misc:quit(2) @@ -90,7 +100,7 @@ action(enable, ToEnable0, _Opts, PluginsFile, PluginsDir) -> case ToEnable0 of - [] -> throw("Not enough arguments for 'enable'"); + [] -> throw({error_string, "Not enough arguments for 'enable'"}); _ -> ok end, AllPlugins = find_plugins(PluginsDir), @@ -100,8 +110,9 @@ Missing = ToEnable -- plugin_names(AllPlugins), case Missing of [] -> ok; - _ -> throw(fmt_list("The following plugins could not be found:", - Missing)) + _ -> throw({error_string, + fmt_list("The following plugins could not be found:", + Missing)}) end, NewEnabled = lists:usort(Enabled ++ ToEnable), write_enabled_plugins(PluginsFile, NewEnabled), @@ -116,7 +127,7 @@ action(disable, ToDisable0, _Opts, PluginsFile, PluginsDir) -> case ToDisable0 of - [] -> throw("Not enough arguments for 'disable'"); + [] -> throw({error_string, "Not enough arguments for 'disable'"}); _ -> ok end, ToDisable = [list_to_atom(Name) || Name <- ToDisable0], @@ -231,7 +242,8 @@ {false, false} -> normal; {true, false} -> verbose; {false, true} -> minimal; - {true, true} -> throw("Cannot specify -m and -v together") + {true, true} -> throw({error_string, + "Cannot specify -m and -v together"}) end, OnlyEnabled = proplists:get_bool(?ENABLED_OPT, Opts), OnlyEnabledAll = proplists:get_bool(?ENABLED_ALL_OPT, Opts), @@ -289,7 +301,7 @@ fmt_list(Header, Plugins) -> lists:flatten( - [Header, $\n, [io_lib:format(" ~s~n", [P]) || P <- Plugins], $\n]). + [Header, $\n, [io_lib:format(" ~s~n", [P]) || P <- Plugins]]). usort_plugins(Plugins) -> lists:usort(fun plugins_cmp/2, Plugins). @@ -325,6 +337,9 @@ read_enabled_plugins(PluginsFile) -> case rabbit_file:read_term_file(PluginsFile) of {ok, [Plugins]} -> Plugins; + {ok, []} -> []; + {ok, [_|_]} -> throw({error, {malformed_enabled_plugins_file, + PluginsFile}}); {error, enoent} -> []; {error, Reason} -> throw({error, {cannot_read_enabled_plugins_file, PluginsFile, Reason}}) diff -Nru rabbitmq-server-2.7.1/src/rabbit_prelaunch.erl rabbitmq-server-2.8.4/src/rabbit_prelaunch.erl --- rabbitmq-server-2.7.1/src/rabbit_prelaunch.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_prelaunch.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_prelaunch). @@ -22,7 +22,6 @@ -define(BaseApps, [rabbit]). -define(ERROR_CODE, 1). --define(EPMD_TIMEOUT, 30000). %%---------------------------------------------------------------------------- %% Specs @@ -244,16 +243,15 @@ %% Ignore running node while installing windows service ok; duplicate_node_check(NodeStr) -> - Node = rabbit_misc:makenode(NodeStr), - {NodeName, NodeHost} = rabbit_misc:nodeparts(Node), - case names(NodeHost) of + Node = rabbit_nodes:make(NodeStr), + {NodeName, NodeHost} = rabbit_nodes:parts(Node), + case rabbit_nodes:names(NodeHost) of {ok, NamePorts} -> case proplists:is_defined(NodeName, NamePorts) of true -> io:format("node with name ~p " "already running on ~p~n", [NodeName, NodeHost]), - [io:format(Fmt ++ "~n", Args) || - {Fmt, Args} <- rabbit_control:diagnostics(Node)], + io:format(rabbit_nodes:diagnostics([Node]) ++ "~n"), terminate(?ERROR_CODE); false -> ok end; @@ -279,15 +277,3 @@ after infinity -> ok end end. - -names(Hostname) -> - Self = self(), - process_flag(trap_exit, true), - Pid = spawn_link(fun () -> Self ! {names, net_adm:names(Hostname)} end), - timer:exit_after(?EPMD_TIMEOUT, Pid, timeout), - Res = receive - {names, Names} -> Names; - {'EXIT', Pid, Reason} -> {error, Reason} - end, - process_flag(trap_exit, false), - Res. diff -Nru rabbitmq-server-2.7.1/src/rabbit_queue_collector.erl rabbitmq-server-2.8.4/src/rabbit_queue_collector.erl --- rabbitmq-server-2.7.1/src/rabbit_queue_collector.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_queue_collector.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_queue_collector). @@ -23,7 +23,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --record(state, {queues, delete_from}). +-record(state, {monitors, delete_from}). -include("rabbit.hrl"). @@ -32,7 +32,7 @@ -ifdef(use_specs). -spec(start_link/0 :: () -> rabbit_types:ok_pid_or_error()). --spec(register/2 :: (pid(), rabbit_types:amqqueue()) -> 'ok'). +-spec(register/2 :: (pid(), pid()) -> 'ok'). -spec(delete_all/1 :: (pid()) -> 'ok'). -endif. @@ -51,39 +51,37 @@ %%---------------------------------------------------------------------------- init([]) -> - {ok, #state{queues = dict:new(), delete_from = undefined}}. + {ok, #state{monitors = pmon:new(), delete_from = undefined}}. %%-------------------------------------------------------------------------- -handle_call({register, Q}, _From, - State = #state{queues = Queues, delete_from = Deleting}) -> - MonitorRef = erlang:monitor(process, Q#amqqueue.pid), +handle_call({register, QPid}, _From, + State = #state{monitors = QMons, delete_from = Deleting}) -> case Deleting of undefined -> ok; - _ -> rabbit_amqqueue:delete_immediately(Q) + _ -> ok = rabbit_amqqueue:delete_immediately([QPid]) end, - {reply, ok, State#state{queues = dict:store(MonitorRef, Q, Queues)}}; + {reply, ok, State#state{monitors = pmon:monitor(QPid, QMons)}}; -handle_call(delete_all, From, State = #state{queues = Queues, +handle_call(delete_all, From, State = #state{monitors = QMons, delete_from = undefined}) -> - case dict:size(Queues) of - 0 -> {reply, ok, State#state{delete_from = From}}; - _ -> [rabbit_amqqueue:delete_immediately(Q) - || {_MRef, Q} <- dict:to_list(Queues)], - {noreply, State#state{delete_from = From}} + case pmon:monitored(QMons) of + [] -> {reply, ok, State#state{delete_from = From}}; + QPids -> ok = rabbit_amqqueue:delete_immediately(QPids), + {noreply, State#state{delete_from = From}} end. handle_cast(Msg, State) -> {stop, {unhandled_cast, Msg}, State}. -handle_info({'DOWN', MonitorRef, process, _DownPid, _Reason}, - State = #state{queues = Queues, delete_from = Deleting}) -> - Queues1 = dict:erase(MonitorRef, Queues), - case Deleting =/= undefined andalso dict:size(Queues1) =:= 0 of +handle_info({'DOWN', _MRef, process, DownPid, _Reason}, + State = #state{monitors = QMons, delete_from = Deleting}) -> + QMons1 = pmon:erase(DownPid, QMons), + case Deleting =/= undefined andalso pmon:is_empty(QMons1) of true -> gen_server:reply(Deleting, ok); false -> ok end, - {noreply, State#state{queues = Queues1}}. + {noreply, State#state{monitors = QMons1}}. terminate(_Reason, _State) -> ok. diff -Nru rabbitmq-server-2.7.1/src/rabbit_queue_index.erl rabbitmq-server-2.8.4/src/rabbit_queue_index.erl --- rabbitmq-server-2.7.1/src/rabbit_queue_index.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_queue_index.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,15 +11,17 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_queue_index). -export([init/2, shutdown_terms/1, recover/5, terminate/2, delete_and_terminate/1, - publish/5, deliver/2, ack/2, sync/1, sync/2, flush/1, read/3, - next_segment_boundary/1, bounds/1, recover/1]). + publish/5, deliver/2, ack/2, sync/1, needs_sync/1, flush/1, + read/3, next_segment_boundary/1, bounds/1, recover/1]). + +-export([scan/3]). -export([add_queue_ttl/0]). @@ -207,7 +209,8 @@ -> qistate()). -spec(deliver/2 :: ([seq_id()], qistate()) -> qistate()). -spec(ack/2 :: ([seq_id()], qistate()) -> qistate()). --spec(sync/2 :: ([seq_id()], qistate()) -> qistate()). +-spec(sync/1 :: (qistate()) -> qistate()). +-spec(needs_sync/1 :: (qistate()) -> boolean()). -spec(flush/1 :: (qistate()) -> qistate()). -spec(read/3 :: (seq_id(), seq_id(), qistate()) -> {[{rabbit_types:msg_id(), seq_id(), @@ -218,6 +221,12 @@ {non_neg_integer(), non_neg_integer(), qistate()}). -spec(recover/1 :: ([rabbit_amqqueue:name()]) -> {[[any()]], {walker(A), A}}). +-spec(scan/3 :: (file:filename(), + fun ((seq_id(), rabbit_types:msg_id(), + rabbit_types:message_properties(), boolean(), + ('del' | 'no_del'), ('ack' | 'no_ack'), A) -> A), + A) -> A). + -spec(add_queue_ttl/0 :: () -> 'ok'). -endif. @@ -283,20 +292,18 @@ ack(SeqIds, State) -> deliver_or_ack(ack, SeqIds, State). -%% This is only called when there are outstanding confirms and the -%% queue is idle. -sync(State = #qistate { unsynced_msg_ids = MsgIds }) -> - sync_if(not gb_sets:is_empty(MsgIds), State). - -sync(SeqIds, State) -> - %% The SeqIds here contains the SeqId of every publish and ack to - %% be sync'ed. Ideally we should go through these seqids and only - %% sync the journal if the pubs or acks appear in the - %% journal. However, this would be complex to do, and given that - %% the variable queue publishes and acks to the qi, and then - %% syncs, all in one operation, there is no possibility of the - %% seqids not being in the journal. - sync_if([] =/= SeqIds, State). +%% This is called when there are outstanding confirms or when the +%% queue is idle and the journal needs syncing (see needs_sync/1). +sync(State = #qistate { journal_handle = undefined }) -> + State; +sync(State = #qistate { journal_handle = JournalHdl }) -> + ok = file_handle_cache:sync(JournalHdl), + notify_sync(State). + +needs_sync(#qistate { journal_handle = undefined }) -> + false; +needs_sync(#qistate { journal_handle = JournalHdl }) -> + file_handle_cache:needs_sync(JournalHdl). flush(State = #qistate { dirty_count = 0 }) -> State; flush(State) -> flush_journal(State). @@ -379,7 +386,10 @@ %%---------------------------------------------------------------------------- blank_state(QueueName) -> - Dir = filename:join(queues_dir(), queue_name_to_dir_name(QueueName)), + blank_state_dir( + filename:join(queues_dir(), queue_name_to_dir_name(QueueName))). + +blank_state_dir(Dir) -> {ok, MaxJournal} = application:get_env(rabbit, queue_index_max_journal_entries), #qistate { dir = Dir, @@ -491,7 +501,7 @@ queue_name_to_dir_name(Name = #resource { kind = queue }) -> <> = erlang:md5(term_to_binary(Name)), - lists:flatten(io_lib:format("~.36B", [Num])). + rabbit_misc:format("~.36B", [Num]). queues_dir() -> filename:join(rabbit_mnesia:dir(), "queues"). @@ -524,19 +534,34 @@ end. queue_index_walker_reader(QueueName, Gatherer) -> - State = #qistate { segments = Segments, dir = Dir } = - recover_journal(blank_state(QueueName)), - [ok = segment_entries_foldr( - fun (_RelSeq, {{MsgId, _MsgProps, true}, _IsDelivered, no_ack}, - ok) -> - gatherer:in(Gatherer, {MsgId, 1}); - (_RelSeq, _Value, Acc) -> - Acc - end, ok, segment_find_or_new(Seg, Dir, Segments)) || - Seg <- all_segment_nums(State)], - {_SegmentCounts, _State} = terminate(State), + State = blank_state(QueueName), + ok = scan_segments( + fun (_SeqId, MsgId, _MsgProps, true, _IsDelivered, no_ack, ok) -> + gatherer:in(Gatherer, {MsgId, 1}); + (_SeqId, _MsgId, _MsgProps, _IsPersistent, _IsDelivered, + _IsAcked, Acc) -> + Acc + end, ok, State), ok = gatherer:finish(Gatherer). +scan(Dir, Fun, Acc) -> + scan_segments(Fun, Acc, blank_state_dir(Dir)). + +scan_segments(Fun, Acc, State) -> + State1 = #qistate { segments = Segments, dir = Dir } = + recover_journal(State), + Result = lists:foldr( + fun (Seg, AccN) -> + segment_entries_foldr( + fun (RelSeq, {{MsgId, MsgProps, IsPersistent}, + IsDelivered, IsAcked}, AccM) -> + Fun(reconstruct_seq_id(Seg, RelSeq), MsgId, MsgProps, + IsPersistent, IsDelivered, IsAcked, AccM) + end, AccN, segment_find_or_new(Seg, Dir, Segments)) + end, Acc, all_segment_nums(State1)), + {_SegmentCounts, _State} = terminate(State1), + Result. + %%---------------------------------------------------------------------------- %% expiry/binary manipulation %%---------------------------------------------------------------------------- @@ -707,14 +732,6 @@ add_to_journal(SeqId, Kind, StateN) end, State1, SeqIds)). -sync_if(false, State) -> - State; -sync_if(_Bool, State = #qistate { journal_handle = undefined }) -> - State; -sync_if(true, State = #qistate { journal_handle = JournalHdl }) -> - ok = file_handle_cache:sync(JournalHdl), - notify_sync(State). - notify_sync(State = #qistate { unsynced_msg_ids = UG, on_sync = OnSyncFun }) -> OnSyncFun(UG), State #qistate { unsynced_msg_ids = gb_sets:new() }. diff -Nru rabbitmq-server-2.7.1/src/rabbit_reader.erl rabbitmq-server-2.8.4/src/rabbit_reader.erl --- rabbitmq-server-2.7.1/src/rabbit_reader.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_reader.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_reader). @@ -25,13 +25,11 @@ -export([init/4, mainloop/2]). --export([conserve_memory/2, server_properties/1]). - --export([process_channel_frame/5]). %% used by erlang-client +-export([conserve_resources/3, server_properties/1]). -define(HANDSHAKE_TIMEOUT, 10). -define(NORMAL_TIMEOUT, 3). --define(CLOSING_TIMEOUT, 1). +-define(CLOSING_TIMEOUT, 30). -define(CHANNEL_TERMINATION_TIMEOUT, 3). -define(SILENT_CLOSE_DELAY, 3). @@ -40,13 +38,15 @@ -record(v1, {parent, sock, connection, callback, recv_len, pending_recv, connection_state, queue_collector, heartbeater, stats_timer, channel_sup_sup_pid, start_heartbeat_fun, buf, buf_len, - auth_mechanism, auth_state}). + auth_mechanism, auth_state, conserve_resources, + last_blocked_by, last_blocked_at}). -define(STATISTICS_KEYS, [pid, recv_oct, recv_cnt, send_oct, send_cnt, - send_pend, state, channels]). + send_pend, state, last_blocked_by, last_blocked_age, + channels]). --define(CREATION_EVENT_KEYS, [pid, address, port, peer_address, peer_port, ssl, - peer_cert_subject, peer_cert_issuer, +-define(CREATION_EVENT_KEYS, [pid, name, address, port, peer_address, peer_port, + ssl, peer_cert_subject, peer_cert_issuer, peer_cert_validity, auth_mechanism, ssl_protocol, ssl_key_exchange, ssl_cipher, ssl_hash, @@ -71,7 +71,7 @@ -spec(info/2 :: (pid(), rabbit_types:info_keys()) -> rabbit_types:infos()). -spec(force_event_refresh/1 :: (pid()) -> 'ok'). -spec(shutdown/2 :: (pid(), string()) -> 'ok'). --spec(conserve_memory/2 :: (pid(), boolean()) -> 'ok'). +-spec(conserve_resources/3 :: (pid(), atom(), boolean()) -> 'ok'). -spec(server_properties/1 :: (rabbit_types:protocol()) -> rabbit_framing:amqp_table()). @@ -90,10 +90,6 @@ -spec(system_continue/3 :: (_,_,#v1{}) -> any()). -spec(system_terminate/4 :: (_,_,_,_) -> none()). --spec(process_channel_frame/5 :: - (rabbit_command_assembler:frame(), pid(), non_neg_integer(), pid(), - tuple()) -> tuple()). - -endif. %%-------------------------------------------------------------------------- @@ -137,8 +133,8 @@ force_event_refresh(Pid) -> gen_server:cast(Pid, force_event_refresh). -conserve_memory(Pid, Conserve) -> - Pid ! {conserve_memory, Conserve}, +conserve_resources(Pid, _Source, Conserve) -> + Pid ! {conserve_resources, Conserve}, ok. server_properties(Protocol) -> @@ -177,25 +173,26 @@ server_capabilities(_) -> []. +log(Level, Fmt, Args) -> rabbit_log:log(connection, Level, Fmt, Args). + inet_op(F) -> rabbit_misc:throw_on_error(inet_error, F). socket_op(Sock, Fun) -> case Fun(Sock) of {ok, Res} -> Res; - {error, Reason} -> rabbit_log:error("error on TCP connection ~p:~p~n", - [self(), Reason]), - rabbit_log:info("closing TCP connection ~p~n", - [self()]), + {error, Reason} -> log(error, "error on AMQP connection ~p: ~p~n", + [self(), Reason]), exit(normal) end. +name(Sock) -> + socket_op(Sock, fun (S) -> rabbit_net:connection_string(S, inbound) end). + start_connection(Parent, ChannelSupSupPid, Collector, StartHeartbeatFun, Deb, Sock, SockTransform) -> process_flag(trap_exit, true), - {PeerAddress, PeerPort} = socket_op(Sock, fun rabbit_net:peername/1), - PeerAddressS = rabbit_misc:ntoab(PeerAddress), - rabbit_log:info("starting TCP connection ~p from ~s:~p~n", - [self(), PeerAddressS, PeerPort]), + ConnStr = name(Sock), + log(info, "accepting AMQP connection ~p (~s)~n", [self(), ConnStr]), ClientSock = socket_op(Sock, SockTransform), erlang:send_after(?HANDSHAKE_TIMEOUT * 1000, self(), handshake_timeout), @@ -220,27 +217,39 @@ buf = [], buf_len = 0, auth_mechanism = none, - auth_state = none}, + auth_state = none, + conserve_resources = false, + last_blocked_by = none, + last_blocked_at = never}, try + BufSizes = inet_op(fun () -> + rabbit_net:getopts( + ClientSock, [sndbuf, recbuf, buffer]) + end), + BufSz = lists:max([Sz || {_Opt, Sz} <- BufSizes]), + ok = inet_op(fun () -> + rabbit_net:setopts(ClientSock, [{buffer, BufSz}]) + end), recvloop(Deb, switch_callback(rabbit_event:init_stats_timer( State, #v1.stats_timer), - handshake, 8)) + handshake, 8)), + log(info, "closing AMQP connection ~p (~s)~n", [self(), ConnStr]) catch - Ex -> (if Ex == connection_closed_abruptly -> - fun rabbit_log:warning/2; - true -> - fun rabbit_log:error/2 - end)("exception on TCP connection ~p from ~s:~p~n~p~n", - [self(), PeerAddressS, PeerPort, Ex]) + Ex -> log(case Ex of + connection_closed_abruptly -> warning; + _ -> error + end, "closing AMQP connection ~p (~s):~n~p~n", + [self(), ConnStr, Ex]) after - rabbit_log:info("closing TCP connection ~p from ~s:~p~n", - [self(), PeerAddressS, PeerPort]), - %% We don't close the socket explicitly. The reader is the - %% controlling process and hence its termination will close - %% the socket. Furthermore, gen_tcp:close/1 waits for pending - %% output to be sent, which results in unnecessary delays. + %% The reader is the controlling process and hence its + %% termination will close the socket. Furthermore, + %% gen_tcp:close/1 waits for pending output to be sent, which + %% results in unnecessary delays. However, to keep the + %% file_handle_cache accounting as accurate as possible it + %% would be good to close the socket immediately if we + %% can. But we can only do this for non-ssl sockets. %% - %% gen_tcp:close(ClientSock), + rabbit_net:maybe_fast_close(ClientSock), rabbit_event:notify(connection_closed, [{pid, self()}]) end, done. @@ -267,21 +276,20 @@ {data, Data} -> recvloop(Deb, State#v1{buf = [Data | Buf], buf_len = BufLen + size(Data), pending_recv = false}); - closed -> if State#v1.connection_state =:= closed -> - State; - true -> - throw(connection_closed_abruptly) + closed -> case State#v1.connection_state of + closed -> State; + _ -> throw(connection_closed_abruptly) end; {error, Reason} -> throw({inet_error, Reason}); {other, Other} -> handle_other(Other, Deb, State) end. -handle_other({conserve_memory, Conserve}, Deb, State) -> - recvloop(Deb, internal_conserve_memory(Conserve, State)); +handle_other({conserve_resources, Conserve}, Deb, State) -> + recvloop(Deb, control_throttle(State#v1{conserve_resources = Conserve})); handle_other({channel_closing, ChPid}, Deb, State) -> ok = rabbit_channel:ready_for_close(ChPid), channel_cleanup(ChPid), - mainloop(Deb, maybe_close(State)); + mainloop(Deb, maybe_close(control_throttle(State))); handle_other({'EXIT', Parent, Reason}, _Deb, State = #v1{parent = Parent}) -> terminate(io_lib:format("broker forced connection closure " "with reason '~w'", [Reason]), State), @@ -341,14 +349,13 @@ mainloop(Deb, emit_stats(State)); handle_other({system, From, Request}, Deb, State = #v1{parent = Parent}) -> sys:handle_system_msg(Request, From, Parent, ?MODULE, Deb, State); +handle_other({bump_credit, Msg}, Deb, State) -> + credit_flow:handle_bump_msg(Msg), + recvloop(Deb, control_throttle(State)); handle_other(Other, _Deb, _State) -> %% internal error -> something worth dying for exit({unexpected_message, Other}). -switch_callback(State = #v1{connection_state = blocked, - heartbeater = Heartbeater}, Callback, Length) -> - ok = rabbit_heartbeat:pause_monitor(Heartbeater), - State#v1{callback = Callback, recv_len = Length}; switch_callback(State, Callback, Length) -> State#v1{callback = Callback, recv_len = Length}. @@ -359,17 +366,30 @@ terminate(_Explanation, State) -> {force, State}. -internal_conserve_memory(true, State = #v1{connection_state = running}) -> - State#v1{connection_state = blocking}; -internal_conserve_memory(false, State = #v1{connection_state = blocking}) -> - State#v1{connection_state = running}; -internal_conserve_memory(false, State = #v1{connection_state = blocked, - heartbeater = Heartbeater}) -> - ok = rabbit_heartbeat:resume_monitor(Heartbeater), - State#v1{connection_state = running}; -internal_conserve_memory(_Conserve, State) -> +control_throttle(State = #v1{connection_state = CS, + conserve_resources = Mem}) -> + case {CS, Mem orelse credit_flow:blocked()} of + {running, true} -> State#v1{connection_state = blocking}; + {blocking, false} -> State#v1{connection_state = running}; + {blocked, false} -> ok = rabbit_heartbeat:resume_monitor( + State#v1.heartbeater), + State#v1{connection_state = running}; + {blocked, true} -> update_last_blocked_by(State); + {_, _} -> State + end. + +maybe_block(State = #v1{connection_state = blocking}) -> + ok = rabbit_heartbeat:pause_monitor(State#v1.heartbeater), + update_last_blocked_by(State#v1{connection_state = blocked, + last_blocked_at = erlang:now()}); +maybe_block(State) -> State. +update_last_blocked_by(State = #v1{conserve_resources = true}) -> + State#v1{last_blocked_by = resource}; +update_last_blocked_by(State = #v1{conserve_resources = false}) -> + State#v1{last_blocked_by = flow}. + close_connection(State = #v1{queue_collector = Collector, connection = #connection{ timeout_sec = TimeoutSec}}) -> @@ -380,34 +400,30 @@ rabbit_queue_collector:delete_all(Collector), %% We terminate the connection after the specified interval, but %% no later than ?CLOSING_TIMEOUT seconds. - TimeoutMillisec = - 1000 * if TimeoutSec > 0 andalso - TimeoutSec < ?CLOSING_TIMEOUT -> TimeoutSec; - true -> ?CLOSING_TIMEOUT - end, - erlang:send_after(TimeoutMillisec, self(), terminate_connection), + erlang:send_after((if TimeoutSec > 0 andalso + TimeoutSec < ?CLOSING_TIMEOUT -> TimeoutSec; + true -> ?CLOSING_TIMEOUT + end) * 1000, self(), terminate_connection), State#v1{connection_state = closed}. handle_dependent_exit(ChPid, Reason, State) -> - case termination_kind(Reason) of - controlled -> - channel_cleanup(ChPid), - maybe_close(State); - uncontrolled -> - case channel_cleanup(ChPid) of - undefined -> exit({abnormal_dependent_exit, ChPid, Reason}); - Channel -> rabbit_log:error( - "connection ~p, channel ~p - error:~n~p~n", - [self(), Channel, Reason]), - maybe_close( - handle_exception(State, Channel, Reason)) - end + case {channel_cleanup(ChPid), termination_kind(Reason)} of + {undefined, uncontrolled} -> + exit({abnormal_dependent_exit, ChPid, Reason}); + {_Channel, controlled} -> + maybe_close(control_throttle(State)); + {Channel, uncontrolled} -> + log(error, "AMQP connection ~p, channel ~p - error:~n~p~n", + [self(), Channel, Reason]), + maybe_close(handle_exception(control_throttle(State), + Channel, Reason)) end. channel_cleanup(ChPid) -> case get({ch_pid, ChPid}) of undefined -> undefined; - {Channel, MRef} -> erase({channel, Channel}), + {Channel, MRef} -> credit_flow:peer_down(ChPid), + erase({channel, Channel}), erase({ch_pid, ChPid}), erlang:demonitor(MRef, [flush]), Channel @@ -436,19 +452,16 @@ wait_for_channel_termination(N, TimerRef) -> receive {'DOWN', _MRef, process, ChPid, Reason} -> - case channel_cleanup(ChPid) of - undefined -> + case {channel_cleanup(ChPid), termination_kind(Reason)} of + {undefined, _} -> exit({abnormal_dependent_exit, ChPid, Reason}); - Channel -> - case termination_kind(Reason) of - controlled -> - ok; - uncontrolled -> - rabbit_log:error( - "connection ~p, channel ~p - " - "error while terminating:~n~p~n", - [self(), Channel, Reason]) - end, + {_Channel, controlled} -> + wait_for_channel_termination(N-1, TimerRef); + {Channel, uncontrolled} -> + log(error, + "AMQP connection ~p, channel ~p - " + "error while terminating:~n~p~n", + [self(), Channel, Reason]), wait_for_channel_termination(N-1, TimerRef) end; cancel_wait -> @@ -497,41 +510,38 @@ case rabbit_command_assembler:analyze_frame(Type, Payload, Protocol) of error -> throw({unknown_frame, Channel, Type, Payload}); heartbeat -> throw({unexpected_heartbeat_frame, Channel}); - AnalyzedFrame -> - case get({channel, Channel}) of - {ChPid, FramingState} -> - NewAState = process_channel_frame( - AnalyzedFrame, self(), - Channel, ChPid, FramingState), - put({channel, Channel}, {ChPid, NewAState}), - post_process_frame(AnalyzedFrame, ChPid, State); - undefined -> - case ?IS_RUNNING(State) of - true -> send_to_new_channel( - Channel, AnalyzedFrame, State); - false -> throw({channel_frame_while_starting, - Channel, State#v1.connection_state, - AnalyzedFrame}) - end - end + AnalyzedFrame -> process_frame(AnalyzedFrame, Channel, State) + end. + +process_frame(Frame, Channel, State) -> + case get({channel, Channel}) of + {ChPid, AState} -> + case process_channel_frame(Frame, ChPid, AState) of + {ok, NewAState} -> put({channel, Channel}, {ChPid, NewAState}), + post_process_frame(Frame, ChPid, State); + {error, Reason} -> handle_exception(State, Channel, Reason) + end; + undefined when ?IS_RUNNING(State) -> + ok = create_channel(Channel, State), + process_frame(Frame, Channel, State); + undefined -> + throw({channel_frame_while_starting, + Channel, State#v1.connection_state, Frame}) end. post_process_frame({method, 'channel.close_ok', _}, ChPid, State) -> channel_cleanup(ChPid), - State; + control_throttle(State); post_process_frame({method, MethodName, _}, _ChPid, State = #v1{connection = #connection{ protocol = Protocol}}) -> case Protocol:method_has_content(MethodName) of true -> erlang:bump_reductions(2000), - case State#v1.connection_state of - blocking -> State#v1{connection_state = blocked}; - _ -> State - end; - false -> State + maybe_block(control_throttle(State)); + false -> control_throttle(State) end; post_process_frame(_Frame, _ChPid, State) -> - State. + control_throttle(State). handle_input(frame_header, <>, State) -> ensure_stats_timer( @@ -699,10 +709,11 @@ ok = rabbit_access_control:check_vhost_access(User, VHostPath), NewConnection = Connection#connection{vhost = VHostPath}, ok = send_on_channel0(Sock, #'connection.open_ok'{}, Protocol), - State1 = internal_conserve_memory( - rabbit_alarm:register(self(), {?MODULE, conserve_memory, []}), - State#v1{connection_state = running, - connection = NewConnection}), + Conserve = rabbit_alarm:register(self(), {?MODULE, conserve_resources, []}), + State1 = control_throttle( + State#v1{connection_state = running, + connection = NewConnection, + conserve_resources = Conserve}), rabbit_event:notify(connection_created, [{type, network} | infos(?CREATION_EVENT_KEYS, State1)]), @@ -801,6 +812,8 @@ i(pid, #v1{}) -> self(); +i(name, #v1{sock = Sock}) -> + list_to_binary(name(Sock)); i(address, #v1{sock = Sock}) -> socket_info(fun rabbit_net:sockname/1, fun ({A, _}) -> A end, Sock); i(port, #v1{sock = Sock}) -> @@ -834,6 +847,12 @@ fun ([{_, I}]) -> I end); i(state, #v1{connection_state = S}) -> S; +i(last_blocked_by, #v1{last_blocked_by = By}) -> + By; +i(last_blocked_age, #v1{last_blocked_at = never}) -> + infinity; +i(last_blocked_age, #v1{last_blocked_at = T}) -> + timer:now_diff(erlang:now(), T) / 1000000; i(channels, #v1{}) -> length(all_channels()); i(protocol, #v1{connection = #connection{protocol = none}}) -> @@ -889,7 +908,7 @@ %%-------------------------------------------------------------------------- -send_to_new_channel(Channel, AnalyzedFrame, State) -> +create_channel(Channel, State) -> #v1{sock = Sock, queue_collector = Collector, channel_sup_sup_pid = ChanSupSup, connection = #connection{protocol = Protocol, @@ -899,26 +918,22 @@ capabilities = Capabilities}} = State, {ok, _ChSupPid, {ChPid, AState}} = rabbit_channel_sup_sup:start_channel( - ChanSupSup, {tcp, Sock, Channel, FrameMax, self(), Protocol, User, - VHost, Capabilities, Collector}), + ChanSupSup, {tcp, Sock, Channel, FrameMax, self(), name(Sock), + Protocol, User, VHost, Capabilities, Collector}), MRef = erlang:monitor(process, ChPid), - NewAState = process_channel_frame(AnalyzedFrame, self(), - Channel, ChPid, AState), - put({channel, Channel}, {ChPid, NewAState}), put({ch_pid, ChPid}, {Channel, MRef}), - State. + put({channel, Channel}, {ChPid, AState}), + ok. -process_channel_frame(Frame, ErrPid, Channel, ChPid, AState) -> +process_channel_frame(Frame, ChPid, AState) -> case rabbit_command_assembler:process(Frame, AState) of - {ok, NewAState} -> NewAState; + {ok, NewAState} -> {ok, NewAState}; {ok, Method, NewAState} -> rabbit_channel:do(ChPid, Method), - NewAState; - {ok, Method, Content, NewAState} -> rabbit_channel:do(ChPid, - Method, Content), - NewAState; - {error, Reason} -> ErrPid ! {channel_exit, Channel, - Reason}, - AState + {ok, NewAState}; + {ok, Method, Content, NewAState} -> rabbit_channel:do_flow( + ChPid, Method, Content), + {ok, NewAState}; + {error, Reason} -> {error, Reason} end. handle_exception(State = #v1{connection_state = closed}, _Channel, _Reason) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_registry.erl rabbitmq-server-2.8.4/src/rabbit_registry.erl --- rabbitmq-server-2.7.1/src/rabbit_registry.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_registry.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_registry). diff -Nru rabbitmq-server-2.7.1/src/rabbit_restartable_sup.erl rabbitmq-server-2.8.4/src/rabbit_restartable_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_restartable_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_restartable_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_restartable_sup). @@ -28,7 +28,8 @@ -ifdef(use_specs). --spec(start_link/2 :: (atom(), mfa()) -> rabbit_types:ok_pid_or_error()). +-spec(start_link/2 :: (atom(), rabbit_types:mfargs()) -> + rabbit_types:ok_pid_or_error()). -endif. diff -Nru rabbitmq-server-2.7.1/src/rabbit_router.erl rabbitmq-server-2.8.4/src/rabbit_router.erl --- rabbitmq-server-2.7.1/src/rabbit_router.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_router.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,28 +11,24 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_router). -include_lib("stdlib/include/qlc.hrl"). -include("rabbit.hrl"). --export([deliver/2, match_bindings/2, match_routing_key/2]). +-export([match_bindings/2, match_routing_key/2]). %%---------------------------------------------------------------------------- -ifdef(use_specs). --export_type([routing_key/0, routing_result/0, match_result/0]). +-export_type([routing_key/0, match_result/0]). -type(routing_key() :: binary()). --type(routing_result() :: 'routed' | 'unroutable' | 'not_delivered'). --type(qpids() :: [pid()]). -type(match_result() :: [rabbit_types:binding_destination()]). --spec(deliver/2 :: ([rabbit_amqqueue:name()], rabbit_types:delivery()) -> - {routing_result(), qpids()}). -spec(match_bindings/2 :: (rabbit_types:binding_source(), fun ((rabbit_types:binding()) -> boolean())) -> match_result()). @@ -44,38 +40,6 @@ %%---------------------------------------------------------------------------- -deliver([], #delivery{mandatory = false, - immediate = false}) -> - %% /dev/null optimisation - {routed, []}; - -deliver(QNames, Delivery = #delivery{mandatory = false, - immediate = false}) -> - %% optimisation: when Mandatory = false and Immediate = false, - %% rabbit_amqqueue:deliver will deliver the message to the queue - %% process asynchronously, and return true, which means all the - %% QPids will always be returned. It is therefore safe to use a - %% fire-and-forget cast here and return the QPids - the semantics - %% is preserved. This scales much better than the non-immediate - %% case below. - QPids = lookup_qpids(QNames), - delegate:invoke_no_result( - QPids, fun (Pid) -> rabbit_amqqueue:deliver(Pid, Delivery) end), - {routed, QPids}; - -deliver(QNames, Delivery = #delivery{mandatory = Mandatory, - immediate = Immediate}) -> - QPids = lookup_qpids(QNames), - {Success, _} = - delegate:invoke(QPids, - fun (Pid) -> - rabbit_amqqueue:deliver(Pid, Delivery) - end), - {Routed, Handled} = - lists:foldl(fun fold_deliveries/2, {false, []}, Success), - check_delivery(Mandatory, Immediate, {Routed, Handled}). - - %% TODO: Maybe this should be handled by a cursor instead. %% TODO: This causes a full scan for each entry with the same source match_bindings(SrcName, Match) -> @@ -104,26 +68,6 @@ %%-------------------------------------------------------------------- -fold_deliveries({Pid, true},{_, Handled}) -> {true, [Pid|Handled]}; -fold_deliveries({_, false},{_, Handled}) -> {true, Handled}. - -%% check_delivery(Mandatory, Immediate, {WasRouted, QPids}) -check_delivery(true, _ , {false, []}) -> {unroutable, []}; -check_delivery(_ , true, {_ , []}) -> {not_delivered, []}; -check_delivery(_ , _ , {_ , Qs}) -> {routed, Qs}. - -%% Normally we'd call mnesia:dirty_read/1 here, but that is quite -%% expensive for the reasons explained in rabbit_misc:dirty_read/1. -lookup_qpids(QNames) -> - lists:foldl(fun (QName, QPids) -> - case ets:lookup(rabbit_queue, QName) of - [#amqqueue{pid = QPid, slave_pids = SPids}] -> - [QPid | SPids ++ QPids]; - [] -> - QPids - end - end, [], QNames). - %% Normally we'd call mnesia:dirty_select/2 here, but that is quite %% expensive for the same reasons as above, and, additionally, due to %% mnesia 'fixing' the table with ets:safe_fixtable/2, which is wholly diff -Nru rabbitmq-server-2.7.1/src/rabbit_sasl_report_file_h.erl rabbitmq-server-2.8.4/src/rabbit_sasl_report_file_h.erl --- rabbitmq-server-2.7.1/src/rabbit_sasl_report_file_h.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_sasl_report_file_h.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_sasl_report_file_h). diff -Nru rabbitmq-server-2.7.1/src/rabbit_ssl.erl rabbitmq-server-2.8.4/src/rabbit_ssl.erl --- rabbitmq-server-2.7.1/src/rabbit_ssl.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_ssl.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_ssl). @@ -21,7 +21,7 @@ -include_lib("public_key/include/public_key.hrl"). -export([peer_cert_issuer/1, peer_cert_subject/1, peer_cert_validity/1]). --export([peer_cert_subject_item/2]). +-export([peer_cert_subject_items/2, peer_cert_auth_name/1]). %%-------------------------------------------------------------------------- @@ -34,8 +34,10 @@ -spec(peer_cert_issuer/1 :: (certificate()) -> string()). -spec(peer_cert_subject/1 :: (certificate()) -> string()). -spec(peer_cert_validity/1 :: (certificate()) -> string()). --spec(peer_cert_subject_item/2 :: - (certificate(), tuple()) -> string() | 'not_found'). +-spec(peer_cert_subject_items/2 :: + (certificate(), tuple()) -> [string()] | 'not_found'). +-spec(peer_cert_auth_name/1 :: + (certificate()) -> binary() | 'not_found' | 'unsafe'). -endif. @@ -59,8 +61,8 @@ format_rdn_sequence(Subject) end, Cert). -%% Return a part of the certificate's subject. -peer_cert_subject_item(Cert, Type) -> +%% Return the parts of the certificate's subject. +peer_cert_subject_items(Cert, Type) -> cert_info(fun(#'OTPCertificate' { tbsCertificate = #'OTPTBSCertificate' { subject = Subject }}) -> @@ -72,11 +74,47 @@ cert_info(fun(#'OTPCertificate' { tbsCertificate = #'OTPTBSCertificate' { validity = {'Validity', Start, End} }}) -> - lists:flatten( - io_lib:format("~s - ~s", [format_asn1_value(Start), - format_asn1_value(End)])) + rabbit_misc:format("~s - ~s", [format_asn1_value(Start), + format_asn1_value(End)]) end, Cert). +%% Extract a username from the certificate +peer_cert_auth_name(Cert) -> + {ok, Mode} = application:get_env(rabbit, ssl_cert_login_from), + peer_cert_auth_name(Mode, Cert). + +peer_cert_auth_name(distinguished_name, Cert) -> + case auth_config_sane() of + true -> iolist_to_binary(peer_cert_subject(Cert)); + false -> unsafe + end; + +peer_cert_auth_name(common_name, Cert) -> + %% If there is more than one CN then we join them with "," in a + %% vaguely DN-like way. But this is more just so we do something + %% more intelligent than crashing, if you actually want to escape + %% things properly etc, use DN mode. + case auth_config_sane() of + true -> case peer_cert_subject_items(Cert, ?'id-at-commonName') of + not_found -> not_found; + CNs -> list_to_binary(string:join(CNs, ",")) + end; + false -> unsafe + end. + +auth_config_sane() -> + {ok, Opts} = application:get_env(rabbit, ssl_options), + case {proplists:get_value(fail_if_no_peer_cert, Opts), + proplists:get_value(verify, Opts)} of + {true, verify_peer} -> + true; + {F, V} -> + rabbit_log:warning("SSL certificate authentication disabled, " + "fail_if_no_peer_cert=~p; " + "verify=~p~n", [F, V]), + false + end. + %%-------------------------------------------------------------------------- cert_info(F, Cert) -> @@ -89,8 +127,8 @@ case [V || #'AttributeTypeAndValue'{type = T, value = V} <- lists:flatten(RDNs), T == Type] of - [Val] -> format_asn1_value(Val); - [] -> not_found + [] -> not_found; + L -> [format_asn1_value(V) || V <- L] end. %%-------------------------------------------------------------------------- @@ -150,11 +188,12 @@ escape_rdn_value([C | S], middle) when C =:= $"; C =:= $+; C =:= $,; C =:= $;; C =:= $<; C =:= $>; C =:= $\\ -> [$\\, C | escape_rdn_value(S, middle)]; -escape_rdn_value([C | S], middle) when C < 32 ; C =:= 127 -> - %% only U+0000 needs escaping, but for display purposes it's handy - %% to escape all non-printable chars - lists:flatten(io_lib:format("\\~2.16.0B", [C])) ++ - escape_rdn_value(S, middle); +escape_rdn_value([C | S], middle) when C < 32 ; C >= 126 -> + %% Of ASCII characters only U+0000 needs escaping, but for display + %% purposes it's handy to escape all non-printable chars. All non-ASCII + %% characters get converted to UTF-8 sequences and then escaped. We've + %% already got a UTF-8 sequence here, so just escape it. + rabbit_misc:format("\\~2.16.0B", [C]) ++ escape_rdn_value(S, middle); escape_rdn_value([C | S], middle) -> [C | escape_rdn_value(S, middle)]. @@ -167,6 +206,10 @@ Min1, Min2, S1, S2, $Z]}) -> io_lib:format("20~c~c-~c~c-~c~cT~c~c:~c~c:~c~cZ", [Y1, Y2, M1, M2, D1, D2, H1, H2, Min1, Min2, S1, S2]); +%% We appear to get an untagged value back for an ia5string +%% (e.g. domainComponent). +format_asn1_value(V) when is_list(V) -> + V; format_asn1_value(V) -> io_lib:format("~p", [V]). diff -Nru rabbitmq-server-2.7.1/src/rabbit_sup.erl rabbitmq-server-2.8.4/src/rabbit_sup.erl --- rabbitmq-server-2.7.1/src/rabbit_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_sup). @@ -52,22 +52,20 @@ start_child(Mod, Mod, Args). start_child(ChildId, Mod, Args) -> - {ok, _} = supervisor:start_child(?SERVER, - {ChildId, {Mod, start_link, Args}, - transient, ?MAX_WAIT, worker, [Mod]}), - ok. + child_reply(supervisor:start_child(?SERVER, + {ChildId, {Mod, start_link, Args}, + transient, ?MAX_WAIT, worker, [Mod]})). start_restartable_child(Mod) -> start_restartable_child(Mod, []). start_restartable_child(Mod, Args) -> Name = list_to_atom(atom_to_list(Mod) ++ "_sup"), - {ok, _} = supervisor:start_child( - ?SERVER, - {Name, {rabbit_restartable_sup, start_link, - [Name, {Mod, start_link, Args}]}, - transient, infinity, supervisor, [rabbit_restartable_sup]}), - ok. + child_reply(supervisor:start_child( + ?SERVER, + {Name, {rabbit_restartable_sup, start_link, + [Name, {Mod, start_link, Args}]}, + transient, infinity, supervisor, [rabbit_restartable_sup]})). stop_child(ChildId) -> case supervisor:terminate_child(?SERVER, ChildId) of @@ -77,3 +75,9 @@ init([]) -> {ok, {{one_for_all, 0, 1}, []}}. + + +%%---------------------------------------------------------------------------- + +child_reply({ok, _}) -> ok; +child_reply(X) -> X. diff -Nru rabbitmq-server-2.7.1/src/rabbit_tests.erl rabbitmq-server-2.8.4/src/rabbit_tests.erl --- rabbitmq-server-2.7.1/src/rabbit_tests.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_tests.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tests). @@ -35,6 +35,7 @@ passed = mirrored_supervisor_tests:all_tests(), application:set_env(rabbit, file_handles_high_watermark, 10, infinity), ok = file_handle_cache:set_limit(10), + passed = test_multi_call(), passed = test_file_handle_cache(), passed = test_backing_queue(), passed = test_priority_queue(), @@ -59,7 +60,7 @@ passed. maybe_run_cluster_dependent_tests() -> - SecondaryNode = rabbit_misc:makenode("hare"), + SecondaryNode = rabbit_nodes:make("hare"), case net_adm:ping(SecondaryNode) of pong -> passed = run_cluster_dependent_tests(SecondaryNode); @@ -71,10 +72,13 @@ run_cluster_dependent_tests(SecondaryNode) -> SecondaryNodeS = atom_to_list(SecondaryNode), + cover:stop(SecondaryNode), ok = control_action(stop_app, []), ok = control_action(reset, []), ok = control_action(cluster, [SecondaryNodeS]), ok = control_action(start_app, []), + cover:start(SecondaryNode), + ok = control_action(start_app, SecondaryNode, [], []), io:format("Running cluster dependent tests with node ~p~n", [SecondaryNode]), passed = test_delegates_async(SecondaryNode), @@ -104,6 +108,26 @@ passed. +test_multi_call() -> + Fun = fun() -> + receive + {'$gen_call', {From, Mref}, request} -> + From ! {Mref, response} + end, + receive + never -> ok + end + end, + Pid1 = spawn(Fun), + Pid2 = spawn(Fun), + Pid3 = spawn(Fun), + exit(Pid2, bang), + {[{Pid1, response}, {Pid3, response}], [{Pid2, _Fail}]} = + rabbit_misc:multi_call([Pid1, Pid2, Pid3], request), + exit(Pid1, bang), + exit(Pid3, bang), + passed. + test_priority_queue() -> false = priority_queue:is_queue(not_a_queue), @@ -859,7 +883,9 @@ "invalid2@invalid"]), ok = assert_ram_node(), - SecondaryNode = rabbit_misc:makenode("hare"), + ok = control_action(reset, []), + + SecondaryNode = rabbit_nodes:make("hare"), case net_adm:ping(SecondaryNode) of pong -> passed = test_cluster_management2(SecondaryNode); pang -> io:format("Skipping clustering tests with node ~p~n", @@ -874,7 +900,6 @@ SecondaryNodeS = atom_to_list(SecondaryNode), %% make a disk node - ok = control_action(reset, []), ok = control_action(cluster, [NodeS]), ok = assert_disc_node(), %% make a ram node @@ -889,6 +914,14 @@ ok = control_action(stop_app, []), ok = assert_ram_node(), + %% ram node will not start by itself + ok = control_action(stop_app, []), + ok = control_action(stop_app, SecondaryNode, [], []), + {error, _} = control_action(start_app, []), + ok = control_action(start_app, SecondaryNode, [], []), + ok = control_action(start_app, []), + ok = control_action(stop_app, []), + %% change cluster config while remaining in same cluster ok = control_action(force_cluster, ["invalid2@invalid", SecondaryNodeS]), ok = control_action(start_app, []), @@ -897,8 +930,7 @@ %% join non-existing cluster as a ram node ok = control_action(force_cluster, ["invalid1@invalid", "invalid2@invalid"]), - ok = control_action(start_app, []), - ok = control_action(stop_app, []), + {error, _} = control_action(start_app, []), ok = assert_ram_node(), %% join empty cluster as a ram node (converts to disc) @@ -953,7 +985,9 @@ ok = control_action(cluster, [SecondaryNodeS, NodeS]), ok = control_action(start_app, []), ok = control_action(stop_app, []), + cover:stop(SecondaryNode), ok = control_action(reset, []), + cover:start(SecondaryNode), %% attempt to leave cluster when no other node is alive ok = control_action(cluster, [SecondaryNodeS, NodeS]), @@ -970,7 +1004,15 @@ %% leave system clustered, with the secondary node as a ram node ok = control_action(force_reset, []), ok = control_action(start_app, []), - ok = control_action(force_reset, SecondaryNode, [], []), + %% Yes, this is rather ugly. But since we're a clustered Mnesia + %% node and we're telling another clustered node to reset itself, + %% we will get disconnected half way through causing a + %% badrpc. This never happens in real life since rabbitmqctl is + %% not a clustered Mnesia node. + cover:stop(SecondaryNode), + {badrpc, nodedown} = control_action(force_reset, SecondaryNode, [], []), + pong = net_adm:ping(SecondaryNode), + cover:start(SecondaryNode), ok = control_action(cluster, SecondaryNode, [NodeS], []), ok = control_action(start_app, SecondaryNode, [], []), @@ -1059,7 +1101,7 @@ %% create a few things so there is some useful information to list Writer = spawn(fun () -> receive shutdown -> ok end end), {ok, Ch} = rabbit_channel:start_link( - 1, self(), Writer, self(), rabbit_framing_amqp_0_9_1, + 1, self(), Writer, self(), "", rabbit_framing_amqp_0_9_1, user(<<"user">>), <<"/">>, [], self(), rabbit_limiter:make_token(self())), [Q, Q2] = [Queue || Name <- [<<"foo">>, <<"bar">>], @@ -1130,7 +1172,7 @@ Me = self(), Writer = spawn(fun () -> test_writer(Me) end), {ok, Ch} = rabbit_channel:start_link( - 1, Me, Writer, Me, rabbit_framing_amqp_0_9_1, + 1, Me, Writer, Me, "", rabbit_framing_amqp_0_9_1, user(<<"guest">>), <<"/">>, [], Me, rabbit_limiter:make_token(self())), ok = rabbit_channel:do(Ch, #'channel.open'{}), @@ -1203,6 +1245,9 @@ }, rabbit_basic:build_content( #'P_basic'{delivery_mode = 2}, <<"">>)), + %% We must not kill the queue before the channel has processed the + %% 'publish'. + ok = rabbit_channel:flush(Ch), %% Crash the queue QPid1 ! boom, %% Wait for a nack @@ -1779,10 +1824,10 @@ restart_msg_store_empty(), MsgIds = [msg_id_bin(M) || M <- lists:seq(1,100)], {MsgIds1stHalf, MsgIds2ndHalf} = lists:split(length(MsgIds) div 2, MsgIds), - Ref = rabbit_guid:guid(), + Ref = rabbit_guid:gen(), {Cap, MSCState} = msg_store_client_init_capture( ?PERSISTENT_MSG_STORE, Ref), - Ref2 = rabbit_guid:guid(), + Ref2 = rabbit_guid:gen(), {Cap2, MSC2State} = msg_store_client_init_capture( ?PERSISTENT_MSG_STORE, Ref2), %% check we don't contain any of the msgs we're about to publish @@ -1934,7 +1979,7 @@ passed. test_msg_store_confirm_timer() -> - Ref = rabbit_guid:guid(), + Ref = rabbit_guid:gen(), MsgId = msg_id_bin(1), Self = self(), MSCState = rabbit_msg_store:client_init( @@ -1963,7 +2008,7 @@ test_msg_store_client_delete_and_terminate() -> restart_msg_store_empty(), MsgIds = [msg_id_bin(M) || M <- lists:seq(1, 10)], - Ref = rabbit_guid:guid(), + Ref = rabbit_guid:gen(), MSCState = msg_store_client_init(?PERSISTENT_MSG_STORE, Ref), ok = msg_store_write(MsgIds, MSCState), %% test the 'dying client' fast path for writes @@ -1979,7 +2024,7 @@ init_test_queue() -> TestQueue = test_queue(), Terms = rabbit_queue_index:shutdown_terms(TestQueue), - PRef = proplists:get_value(persistent_ref, Terms, rabbit_guid:guid()), + PRef = proplists:get_value(persistent_ref, Terms, rabbit_guid:gen()), PersistentClient = msg_store_client_init(?PERSISTENT_MSG_STORE, PRef), Res = rabbit_queue_index:recover( TestQueue, Terms, false, @@ -2013,7 +2058,7 @@ rabbit:start(). queue_index_publish(SeqIds, Persistent, Qi) -> - Ref = rabbit_guid:guid(), + Ref = rabbit_guid:gen(), MsgStore = case Persistent of true -> ?PERSISTENT_MSG_STORE; false -> ?TRANSIENT_MSG_STORE @@ -2022,7 +2067,7 @@ {A, B = [{_SeqId, LastMsgIdWritten} | _]} = lists:foldl( fun (SeqId, {QiN, SeqIdsMsgIdsAcc}) -> - MsgId = rabbit_guid:guid(), + MsgId = rabbit_guid:gen(), QiM = rabbit_queue_index:publish( MsgId, SeqId, #message_properties{}, Persistent, QiN), ok = rabbit_msg_store:write(MsgId, MsgId, MSCState), @@ -2045,7 +2090,7 @@ test_queue_index_props() -> with_empty_test_queue( fun(Qi0) -> - MsgId = rabbit_guid:guid(), + MsgId = rabbit_guid:gen(), Props = #message_properties{expiry=12345}, Qi1 = rabbit_queue_index:publish(MsgId, 1, Props, true, Qi0), {[{MsgId, 1, Props, _, _}], Qi2} = @@ -2222,17 +2267,29 @@ #amqqueue { durable = Durable }. with_fresh_variable_queue(Fun) -> - ok = empty_test_queue(), - VQ = variable_queue_init(test_amqqueue(true), false), - S0 = rabbit_variable_queue:status(VQ), - assert_props(S0, [{q1, 0}, {q2, 0}, - {delta, {delta, undefined, 0, undefined}}, - {q3, 0}, {q4, 0}, - {len, 0}]), - _ = rabbit_variable_queue:delete_and_terminate(shutdown, Fun(VQ)), + Ref = make_ref(), + Me = self(), + %% Run in a separate process since rabbit_msg_store will send + %% bump_credit messages and we want to ignore them + spawn_link(fun() -> + ok = empty_test_queue(), + VQ = variable_queue_init(test_amqqueue(true), false), + S0 = rabbit_variable_queue:status(VQ), + assert_props(S0, [{q1, 0}, {q2, 0}, + {delta, + {delta, undefined, 0, undefined}}, + {q3, 0}, {q4, 0}, + {len, 0}]), + _ = rabbit_variable_queue:delete_and_terminate( + shutdown, Fun(VQ)), + Me ! Ref + end), + receive + Ref -> ok + end, passed. -publish_and_confirm(QPid, Payload, Count) -> +publish_and_confirm(Q, Payload, Count) -> Seqs = lists:seq(1, Count), [begin Msg = rabbit_basic:message(rabbit_misc:r(<<>>, exchange, <<>>), @@ -2240,7 +2297,7 @@ Payload), Delivery = #delivery{mandatory = false, immediate = false, sender = self(), message = Msg, msg_seq_no = Seq}, - true = rabbit_amqqueue:deliver(QPid, Delivery) + {routed, _} = rabbit_amqqueue:deliver([Q], Delivery) end || Seq <- Seqs], wait_for_confirms(gb_sets:from_list(Seqs)). @@ -2249,8 +2306,8 @@ true -> ok; false -> receive {'$gen_cast', {confirm, Confirmed, _}} -> wait_for_confirms( - gb_sets:difference(Unconfirmed, - gb_sets:from_list(Confirmed))) + rabbit_misc:gb_sets_difference( + Unconfirmed, gb_sets:from_list(Confirmed))) after 5000 -> exit(timeout_waiting_for_confirm) end end. @@ -2331,10 +2388,10 @@ fun (N, Props) -> Props#message_properties{expiry = N} end, VQ0), %% drop the first 5 messages - VQ2 = rabbit_variable_queue:dropwhile( - fun(#message_properties { expiry = Expiry }) -> - Expiry =< 5 - end, VQ1), + {undefined, VQ2} = rabbit_variable_queue:dropwhile( + fun(#message_properties { expiry = Expiry }) -> + Expiry =< 5 + end, false, VQ1), %% fetch five now VQ3 = lists:foldl(fun (_N, VQN) -> @@ -2351,10 +2408,13 @@ test_dropwhile_varying_ram_duration(VQ0) -> VQ1 = variable_queue_publish(false, 1, VQ0), VQ2 = rabbit_variable_queue:set_ram_duration_target(0, VQ1), - VQ3 = rabbit_variable_queue:dropwhile(fun(_) -> false end, VQ2), + {undefined, VQ3} = rabbit_variable_queue:dropwhile( + fun(_) -> false end, false, VQ2), VQ4 = rabbit_variable_queue:set_ram_duration_target(infinity, VQ3), VQ5 = variable_queue_publish(false, 1, VQ4), - rabbit_variable_queue:dropwhile(fun(_) -> false end, VQ5). + {undefined, VQ6} = + rabbit_variable_queue:dropwhile(fun(_) -> false end, false, VQ5), + VQ6. test_variable_queue_dynamic_duration_change(VQ0) -> SegmentSize = rabbit_queue_index:next_segment_boundary(0), @@ -2477,7 +2537,7 @@ Count = 2 * rabbit_queue_index:next_segment_boundary(0), {new, #amqqueue { pid = QPid, name = QName } = Q} = rabbit_amqqueue:declare(test_queue(), true, false, [], none), - publish_and_confirm(QPid, <<>>, Count), + publish_and_confirm(Q, <<>>, Count), exit(QPid, kill), MRef = erlang:monitor(process, QPid), @@ -2497,7 +2557,7 @@ {{_Msg1, true, _AckTag1, CountMinusOne}, VQ2} = rabbit_variable_queue:fetch(true, VQ1), _VQ3 = rabbit_variable_queue:delete_and_terminate(shutdown, VQ2), - rabbit_amqqueue:internal_delete(QName) + rabbit_amqqueue:internal_delete(QName, QPid1) end), passed. @@ -2507,7 +2567,7 @@ rabbit_amqqueue:declare(test_queue(), true, false, [], none), Payload = <<0:8388608>>, %% 1MB Count = 30, - publish_and_confirm(QPid, Payload, Count), + publish_and_confirm(Q, Payload, Count), rabbit_amqqueue:set_ram_duration_target(QPid, 0), diff -Nru rabbitmq-server-2.7.1/src/rabbit_tests_event_receiver.erl rabbitmq-server-2.8.4/src/rabbit_tests_event_receiver.erl --- rabbitmq-server-2.7.1/src/rabbit_tests_event_receiver.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_tests_event_receiver.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_tests_event_receiver). diff -Nru rabbitmq-server-2.7.1/src/rabbit_trace.erl rabbitmq-server-2.8.4/src/rabbit_trace.erl --- rabbitmq-server-2.7.1/src/rabbit_trace.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_trace.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_trace). diff -Nru rabbitmq-server-2.7.1/src/rabbit_types.erl rabbitmq-server-2.8.4/src/rabbit_types.erl --- rabbitmq-server-2.7.1/src/rabbit_types.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_types.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_types). @@ -28,12 +28,9 @@ binding/0, binding_source/0, binding_destination/0, amqqueue/0, exchange/0, connection/0, protocol/0, user/0, internal_user/0, - username/0, password/0, password_hash/0, ok/1, error/1, - ok_or_error/1, ok_or_error2/2, ok_pid_or_error/0, channel_exit/0, - connection_exit/0]). - --type(channel_exit() :: no_return()). --type(connection_exit() :: no_return()). + username/0, password/0, password_hash/0, + ok/1, error/1, ok_or_error/1, ok_or_error2/2, ok_pid_or_error/0, + channel_exit/0, connection_exit/0, mfargs/0]). -type(maybe(T) :: T | 'none'). -type(vhost() :: binary()). @@ -156,4 +153,9 @@ -type(ok_or_error2(A, B) :: ok(A) | error(B)). -type(ok_pid_or_error() :: ok_or_error2(pid(), any())). +-type(channel_exit() :: no_return()). +-type(connection_exit() :: no_return()). + +-type(mfargs() :: {atom(), atom(), [any()]}). + -endif. % use_specs diff -Nru rabbitmq-server-2.7.1/src/rabbit_upgrade.erl rabbitmq-server-2.8.4/src/rabbit_upgrade.erl --- rabbitmq-server-2.7.1/src/rabbit_upgrade.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_upgrade.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_upgrade). @@ -28,7 +28,9 @@ -ifdef(use_specs). -spec(maybe_upgrade_mnesia/0 :: () -> 'ok'). --spec(maybe_upgrade_local/0 :: () -> 'ok' | 'version_not_available'). +-spec(maybe_upgrade_local/0 :: () -> 'ok' | + 'version_not_available' | + 'starting_from_scratch'). -endif. @@ -119,8 +121,13 @@ info("upgrades: Mnesia backup removed~n", []). maybe_upgrade_mnesia() -> - AllNodes = rabbit_mnesia:all_clustered_nodes(), + %% rabbit_mnesia:all_clustered_nodes/0 will return [] at this point + %% if we are a RAM node since Mnesia has not started yet. + AllNodes = lists:usort(rabbit_mnesia:all_clustered_nodes() ++ + rabbit_mnesia:read_cluster_nodes_config()), case rabbit_version:upgrades_required(mnesia) of + {error, starting_from_scratch} -> + ok; {error, version_not_available} -> case AllNodes of [_] -> ok; @@ -235,6 +242,7 @@ maybe_upgrade_local() -> case rabbit_version:upgrades_required(local) of {error, version_not_available} -> version_not_available; + {error, starting_from_scratch} -> starting_from_scratch; {error, _} = Err -> throw(Err); {ok, []} -> ensure_backup_removed(), ok; diff -Nru rabbitmq-server-2.7.1/src/rabbit_upgrade_functions.erl rabbitmq-server-2.8.4/src/rabbit_upgrade_functions.erl --- rabbitmq-server-2.7.1/src/rabbit_upgrade_functions.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_upgrade_functions.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_upgrade_functions). @@ -35,6 +35,7 @@ -rabbit_upgrade({gm, mnesia, []}). -rabbit_upgrade({exchange_scratch, mnesia, [trace_exchanges]}). -rabbit_upgrade({mirrored_supervisor, mnesia, []}). +-rabbit_upgrade({topic_trie_node, mnesia, []}). %% ------------------------------------------------------------------- @@ -54,6 +55,7 @@ -spec(gm/0 :: () -> 'ok'). -spec(exchange_scratch/0 :: () -> 'ok'). -spec(mirrored_supervisor/0 :: () -> 'ok'). +-spec(topic_trie_node/0 :: () -> 'ok'). -endif. @@ -177,6 +179,12 @@ [{record_name, mirrored_sup_childspec}, {attributes, [key, mirroring_pid, childspec]}]). +topic_trie_node() -> + create(rabbit_topic_trie_node, + [{record_name, topic_trie_node}, + {attributes, [trie_node, edge_count, binding_count]}, + {type, ordered_set}]). + %%-------------------------------------------------------------------- transform(TableName, Fun, FieldList) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_variable_queue.erl rabbitmq-server-2.8.4/src/rabbit_variable_queue.erl --- rabbitmq-server-2.7.1/src/rabbit_variable_queue.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_variable_queue.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,18 +11,17 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_variable_queue). --export([init/3, terminate/2, delete_and_terminate/2, - purge/1, publish/4, publish_delivered/5, drain_confirmed/1, - dropwhile/2, fetch/2, ack/2, requeue/2, len/1, is_empty/1, - set_ram_duration_target/2, ram_duration/1, - needs_timeout/1, timeout/1, handle_pre_hibernate/1, - status/1, invoke/3, is_duplicate/2, discard/3, - multiple_routing_keys/0]). +-export([init/3, terminate/2, delete_and_terminate/2, purge/1, + publish/4, publish_delivered/5, drain_confirmed/1, + dropwhile/3, fetch/2, ack/2, requeue/2, len/1, is_empty/1, + set_ram_duration_target/2, ram_duration/1, needs_timeout/1, + timeout/1, handle_pre_hibernate/1, status/1, invoke/3, + is_duplicate/2, discard/3, multiple_routing_keys/0, fold/3]). -export([start/1, stop/0]). @@ -351,7 +350,7 @@ durable :: boolean(), transient_threshold :: non_neg_integer(), - async_callback :: async_callback(), + async_callback :: rabbit_backing_queue:async_callback(), len :: non_neg_integer(), persistent_count :: non_neg_integer(), @@ -370,8 +369,6 @@ ack_in_counter :: non_neg_integer(), ack_rates :: rates() }). --include("rabbit_backing_queue_spec.hrl"). - -spec(multiple_routing_keys/0 :: () -> 'ok'). -endif. @@ -434,7 +431,7 @@ Terms = rabbit_queue_index:shutdown_terms(QueueName), {PRef, Terms1} = case proplists:get_value(persistent_ref, Terms) of - undefined -> {rabbit_guid:guid(), []}; + undefined -> {rabbit_guid:gen(), []}; PRef1 -> {PRef1, Terms} end, PersistentClient = msg_store_client_init(?PERSISTENT_MSG_STORE, PRef, @@ -581,15 +578,27 @@ confirmed = gb_sets:new() }} end. -dropwhile(Pred, State) -> +dropwhile(Pred, AckRequired, State) -> dropwhile(Pred, AckRequired, State, []). + +dropwhile(Pred, AckRequired, State, Msgs) -> + End = fun(S) when AckRequired -> {lists:reverse(Msgs), S}; + (S) -> {undefined, S} + end, case queue_out(State) of {empty, State1} -> - a(State1); + End(a(State1)); {{value, MsgStatus = #msg_status { msg_props = MsgProps }}, State1} -> - case Pred(MsgProps) of - true -> {_, State2} = internal_fetch(false, MsgStatus, State1), - dropwhile(Pred, State2); - false -> a(in_r(MsgStatus, State1)) + case {Pred(MsgProps), AckRequired} of + {true, true} -> + {MsgStatus1, State2} = read_msg(MsgStatus, State1), + {{Msg, _, AckTag, _}, State3} = + internal_fetch(true, MsgStatus1, State2), + dropwhile(Pred, AckRequired, State3, [{Msg, AckTag} | Msgs]); + {true, false} -> + {_, State2} = internal_fetch(false, MsgStatus, State1), + dropwhile(Pred, AckRequired, State2, undefined); + {false, _} -> + End(a(in_r(MsgStatus, State1))) end end. @@ -628,11 +637,22 @@ persistent_count = PCount1, ack_out_counter = AckOutCount + length(AckTags) })}. -requeue(AckTags, #vqstate { delta = Delta, - q3 = Q3, - q4 = Q4, - in_counter = InCounter, - len = Len } = State) -> +fold(undefined, State, _AckTags) -> + State; +fold(MsgFun, State = #vqstate{pending_ack = PA}, AckTags) -> + lists:foldl( + fun(SeqId, State1) -> + {MsgStatus, State2} = + read_msg(gb_trees:get(SeqId, PA), State1), + MsgFun(MsgStatus#msg_status.msg, SeqId), + State2 + end, State, AckTags). + +requeue(AckTags, #vqstate { delta = Delta, + q3 = Q3, + q4 = Q4, + in_counter = InCounter, + len = Len } = State) -> {SeqIds, Q4a, MsgIds, State1} = queue_merge(lists:sort(AckTags), Q4, [], beta_limit(Q3), fun publish_alpha/2, State), @@ -731,21 +751,27 @@ ram_msg_count_prev = RamMsgCount, ram_ack_count_prev = RamAckCount }}. -needs_timeout(State) -> - case needs_index_sync(State) of - false -> case reduce_memory_use( - fun (_Quota, State1) -> {0, State1} end, - fun (_Quota, State1) -> State1 end, - fun (_Quota, State1) -> {0, State1} end, - State) of - {true, _State} -> idle; - {false, _State} -> false - end; - true -> timed +needs_timeout(State = #vqstate { index_state = IndexState }) -> + case must_sync_index(State) of + true -> timed; + false -> + case rabbit_queue_index:needs_sync(IndexState) of + true -> idle; + false -> case reduce_memory_use( + fun (_Quota, State1) -> {0, State1} end, + fun (_Quota, State1) -> State1 end, + fun (_Quota, State1) -> {0, State1} end, + State) of + {true, _State} -> idle; + {false, _State} -> false + end + end end. -timeout(State) -> - a(reduce_memory_use(confirm_commit_index(State))). +timeout(State = #vqstate { index_state = IndexState }) -> + IndexState1 = rabbit_queue_index:sync(IndexState), + State1 = State #vqstate { index_state = IndexState1 }, + a(reduce_memory_use(State1)). handle_pre_hibernate(State = #vqstate { index_state = IndexState }) -> State #vqstate { index_state = rabbit_queue_index:flush(IndexState) }. @@ -860,7 +886,8 @@ Res. msg_store_client_init(MsgStore, MsgOnDiskFun, Callback) -> - msg_store_client_init(MsgStore, rabbit_guid:guid(), MsgOnDiskFun, Callback). + msg_store_client_init(MsgStore, rabbit_guid:gen(), MsgOnDiskFun, + Callback). msg_store_client_init(MsgStore, Ref, MsgOnDiskFun, Callback) -> CloseFDsFun = msg_store_close_fds_fun(MsgStore =:= ?PERSISTENT_MSG_STORE), @@ -870,17 +897,23 @@ msg_store_write(MSCState, IsPersistent, MsgId, Msg) -> with_immutable_msg_store_state( MSCState, IsPersistent, - fun (MSCState1) -> rabbit_msg_store:write(MsgId, Msg, MSCState1) end). + fun (MSCState1) -> + rabbit_msg_store:write_flow(MsgId, Msg, MSCState1) + end). msg_store_read(MSCState, IsPersistent, MsgId) -> with_msg_store_state( MSCState, IsPersistent, - fun (MSCState1) -> rabbit_msg_store:read(MsgId, MSCState1) end). + fun (MSCState1) -> + rabbit_msg_store:read(MsgId, MSCState1) + end). msg_store_remove(MSCState, IsPersistent, MsgIds) -> with_immutable_msg_store_state( MSCState, IsPersistent, - fun (MCSState1) -> rabbit_msg_store:remove(MsgIds, MCSState1) end). + fun (MCSState1) -> + rabbit_msg_store:remove(MsgIds, MCSState1) + end). msg_store_close_fds(MSCState, IsPersistent) -> with_msg_store_state( @@ -1255,24 +1288,18 @@ %% Internal plumbing for confirms (aka publisher acks) %%---------------------------------------------------------------------------- -confirm_commit_index(State = #vqstate { index_state = IndexState }) -> - case needs_index_sync(State) of - true -> State #vqstate { - index_state = rabbit_queue_index:sync(IndexState) }; - false -> State - end. - record_confirms(MsgIdSet, State = #vqstate { msgs_on_disk = MOD, msg_indices_on_disk = MIOD, unconfirmed = UC, confirmed = C }) -> - State #vqstate { msgs_on_disk = gb_sets:difference(MOD, MsgIdSet), - msg_indices_on_disk = gb_sets:difference(MIOD, MsgIdSet), - unconfirmed = gb_sets:difference(UC, MsgIdSet), - confirmed = gb_sets:union (C, MsgIdSet) }. + State #vqstate { + msgs_on_disk = rabbit_misc:gb_sets_difference(MOD, MsgIdSet), + msg_indices_on_disk = rabbit_misc:gb_sets_difference(MIOD, MsgIdSet), + unconfirmed = rabbit_misc:gb_sets_difference(UC, MsgIdSet), + confirmed = gb_sets:union(C, MsgIdSet) }. -needs_index_sync(#vqstate { msg_indices_on_disk = MIOD, - unconfirmed = UC }) -> +must_sync_index(#vqstate { msg_indices_on_disk = MIOD, + unconfirmed = UC }) -> %% If UC is empty then by definition, MIOD and MOD are also empty %% and there's nothing that can be pending a sync. diff -Nru rabbitmq-server-2.7.1/src/rabbit_version.erl rabbitmq-server-2.8.4/src/rabbit_version.erl --- rabbitmq-server-2.7.1/src/rabbit_version.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_version.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_version). @@ -96,7 +96,10 @@ upgrades_required(Scope) -> case recorded_for_scope(Scope) of {error, enoent} -> - {error, version_not_available}; + case filelib:is_file(rabbit_guid:filename()) of + false -> {error, starting_from_scratch}; + true -> {error, version_not_available} + end; {ok, CurrentHeads} -> with_upgrade_graph( fun (G) -> diff -Nru rabbitmq-server-2.7.1/src/rabbit_vhost.erl rabbitmq-server-2.8.4/src/rabbit_vhost.erl --- rabbitmq-server-2.7.1/src/rabbit_vhost.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_vhost.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_vhost). diff -Nru rabbitmq-server-2.7.1/src/rabbit_writer.erl rabbitmq-server-2.8.4/src/rabbit_writer.erl --- rabbitmq-server-2.7.1/src/rabbit_writer.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/rabbit_writer.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(rabbit_writer). @@ -24,7 +24,7 @@ send_command_and_notify/4, send_command_and_notify/5]). -export([internal_send_command/4, internal_send_command/6]). --record(wstate, {sock, channel, frame_max, protocol}). +-record(wstate, {sock, channel, frame_max, protocol, pending}). -define(HIBERNATE_AFTER, 5000). @@ -80,7 +80,8 @@ #wstate{sock = Sock, channel = Channel, frame_max = FrameMax, - protocol = Protocol}])}. + protocol = Protocol, + pending = []}])}. start_link(Sock, Channel, FrameMax, Protocol, ReaderPid) -> {ok, @@ -88,7 +89,8 @@ #wstate{sock = Sock, channel = Channel, frame_max = FrameMax, - protocol = Protocol}])}. + protocol = Protocol, + pending = []}])}. mainloop(ReaderPid, State) -> try @@ -98,36 +100,43 @@ end, done. -mainloop1(ReaderPid, State) -> +mainloop1(ReaderPid, State = #wstate{pending = []}) -> receive Message -> ?MODULE:mainloop1(ReaderPid, handle_message(Message, State)) after ?HIBERNATE_AFTER -> erlang:hibernate(?MODULE, mainloop, [ReaderPid, State]) + end; +mainloop1(ReaderPid, State) -> + receive + Message -> ?MODULE:mainloop1(ReaderPid, handle_message(Message, State)) + after 0 -> + ?MODULE:mainloop1(ReaderPid, flush(State)) end. handle_message({send_command, MethodRecord}, State) -> - ok = internal_send_command_async(MethodRecord, State), - State; + internal_send_command_async(MethodRecord, State); handle_message({send_command, MethodRecord, Content}, State) -> - ok = internal_send_command_async(MethodRecord, Content, State), - State; + internal_send_command_async(MethodRecord, Content, State); handle_message({'$gen_call', From, {send_command_sync, MethodRecord}}, State) -> - ok = internal_send_command_async(MethodRecord, State), + State1 = flush(internal_send_command_async(MethodRecord, State)), gen_server:reply(From, ok), - State; + State1; handle_message({'$gen_call', From, {send_command_sync, MethodRecord, Content}}, State) -> - ok = internal_send_command_async(MethodRecord, Content, State), + State1 = flush(internal_send_command_async(MethodRecord, Content, State)), gen_server:reply(From, ok), - State; + State1; handle_message({send_command_and_notify, QPid, ChPid, MethodRecord}, State) -> - ok = internal_send_command_async(MethodRecord, State), + State1 = internal_send_command_async(MethodRecord, State), rabbit_amqqueue:notify_sent(QPid, ChPid), - State; + State1; handle_message({send_command_and_notify, QPid, ChPid, MethodRecord, Content}, State) -> - ok = internal_send_command_async(MethodRecord, Content, State), + State1 = internal_send_command_async(MethodRecord, Content, State), rabbit_amqqueue:notify_sent(QPid, ChPid), + State1; +handle_message({'DOWN', _MRef, process, QPid, _Reason}, State) -> + rabbit_amqqueue:notify_sent_queue_down(QPid), State; handle_message({inet_reply, _, ok}, State) -> State; @@ -169,12 +178,10 @@ %%--------------------------------------------------------------------------- assemble_frame(Channel, MethodRecord, Protocol) -> - ?LOGMESSAGE(out, Channel, MethodRecord, none), rabbit_binary_generator:build_simple_method_frame( Channel, MethodRecord, Protocol). assemble_frames(Channel, MethodRecord, Content, FrameMax, Protocol) -> - ?LOGMESSAGE(out, Channel, MethodRecord, Content), MethodName = rabbit_misc:method_record_type(MethodRecord), true = Protocol:method_has_content(MethodName), % assertion MethodFrame = rabbit_binary_generator:build_simple_method_frame( @@ -183,22 +190,6 @@ Channel, Content, FrameMax, Protocol), [MethodFrame | ContentFrames]. -%% We optimise delivery of small messages. Content-bearing methods -%% require at least three frames. Small messages always fit into -%% that. We hand their frames to the Erlang network functions in one -%% go, which may lead to somewhat more efficient processing in the -%% runtime and a greater chance of coalescing into fewer TCP packets. -%% -%% By contrast, for larger messages, split across many frames, we want -%% to allow interleaving of frames on different channels. Hence we -%% hand them to the Erlang network functions one frame at a time. -send_frames(Fun, Sock, Frames) when length(Frames) =< 3 -> - Fun(Sock, Frames); -send_frames(Fun, Sock, Frames) -> - lists:foldl(fun (Frame, ok) -> Fun(Sock, Frame); - (_Frame, Other) -> Other - end, ok, Frames). - tcp_send(Sock, Data) -> rabbit_misc:throw_on_error(inet_error, fun () -> rabbit_net:send(Sock, Data) end). @@ -208,9 +199,44 @@ internal_send_command(Sock, Channel, MethodRecord, Content, FrameMax, Protocol) -> - ok = send_frames(fun tcp_send/2, Sock, - assemble_frames(Channel, MethodRecord, - Content, FrameMax, Protocol)). + ok = lists:foldl(fun (Frame, ok) -> tcp_send(Sock, Frame); + (_Frame, Other) -> Other + end, ok, assemble_frames(Channel, MethodRecord, + Content, FrameMax, Protocol)). + +internal_send_command_async(MethodRecord, + State = #wstate{channel = Channel, + protocol = Protocol, + pending = Pending}) -> + Frame = assemble_frame(Channel, MethodRecord, Protocol), + maybe_flush(State#wstate{pending = [Frame | Pending]}). + +internal_send_command_async(MethodRecord, Content, + State = #wstate{channel = Channel, + frame_max = FrameMax, + protocol = Protocol, + pending = Pending}) -> + Frames = assemble_frames(Channel, MethodRecord, Content, FrameMax, + Protocol), + maybe_flush(State#wstate{pending = [Frames | Pending]}). + +%% This magic number is the tcp-over-ethernet MSS (1460) minus the +%% minimum size of a AMQP basic.deliver method frame (24) plus basic +%% content header (22). The idea is that we want to flush just before +%% exceeding the MSS. +-define(FLUSH_THRESHOLD, 1414). + +maybe_flush(State = #wstate{pending = Pending}) -> + case iolist_size(Pending) >= ?FLUSH_THRESHOLD of + true -> flush(State); + false -> State + end. + +flush(State = #wstate{pending = []}) -> + State; +flush(State = #wstate{sock = Sock, pending = Pending}) -> + ok = port_cmd(Sock, lists:reverse(Pending)), + State#wstate{pending = []}. %% gen_tcp:send/2 does a selective receive of {inet_reply, Sock, %% Status} to obtain the result. That is bad when it is called from @@ -230,21 +256,6 @@ %% Also note that the port has bounded buffers and port_command blocks %% when these are full. So the fact that we process the result %% asynchronously does not impact flow control. -internal_send_command_async(MethodRecord, - #wstate{sock = Sock, - channel = Channel, - protocol = Protocol}) -> - ok = port_cmd(Sock, assemble_frame(Channel, MethodRecord, Protocol)). - -internal_send_command_async(MethodRecord, Content, - #wstate{sock = Sock, - channel = Channel, - frame_max = FrameMax, - protocol = Protocol}) -> - ok = send_frames(fun port_cmd/2, Sock, - assemble_frames(Channel, MethodRecord, - Content, FrameMax, Protocol)). - port_cmd(Sock, Data) -> true = try rabbit_net:port_command(Sock, Data) catch error:Error -> exit({writer, send_failed, Error}) diff -Nru rabbitmq-server-2.7.1/src/supervisor2.erl rabbitmq-server-2.8.4/src/supervisor2.erl --- rabbitmq-server-2.7.1/src/supervisor2.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/supervisor2.erl 2012-06-22 16:03:48.000000000 +0000 @@ -9,15 +9,15 @@ %% terminated as per the shutdown component of the child_spec. %% %% 3) child specifications can contain, as the restart type, a tuple -%% {permanent, Delay} | {transient, Delay} where Delay >= 0. The -%% delay, in seconds, indicates what should happen if a child, upon -%% being restarted, exceeds the MaxT and MaxR parameters. Thus, if -%% a child exits, it is restarted as normal. If it exits -%% sufficiently quickly and often to exceed the boundaries set by -%% the MaxT and MaxR parameters, and a Delay is specified, then -%% rather than stopping the supervisor, the supervisor instead -%% continues and tries to start up the child again, Delay seconds -%% later. +%% {permanent, Delay} | {transient, Delay} | {intrinsic, Delay} +%% where Delay >= 0 (see point (4) below for intrinsic). The delay, +%% in seconds, indicates what should happen if a child, upon being +%% restarted, exceeds the MaxT and MaxR parameters. Thus, if a +%% child exits, it is restarted as normal. If it exits sufficiently +%% quickly and often to exceed the boundaries set by the MaxT and +%% MaxR parameters, and a Delay is specified, then rather than +%% stopping the supervisor, the supervisor instead continues and +%% tries to start up the child again, Delay seconds later. %% %% Note that you can never restart more frequently than the MaxT %% and MaxR parameters allow: i.e. you must wait until *both* the @@ -31,6 +31,16 @@ %% the MaxT and MaxR parameters to permit the child to be %% restarted. This may require waiting for longer than Delay. %% +%% Sometimes, you may wish for a transient or intrinsic child to +%% exit abnormally so that it gets restarted, but still log +%% nothing. gen_server will log any exit reason other than +%% 'normal', 'shutdown' or {'shutdown', _}. Thus the exit reason of +%% {'shutdown', 'restart'} is interpreted to mean you wish the +%% child to be restarted according to the delay parameters, but +%% gen_server will not log the error. Thus from gen_server's +%% perspective it's a normal exit, whilst from supervisor's +%% perspective, it's an abnormal exit. +%% %% 4) Added an 'intrinsic' restart type. Like the transient type, this %% type means the child should only be restarted if the child exits %% abnormally. Unlike the transient type, if the child exits @@ -41,7 +51,7 @@ %% 5) normal, and {shutdown, _} exit reasons are all treated the same %% (i.e. are regarded as normal exits) %% -%% All modifications are (C) 2010-2011 VMware, Inc. +%% All modifications are (C) 2010-2012 VMware, Inc. %% %% %CopyrightBegin% %% @@ -71,8 +81,6 @@ which_children/1, find_child/2, check_childspecs/1]). --export([behaviour_info/1]). - %% Internal exports -export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]). -export([handle_cast/2]). @@ -102,11 +110,144 @@ -define(is_terminate_simple(State), State#state.strategy =:= simple_one_for_one_terminate). +-ifdef(use_specs). + +%%-------------------------------------------------------------------------- +%% Types +%%-------------------------------------------------------------------------- + +-export_type([child_spec/0, startchild_ret/0, strategy/0, sup_name/0]). + +-type child() :: 'undefined' | pid(). +-type child_id() :: term(). +-type mfargs() :: {M :: module(), F :: atom(), A :: [term()] | undefined}. +-type modules() :: [module()] | 'dynamic'. +-type delay() :: non_neg_integer(). +-type restart() :: 'permanent' | 'transient' | 'temporary' | 'intrinsic' + | {'permanent', delay()} | {'transient', delay()} + | {'intrinsic', delay()}. +-type shutdown() :: 'brutal_kill' | timeout(). +-type worker() :: 'worker' | 'supervisor'. +-type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}. +-type sup_ref() :: (Name :: atom()) + | {Name :: atom(), Node :: node()} + | {'global', Name :: atom()} + | pid(). +-type child_spec() :: {Id :: child_id(), + StartFunc :: mfargs(), + Restart :: restart(), + Shutdown :: shutdown(), + Type :: worker(), + Modules :: modules()}. + + +-type strategy() :: 'one_for_all' | 'one_for_one' + | 'rest_for_one' | 'simple_one_for_one' + | 'simple_one_for_one_terminate'. + +-type child_rec() :: #child{pid :: child() | {restarting,pid()} | [pid()], + name :: child_id(), + mfa :: mfargs(), + restart_type :: restart(), + shutdown :: shutdown(), + child_type :: worker(), + modules :: modules()}. + +-type state() :: #state{strategy :: strategy(), + children :: [child_rec()], + dynamics :: ?DICT(), + intensity :: non_neg_integer(), + period :: pos_integer()}. + +%%-------------------------------------------------------------------------- +%% Callback behaviour +%%-------------------------------------------------------------------------- + +-callback init(Args :: term()) -> + {ok, {{RestartStrategy :: strategy(), + MaxR :: non_neg_integer(), + MaxT :: non_neg_integer()}, + [ChildSpec :: child_spec()]}} + | ignore. + +%%-------------------------------------------------------------------------- +%% Specs +%%-------------------------------------------------------------------------- + +-type startchild_err() :: 'already_present' + | {'already_started', Child :: child()} | term(). +-type startchild_ret() :: {'ok', Child :: child()} + | {'ok', Child :: child(), Info :: term()} + | {'error', startchild_err()}. + +-spec start_child(SupRef, ChildSpec) -> startchild_ret() when + SupRef :: sup_ref(), + ChildSpec :: child_spec() | (List :: [term()]). + +-spec restart_child(SupRef, Id) -> Result when + SupRef :: sup_ref(), + Id :: child_id(), + Result :: {'ok', Child :: child()} + | {'ok', Child :: child(), Info :: term()} + | {'error', Error}, + Error :: 'running' | 'not_found' | 'simple_one_for_one' | term(). + +-spec delete_child(SupRef, Id) -> Result when + SupRef :: sup_ref(), + Id :: child_id(), + Result :: 'ok' | {'error', Error}, + Error :: 'running' | 'not_found' | 'simple_one_for_one'. + +-spec terminate_child(SupRef, Id) -> Result when + SupRef :: sup_ref(), + Id :: pid() | child_id(), + Result :: 'ok' | {'error', Error}, + Error :: 'not_found' | 'simple_one_for_one'. + +-spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when + SupRef :: sup_ref(), + Id :: child_id() | 'undefined', + Child :: child(), + Type :: worker(), + Modules :: modules(). + +-spec check_childspecs(ChildSpecs) -> Result when + ChildSpecs :: [child_spec()], + Result :: 'ok' | {'error', Error :: term()}. + +-type init_sup_name() :: sup_name() | 'self'. + +-type stop_rsn() :: 'shutdown' | {'bad_return', {module(),'init', term()}} + | {'bad_start_spec', term()} | {'start_spec', term()} + | {'supervisor_data', term()}. + +-spec init({init_sup_name(), module(), [term()]}) -> + {'ok', state()} | 'ignore' | {'stop', stop_rsn()}. + +-type call() :: 'which_children'. +-spec handle_call(call(), term(), state()) -> {'reply', term(), state()}. + +-spec handle_cast('null', state()) -> {'noreply', state()}. + +-spec handle_info(term(), state()) -> + {'noreply', state()} | {'stop', 'shutdown', state()}. + +-spec terminate(term(), state()) -> 'ok'. + +-spec code_change(term(), state(), term()) -> + {'ok', state()} | {'error', term()}. + +-else. + +-export([behaviour_info/1]). + behaviour_info(callbacks) -> [{init,1}]; behaviour_info(_Other) -> undefined. +-endif. + %%% --------------------------------------------------- %%% This is a general process supervisor built upon gen_server.erl. %%% Servers/processes should/could also be built using gen_server.erl. @@ -270,6 +411,8 @@ #child{mfa = {M, F, A}} = hd(State#state.children), Args = A ++ EArgs, case do_start_child_i(M, F, Args) of + {ok, undefined} -> + {reply, {ok, undefined}, State}; {ok, Pid} -> NState = State#state{dynamics = ?DICT:store(Pid, Args, State#state.dynamics)}, @@ -529,25 +672,23 @@ {ok, State} end. -do_restart({RestartType, Delay}, Reason, Child, State) -> - case restart1(Child, State) of - {ok, NState} -> - {ok, NState}; - {terminate, NState} -> - _TRef = erlang:send_after(trunc(Delay*1000), self(), - {delayed_restart, - {{RestartType, Delay}, Reason, Child}}), - {ok, state_del_child(Child, NState)} - end; +do_restart({permanent = RestartType, Delay}, Reason, Child, State) -> + do_restart_delay({RestartType, Delay}, Reason, Child, State); do_restart(permanent, Reason, Child, State) -> report_error(child_terminated, Reason, Child, State#state.name), restart(Child, State); do_restart(Type, normal, Child, State) -> del_child_and_maybe_shutdown(Type, Child, State); +do_restart({RestartType, Delay}, {shutdown, restart} = Reason, Child, State) + when RestartType =:= transient orelse RestartType =:= intrinsic -> + do_restart_delay({RestartType, Delay}, Reason, Child, State); do_restart(Type, {shutdown, _}, Child, State) -> del_child_and_maybe_shutdown(Type, Child, State); do_restart(Type, shutdown, Child = #child{child_type = supervisor}, State) -> del_child_and_maybe_shutdown(Type, Child, State); +do_restart({RestartType, Delay}, Reason, Child, State) + when RestartType =:= transient orelse RestartType =:= intrinsic -> + do_restart_delay({RestartType, Delay}, Reason, Child, State); do_restart(Type, Reason, Child, State) when Type =:= transient orelse Type =:= intrinsic -> report_error(child_terminated, Reason, Child, State#state.name), @@ -557,8 +698,21 @@ NState = state_del_child(Child, State), {ok, NState}. +do_restart_delay({RestartType, Delay}, Reason, Child, State) -> + case restart1(Child, State) of + {ok, NState} -> + {ok, NState}; + {terminate, NState} -> + _TRef = erlang:send_after(trunc(Delay*1000), self(), + {delayed_restart, + {{RestartType, Delay}, Reason, Child}}), + {ok, state_del_child(Child, NState)} + end. + del_child_and_maybe_shutdown(intrinsic, Child, State) -> {shutdown, state_del_child(Child, State)}; +del_child_and_maybe_shutdown({intrinsic, _Delay}, Child, State) -> + {shutdown, state_del_child(Child, State)}; del_child_and_maybe_shutdown(_, Child, State) -> {ok, state_del_child(Child, State)}. @@ -591,6 +745,8 @@ #child{mfa = {M, F, A}} = Child, Dynamics = ?DICT:erase(Child#child.pid, State#state.dynamics), case do_start_child_i(M, F, A) of + {ok, undefined} -> + {ok, State}; {ok, Pid} -> NState = State#state{dynamics = ?DICT:store(Pid, A, Dynamics)}, {ok, NState}; @@ -717,8 +873,8 @@ ok; {error, normal} -> case Child#child.restart_type of - permanent -> ReportError(normal); - {permanent, _Delay} -> ReportError(normal); + permanent -> ReportError(normal, Child); + {permanent, _Delay} -> ReportError(normal, Child); _ -> ok end; {error, OtherReason} -> @@ -911,7 +1067,8 @@ %%% Func is {Mod, Fun, Args} == {atom, atom, list} %%% RestartType is permanent | temporary | transient | %%% intrinsic | {permanent, Delay} | -%%% {transient, Delay} where Delay >= 0 +%%% {transient, Delay} | {intrinsic, Delay} +%% where Delay >= 0 %%% Shutdown = integer() | infinity | brutal_kill %%% ChildType = supervisor | worker %%% Modules = [atom()] | dynamic @@ -962,6 +1119,7 @@ validRestartType(transient) -> true; validRestartType(intrinsic) -> true; validRestartType({permanent, Delay}) -> validDelay(Delay); +validRestartType({intrinsic, Delay}) -> validDelay(Delay); validRestartType({transient, Delay}) -> validDelay(Delay); validRestartType(RestartType) -> throw({invalid_restart_type, RestartType}). diff -Nru rabbitmq-server-2.7.1/src/tcp_acceptor.erl rabbitmq-server-2.8.4/src/tcp_acceptor.erl --- rabbitmq-server-2.7.1/src/tcp_acceptor.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/tcp_acceptor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(tcp_acceptor). @@ -54,28 +54,9 @@ {ok, Mod} = inet_db:lookup_socket(LSock), inet_db:register_socket(Sock, Mod), - try - %% report - {Address, Port} = inet_op(fun () -> inet:sockname(LSock) end), - {PeerAddress, PeerPort} = inet_op(fun () -> inet:peername(Sock) end), - error_logger:info_msg("accepted TCP connection on ~s:~p from ~s:~p~n", - [rabbit_misc:ntoab(Address), Port, - rabbit_misc:ntoab(PeerAddress), PeerPort]), - %% In the event that somebody floods us with connections we can spew - %% the above message at error_logger faster than it can keep up. - %% So error_logger's mailbox grows unbounded until we eat all the - %% memory available and crash. So here's a meaningless synchronous call - %% to the underlying gen_event mechanism - when it returns the mailbox - %% is drained. - gen_event:which_handlers(error_logger), - %% handle - file_handle_cache:transfer(apply(M, F, A ++ [Sock])), - ok = file_handle_cache:obtain() - catch {inet_error, Reason} -> - gen_tcp:close(Sock), - error_logger:error_msg("unable to accept TCP connection: ~p~n", - [Reason]) - end, + %% handle + file_handle_cache:transfer(apply(M, F, A ++ [Sock])), + ok = file_handle_cache:obtain(), %% accept more accept(State); @@ -86,6 +67,10 @@ %% know this will fail. {stop, normal, State}; +handle_info({inet_async, LSock, Ref, {error, Reason}}, + State=#state{sock=LSock, ref=Ref}) -> + {stop, {accept_failed, Reason}, State}; + handle_info(_Info, State) -> {noreply, State}. @@ -97,8 +82,6 @@ %%-------------------------------------------------------------------- -inet_op(F) -> rabbit_misc:throw_on_error(inet_error, F). - accept(State = #state{sock=LSock}) -> case prim_inet:async_accept(LSock, -1) of {ok, Ref} -> {noreply, State#state{ref=Ref}}; diff -Nru rabbitmq-server-2.7.1/src/tcp_acceptor_sup.erl rabbitmq-server-2.8.4/src/tcp_acceptor_sup.erl --- rabbitmq-server-2.7.1/src/tcp_acceptor_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/tcp_acceptor_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(tcp_acceptor_sup). @@ -25,7 +25,11 @@ %%---------------------------------------------------------------------------- -ifdef(use_specs). --spec(start_link/2 :: (atom(), mfa()) -> rabbit_types:ok_pid_or_error()). + +-type(mfargs() :: {atom(), atom(), [any()]}). + +-spec(start_link/2 :: (atom(), mfargs()) -> rabbit_types:ok_pid_or_error()). + -endif. %%---------------------------------------------------------------------------- diff -Nru rabbitmq-server-2.7.1/src/tcp_listener.erl rabbitmq-server-2.8.4/src/tcp_listener.erl --- rabbitmq-server-2.7.1/src/tcp_listener.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/tcp_listener.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(tcp_listener). @@ -28,9 +28,14 @@ %%---------------------------------------------------------------------------- -ifdef(use_specs). + +-type(mfargs() :: {atom(), atom(), [any()]}). + -spec(start_link/8 :: - (gen_tcp:ip_address(), integer(), rabbit_types:infos(), integer(), - atom(), mfa(), mfa(), string()) -> rabbit_types:ok_pid_or_error()). + (inet:ip_address(), inet:port_number(), [gen_tcp:listen_option()], + integer(), atom(), mfargs(), mfargs(), string()) -> + rabbit_types:ok_pid_or_error()). + -endif. %%-------------------------------------------------------------------- @@ -67,8 +72,9 @@ label = Label}}; {error, Reason} -> error_logger:error_msg( - "failed to start ~s on ~s:~p - ~p~n", - [Label, rabbit_misc:ntoab(IPAddress), Port, Reason]), + "failed to start ~s on ~s:~p - ~p (~s)~n", + [Label, rabbit_misc:ntoab(IPAddress), Port, + Reason, inet:format_error(Reason)]), {stop, {cannot_listen, IPAddress, Port, Reason}} end. diff -Nru rabbitmq-server-2.7.1/src/tcp_listener_sup.erl rabbitmq-server-2.8.4/src/tcp_listener_sup.erl --- rabbitmq-server-2.7.1/src/tcp_listener_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/tcp_listener_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(tcp_listener_sup). @@ -26,12 +26,16 @@ -ifdef(use_specs). +-type(mfargs() :: {atom(), atom(), [any()]}). + -spec(start_link/7 :: - (gen_tcp:ip_address(), integer(), rabbit_types:infos(), mfa(), mfa(), - mfa(), string()) -> rabbit_types:ok_pid_or_error()). + (inet:ip_address(), inet:port_number(), [gen_tcp:listen_option()], + mfargs(), mfargs(), mfargs(), string()) -> + rabbit_types:ok_pid_or_error()). -spec(start_link/8 :: - (gen_tcp:ip_address(), integer(), rabbit_types:infos(), mfa(), mfa(), - mfa(), integer(), string()) -> rabbit_types:ok_pid_or_error()). + (inet:ip_address(), inet:port_number(), [gen_tcp:listen_option()], + mfargs(), mfargs(), mfargs(), integer(), string()) -> + rabbit_types:ok_pid_or_error()). -endif. diff -Nru rabbitmq-server-2.7.1/src/test_sup.erl rabbitmq-server-2.8.4/src/test_sup.erl --- rabbitmq-server-2.7.1/src/test_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/test_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(test_sup). diff -Nru rabbitmq-server-2.7.1/src/vm_memory_monitor.erl rabbitmq-server-2.8.4/src/vm_memory_monitor.erl --- rabbitmq-server-2.7.1/src/vm_memory_monitor.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/vm_memory_monitor.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% %% In practice Erlang shouldn't be allowed to grow to more than a half @@ -181,10 +181,10 @@ case {Alarmed, NewAlarmed} of {false, true} -> emit_update_info(set, MemUsed, MemLimit), - alarm_handler:set_alarm({{vm_memory_high_watermark, node()}, []}); + alarm_handler:set_alarm({{resource_limit, memory, node()}, []}); {true, false} -> emit_update_info(clear, MemUsed, MemLimit), - alarm_handler:clear_alarm({vm_memory_high_watermark, node()}); + alarm_handler:clear_alarm({resource_limit, memory, node()}); _ -> ok end, diff -Nru rabbitmq-server-2.7.1/src/worker_pool.erl rabbitmq-server-2.8.4/src/worker_pool.erl --- rabbitmq-server-2.7.1/src/worker_pool.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/worker_pool.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(worker_pool). @@ -37,10 +37,11 @@ -ifdef(use_specs). +-type(mfargs() :: {atom(), atom(), [any()]}). + -spec(start_link/0 :: () -> {'ok', pid()} | {'error', any()}). --spec(submit/1 :: (fun (() -> A) | {atom(), atom(), [any()]}) -> A). --spec(submit_async/1 :: - (fun (() -> any()) | {atom(), atom(), [any()]}) -> 'ok'). +-spec(submit/1 :: (fun (() -> A) | mfargs()) -> A). +-spec(submit_async/1 :: (fun (() -> any()) | mfargs()) -> 'ok'). -spec(idle/1 :: (any()) -> 'ok'). -endif. diff -Nru rabbitmq-server-2.7.1/src/worker_pool_sup.erl rabbitmq-server-2.8.4/src/worker_pool_sup.erl --- rabbitmq-server-2.7.1/src/worker_pool_sup.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/worker_pool_sup.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(worker_pool_sup). diff -Nru rabbitmq-server-2.7.1/src/worker_pool_worker.erl rabbitmq-server-2.8.4/src/worker_pool_worker.erl --- rabbitmq-server-2.7.1/src/worker_pool_worker.erl 2011-12-16 12:24:15.000000000 +0000 +++ rabbitmq-server-2.8.4/src/worker_pool_worker.erl 2012-06-22 16:03:48.000000000 +0000 @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2011 VMware, Inc. All rights reserved. +%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved. %% -module(worker_pool_worker). @@ -29,12 +29,12 @@ -ifdef(use_specs). +-type(mfargs() :: {atom(), atom(), [any()]}). + -spec(start_link/1 :: (any()) -> {'ok', pid()} | {'error', any()}). --spec(submit/2 :: (pid(), fun (() -> A) | {atom(), atom(), [any()]}) -> A). --spec(submit_async/2 :: - (pid(), fun (() -> any()) | {atom(), atom(), [any()]}) -> 'ok'). --spec(run/1 :: (fun (() -> A)) -> A; - ({atom(), atom(), [any()]}) -> any()). +-spec(submit/2 :: (pid(), fun (() -> A) | mfargs()) -> A). +-spec(submit_async/2 :: (pid(), fun (() -> any()) | mfargs()) -> 'ok'). +-spec(run/1 :: (fun (() -> A)) -> A; (mfargs()) -> any()). -spec(set_maximum_since_use/2 :: (pid(), non_neg_integer()) -> 'ok'). -endif.