You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by gs...@apache.org on 2014/11/26 21:05:48 UTC
[01/35] qpid-proton git commit: PROTON-745: update DataImpl to return
arrays of Symbol as Symbol[] instance rather than Object[] instance,
and enable Data#putObject() to accept the Symbol[].
Repository: qpid-proton
Updated Branches:
refs/heads/examples 0fd8b1fc5 -> 2f4d1ba29
PROTON-745: update DataImpl to return arrays of Symbol as Symbol[] instance rather than Object[] instance, and enable Data#putObject() to accept the Symbol[].
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a04193d2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a04193d2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a04193d2
Branch: refs/heads/examples
Commit: a04193d2c745bbf045fcc191a5d5de8fbdba9812
Parents: c5c1879
Author: Robert Gemmell <ro...@apache.org>
Authored: Fri Nov 14 15:46:44 2014 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Fri Nov 14 15:46:44 2014 +0000
----------------------------------------------------------------------
.../qpid/proton/codec/impl/ArrayElement.java | 13 +++
.../apache/qpid/proton/codec/impl/DataImpl.java | 10 +++
.../qpid/proton/codec/impl/DataImplTest.java | 84 ++++++++++++++++++++
3 files changed, 107 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a04193d2/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/ArrayElement.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/ArrayElement.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/ArrayElement.java
index 2ac9668..22251fe 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/ArrayElement.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/ArrayElement.java
@@ -24,6 +24,7 @@ package org.apache.qpid.proton.codec.impl;
import java.nio.ByteBuffer;
import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.codec.Data;
class ArrayElement extends AbstractElement<Object[]>
@@ -160,6 +161,18 @@ class ArrayElement extends AbstractElement<Object[]>
}
return rVal;
}
+ else if(_arrayType == Data.DataType.SYMBOL)
+ {
+ Symbol[] rVal = new Symbol[(int) count()];
+ SymbolElement element = (SymbolElement) _first;
+ int i = 0;
+ while (element!=null)
+ {
+ rVal[i++] = element.getValue();
+ element = (SymbolElement) element.next();
+ }
+ return rVal;
+ }
else
{
Object[] rVal = new Object[(int) count()];
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a04193d2/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataImpl.java
index b22ae30..c6520ed 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/impl/DataImpl.java
@@ -458,6 +458,16 @@ public class DataImpl implements Data
{
putDescribedType((DescribedType)o);
}
+ else if(o instanceof Symbol[])
+ {
+ putArray(false, Data.DataType.SYMBOL);
+ enter();
+ for(Symbol s : (Symbol[]) o)
+ {
+ putSymbol(s);
+ }
+ exit();
+ }
else if(o instanceof Object[])
{
putJavaArray((Object[]) o);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a04193d2/proton-j/src/test/java/org/apache/qpid/proton/codec/impl/DataImplTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/impl/DataImplTest.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/impl/DataImplTest.java
new file mode 100644
index 0000000..6bb3f2c
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/impl/DataImplTest.java
@@ -0,0 +1,84 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.codec.impl;
+
+import static org.junit.Assert.*;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.codec.Data;
+import org.junit.Test;
+
+public class DataImplTest
+{
+ @Test
+ public void testEncodeDecodeSymbolArrayUsingPutArray()
+ {
+ Symbol symbol1 = Symbol.valueOf("testRoundtripSymbolArray1");
+ Symbol symbol2 = Symbol.valueOf("testRoundtripSymbolArray2");
+
+ Data data1 = new DataImpl();
+ data1.putArray(false, Data.DataType.SYMBOL);
+ data1.enter();
+ data1.putSymbol(symbol1);
+ data1.putSymbol(symbol2);
+ data1.exit();
+
+ Binary encoded = data1.encode();
+ encoded.asByteBuffer();
+
+ Data data2 = new DataImpl();
+ data2.decode(encoded.asByteBuffer());
+
+ assertEquals("unexpected array length", 2, data2.getArray());
+ assertEquals("unexpected array length", Data.DataType.SYMBOL, data2.getArrayType());
+
+ Object[] array = data2.getJavaArray();
+ assertNotNull("Array should not be null", array);
+ assertEquals("Expected a Symbol array", Symbol[].class, array.getClass());
+ assertEquals("unexpected array length", 2, array.length);
+ assertEquals("unexpected value", symbol1, array[0]);
+ assertEquals("unexpected value", symbol2, array[1]);
+ }
+
+ @Test
+ public void testEncodeDecodeSymbolArrayUsingPutObject()
+ {
+ Symbol symbol1 = Symbol.valueOf("testRoundtripSymbolArray1");
+ Symbol symbol2 = Symbol.valueOf("testRoundtripSymbolArray2");
+ Symbol[] input = new Symbol[]{symbol1, symbol2};
+
+ Data data1 = new DataImpl();
+ data1.putObject(input);
+
+ Binary encoded = data1.encode();
+ encoded.asByteBuffer();
+
+ Data data2 = new DataImpl();
+ data2.decode(encoded.asByteBuffer());
+
+ assertEquals("unexpected array length", 2, data2.getArray());
+ assertEquals("unexpected array length", Data.DataType.SYMBOL, data2.getArrayType());
+
+ Object[] array = data2.getJavaArray();
+ assertArrayEquals("Array not as expected", input, array);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[33/35] qpid-proton git commit: fix installation of new package
Posted by gs...@apache.org.
fix installation of new package
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/805cd17e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/805cd17e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/805cd17e
Branch: refs/heads/examples
Commit: 805cd17e360fd77eab29d60955a2193c7e7f0635
Parents: d02fdad
Author: Gordon Sim <gs...@redhat.com>
Authored: Wed Nov 26 17:15:38 2014 +0000
Committer: Gordon Sim <gs...@redhat.com>
Committed: Wed Nov 26 17:15:38 2014 +0000
----------------------------------------------------------------------
proton-c/bindings/python/CMakeLists.txt | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/805cd17e/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index 6be421e..eb53174 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -55,20 +55,20 @@ endif()
set (pysrc-generated cproton.py)
set (pysrc proton/__init__.py)
-macro (py_compile directory files)
+macro (py_compile directory files artifacts)
foreach (src_file ${files})
install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile ${src_file}
WORKING_DIRECTORY ${directory})")
install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile ${src_file}
WORKING_DIRECTORY ${directory})")
- list(APPEND PYTHON_ARTIFACTS ${directory}/${src_file}
+ list(APPEND ${artifacts} ${directory}/${src_file}
${directory}/${src_file}c
${directory}/${src_file}o)
endforeach (src_file)
endmacro(py_compile)
-py_compile(${CMAKE_CURRENT_BINARY_DIR} ${pysrc-generated})
-py_compile(${CMAKE_CURRENT_SOURCE_DIR} ${pysrc})
+py_compile(${CMAKE_CURRENT_BINARY_DIR} ${pysrc-generated} CPROTON_ARTIFACTS)
+py_compile(${CMAKE_CURRENT_SOURCE_DIR} ${pysrc} PROTON_ARTIFACTS)
find_program(EPYDOC_EXE epydoc)
mark_as_advanced (EPYDOC_EXE)
@@ -84,9 +84,12 @@ if (EPYDOC_EXE)
${OPTIONAL_ARG})
endif (EPYDOC_EXE)
-install(FILES ${PYTHON_ARTIFACTS}
+install(FILES ${CPROTON_ARTIFACTS}
DESTINATION ${PYTHON_SITEARCH_PACKAGES}
COMPONENT Python)
+install(FILES ${PROTON_ARTIFACTS}
+ DESTINATION "${PYTHON_SITEARCH_PACKAGES}/proton/"
+ COMPONENT Python)
install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
DESTINATION ${PYTHON_SITEARCH_PACKAGES}
COMPONENT Python)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[29/35] qpid-proton git commit: NO-JIRA: Fix protocol tracing for
transactional states.
Posted by gs...@apache.org.
NO-JIRA: Fix protocol tracing for transactional states.
Add transactions.xml to the set of files processed by protocol.py.
Logs "state=@transactional-state(52)" instead of just "state=52"
'
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/061da30b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/061da30b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/061da30b
Branch: refs/heads/examples
Commit: 061da30be815467217ecb365cfc1d7581367ba32
Parents: 3ac2e3b
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 19 20:31:29 2014 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Nov 24 14:58:48 2014 -0500
----------------------------------------------------------------------
proton-c/src/protocol.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/061da30b/proton-c/src/protocol.py
----------------------------------------------------------------------
diff --git a/proton-c/src/protocol.py b/proton-c/src/protocol.py
index 685e63b..ae65150 100644
--- a/proton-c/src/protocol.py
+++ b/proton-c/src/protocol.py
@@ -22,6 +22,7 @@ doc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "transport.xml"))
mdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "messaging.xml"))
tdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "transactions.xml"))
sdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "security.xml"))
+tdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "transactions.xml"))
def eq(attr, value):
return lambda nd: nd[attr] == value
@@ -30,12 +31,14 @@ TYPES = doc.query["amqp/section/type", eq("@class", "composite")] + \
mdoc.query["amqp/section/type", eq("@class", "composite")] + \
tdoc.query["amqp/section/type", eq("@class", "composite")] + \
sdoc.query["amqp/section/type", eq("@class", "composite")] + \
- mdoc.query["amqp/section/type", eq("@provides", "section")]
+ mdoc.query["amqp/section/type", eq("@provides", "section")] + \
+ tdoc.query["amqp/section/type", eq("@class", "composite")]
+
RESTRICTIONS = {}
COMPOSITES = {}
for type in doc.query["amqp/section/type"] + mdoc.query["amqp/section/type"] + \
- sdoc.query["amqp/section/type"]:
+ sdoc.query["amqp/section/type"] + tdoc.query["amqp/section/type"]:
source = type["@source"]
if source:
RESTRICTIONS[type["@name"]] = source
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[23/35] qpid-proton git commit: Revert "PROTON-755: Update Ruby smoke
tests to use Minitest"
Posted by gs...@apache.org.
Revert "PROTON-755: Update Ruby smoke tests to use Minitest"
This reverts commit 1d3a13863117cfca5aef56244b20773760428796.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2276c097
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2276c097
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2276c097
Branch: refs/heads/examples
Commit: 2276c09715683ace9e761a6d5aab5b74add3b7b9
Parents: b13222b
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Sat Nov 22 05:51:13 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Sat Nov 22 06:03:01 2014 -0500
----------------------------------------------------------------------
tests/ruby/proton-test | 2 +-
tests/ruby/proton_tests/interop.rb | 4 ++--
tests/ruby/proton_tests/smoke.rb | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2276c097/tests/ruby/proton-test
----------------------------------------------------------------------
diff --git a/tests/ruby/proton-test b/tests/ruby/proton-test
index acb0d43..748e6f0 100755
--- a/tests/ruby/proton-test
+++ b/tests/ruby/proton-test
@@ -1,5 +1,5 @@
#!/usr/bin/env ruby
-require 'minitest/autorun'
+require 'test/unit'
require 'proton_tests/interop.rb'
require 'proton_tests/smoke.rb'
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2276c097/tests/ruby/proton_tests/interop.rb
----------------------------------------------------------------------
diff --git a/tests/ruby/proton_tests/interop.rb b/tests/ruby/proton_tests/interop.rb
index 21d92d9..e14cba1 100755
--- a/tests/ruby/proton_tests/interop.rb
+++ b/tests/ruby/proton_tests/interop.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-require 'minitest/autorun'
+require 'test/unit'
require 'qpid_proton'
if ((RUBY_VERSION.split(".").map {|x| x.to_i} <=> [1, 9]) < 0)
@@ -12,7 +12,7 @@ if ((RUBY_VERSION.split(".").map {|x| x.to_i} <=> [1, 9]) < 0)
end
end
-class InteropTest < Minitest::Test
+class InteropTest < Test::Unit::TestCase
Data = Qpid::Proton::Data
Message = Qpid::Proton::Message
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2276c097/tests/ruby/proton_tests/smoke.rb
----------------------------------------------------------------------
diff --git a/tests/ruby/proton_tests/smoke.rb b/tests/ruby/proton_tests/smoke.rb
index a382a0b..b9265e8 100644
--- a/tests/ruby/proton_tests/smoke.rb
+++ b/tests/ruby/proton_tests/smoke.rb
@@ -1,9 +1,9 @@
#!/usr/bin/env ruby
-require 'minitest/autorun'
+require 'test/unit'
require 'qpid_proton'
-class SmokeTest < Minitest::Test
+class SmokeTest < Test::Unit::TestCase
Messenger = Qpid::Proton::Messenger
Message = Qpid::Proton::Message
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[13/35] qpid-proton git commit: PROTON-749: Split transport into
server/client sides - This allows the server and client sides of the
transport to have different default behaviours. - We set the SASL
client/server from the transport setting - There are
Posted by gs...@apache.org.
PROTON-749: Split transport into server/client sides
- This allows the server and client sides of the transport
to have different default behaviours.
- We set the SASL client/server from the transport setting
- There are some workarounds in the tests because the full logic isn't
implemented in proton-j, but the shared python tests must run against both.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9c9872b5
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9c9872b5
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9c9872b5
Branch: refs/heads/examples
Commit: 9c9872b570664229b3199448c69fd27bf7d325bc
Parents: df02900
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri Aug 15 18:25:31 2014 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed Nov 19 17:21:29 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/python/proton.py | 35 ++++++++++++--------
proton-c/include/proton/cproton.i | 14 +-------
proton-c/include/proton/sasl.h | 21 +-----------
proton-c/include/proton/transport.h | 20 ++++++++++-
proton-c/src/engine/engine-internal.h | 1 +
proton-c/src/messenger/messenger.c | 3 +-
proton-c/src/posix/driver.c | 8 +++--
proton-c/src/proton.c | 10 ++----
proton-c/src/sasl/sasl.c | 33 +++++-------------
proton-c/src/tests/engine.c | 3 ++
proton-c/src/transport/transport.c | 9 ++++-
proton-c/src/windows/driver.c | 7 ++--
.../qpid/proton/engine/impl/SaslImpl.java | 7 +++-
proton-j/src/main/resources/cengine.py | 5 ++-
proton-j/src/main/resources/csasl.py | 14 ++++----
tests/python/proton_tests/common.py | 1 -
tests/python/proton_tests/engine.py | 3 --
tests/python/proton_tests/sasl.py | 14 ++------
18 files changed, 95 insertions(+), 113 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
index 81104f0..573ec14 100644
--- a/proton-c/bindings/python/proton.py
+++ b/proton-c/bindings/python/proton.py
@@ -2984,12 +2984,28 @@ class Transport(object):
TRACE_FRM = PN_TRACE_FRM
TRACE_RAW = PN_TRACE_RAW
- def __init__(self, _trans=None):
- if not _trans:
+ CLIENT = 1
+ SERVER = 2
+
+ @staticmethod
+ def _wrap_transport(c_trans):
+ if not c_trans: return None
+ wrapper = Transport(_trans=c_trans)
+ return wrapper
+
+ def __init__(self, mode=None, _trans=None):
+ if not mode and not _trans:
self._trans = pn_transport()
- else:
+ elif not mode:
self._shared_trans = True
self._trans = _trans
+ elif mode==Transport.CLIENT:
+ self._trans = pn_transport()
+ elif mode==Transport.SERVER:
+ self._trans = pn_transport()
+ pn_transport_set_server(self._trans)
+ else:
+ raise TransportException("Cannot initialise Transport from mode: %s" % str(mode))
self._sasl = None
self._ssl = None
@@ -3177,12 +3193,6 @@ class SASL(object):
def mechanisms(self, mechs):
pn_sasl_mechanisms(self._sasl, mechs)
- def client(self):
- pn_sasl_client(self._sasl)
-
- def server(self):
- pn_sasl_server(self._sasl)
-
def allow_skip(self, allow):
pn_sasl_allow_skip(self._sasl, allow)
@@ -3216,7 +3226,6 @@ class SASL(object):
def done(self, outcome):
pn_sasl_done(self._sasl, outcome)
- STATE_CONF = PN_SASL_CONF
STATE_IDLE = PN_SASL_IDLE
STATE_STEP = PN_SASL_STEP
STATE_PASS = PN_SASL_PASS
@@ -3355,7 +3364,7 @@ wrappers = {
"pn_session": lambda x: Session._wrap_session(pn_cast_pn_session(x)),
"pn_link": lambda x: Link._wrap_link(pn_cast_pn_link(x)),
"pn_delivery": lambda x: Delivery._wrap_delivery(pn_cast_pn_delivery(x)),
- "pn_transport": lambda x: Transport(pn_cast_pn_transport(x))
+ "pn_transport": lambda x: Transport._wrap_transport(pn_cast_pn_transport(x))
}
class Collector:
@@ -3590,9 +3599,7 @@ class Connector(object):
@property
def transport(self):
trans = pn_connector_transport(self._cxtr)
- if trans:
- return Transport(trans)
- return None
+ return Transport._wrap_transport(trans)
def close(self):
return pn_connector_close(self._cxtr)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index dd35c0a..3c5a1a6 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -87,7 +87,7 @@ typedef unsigned long int uintptr_t;
PN_SASL_SYS, PN_SASL_PERM, PN_SASL_TEMP, PN_SASL_SKIPPED);
%aggregate_check(int, check_sasl_state,
- PN_SASL_CONF, PN_SASL_IDLE, PN_SASL_STEP,
+ PN_SASL_IDLE, PN_SASL_STEP,
PN_SASL_PASS, PN_SASL_FAIL);
@@ -995,18 +995,6 @@ typedef unsigned long int uintptr_t;
sasl != NULL;
}
-%contract pn_sasl_client(pn_sasl_t *sasl)
-{
- require:
- sasl != NULL;
-}
-
-%contract pn_sasl_server(pn_sasl_t *sasl)
-{
- require:
- sasl != NULL;
-}
-
%contract pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
{
require:
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/include/proton/sasl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/sasl.h b/proton-c/include/proton/sasl.h
index 84ddf10..ab64e13 100644
--- a/proton-c/include/proton/sasl.h
+++ b/proton-c/include/proton/sasl.h
@@ -60,7 +60,6 @@ typedef enum {
/** The state of the SASL negotiation process */
typedef enum {
- PN_SASL_CONF, /** Pending configuration by application */
PN_SASL_IDLE, /** Pending SASL Init */
PN_SASL_STEP, /** negotiation in progress */
PN_SASL_PASS, /** negotiation completed successfully */
@@ -96,24 +95,6 @@ PN_EXTERN void pn_sasl_mechanisms(pn_sasl_t *sasl, const char *mechanisms);
*/
PN_EXTERN const char *pn_sasl_remote_mechanisms(pn_sasl_t *sasl);
-/** Configure the SASL layer to act as a SASL client.
- *
- * The role of client is similar to a TCP client - the peer requesting
- * the connection.
- *
- * @param[in] sasl the SASL layer to configure as a client
- */
-PN_EXTERN void pn_sasl_client(pn_sasl_t *sasl);
-
-/** Configure the SASL layer to act as a server.
- *
- * The role of server is similar to a TCP server - the peer accepting
- * the connection.
- *
- * @param[in] sasl the SASL layer to configure as a server
- */
-PN_EXTERN void pn_sasl_server(pn_sasl_t *sasl);
-
/** Configure a SASL server layer to permit the client to skip the SASL exchange.
*
* If the peer client skips the SASL exchange (i.e. goes right to the AMQP header)
@@ -124,7 +105,7 @@ PN_EXTERN void pn_sasl_server(pn_sasl_t *sasl);
* @param[in] sasl the SASL layer to configure
* @param[in] allow true -> allow skip; false -> forbid skip
*/
- PN_EXTERN void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow);
+PN_EXTERN void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow);
/** Configure the SASL layer to use the "PLAIN" mechanism.
*
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/include/proton/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/transport.h b/proton-c/include/proton/transport.h
index 2262e7c..537e27d 100644
--- a/proton-c/include/proton/transport.h
+++ b/proton-c/include/proton/transport.h
@@ -84,16 +84,34 @@ typedef void (*pn_tracer_t)(pn_transport_t *transport, const char *message);
/**
* Factory for creating a transport.
- *
* A transport is used by a connection to interface with the network.
* There can only be one connection associated with a transport. See
* pn_transport_bind().
*
+ * Initially a transport is configured to be a client transport. Use pn_transport_set_server()
+ * to configure the transport as a server transport.
+ *
+ * A client transport initiates outgoing connections.
+ *
+ * A client transport must be configured with the protocol layers to use and cannot
+ * configure itself automatically.
+ *
+ * A server transport accepts incoming connections. It can automatically
+ * configure itself to include the various protocol layers depending on
+ * the incoming protocol headers.
+ *
* @return pointer to new transport
*/
PN_EXTERN pn_transport_t *pn_transport(void);
/**
+ * Configure a transport as a server
+ *
+ * @param[in] transport a transport object
+ */
+PN_EXTERN void pn_transport_set_server(pn_transport_t *transport);
+
+/**
* Free a transport object.
*
* When a transport is freed, it is automatically unbound from its
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index 3960acf..ab66ef5 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -178,6 +178,7 @@ struct pn_transport_t {
bool head_closed;
bool done_processing; // if true, don't call pn_process again
bool posted_idle_timeout;
+ bool server;
};
struct pn_connection_t {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index f0df36a..b4d7fe2 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -328,13 +328,13 @@ static void pni_listener_readable(pn_selectable_t *sel)
pn_socket_t sock = pn_accept(ctx->messenger->io, pn_selectable_fd(sel), name, 1024);
pn_transport_t *t = pn_transport();
+ pn_transport_set_server(t);
pn_ssl_t *ssl = pn_ssl(t);
pn_ssl_init(ssl, ctx->domain, NULL);
pn_sasl_t *sasl = pn_sasl(t);
pn_sasl_mechanisms(sasl, "ANONYMOUS");
- pn_sasl_server(sasl);
pn_sasl_done(sasl, PN_SASL_OK);
pn_connection_t *conn = pn_messenger_connection(ctx->messenger, sock, scheme, NULL, NULL, NULL, NULL, ctx);
@@ -960,7 +960,6 @@ static int pn_transport_config(pn_messenger_t *messenger,
pn_sasl_plain(sasl, ctx->user, ctx->pass);
} else {
pn_sasl_mechanisms(sasl, "ANONYMOUS");
- pn_sasl_client(sasl);
}
return 0;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/posix/driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/driver.c b/proton-c/src/posix/driver.c
index 4bc71bb..fc583ec 100644
--- a/proton-c/src/posix/driver.c
+++ b/proton-c/src/posix/driver.c
@@ -208,6 +208,9 @@ pn_connector_t *pn_listener_accept(pn_listener_t *l)
pn_connector_t *c = pn_connector_fd(l->driver, sock, NULL);
snprintf(c->name, PN_NAME_MAX, "%s", name);
c->listener = l;
+ c->transport = pn_transport();
+ pn_transport_set_server(c->transport);
+ c->sasl = pn_sasl(c->transport);
return c;
}
}
@@ -264,6 +267,8 @@ pn_connector_t *pn_connector(pn_driver_t *driver, const char *host,
pn_socket_t sock = pn_connect(driver->io, host, port);
pn_connector_t *c = pn_connector_fd(driver, sock, context);
+ c->transport = pn_transport();
+ c->sasl = pn_sasl(c->transport);
snprintf(c->name, PN_NAME_MAX, "%s:%s", host, port);
if (driver->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV))
fprintf(stderr, "Connected to %s\n", c->name);
@@ -290,8 +295,7 @@ pn_connector_t *pn_connector_fd(pn_driver_t *driver, int fd, void *context)
c->closed = false;
c->wakeup = 0;
c->connection = NULL;
- c->transport = pn_transport();
- c->sasl = pn_sasl(c->transport);
+ c->transport = NULL;
c->input_done = false;
c->output_done = false;
c->context = context;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/proton.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proton.c b/proton-c/src/proton.c
index 495659a..6e4f69d 100644
--- a/proton-c/src/proton.c
+++ b/proton-c/src/proton.c
@@ -132,11 +132,8 @@ void server_callback(pn_connector_t *ctor)
while (pn_sasl_state(sasl) != PN_SASL_PASS) {
switch (pn_sasl_state(sasl)) {
case PN_SASL_IDLE:
- return;
- case PN_SASL_CONF:
pn_sasl_mechanisms(sasl, "PLAIN ANONYMOUS");
- pn_sasl_server(sasl);
- break;
+ return;
case PN_SASL_STEP:
{
size_t n = pn_sasl_pending(sasl);
@@ -283,15 +280,12 @@ void client_callback(pn_connector_t *ctor)
pn_sasl_state_t st = pn_sasl_state(sasl);
switch (st) {
case PN_SASL_IDLE:
- return;
- case PN_SASL_CONF:
if (ctx->mechanism && !strcmp(ctx->mechanism, "PLAIN")) {
pn_sasl_plain(sasl, ctx->username, ctx->password);
} else {
pn_sasl_mechanisms(sasl, ctx->mechanism);
- pn_sasl_client(sasl);
}
- break;
+ return;
case PN_SASL_STEP:
if (pn_sasl_pending(sasl)) {
fprintf(stderr, "challenge failed\n");
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index ffa310b..90adcf6 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -42,7 +42,6 @@ struct pni_sasl_t {
pn_buffer_t *recv_data;
pn_sasl_outcome_t outcome;
bool client;
- bool configured;
bool allow_skip;
bool sent_init;
bool rcvd_init;
@@ -104,8 +103,7 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
sasl->disp = pn_dispatcher(1, transport);
sasl->disp->batch = false;
- sasl->client = false;
- sasl->configured = false;
+ sasl->client = !transport->server;
sasl->mechanisms = NULL;
sasl->remote_mechanisms = NULL;
sasl->send_data = pn_buffer(16);
@@ -131,7 +129,6 @@ pn_sasl_state_t pn_sasl_state(pn_sasl_t *sasl0)
{
pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
- if (!sasl->configured) return PN_SASL_CONF;
if (sasl->outcome == PN_SASL_NONE) {
return sasl->rcvd_init ? PN_SASL_STEP : PN_SASL_IDLE;
} else {
@@ -200,24 +197,6 @@ ssize_t pn_sasl_recv(pn_sasl_t *sasl0, char *bytes, size_t size)
}
}
-void pn_sasl_client(pn_sasl_t *sasl0)
-{
- pni_sasl_t *sasl = get_sasl_internal(sasl0);
- if (sasl) {
- sasl->client = true;
- sasl->configured = true;
- }
-}
-
-void pn_sasl_server(pn_sasl_t *sasl0)
-{
- pni_sasl_t *sasl = get_sasl_internal(sasl0);
- if (sasl) {
- sasl->client = false;
- sasl->configured = true;
- }
-}
-
void pn_sasl_allow_skip(pn_sasl_t *sasl0, bool allow)
{
pni_sasl_t *sasl = get_sasl_internal(sasl0);
@@ -244,7 +223,6 @@ void pn_sasl_plain(pn_sasl_t *sasl0, const char *username, const char *password)
pn_sasl_mechanisms(sasl0, "PLAIN");
pn_sasl_send(sasl0, iresp, size);
- pn_sasl_client(sasl0);
free(iresp);
}
@@ -253,6 +231,13 @@ void pn_sasl_done(pn_sasl_t *sasl0, pn_sasl_outcome_t outcome)
pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
sasl->outcome = outcome;
+ // If we do this on the client it is a hack to tell us that
+ // no actual negatiation is going to happen and we can go
+ // straight to the AMQP layer
+ if (sasl->client) {
+ sasl->rcvd_done = true;
+ sasl->sent_done = true;
+ }
}
}
@@ -330,8 +315,6 @@ void pn_server_done(pn_sasl_t *sasl0)
void pn_sasl_process(pn_transport_t *transport)
{
pni_sasl_t *sasl = transport->sasl;
- if (!sasl->configured) return;
-
if (!sasl->sent_init) {
if (sasl->client) {
pn_client_init(sasl);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/tests/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/engine.c b/proton-c/src/tests/engine.c
index e10e13f..87d8d95 100644
--- a/proton-c/src/tests/engine.c
+++ b/proton-c/src/tests/engine.c
@@ -129,6 +129,7 @@ int test_free_connection(int argc, char **argv)
pn_connection_t *c2 = pn_connection();
pn_transport_t *t2 = pn_transport();
+ pn_transport_set_server(t2);
pn_transport_bind(t2, c2);
//pn_transport_trace(t1, PN_TRACE_FRM);
@@ -181,6 +182,7 @@ int test_free_session(int argc, char **argv)
pn_connection_t *c2 = pn_connection();
pn_transport_t *t2 = pn_transport();
+ pn_transport_set_server(t2);
pn_transport_bind(t2, c2);
//pn_transport_trace(t1, PN_TRACE_FRM);
@@ -243,6 +245,7 @@ int test_free_link(int argc, char **argv)
pn_connection_t *c2 = pn_connection();
pn_transport_t *t2 = pn_transport();
+ pn_transport_set_server(t2);
pn_transport_bind(t2, c2);
//pn_transport_trace(t1, PN_TRACE_FRM);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index 865f8c9..2d5f93a 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -199,6 +199,8 @@ static void pn_transport_initialize(void *object)
transport->done_processing = false;
transport->posted_idle_timeout = false;
+
+ transport->server = false;
}
pn_session_t *pn_channel_state(pn_transport_t *transport, uint16_t channel)
@@ -232,7 +234,7 @@ static void pn_transport_finalize(void *object);
#define pn_transport_compare NULL
#define pn_transport_inspect NULL
-pn_transport_t *pn_transport()
+pn_transport_t *pn_transport(void)
{
static const pn_class_t clazz = PN_CLASS(pn_transport);
pn_transport_t *transport =
@@ -253,6 +255,11 @@ pn_transport_t *pn_transport()
return transport;
}
+void pn_transport_set_server(pn_transport_t *transport)
+{
+ transport->server = true;
+}
+
void pn_transport_free(pn_transport_t *transport)
{
if (!transport) return;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-c/src/windows/driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/driver.c b/proton-c/src/windows/driver.c
index 43662f9..013b422 100644
--- a/proton-c/src/windows/driver.c
+++ b/proton-c/src/windows/driver.c
@@ -285,6 +285,8 @@ pn_connector_t *pn_listener_accept(pn_listener_t *l)
pn_connector_t *c = pn_connector_fd(l->driver, sock, NULL);
snprintf(c->name, PN_NAME_MAX, "%s", name);
c->listener = l;
+ c->transport = pn_transport_server();
+ c->sasl = pn_sasl(c->transport);
return c;
}
}
@@ -383,6 +385,8 @@ pn_connector_t *pn_connector(pn_driver_t *driver, const char *host,
pn_socket_t sock = pn_connect(driver->io, host, port);
pn_connector_t *c = pn_connector_fd(driver, sock, context);
+ c->transport = pn_transport_client();
+ c->sasl = pn_sasl(c->transport);
snprintf(c->name, PN_NAME_MAX, "%s:%s", host, port);
if (driver->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV))
fprintf(stderr, "Connected to %s\n", c->name);
@@ -412,8 +416,7 @@ pn_connector_t *pn_connector_fd(pn_driver_t *driver, pn_socket_t fd, void *conte
c->wakeup = 0;
c->posted_wakeup = 0;
c->connection = NULL;
- c->transport = pn_transport();
- c->sasl = pn_sasl(c->transport);
+ c->transport = NULL;
c->input_done = false;
c->output_done = false;
c->context = context;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
index d587abb..1a933bf 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
@@ -340,7 +340,12 @@ public class SaslImpl implements Sasl, SaslFrameBody.SaslFrameBodyHandler<Void>,
@Override
public void done(SaslOutcome outcome)
{
- checkRole(Role.SERVER);
+ // Support current hack in C code to allow producing sasl frames for
+ // ANONYMOUS in a single chunk
+ if(_role == Role.CLIENT)
+ {
+ return;
+ }
_outcome = outcome;
_done = true;
_state = classifyStateFromOutcome(outcome);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-j/src/main/resources/cengine.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cengine.py b/proton-j/src/main/resources/cengine.py
index f9d4ddb..8f25a0e 100644
--- a/proton-j/src/main/resources/cengine.py
+++ b/proton-j/src/main/resources/cengine.py
@@ -865,14 +865,17 @@ def pn_delivery_settle(dlv):
dlv.impl.settle()
class pn_transport_wrapper:
-
def __init__(self, impl):
self.impl = impl
+ self.server = False
self.condition = pn_condition()
def pn_transport():
return wrap(Proton.transport(), pn_transport_wrapper)
+def pn_transport_set_server(trans):
+ trans.server = True;
+
def pn_transport_get_max_frame(trans):
return trans.impl.getMaxFrameSize()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/proton-j/src/main/resources/csasl.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/csasl.py b/proton-j/src/main/resources/csasl.py
index a24246d..fe184d8 100644
--- a/proton-j/src/main/resources/csasl.py
+++ b/proton-j/src/main/resources/csasl.py
@@ -38,10 +38,14 @@ PN_SASL_PASS = 3
PN_SASL_FAIL = 4
def pn_sasl(tp):
- return tp.impl.sasl()
+ sasl = tp.impl.sasl()
+ if tp.server:
+ sasl.server()
+ else:
+ sasl.client()
+ return sasl
SASL_STATES = {
- Sasl.SaslState.PN_SASL_CONF: PN_SASL_CONF,
Sasl.SaslState.PN_SASL_IDLE: PN_SASL_IDLE,
Sasl.SaslState.PN_SASL_STEP: PN_SASL_STEP,
Sasl.SaslState.PN_SASL_PASS: PN_SASL_PASS,
@@ -74,12 +78,6 @@ def pn_sasl_state(sasl):
def pn_sasl_mechanisms(sasl, mechs):
sasl.setMechanisms(*mechs.split())
-def pn_sasl_client(sasl):
- sasl.client()
-
-def pn_sasl_server(sasl):
- sasl.server()
-
def pn_sasl_allow_skip(sasl, allow):
sasl.allowSkip(allow)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
index e0887e6..d159214 100644
--- a/tests/python/proton_tests/common.py
+++ b/tests/python/proton_tests/common.py
@@ -178,7 +178,6 @@ class TestServer(object):
"""
sasl = cxtr.sasl()
sasl.mechanisms("ANONYMOUS")
- sasl.server()
cxtr.connection = Connection()
if "idle_timeout" in self.args:
cxtr.transport.idle_timeout = self.args["idle_timeout"]
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/tests/python/proton_tests/engine.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/engine.py b/tests/python/proton_tests/engine.py
index d17a57c..6a07aea 100644
--- a/tests/python/proton_tests/engine.py
+++ b/tests/python/proton_tests/engine.py
@@ -1823,7 +1823,6 @@ class ServerTest(Test):
self.cxtr = self.driver.connector(self.server.host, self.server.port)
self.cxtr.transport.idle_timeout = idle_timeout_secs
self.cxtr.sasl().mechanisms("ANONYMOUS")
- self.cxtr.sasl().client()
self.conn = Connection()
self.cxtr.connection = self.conn
self.conn.open()
@@ -1869,7 +1868,6 @@ class ServerTest(Test):
self.driver = Driver()
self.cxtr = self.driver.connector(self.server.host, self.server.port)
self.cxtr.sasl().mechanisms("ANONYMOUS")
- self.cxtr.sasl().client()
self.conn = Connection()
self.cxtr.connection = self.conn
self.conn.open()
@@ -2438,5 +2436,4 @@ class IdleTimeoutEventTest(PeerTest):
def testTimeoutWithZombieServerAndSASL(self):
sasl = self.transport.sasl()
- sasl.client()
self.testTimeoutWithZombieServer()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c9872b5/tests/python/proton_tests/sasl.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/sasl.py b/tests/python/proton_tests/sasl.py
index 5e353d5..c2dc005 100644
--- a/tests/python/proton_tests/sasl.py
+++ b/tests/python/proton_tests/sasl.py
@@ -29,7 +29,7 @@ class SaslTest(Test):
def setup(self):
self.t1 = Transport()
self.s1 = SASL(self.t1)
- self.t2 = Transport()
+ self.t2 = Transport(Transport.SERVER)
self.s2 = SASL(self.t2)
def pump(self):
@@ -37,12 +37,10 @@ class SaslTest(Test):
def testPipelined(self):
self.s1.mechanisms("ANONYMOUS")
- self.s1.client()
assert self.s1.outcome is None
self.s2.mechanisms("ANONYMOUS")
- self.s2.server()
self.s2.done(SASL.OK)
out1 = self.t1.peek(1024)
@@ -60,13 +58,13 @@ class SaslTest(Test):
def testSaslAndAmqpInSingleChunk(self):
self.s1.mechanisms("ANONYMOUS")
- self.s1.client()
+ self.s1.done(SASL.OK)
self.s2.mechanisms("ANONYMOUS")
- self.s2.server()
self.s2.done(SASL.OK)
# send the server's OK to the client
+ # This is still needed for the Java impl
out2 = self.t2.peek(1024)
self.t2.pop(len(out2))
self.t1.push(out2)
@@ -106,9 +104,7 @@ class SaslTest(Test):
def testChallengeResponse(self):
self.s1.mechanisms("FAKE_MECH")
- self.s1.client()
self.s2.mechanisms("FAKE_MECH")
- self.s2.server()
self.pump()
challenge = "Who goes there!"
self.s2.send(challenge)
@@ -130,14 +126,12 @@ class SaslTest(Test):
def testPipelined2(self):
self.s1.mechanisms("ANONYMOUS")
- self.s1.client()
out1 = self.t1.peek(1024)
self.t1.pop(len(out1))
self.t2.push(out1)
self.s2.mechanisms("ANONYMOUS")
- self.s2.server()
self.s2.done(SASL.OK)
c2 = Connection()
c2.open()
@@ -154,7 +148,6 @@ class SaslTest(Test):
""" PROTON-235
"""
self.s1.mechanisms("ANONYMOUS")
- self.s1.client()
assert self.s1.outcome is None
# self.t1.trace(Transport.TRACE_FRM)
@@ -196,7 +189,6 @@ class SaslTest(Test):
"""Verify that the server (with SASL) correctly handles a client without SASL"""
self.t1 = Transport()
self.s2.mechanisms("ANONYMOUS")
- self.s2.server()
self.s2.allow_skip(True)
self.pump()
assert self.s2.outcome == SASL.SKIPPED
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[35/35] qpid-proton git commit: moved supporting code into proton
package
Posted by gs...@apache.org.
moved supporting code into proton package
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2f4d1ba2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2f4d1ba2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2f4d1ba2
Branch: refs/heads/examples
Commit: 2f4d1ba298ca69a731754d8d8d441d96c4ef211d
Parents: 805cd17
Author: Gordon Sim <gs...@redhat.com>
Authored: Wed Nov 26 17:51:36 2014 +0000
Committer: Gordon Sim <gs...@redhat.com>
Committed: Wed Nov 26 17:51:36 2014 +0000
----------------------------------------------------------------------
proton-c/bindings/python/CMakeLists.txt | 18 +-
proton-c/bindings/python/proton/handlers.py | 409 +++++++++++++
proton-c/bindings/python/proton/reactors.py | 749 +++++++++++++++++++++++
proton-c/bindings/python/proton/utils.py | 115 ++++
tutorial/client.py | 4 +-
tutorial/client_http.py | 2 +-
tutorial/db_recv.py | 3 +-
tutorial/db_send.py | 3 +-
tutorial/helloworld.py | 4 +-
tutorial/helloworld_blocking.py | 4 +-
tutorial/helloworld_direct.py | 4 +-
tutorial/helloworld_direct_tornado.py | 2 +-
tutorial/helloworld_tornado.py | 2 +-
tutorial/proton_handlers.py | 409 -------------
tutorial/proton_reactors.py | 749 -----------------------
tutorial/proton_server.py | 4 +-
tutorial/proton_tornado.py | 2 +-
tutorial/proton_utils.py | 115 ----
tutorial/recurring_timer.py | 2 +-
tutorial/selected_recv.py | 12 +-
tutorial/server.py | 4 +-
tutorial/server_tx.py | 4 +-
tutorial/simple_recv.py | 4 +-
tutorial/simple_send.py | 4 +-
tutorial/sync_client.py | 4 +-
tutorial/tx_recv.py | 4 +-
tutorial/tx_recv_interactive.py | 4 +-
tutorial/tx_send.py | 4 +-
tutorial/tx_send_sync.py | 4 +-
29 files changed, 1331 insertions(+), 1317 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index eb53174..a369661 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -53,9 +53,14 @@ if (NOT PYTHON_SITEARCH_PACKAGES)
endif()
set (pysrc-generated cproton.py)
-set (pysrc proton/__init__.py)
+set (pysrc
+ proton/__init__.py
+ proton/handlers.py
+ proton/reactors.py
+ proton/utils.py
+ )
-macro (py_compile directory files artifacts)
+macro (py_compile artifacts directory files)
foreach (src_file ${files})
install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile ${src_file}
WORKING_DIRECTORY ${directory})")
@@ -67,8 +72,13 @@ macro (py_compile directory files artifacts)
endforeach (src_file)
endmacro(py_compile)
-py_compile(${CMAKE_CURRENT_BINARY_DIR} ${pysrc-generated} CPROTON_ARTIFACTS)
-py_compile(${CMAKE_CURRENT_SOURCE_DIR} ${pysrc} PROTON_ARTIFACTS)
+py_compile(CPROTON_ARTIFACTS ${CMAKE_CURRENT_BINARY_DIR} ${pysrc-generated})
+#FIXME: can't get following to work; only appends artefacts for first in list
+#py_compile(PROTON_ARTIFACTS ${CMAKE_CURRENT_SOURCE_DIR} ${pysrc})
+py_compile(PROTON_ARTIFACTS ${CMAKE_CURRENT_SOURCE_DIR} proton/__init__.py)
+py_compile(PROTON_ARTIFACTS ${CMAKE_CURRENT_SOURCE_DIR} proton/handlers.py)
+py_compile(PROTON_ARTIFACTS ${CMAKE_CURRENT_SOURCE_DIR} proton/reactors.py)
+py_compile(PROTON_ARTIFACTS ${CMAKE_CURRENT_SOURCE_DIR} proton/utils.py)
find_program(EPYDOC_EXE epydoc)
mark_as_advanced (EPYDOC_EXE)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/proton-c/bindings/python/proton/handlers.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/handlers.py b/proton-c/bindings/python/proton/handlers.py
new file mode 100644
index 0000000..c0d9685
--- /dev/null
+++ b/proton-c/bindings/python/proton/handlers.py
@@ -0,0 +1,409 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import heapq, os, Queue, re, socket, time, types
+from proton import dispatch, generate_uuid, PN_ACCEPTED, SASL, symbol, ulong, Url
+from proton import Collector, Connection, Delivery, Described, Endpoint, Event, Link, Terminus, Timeout
+from proton import Message, Handler, ProtonException, Transport, TransportException, ConnectionException
+from select import select
+
+class FlowController(Handler):
+
+ def __init__(self, window=1):
+ self.window = window
+
+ def top_up(self, link):
+ delta = self.window - link.credit
+ link.flow(delta)
+
+ def on_link_local_open(self, event):
+ if event.link.is_receiver:
+ self.top_up(event.link)
+
+ def on_link_remote_open(self, event):
+ if event.link.is_receiver:
+ self.top_up(event.link)
+
+ def on_link_flow(self, event):
+ if event.link.is_receiver:
+ self.top_up(event.link)
+
+ def on_delivery(self, event):
+ if not event.delivery.released and event.delivery.link.is_receiver:
+ self.top_up(event.delivery.link)
+
+def nested_handlers(handlers):
+ # currently only allows for a single level of nesting
+ nested = []
+ for h in handlers:
+ nested.append(h)
+ if hasattr(h, 'handlers'):
+ nested.extend(getattr(h, 'handlers'))
+ return nested
+
+def add_nested_handler(handler, nested):
+ if hasattr(handler, 'handlers'):
+ getattr(handler, 'handlers').append(nested)
+ else:
+ handler.handlers = [nested]
+
+class ScopedHandler(Handler):
+
+ scopes = {
+ "pn_connection": ["connection"],
+ "pn_session": ["session", "connection"],
+ "pn_link": ["link", "session", "connection"],
+ "pn_delivery": ["delivery", "link", "session", "connection"]
+ }
+
+ def on_unhandled(self, method, args):
+ event = args[0]
+ if event.type in [Event.CONNECTION_FINAL, Event.SESSION_FINAL, Event.LINK_FINAL]:
+ return
+ objects = [getattr(event, attr) for attr in self.scopes.get(event.clazz, [])]
+ targets = [getattr(o, "context") for o in objects if hasattr(o, "context")]
+ handlers = [getattr(t, event.type.method) for t in nested_handlers(targets) if hasattr(t, event.type.method)]
+ for h in handlers:
+ h(event)
+
+class OutgoingMessageHandler(Handler):
+ def __init__(self, auto_settle=True, delegate=None):
+ self.auto_settle = auto_settle
+ self.delegate = delegate
+
+ def on_link_flow(self, event):
+ if event.link.is_sender and event.link.credit:
+ self.on_credit(event)
+
+ def on_delivery(self, event):
+ dlv = event.delivery
+ if dlv.released: return
+ if dlv.link.is_sender and dlv.updated:
+ if dlv.remote_state == Delivery.ACCEPTED:
+ self.on_accepted(event)
+ elif dlv.remote_state == Delivery.REJECTED:
+ self.on_rejected(event)
+ elif dlv.remote_state == Delivery.RELEASED:
+ self.on_released(event)
+ elif dlv.remote_state == Delivery.MODIFIED:
+ self.on_modified(event)
+ if dlv.settled:
+ self.on_settled(event)
+ if self.auto_settle:
+ dlv.settle()
+
+ def on_credit(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_credit', event)
+
+ def on_accepted(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_accepted', event)
+
+ def on_rejected(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_rejected', event)
+
+ def on_released(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_released', event)
+
+ def on_modified(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_modified', event)
+
+ def on_settled(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_settled', event)
+
+def recv_msg(delivery):
+ msg = Message()
+ msg.decode(delivery.link.recv(delivery.pending))
+ delivery.link.advance()
+ return msg
+
+class Reject(ProtonException):
+ """
+ An exception that indicate a message should be rejected
+ """
+ pass
+
+class Acking(object):
+ def accept(self, delivery):
+ self.settle(delivery, Delivery.ACCEPTED)
+
+ def reject(self, delivery):
+ self.settle(delivery, Delivery.REJECTED)
+
+ def release(self, delivery, delivered=True):
+ if delivered:
+ self.settle(delivery, Delivery.MODIFIED)
+ else:
+ self.settle(delivery, Delivery.RELEASED)
+
+ def settle(self, delivery, state=None):
+ if state:
+ delivery.update(state)
+ delivery.settle()
+
+class IncomingMessageHandler(Handler, Acking):
+ def __init__(self, auto_accept=True, delegate=None):
+ self.delegate = delegate
+ self.auto_accept = auto_accept
+
+ def on_delivery(self, event):
+ dlv = event.delivery
+ if dlv.released or not dlv.link.is_receiver: return
+ if dlv.readable and not dlv.partial:
+ event.message = recv_msg(dlv)
+ try:
+ self.on_message(event)
+ if self.auto_accept:
+ dlv.update(Delivery.ACCEPTED)
+ dlv.settle()
+ except Reject:
+ dlv.update(Delivery.REJECTED)
+ dlv.settle()
+ elif dlv.updated and dlv.settled:
+ self.on_settled(event)
+
+ def on_message(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_message', event)
+
+ def on_settled(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_settled', event)
+
+class EndpointStateHandler(Handler):
+ def __init__(self, peer_close_is_error=False, delegate=None):
+ self.delegate = delegate
+ self.peer_close_is_error = peer_close_is_error
+
+ def is_local_open(self, endpoint):
+ return endpoint.state & Endpoint.LOCAL_ACTIVE
+
+ def is_local_uninitialised(self, endpoint):
+ return endpoint.state & Endpoint.LOCAL_UNINIT
+
+ def is_local_closed(self, endpoint):
+ return endpoint.state & Endpoint.LOCAL_CLOSED
+
+ def is_remote_open(self, endpoint):
+ return endpoint.state & Endpoint.REMOTE_ACTIVE
+
+ def is_remote_closed(self, endpoint):
+ return endpoint.state & Endpoint.REMOTE_CLOSED
+
+ def print_error(self, endpoint, endpoint_type):
+ if endpoint.remote_condition:
+ print endpoint.remote_condition.description
+ elif self.is_local_open(endpoint) and self.is_remote_closed(endpoint):
+ print "%s closed by peer" % endpoint_type
+
+ def on_link_remote_close(self, event):
+ if event.link.remote_condition:
+ self.on_link_error(event)
+ elif self.is_local_closed(event.link):
+ self.on_link_closed(event)
+ else:
+ self.on_link_closing(event)
+ event.link.close()
+
+ def on_session_remote_close(self, event):
+ if event.session.remote_condition:
+ self.on_session_error(event)
+ elif self.is_local_closed(event.session):
+ self.on_session_closed(event)
+ else:
+ self.on_session_closing(event)
+ event.session.close()
+
+ def on_connection_remote_close(self, event):
+ if event.connection.remote_condition:
+ self.on_connection_error(event)
+ elif self.is_local_closed(event.connection):
+ self.on_connection_closed(event)
+ else:
+ self.on_connection_closing(event)
+ event.connection.close()
+
+ def on_connection_local_open(self, event):
+ if self.is_remote_open(event.connection):
+ self.on_connection_opened(event)
+
+ def on_connection_remote_open(self, event):
+ if self.is_local_open(event.connection):
+ self.on_connection_opened(event)
+ elif self.is_local_uninitialised(event.connection):
+ self.on_connection_opening(event)
+ event.connection.open()
+
+ def on_session_local_open(self, event):
+ if self.is_remote_open(event.session):
+ self.on_session_opened(event)
+
+ def on_session_remote_open(self, event):
+ if self.is_local_open(event.session):
+ self.on_session_opened(event)
+ elif self.is_local_uninitialised(event.session):
+ self.on_session_opening(event)
+ event.session.open()
+
+ def on_link_local_open(self, event):
+ if self.is_remote_open(event.link):
+ self.on_link_opened(event)
+
+ def on_link_remote_open(self, event):
+ if self.is_local_open(event.link):
+ self.on_link_opened(event)
+ elif self.is_local_uninitialised(event.link):
+ self.on_link_opening(event)
+ event.link.open()
+
+ def on_connection_opened(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_connection_opened', event)
+
+ def on_session_opened(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_session_opened', event)
+
+ def on_link_opened(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_link_opened', event)
+
+ def on_connection_opening(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_connection_opening', event)
+
+ def on_session_opening(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_session_opening', event)
+
+ def on_link_opening(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_link_opening', event)
+
+ def on_connection_error(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_connection_error', event)
+ else:
+ self.print_error(event.connection, "connection")
+
+ def on_session_error(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_session_error', event)
+ else:
+ self.print_error(event.session, "session")
+ event.connection.close()
+
+ def on_link_error(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_link_error', event)
+ else:
+ self.print_error(event.link, "link")
+ event.connection.close()
+
+ def on_connection_closed(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_connection_closed', event)
+
+ def on_session_closed(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_session_closed', event)
+
+ def on_link_closed(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_link_closed', event)
+
+ def on_connection_closing(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_connection_closing', event)
+ elif self.peer_close_is_error:
+ self.on_connection_error(event)
+
+ def on_session_closing(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_session_closing', event)
+ elif self.peer_close_is_error:
+ self.on_session_error(event)
+
+ def on_link_closing(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_link_closing', event)
+ elif self.peer_close_is_error:
+ self.on_link_error(event)
+
+class MessagingHandler(Handler, Acking):
+ def __init__(self, prefetch=10, auto_accept=True, auto_settle=True, peer_close_is_error=False):
+ self.handlers = []
+ # FlowController if used needs to see event before
+ # IncomingMessageHandler, as the latter may involve the
+ # delivery being released
+ if prefetch:
+ self.handlers.append(FlowController(prefetch))
+ self.handlers.append(EndpointStateHandler(peer_close_is_error, self))
+ self.handlers.append(IncomingMessageHandler(auto_accept, self))
+ self.handlers.append(OutgoingMessageHandler(auto_settle, self))
+
+class TransactionalAcking(object):
+ def accept(self, delivery, transaction):
+ transaction.accept(delivery)
+
+class TransactionHandler(OutgoingMessageHandler, TransactionalAcking):
+ def __init__(self, auto_settle=True, delegate=None):
+ super(TransactionHandler, self).__init__(auto_settle, delegate)
+
+ def on_settled(self, event):
+ if hasattr(event.delivery, "transaction"):
+ event.transaction = event.delivery.transaction
+ event.delivery.transaction.handle_outcome(event)
+
+ def on_transaction_declared(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_transaction_declared', event)
+
+ def on_transaction_committed(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_transaction_committed', event)
+
+ def on_transaction_aborted(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_transaction_aborted', event)
+
+ def on_transaction_declare_failed(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_transaction_declare_failed', event)
+
+ def on_transaction_commit_failed(self, event):
+ if self.delegate:
+ dispatch(self.delegate, 'on_transaction_commit_failed', event)
+
+class TransactionalClientHandler(Handler, TransactionalAcking):
+ def __init__(self, prefetch=10, auto_accept=False, auto_settle=True, peer_close_is_error=False):
+ super(TransactionalClientHandler, self).__init__()
+ self.handlers = []
+ # FlowController if used needs to see event before
+ # IncomingMessageHandler, as the latter may involve the
+ # delivery being released
+ if prefetch:
+ self.handlers.append(FlowController(prefetch))
+ self.handlers.append(EndpointStateHandler(peer_close_is_error, self))
+ self.handlers.append(IncomingMessageHandler(auto_accept, self))
+ self.handlers.append(TransactionHandler(auto_settle, self))
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/proton-c/bindings/python/proton/reactors.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/reactors.py b/proton-c/bindings/python/proton/reactors.py
new file mode 100644
index 0000000..3e96a56
--- /dev/null
+++ b/proton-c/bindings/python/proton/reactors.py
@@ -0,0 +1,749 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import heapq, os, Queue, socket, time, types
+from proton import dispatch, generate_uuid, PN_ACCEPTED, SASL, symbol, ulong, Url
+from proton import Collector, Connection, Delivery, Described, Endpoint, Event, Link, Terminus, Timeout
+from proton import Message, Handler, ProtonException, Transport, TransportException, ConnectionException
+from select import select
+from proton.handlers import nested_handlers, ScopedHandler
+
+
+class AmqpSocket(object):
+
+ def __init__(self, conn, sock, events, heartbeat=None):
+ self.events = events
+ self.conn = conn
+ self.transport = Transport()
+ if heartbeat: self.transport.idle_timeout = heartbeat
+ self.transport.bind(self.conn)
+ self.socket = sock
+ self.socket.setblocking(0)
+ self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ self.write_done = False
+ self.read_done = False
+ self._closed = False
+
+ def accept(self, force_sasl=True):
+ if force_sasl:
+ sasl = self.transport.sasl()
+ sasl.mechanisms("ANONYMOUS")
+ sasl.server()
+ sasl.done(SASL.OK)
+ #TODO: use SASL anyway if requested by peer
+ return self
+
+ def connect(self, host, port=None, username=None, password=None, force_sasl=True):
+ if username and password:
+ sasl = self.transport.sasl()
+ sasl.plain(username, password)
+ elif force_sasl:
+ sasl = self.transport.sasl()
+ sasl.mechanisms('ANONYMOUS')
+ sasl.client()
+ try:
+ self.socket.connect_ex((host, port or 5672))
+ except socket.gaierror, e:
+ raise ConnectionException("Cannot resolve '%s': %s" % (host, e))
+ return self
+
+ def _closed_cleanly(self):
+ return self.conn.state & Endpoint.LOCAL_CLOSED and self.conn.state & Endpoint.REMOTE_CLOSED
+
+ def closed(self):
+ if not self._closed and self.write_done and self.read_done:
+ self.close()
+ return True
+ else:
+ return False
+
+ def close(self):
+ self.socket.close()
+ self._closed = True
+
+ def fileno(self):
+ return self.socket.fileno()
+
+ def reading(self):
+ if self.read_done: return False
+ c = self.transport.capacity()
+ if c > 0:
+ return True
+ elif c < 0:
+ self.read_done = True
+ return False
+
+ def writing(self):
+ if self.write_done: return False
+ try:
+ p = self.transport.pending()
+ if p > 0:
+ return True
+ elif p < 0:
+ self.write_done = True
+ return False
+ else: # p == 0
+ return False
+ except TransportException, e:
+ self.write_done = True
+ return False
+
+ def readable(self):
+ c = self.transport.capacity()
+ if c > 0:
+ try:
+ data = self.socket.recv(c)
+ if data:
+ self.transport.push(data)
+ else:
+ if not self._closed_cleanly():
+ self.read_done = True
+ self.write_done = True
+ else:
+ self.transport.close_tail()
+ except TransportException, e:
+ print "Error on read: %s" % e
+ self.read_done = True
+ except socket.error, e:
+ print "Error on recv: %s" % e
+ self.read_done = True
+ self.write_done = True
+ elif c < 0:
+ self.read_done = True
+
+ def writable(self):
+ try:
+ p = self.transport.pending()
+ if p > 0:
+ data = self.transport.peek(p)
+ n = self.socket.send(data)
+ self.transport.pop(n)
+ elif p < 0:
+ self.write_done = True
+ except TransportException, e:
+ print "Error on write: %s" % e
+ self.write_done = True
+ except socket.error, e:
+ print "Error on send: %s" % e
+ self.write_done = True
+
+ def removed(self):
+ if not self._closed_cleanly():
+ self.transport.unbind()
+ self.events.dispatch(ApplicationEvent("disconnected", connection=self.conn))
+
+ def tick(self):
+ t = self.transport.tick(time.time())
+ if t: return t - time.time()
+ else: return None
+
+class Acceptor:
+
+ def __init__(self, events, loop, host, port):
+ self.events = events
+ self.loop = loop
+ self.socket = socket.socket()
+ self.socket.setblocking(0)
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.socket.bind((host, port))
+ self.socket.listen(5)
+ self.loop.add(self)
+ self._closed = False
+
+ def closed(self):
+ if self._closed:
+ self.socket.close()
+ return True
+ else:
+ return False
+
+ def close(self):
+ self._closed = True
+
+ def fileno(self):
+ return self.socket.fileno()
+
+ def reading(self):
+ return not self._closed
+
+ def writing(self):
+ return False
+
+ def readable(self):
+ sock, addr = self.socket.accept()
+ if sock:
+ self.loop.add(AmqpSocket(self.events.connection(), sock, self.events).accept())
+
+ def removed(self): pass
+ def tick(self): return None
+
+class EventInjector(object):
+ def __init__(self, events):
+ self.events = events
+ self.queue = Queue.Queue()
+ self.pipe = os.pipe()
+ self._closed = False
+
+ def trigger(self, event):
+ self.queue.put(event)
+ os.write(self.pipe[1], "!")
+
+ def closed(self):
+ return self._closed and self.queue.empty()
+
+ def close(self):
+ self._closed = True
+
+ def fileno(self):
+ return self.pipe[0]
+
+ def reading(self):
+ return True
+
+ def writing(self):
+ return False
+
+ def readable(self):
+ os.read(self.pipe[0], 512)
+ while not self.queue.empty():
+ self.events.dispatch(self.queue.get())
+
+ def removed(self): pass
+ def tick(self): return None
+
+class Events(object):
+ def __init__(self, *handlers):
+ self.collector = Collector()
+ self.handlers = handlers
+
+ def connection(self):
+ conn = Connection()
+ conn.collect(self.collector)
+ return conn
+
+ def process(self):
+ while True:
+ ev = self.collector.peek()
+ if ev:
+ self.dispatch(ev)
+ self.collector.pop()
+ else:
+ return
+
+ def dispatch(self, event):
+ for h in self.handlers:
+ event.dispatch(h)
+
+ @property
+ def next_interval(self):
+ return None
+
+ @property
+ def empty(self):
+ return self.collector.peek() == None
+
+class ExtendedEventType(object):
+ def __init__(self, name):
+ self.name = name
+ self.method = "on_%s" % name
+
+class ApplicationEvent(Event):
+ def __init__(self, typename, connection=None, session=None, link=None, delivery=None, subject=None):
+ self.type = ExtendedEventType(typename)
+ self.subject = subject
+ if delivery:
+ self.context = delivery
+ self.clazz = "pn_delivery"
+ elif link:
+ self.context = link
+ self.clazz = "pn_link"
+ elif session:
+ self.context = session
+ self.clazz = "pn_session"
+ elif connection:
+ self.context = connection
+ self.clazz = "pn_connection"
+ else:
+ self.context = None
+ self.clazz = "none"
+
+ def __repr__(self):
+ objects = [self.context, self.subject]
+ return "%s(%s)" % (self.type.name,
+ ", ".join([str(o) for o in objects if o is not None]))
+
+class StartEvent(ApplicationEvent):
+ def __init__(self, reactor):
+ super(StartEvent, self).__init__("start")
+ self.reactor = reactor
+
+class ScheduledEvents(Events):
+ def __init__(self, *handlers):
+ super(ScheduledEvents, self).__init__(*handlers)
+ self._events = []
+
+ def schedule(self, deadline, event):
+ heapq.heappush(self._events, (deadline, event))
+
+ def process(self):
+ super(ScheduledEvents, self).process()
+ while self._events and self._events[0][0] <= time.time():
+ self.dispatch(heapq.heappop(self._events)[1])
+
+ @property
+ def next_interval(self):
+ if len(self._events):
+ deadline = self._events[0][0]
+ now = time.time()
+ return deadline - now if deadline > now else 0
+ else:
+ return None
+
+ @property
+ def empty(self):
+ return super(ScheduledEvents, self).empty and len(self._events) == 0
+
+def _min(a, b):
+ if a and b: return min(a, b)
+ elif a: return a
+ else: return b
+
+class SelectLoop(object):
+
+ def __init__(self, events):
+ self.events = events
+ self.selectables = []
+ self._abort = False
+
+ def abort(self):
+ self._abort = True
+
+ def add(self, selectable):
+ self.selectables.append(selectable)
+
+ def remove(self, selectable):
+ self.selectables.remove(selectable)
+
+ @property
+ def redundant(self):
+ return self.events.empty and not self.selectables
+
+ @property
+ def aborted(self):
+ return self._abort
+
+ def run(self):
+ while not (self._abort or self.redundant):
+ self.do_work()
+
+ def do_work(self, timeout=None):
+ """@return True if some work was done, False if time-out expired"""
+ self.events.process()
+ if self._abort: return
+
+ stable = False
+ while not stable:
+ reading = []
+ writing = []
+ closed = []
+ tick = None
+ for s in self.selectables:
+ if s.reading(): reading.append(s)
+ if s.writing(): writing.append(s)
+ if s.closed(): closed.append(s)
+ else: tick = _min(tick, s.tick())
+
+ for s in closed:
+ self.selectables.remove(s)
+ s.removed()
+ stable = len(closed) == 0
+
+ if self.redundant:
+ return
+
+ if timeout and timeout < 0:
+ timeout = 0
+ if self.events.next_interval and (timeout is None or self.events.next_interval < timeout):
+ timeout = self.events.next_interval
+ if tick:
+ timeout = _min(tick, timeout)
+ if reading or writing or timeout:
+ readable, writable, _ = select(reading, writing, [], timeout)
+ for s in self.selectables:
+ s.tick()
+ for s in readable:
+ s.readable()
+ for s in writable:
+ s.writable()
+
+ return bool(readable or writable)
+ else:
+ return False
+
+def delivery_tags():
+ count = 1
+ while True:
+ yield str(count)
+ count += 1
+
+def send_msg(sender, msg, tag=None, handler=None, transaction=None):
+ dlv = sender.delivery(tag or next(sender.tags))
+ if transaction:
+ dlv.local.data = [transaction.id]
+ dlv.update(0x34)
+ if handler:
+ dlv.context = handler
+ sender.send(msg.encode())
+ sender.advance()
+ return dlv
+
+def _send_msg(self, msg, tag=None, handler=None, transaction=None):
+ return send_msg(self, msg, tag, handler, transaction)
+
+
+class Transaction(object):
+ def __init__(self, txn_ctrl, handler, settle_before_discharge=False):
+ self.txn_ctrl = txn_ctrl
+ self.handler = handler
+ self.id = None
+ self._declare = None
+ self._discharge = None
+ self.failed = False
+ self._pending = []
+ self.settle_before_discharge = settle_before_discharge
+ self.declare()
+
+ def commit(self):
+ self.discharge(False)
+
+ def abort(self):
+ self.discharge(True)
+
+ def declare(self):
+ self._declare = self._send_ctrl(symbol(u'amqp:declare:list'), [None])
+
+ def discharge(self, failed):
+ self.failed = failed
+ self._discharge = self._send_ctrl(symbol(u'amqp:discharge:list'), [self.id, failed])
+
+ def _send_ctrl(self, descriptor, value):
+ delivery = self.txn_ctrl.send_msg(Message(body=Described(descriptor, value)), handler=self.handler)
+ delivery.transaction = self
+ return delivery
+
+ def accept(self, delivery):
+ self.update(delivery, PN_ACCEPTED)
+ if self.settle_before_discharge:
+ delivery.settle()
+ else:
+ self._pending.append(delivery)
+
+ def update(self, delivery, state=None):
+ if state:
+ delivery.local.data = [self.id, Described(ulong(state), [])]
+ delivery.update(0x34)
+
+ def _release_pending(self):
+ for d in self._pending:
+ d.update(Delivery.RELEASED)
+ d.settle()
+ self._clear_pending()
+
+ def _clear_pending(self):
+ self._pending = []
+
+ def handle_outcome(self, event):
+ if event.delivery == self._declare:
+ if event.delivery.remote.data:
+ self.id = event.delivery.remote.data[0]
+ self.handler.on_transaction_declared(event)
+ elif event.delivery.remote_state == Delivery.REJECTED:
+ self.handler.on_transaction_declare_failed(event)
+ else:
+ print "Unexpected outcome for declare: %s" % event.delivery.remote_state
+ self.handler.on_transaction_declare_failed(event)
+ elif event.delivery == self._discharge:
+ if event.delivery.remote_state == Delivery.REJECTED:
+ if not self.failed:
+ self.handler.on_transaction_commit_failed(event)
+ self._release_pending() # make this optional?
+ else:
+ if self.failed:
+ self.handler.on_transaction_aborted(event)
+ self._release_pending()
+ else:
+ self.handler.on_transaction_committed(event)
+ self._clear_pending()
+
+class LinkOption(object):
+ def apply(self, link): pass
+ def test(self, link): return True
+
+class AtMostOnce(LinkOption):
+ def apply(self, link):
+ link.snd_settle_mode = Link.SND_SETTLED
+
+class AtLeastOnce(LinkOption):
+ def apply(self, link):
+ link.snd_settle_mode = Link.SND_UNSETTLED
+ link.rcv_settle_mode = Link.RCV_FIRST
+
+class SenderOption(LinkOption):
+ def apply(self, sender): pass
+ def test(self, link): return link.is_sender
+
+class ReceiverOption(LinkOption):
+ def apply(self, receiver): pass
+ def test(self, link): return link.is_receiver
+
+class Filter(ReceiverOption):
+ def __init__(self, filter_set={}):
+ self.filter_set = filter_set
+
+ def apply(self, receiver):
+ receiver.source.filter.put_dict(self.filter_set)
+
+class Selector(Filter):
+ def __init__(self, value, name='selector'):
+ super(Selector, self).__init__({symbol(name): Described(symbol('apache.org:selector-filter:string'), value)})
+
+def _apply_link_options(options, link):
+ if options:
+ if isinstance(options, list):
+ for o in options:
+ if o.test(link): o.apply(link)
+ else:
+ if options.test(link): options.apply(link)
+
+
+class MessagingContext(object):
+ def __init__(self, conn, handler=None, ssn=None):
+ self.conn = conn
+ if handler:
+ self.conn.context = handler
+ self.conn._mc = self
+ self.ssn = ssn
+ self.txn_ctrl = None
+
+ def _get_handler(self):
+ return self.conn.context
+
+ def _set_handler(self, value):
+ self.conn.context = value
+
+ handler = property(_get_handler, _set_handler)
+
+ def create_sender(self, target, source=None, name=None, handler=None, tags=None, options=None):
+ snd = self._get_ssn().sender(name or self._get_id(target, source))
+ if source:
+ snd.source.address = source
+ if target:
+ snd.target.address = target
+ if handler:
+ snd.context = handler
+ snd.tags = tags or delivery_tags()
+ snd.send_msg = types.MethodType(_send_msg, snd)
+ _apply_link_options(options, snd)
+ snd.open()
+ return snd
+
+ def create_receiver(self, source, target=None, name=None, dynamic=False, handler=None, options=None):
+ rcv = self._get_ssn().receiver(name or self._get_id(source, target))
+ if source:
+ rcv.source.address = source
+ if dynamic:
+ rcv.source.dynamic = True
+ if target:
+ rcv.target.address = target
+ if handler:
+ rcv.context = handler
+ _apply_link_options(options, rcv)
+ rcv.open()
+ return rcv
+
+ def create_session(self):
+ return MessageContext(conn=None, ssn=self._new_ssn())
+
+ def declare_transaction(self, handler=None, settle_before_discharge=False):
+ if not self.txn_ctrl:
+ self.txn_ctrl = self.create_sender(None, name="txn-ctrl")
+ self.txn_ctrl.target.type = Terminus.COORDINATOR
+ self.txn_ctrl.target.capabilities.put_object(symbol(u'amqp:local-transactions'))
+ return Transaction(self.txn_ctrl, handler, settle_before_discharge)
+
+ def close(self):
+ if self.ssn:
+ self.ssn.close()
+ if self.conn:
+ self.conn.close()
+
+ def _get_id(self, remote, local):
+ if local and remote: "%s-%s-%s" % (self.conn.container, remote, local)
+ elif local: return "%s-%s" % (self.conn.container, local)
+ elif remote: return "%s-%s" % (self.conn.container, remote)
+ else: return "%s-%s" % (self.conn.container, str(generate_uuid()))
+
+ def _get_ssn(self):
+ if not self.ssn:
+ self.ssn = self._new_ssn()
+ self.ssn.context = self
+ return self.ssn
+
+ def _new_ssn(self):
+ ssn = self.conn.session()
+ ssn.open()
+ return ssn
+
+ def on_session_remote_close(self, event):
+ if self.conn:
+ self.conn.close()
+
+class Connector(Handler):
+ def attach_to(self, loop):
+ self.loop = loop
+
+ def _connect(self, connection):
+ host, port = connection.address.next()
+ #print "connecting to %s:%i" % (host, port)
+ heartbeat = connection.heartbeat if hasattr(connection, 'heartbeat') else None
+ self.loop.add(AmqpSocket(connection, socket.socket(), self.loop.events, heartbeat=heartbeat).connect(host, port))
+
+ def on_connection_local_open(self, event):
+ if hasattr(event.connection, "address"):
+ self._connect(event.connection)
+
+ def on_connection_remote_open(self, event):
+ if hasattr(event.connection, "reconnect"):
+ event.connection.reconnect.reset()
+
+ def on_disconnected(self, event):
+ if hasattr(event.connection, "reconnect"):
+ delay = event.connection.reconnect.next()
+ if delay == 0:
+ print "Disconnected, reconnecting..."
+ self._connect(event.connection)
+ else:
+ print "Disconnected will try to reconnect after %s seconds" % delay
+ self.loop.schedule(time.time() + delay, connection=event.connection, subject=self)
+ else:
+ print "Disconnected"
+
+ def on_timer(self, event):
+ if event.subject == self and event.connection:
+ self._connect(event.connection)
+
+class Backoff(object):
+ def __init__(self):
+ self.delay = 0
+
+ def reset(self):
+ self.delay = 0
+
+ def next(self):
+ current = self.delay
+ if current == 0:
+ self.delay = 0.1
+ else:
+ self.delay = min(10, 2*current)
+ return current
+
+class Urls(object):
+ def __init__(self, values):
+ self.values = [Url(v) for v in values]
+ self.i = iter(self.values)
+
+ def __iter__(self):
+ return self
+
+ def _as_pair(self, url):
+ return (url.host, url.port)
+
+ def next(self):
+ try:
+ return self._as_pair(self.i.next())
+ except StopIteration:
+ self.i = iter(self.values)
+ return self._as_pair(self.i.next())
+
+class EventLoop(object):
+ def __init__(self, *handlers):
+ self.connector = Connector()
+ h = [self.connector, ScopedHandler()]
+ h.extend(nested_handlers(handlers))
+ self.events = ScheduledEvents(*h)
+ self.loop = SelectLoop(self.events)
+ self.connector.attach_to(self)
+ self.trigger = None
+ self.container_id = str(generate_uuid())
+
+ def connect(self, url=None, urls=None, address=None, handler=None, reconnect=None, heartbeat=None):
+ context = MessagingContext(self.events.connection(), handler=handler)
+ context.conn.container = self.container_id or str(generate_uuid())
+ context.conn.heartbeat = heartbeat
+ if url: context.conn.address = Urls([url])
+ elif urls: context.conn.address = Urls(urls)
+ elif address: context.conn.address = address
+ else: raise ValueError("One of url, urls or address required")
+ if reconnect:
+ context.conn.reconnect = reconnect
+ elif reconnect is None:
+ context.conn.reconnect = Backoff()
+ context.conn.open()
+ return context
+
+ def listen(self, url):
+ host, port = Urls([url]).next()
+ return Acceptor(self.events, self, host, port)
+
+ def schedule(self, deadline, connection=None, session=None, link=None, delivery=None, subject=None):
+ self.events.schedule(deadline, ApplicationEvent("timer", connection, session, link, delivery, subject))
+
+ def get_event_trigger(self):
+ if not self.trigger or self.trigger.closed():
+ self.trigger = EventInjector(self.events)
+ self.add(self.trigger)
+ return self.trigger
+
+ def add(self, selectable):
+ self.loop.add(selectable)
+
+ def remove(self, selectable):
+ self.loop.remove(selectable)
+
+ def run(self):
+ self.events.dispatch(StartEvent(self))
+ self.loop.run()
+
+ def stop(self):
+ self.loop.abort()
+
+ def do_work(self, timeout=None):
+ return self.loop.do_work(timeout)
+
+EventLoop.DEFAULT = EventLoop()
+
+def connect(url=None, urls=None, address=None, handler=None, reconnect=None, eventloop=None, heartbeat=None):
+ if not eventloop:
+ eventloop = EventLoop.DEFAULT
+ return eventloop.connect(url=url, urls=urls, address=address, handler=handler, reconnect=reconnect, heartbeat=heartbeat)
+
+def run(eventloop=None):
+ if not eventloop:
+ eventloop = EventLoop.DEFAULT
+ eventloop.run()
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/proton-c/bindings/python/proton/utils.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/utils.py b/proton-c/bindings/python/proton/utils.py
new file mode 100644
index 0000000..db23e55
--- /dev/null
+++ b/proton-c/bindings/python/proton/utils.py
@@ -0,0 +1,115 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+import Queue, socket, time
+from proton import ConnectionException, Endpoint, Handler, Message, Url
+from proton.reactors import AmqpSocket, Events, MessagingContext, SelectLoop, send_msg
+from proton.handlers import ScopedHandler
+
+class BlockingLink(object):
+ def __init__(self, connection, link):
+ self.connection = connection
+ self.link = link
+ self.connection.wait(lambda: not (self.link.state & Endpoint.REMOTE_UNINIT),
+ msg="Opening link %s" % link.name)
+
+ def close(self):
+ self.connection.wait(not (self.link.state & Endpoint.REMOTE_ACTIVE),
+ msg="Closing link %s" % link.name)
+
+ # Access to other link attributes.
+ def __getattr__(self, name): return getattr(self.link, name)
+
+class BlockingSender(BlockingLink):
+ def __init__(self, connection, sender):
+ super(BlockingSender, self).__init__(connection, sender)
+
+ def send_msg(self, msg):
+ delivery = send_msg(self.link, msg)
+ self.connection.wait(lambda: delivery.settled, msg="Sending on sender %s" % self.link.name)
+
+class BlockingReceiver(BlockingLink):
+ def __init__(self, connection, receiver, credit=1):
+ super(BlockingReceiver, self).__init__(connection, receiver)
+ if credit: receiver.flow(credit)
+
+class BlockingConnection(Handler):
+ def __init__(self, url, timeout=None):
+ self.timeout = timeout
+ self.events = Events(ScopedHandler())
+ self.loop = SelectLoop(self.events)
+ self.context = MessagingContext(self.loop.events.connection(), handler=self)
+ if isinstance(url, basestring):
+ self.url = Url(url)
+ else:
+ self.url = url
+ self.loop.add(
+ AmqpSocket(self.context.conn, socket.socket(), self.events).connect(self.url.host, self.url.port))
+ self.context.conn.open()
+ self.wait(lambda: not (self.context.conn.state & Endpoint.REMOTE_UNINIT),
+ msg="Opening connection")
+
+ def create_sender(self, address, handler=None):
+ return BlockingSender(self, self.context.create_sender(address, handler=handler))
+
+ def create_receiver(self, address, credit=1, dynamic=False, handler=None):
+ return BlockingReceiver(
+ self, self.context.create_receiver(address, dynamic=dynamic, handler=handler), credit=credit)
+
+ def close(self):
+ self.context.conn.close()
+ self.wait(lambda: not (self.context.conn.state & Endpoint.REMOTE_ACTIVE),
+ msg="Closing connection")
+
+ def run(self):
+ """ Hand control over to the event loop (e.g. if waiting indefinitely for incoming messages) """
+ self.loop.run()
+
+ def wait(self, condition, timeout=False, msg=None):
+ """Call do_work until condition() is true"""
+ if timeout is False:
+ timeout = self.timeout
+ if timeout is None:
+ while not condition():
+ self.loop.do_work()
+ else:
+ deadline = time.time() + timeout
+ while not condition():
+ if not self.loop.do_work(deadline - time.time()):
+ txt = "Connection %s timed out" % self.url
+ if msg: txt += ": " + msg
+ raise Timeout(txt)
+
+ def on_link_remote_close(self, event):
+ if event.link.state & Endpoint.LOCAL_ACTIVE:
+ self.closed(event.link.remote_condition)
+
+ def on_connection_remote_close(self, event):
+ if event.connection.state & Endpoint.LOCAL_ACTIVE:
+ self.closed(event.connection.remote_condition)
+
+ def on_disconnected(self, event):
+ raise ConnectionException("Connection %s disconnected" % self.url);
+
+ def closed(self, error=None):
+ txt = "Connection %s closed" % self.url
+ if error:
+ txt += " due to: %s" % error
+ else:
+ txt += " by peer"
+ raise ConnectionException(txt)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/client.py
----------------------------------------------------------------------
diff --git a/tutorial/client.py b/tutorial/client.py
index f2bc866..a649dec 100755
--- a/tutorial/client.py
+++ b/tutorial/client.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
-from proton_reactors import EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import EventLoop
class Client(MessagingHandler):
def __init__(self, host, address, requests):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/client_http.py
----------------------------------------------------------------------
diff --git a/tutorial/client_http.py b/tutorial/client_http.py
index 9e7333b..ab7b1cd 100755
--- a/tutorial/client_http.py
+++ b/tutorial/client_http.py
@@ -19,7 +19,7 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
+from proton.handlers import MessagingHandler
from proton_tornado import TornadoLoop
from tornado.ioloop import IOLoop
import tornado.web
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/db_recv.py
----------------------------------------------------------------------
diff --git a/tutorial/db_recv.py b/tutorial/db_recv.py
index 1dfb3e3..5779403 100755
--- a/tutorial/db_recv.py
+++ b/tutorial/db_recv.py
@@ -18,7 +18,8 @@
# under the License.
#
-from proton_events import ApplicationEvent, MessagingHandler, EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import ApplicationEvent, EventLoop
from db_common import Db
class Recv(MessagingHandler):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/db_send.py
----------------------------------------------------------------------
diff --git a/tutorial/db_send.py b/tutorial/db_send.py
index 4701fae..b3a26fd 100755
--- a/tutorial/db_send.py
+++ b/tutorial/db_send.py
@@ -21,7 +21,8 @@
import Queue
import time
from proton import Message
-from proton_events import ApplicationEvent, MessagingHandler, EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import ApplicationEvent, EventLoop
from db_common import Db
class Send(MessagingHandler):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/helloworld.py
----------------------------------------------------------------------
diff --git a/tutorial/helloworld.py b/tutorial/helloworld.py
index 35a93da..5aa1482 100755
--- a/tutorial/helloworld.py
+++ b/tutorial/helloworld.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
-from proton_reactors import EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import EventLoop
class HelloWorld(MessagingHandler):
def __init__(self, server, address):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/helloworld_blocking.py
----------------------------------------------------------------------
diff --git a/tutorial/helloworld_blocking.py b/tutorial/helloworld_blocking.py
index 2c4dca2..9c5e062 100755
--- a/tutorial/helloworld_blocking.py
+++ b/tutorial/helloworld_blocking.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_utils import BlockingConnection
-from proton_handlers import IncomingMessageHandler
+from proton.utils import BlockingConnection
+from proton.handlers import IncomingMessageHandler
class HelloWorldReceiver(IncomingMessageHandler):
def on_message(self, event):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/helloworld_direct.py
----------------------------------------------------------------------
diff --git a/tutorial/helloworld_direct.py b/tutorial/helloworld_direct.py
index 652039b..35ac597 100755
--- a/tutorial/helloworld_direct.py
+++ b/tutorial/helloworld_direct.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
-from proton_reactors import EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import EventLoop
class HelloWorld(MessagingHandler):
def __init__(self, server, address):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/helloworld_direct_tornado.py
----------------------------------------------------------------------
diff --git a/tutorial/helloworld_direct_tornado.py b/tutorial/helloworld_direct_tornado.py
index 1a8365a..45926c6 100755
--- a/tutorial/helloworld_direct_tornado.py
+++ b/tutorial/helloworld_direct_tornado.py
@@ -19,7 +19,7 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
+from proton.handlers import MessagingHandler
from proton_tornado import TornadoLoop
class HelloWorld(MessagingHandler):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/helloworld_tornado.py
----------------------------------------------------------------------
diff --git a/tutorial/helloworld_tornado.py b/tutorial/helloworld_tornado.py
index 541eec4..6a82b69 100755
--- a/tutorial/helloworld_tornado.py
+++ b/tutorial/helloworld_tornado.py
@@ -19,7 +19,7 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
+from proton.handlers import MessagingHandler
from proton_tornado import TornadoLoop
class HelloWorld(MessagingHandler):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/proton_handlers.py
----------------------------------------------------------------------
diff --git a/tutorial/proton_handlers.py b/tutorial/proton_handlers.py
deleted file mode 100644
index 1381f31..0000000
--- a/tutorial/proton_handlers.py
+++ /dev/null
@@ -1,409 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-import heapq, os, Queue, re, socket, time, types
-from proton import dispatch, generate_uuid, PN_ACCEPTED, SASL, symbol, ulong, Url
-from proton import Collector, Connection, Delivery, Described, Endpoint, Event, Link, Terminus, Timeout
-from proton import Message, Handler, ProtonException, Transport, TransportException, ConnectionException
-from select import select
-
-class FlowController(Handler):
-
- def __init__(self, window=1):
- self.window = window
-
- def top_up(self, link):
- delta = self.window - link.credit
- link.flow(delta)
-
- def on_link_local_open(self, event):
- if event.link.is_receiver:
- self.top_up(event.link)
-
- def on_link_remote_open(self, event):
- if event.link.is_receiver:
- self.top_up(event.link)
-
- def on_link_flow(self, event):
- if event.link.is_receiver:
- self.top_up(event.link)
-
- def on_delivery(self, event):
- if not event.delivery.released and event.delivery.link.is_receiver:
- self.top_up(event.delivery.link)
-
-def nested_handlers(handlers):
- # currently only allows for a single level of nesting
- nested = []
- for h in handlers:
- nested.append(h)
- if hasattr(h, 'handlers'):
- nested.extend(getattr(h, 'handlers'))
- return nested
-
-def add_nested_handler(handler, nested):
- if hasattr(handler, 'handlers'):
- getattr(handler, 'handlers').append(nested)
- else:
- handler.handlers = [nested]
-
-class ScopedHandler(Handler):
-
- scopes = {
- "pn_connection": ["connection"],
- "pn_session": ["session", "connection"],
- "pn_link": ["link", "session", "connection"],
- "pn_delivery": ["delivery", "link", "session", "connection"]
- }
-
- def on_unhandled(self, method, args):
- event = args[0]
- if event.type in [Event.CONNECTION_FINAL, Event.SESSION_FINAL, Event.LINK_FINAL]:
- return
- objects = [getattr(event, attr) for attr in self.scopes.get(event.clazz, [])]
- targets = [getattr(o, "context") for o in objects if hasattr(o, "context")]
- handlers = [getattr(t, event.type.method) for t in nested_handlers(targets) if hasattr(t, event.type.method)]
- for h in handlers:
- h(event)
-
-class OutgoingMessageHandler(Handler):
- def __init__(self, auto_settle=True, delegate=None):
- self.auto_settle = auto_settle
- self.delegate = delegate
-
- def on_link_flow(self, event):
- if event.link.is_sender and event.link.credit:
- self.on_credit(event)
-
- def on_delivery(self, event):
- dlv = event.delivery
- if dlv.released: return
- if dlv.link.is_sender and dlv.updated:
- if dlv.remote_state == Delivery.ACCEPTED:
- self.on_accepted(event)
- elif dlv.remote_state == Delivery.REJECTED:
- self.on_rejected(event)
- elif dlv.remote_state == Delivery.RELEASED:
- self.on_released(event)
- elif dlv.remote_state == Delivery.MODIFIED:
- self.on_modified(event)
- if dlv.settled:
- self.on_settled(event)
- if self.auto_settle:
- dlv.settle()
-
- def on_credit(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_credit', event)
-
- def on_accepted(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_accepted', event)
-
- def on_rejected(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_rejected', event)
-
- def on_released(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_released', event)
-
- def on_modified(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_modified', event)
-
- def on_settled(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_settled', event)
-
-def recv_msg(delivery):
- msg = Message()
- msg.decode(delivery.link.recv(delivery.pending))
- delivery.link.advance()
- return msg
-
-class Reject(ProtonException):
- """
- An exception that indicate a message should be rejected
- """
- pass
-
-class Acking(object):
- def accept(self, delivery):
- self.settle(delivery, Delivery.ACCEPTED)
-
- def reject(self, delivery):
- self.settle(delivery, Delivery.REJECTED)
-
- def release(self, delivery, delivered=True):
- if delivered:
- self.settle(delivery, Delivery.MODIFIED)
- else:
- self.settle(delivery, Delivery.RELEASED)
-
- def settle(self, delivery, state=None):
- if state:
- delivery.update(state)
- delivery.settle()
-
-class IncomingMessageHandler(Handler, Acking):
- def __init__(self, auto_accept=True, delegate=None):
- self.delegate = delegate
- self.auto_accept = auto_accept
-
- def on_delivery(self, event):
- dlv = event.delivery
- if dlv.released or not dlv.link.is_receiver: return
- if dlv.readable and not dlv.partial:
- event.message = recv_msg(dlv)
- try:
- self.on_message(event)
- if self.auto_accept:
- dlv.update(Delivery.ACCEPTED)
- dlv.settle()
- except Reject:
- dlv.update(Delivery.REJECTED)
- dlv.settle()
- elif dlv.updated and dlv.settled:
- self.on_settled(event)
-
- def on_message(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_message', event)
-
- def on_settled(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_settled', event)
-
-class EndpointStateHandler(Handler):
- def __init__(self, peer_close_is_error=False, delegate=None):
- self.delegate = delegate
- self.peer_close_is_error = peer_close_is_error
-
- def is_local_open(self, endpoint):
- return endpoint.state & Endpoint.LOCAL_ACTIVE
-
- def is_local_uninitialised(self, endpoint):
- return endpoint.state & Endpoint.LOCAL_UNINIT
-
- def is_local_closed(self, endpoint):
- return endpoint.state & Endpoint.LOCAL_CLOSED
-
- def is_remote_open(self, endpoint):
- return endpoint.state & Endpoint.REMOTE_ACTIVE
-
- def is_remote_closed(self, endpoint):
- return endpoint.state & Endpoint.REMOTE_CLOSED
-
- def print_error(self, endpoint, endpoint_type):
- if endpoint.remote_condition:
- print endpoint.remote_condition.description
- elif self.is_local_open(endpoint) and self.is_remote_closed(endpoint):
- print "%s closed by peer" % endpoint_type
-
- def on_link_remote_close(self, event):
- if event.link.remote_condition:
- self.on_link_error(event)
- elif self.is_local_closed(event.link):
- self.on_link_closed(event)
- else:
- self.on_link_closing(event)
- event.link.close()
-
- def on_session_remote_close(self, event):
- if event.session.remote_condition:
- self.on_session_error(event)
- elif self.is_local_closed(event.session):
- self.on_session_closed(event)
- else:
- self.on_session_closing(event)
- event.session.close()
-
- def on_connection_remote_close(self, event):
- if event.connection.remote_condition:
- self.on_connection_error(event)
- elif self.is_local_closed(event.connection):
- self.on_connection_closed(event)
- else:
- self.on_connection_closing(event)
- event.connection.close()
-
- def on_connection_local_open(self, event):
- if self.is_remote_open(event.connection):
- self.on_connection_opened(event)
-
- def on_connection_remote_open(self, event):
- if self.is_local_open(event.connection):
- self.on_connection_opened(event)
- elif self.is_local_uninitialised(event.connection):
- self.on_connection_opening(event)
- event.connection.open()
-
- def on_session_local_open(self, event):
- if self.is_remote_open(event.session):
- self.on_session_opened(event)
-
- def on_session_remote_open(self, event):
- if self.is_local_open(event.session):
- self.on_session_opened(event)
- elif self.is_local_uninitialised(event.session):
- self.on_session_opening(event)
- event.session.open()
-
- def on_link_local_open(self, event):
- if self.is_remote_open(event.link):
- self.on_link_opened(event)
-
- def on_link_remote_open(self, event):
- if self.is_local_open(event.link):
- self.on_link_opened(event)
- elif self.is_local_uninitialised(event.link):
- self.on_link_opening(event)
- event.link.open()
-
- def on_connection_opened(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_connection_opened', event)
-
- def on_session_opened(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_session_opened', event)
-
- def on_link_opened(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_link_opened', event)
-
- def on_connection_opening(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_connection_opening', event)
-
- def on_session_opening(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_session_opening', event)
-
- def on_link_opening(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_link_opening', event)
-
- def on_connection_error(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_connection_error', event)
- else:
- self.print_error(event.connection, "connection")
-
- def on_session_error(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_session_error', event)
- else:
- self.print_error(event.session, "session")
- event.connection.close()
-
- def on_link_error(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_link_error', event)
- else:
- self.print_error(event.link, "link")
- event.connection.close()
-
- def on_connection_closed(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_connection_closed', event)
-
- def on_session_closed(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_session_closed', event)
-
- def on_link_closed(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_link_closed', event)
-
- def on_connection_closing(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_connection_closing', event)
- elif self.peer_close_is_error:
- self.on_connection_error(event)
-
- def on_session_closing(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_session_closing', event)
- elif self.peer_close_is_error:
- self.on_session_error(event)
-
- def on_link_closing(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_link_closing', event)
- elif self.peer_close_is_error:
- self.on_link_error(event)
-
-class MessagingHandler(Handler, Acking):
- def __init__(self, prefetch=10, auto_accept=True, auto_settle=True, peer_close_is_error=False):
- self.handlers = []
- # FlowController if used needs to see event before
- # IncomingMessageHandler, as the latter may involve the
- # delivery being released
- if prefetch:
- self.handlers.append(FlowController(prefetch))
- self.handlers.append(EndpointStateHandler(peer_close_is_error, self))
- self.handlers.append(IncomingMessageHandler(auto_accept, self))
- self.handlers.append(OutgoingMessageHandler(auto_settle, self))
-
-class TransactionalAcking(object):
- def accept(self, delivery, transaction, settle=True):
- transaction.accept(delivery, settle)
-
-class TransactionHandler(OutgoingMessageHandler, TransactionalAcking):
- def __init__(self, auto_settle=True, delegate=None):
- super(TransactionHandler, self).__init__(auto_settle, delegate)
-
- def on_settled(self, event):
- if hasattr(event.delivery, "transaction"):
- event.transaction = event.delivery.transaction
- event.delivery.transaction.handle_outcome(event)
-
- def on_transaction_declared(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_transaction_declared', event)
-
- def on_transaction_committed(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_transaction_committed', event)
-
- def on_transaction_aborted(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_transaction_aborted', event)
-
- def on_transaction_declare_failed(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_transaction_declare_failed', event)
-
- def on_transaction_commit_failed(self, event):
- if self.delegate:
- dispatch(self.delegate, 'on_transaction_commit_failed', event)
-
-class TransactionalClientHandler(Handler, TransactionalAcking):
- def __init__(self, prefetch=10, auto_accept=False, auto_settle=True, peer_close_is_error=False):
- super(TransactionalClientHandler, self).__init__()
- self.handlers = []
- # FlowController if used needs to see event before
- # IncomingMessageHandler, as the latter may involve the
- # delivery being released
- if prefetch:
- self.handlers.append(FlowController(prefetch))
- self.handlers.append(EndpointStateHandler(peer_close_is_error, self))
- self.handlers.append(IncomingMessageHandler(auto_accept, self))
- self.handlers.append(TransactionHandler(auto_settle, self))
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[24/35] qpid-proton git commit: Revert "PROTON-630: add setup.py for
python bindings"
Posted by gs...@apache.org.
Revert "PROTON-630: add setup.py for python bindings"
This reverts commit 4252758bd3772470bd255d034d3abea157429504.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/f5cbab5e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/f5cbab5e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/f5cbab5e
Branch: refs/heads/examples
Commit: f5cbab5eafeae5bf9e713db1c897c77b2022bfdc
Parents: 2276c09
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Fri Nov 21 22:32:34 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Sat Nov 22 06:03:01 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/python/CMakeLists.txt | 79 +++++++++-----------
proton-c/bindings/python/setup.py.in | 107 ---------------------------
2 files changed, 34 insertions(+), 152 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f5cbab5e/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index b8cdb57..c7eb4aa 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -17,8 +17,8 @@
# under the License.
#
-# NB For python the SWIG module name must have the same name as the
-# input .i file for CMake to generate the correct dependencies
+# NB For python the SWIG module name must have the same name as the input .i file for CMake to generate the
+# correct dependencies
set(CMAKE_SWIG_FLAGS "-threads")
@@ -39,15 +39,27 @@ set_target_properties(${SWIG_MODULE_cproton_REAL_NAME}
find_package(PythonInterp REQUIRED)
-# configure the files needed for generating Pypi packages. Packages
-# can be generated by running "python setup.py" from the build
-# directory.
-get_filename_component(PN_SWIG_PYTHON_C_WRAPPER
- ${swig_generated_file_fullname} NAME)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/proton.py
- ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
- ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY)
+if (CHECK_SYSINSTALL_PYTHON)
+ execute_process(COMMAND ${PYTHON_EXECUTABLE}
+ -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True)"
+ OUTPUT_VARIABLE PYTHON_SITEARCH_PACKAGES_DEFAULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+else ()
+ set (PYTHON_SITEARCH_PACKAGES_DEFAULT ${BINDINGS_DIR}/python)
+endif ()
+
+if (NOT PYTHON_SITEARCH_PACKAGES)
+ set (PYTHON_SITEARCH_PACKAGES ${PYTHON_SITEARCH_PACKAGES_DEFAULT})
+endif()
+
+install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
+install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
+install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
+install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
find_program(EPYDOC_EXE epydoc)
mark_as_advanced (EPYDOC_EXE)
@@ -63,37 +75,14 @@ if (EPYDOC_EXE)
${OPTIONAL_ARG})
endif (EPYDOC_EXE)
-if (CHECK_SYSINSTALL_PYTHON)
- # use the python-native install paths:
-
- install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} setup.py sdist
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
- install(CODE "execute_process(COMMAND
- ${PYTHON_EXECUTABLE} setup.py --proton-install-prefix ${CMAKE_INSTALL_PREFIX} install
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
-
-else ()
- # install the bindings using the CMAKE path variables:
- set (PYTHON_SITEARCH_PACKAGES ${BINDINGS_DIR}/python)
-
- install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
- install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
- install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
- install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
-
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py
- ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc
- ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo
- ${CMAKE_CURRENT_SOURCE_DIR}/proton.py
- ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc
- ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo
- DESTINATION ${PYTHON_SITEARCH_PACKAGES}
- COMPONENT Python)
- install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
- DESTINATION ${PYTHON_SITEARCH_PACKAGES}
- COMPONENT Python)
-endif()
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py
+ ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc
+ ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo
+ ${CMAKE_CURRENT_SOURCE_DIR}/proton.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc
+ ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo
+ DESTINATION ${PYTHON_SITEARCH_PACKAGES}
+ COMPONENT Python)
+install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
+ DESTINATION ${PYTHON_SITEARCH_PACKAGES}
+ COMPONENT Python)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f5cbab5e/proton-c/bindings/python/setup.py.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py.in b/proton-c/bindings/python/setup.py.in
deleted file mode 100644
index 94f3dfc..0000000
--- a/proton-c/bindings/python/setup.py.in
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/env python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-from distutils.core import setup, Extension
-import logging
-import os
-import sys
-
-_c_module = '@SWIG_MODULE_cproton_REAL_NAME@'
-_src_file = '@PN_SWIG_PYTHON_C_WRAPPER@'
-_version = '@PN_VERSION@'
-_release = 0
-
-if "--proton-install-prefix" in sys.argv:
- # special option used only if the python headers and library have been
- # installed to a non-standard directory. This can be done during 'make
- # install' from the proton build tree by using the cmake option
- # -DCMAKE_INSTALL_PREFIX. The location of the headers and library must be
- # specified so we can build the binding's C extension.
- i = sys.argv.index("--proton-install-prefix") + 1
- if i >= len(sys.argv):
- raise ValueError("--proton-install-prefix requires a path parameter.")
- _prefix = sys.argv[i]
- # remove the proton arguments to they don't conflict with setup.py's other
- # command arguments:
- del sys.argv[i]
- sys.argv.remove("--proton-install-prefix")
- _destdir = os.environ.get("DESTDIR", "")
- if _destdir and os.path.isabs(_prefix):
- # DESTDIR may be used on unix systems to put the entire install tree
- # under a particular directory. However, if _prefix is an absolute
- # path, os.path.join will discard DESTDIR, so strip off the leading
- # separator
- _prefix = _prefix.lstrip(os.path.sep)
-
- _inc_dir = os.path.join(_destdir,
- _prefix,
- '@INCLUDE_INSTALL_DIR@')
- _lib_dir = os.path.join(_destdir,
- _prefix,
- '@LIB_INSTALL_DIR@')
-
- swig_ext = Extension(_c_module, [_src_file],
- libraries=['qpid-proton'],
- include_dirs=[_inc_dir],
- library_dirs=[_lib_dir])
-else:
- swig_ext = Extension(_c_module, [_src_file],
- libraries=['qpid-proton'])
-
-_help_description = """Before you can build or install these bindings, you must
-first install version @PN_VERSION@ of the Proton development library
-(libqpid-proton) and its C header files. These files must be available in order
-to build this packages' C-based extension.
-
-Packages for the Proton development library may be provided by your system's
-distribution. For example, the qpid-proton-c-devel RPM is available for
-Centos/RHEL via EPEL. A libqpid-proton2-dev deb file is available for Ubuntu
-via the Apache Qpid PPA (ppa:qpid/released).
-
-If your distribution does not make these packages available, you can download
-the Proton sources directly from the Apache Qpid project:
-
- http://qpid.apache.org
-
-This package is compatible with the @PN_VERSION@ release of the Proton
-development library.
-
-If you need additional help, see http://qpid.apache.org/discussion.html
-"""
-
-_long_description = """This package contains the Python bindings for the Apache
-QPID Proton library.\n%s""" % _help_description
-
-try:
- setup(name="python-qpid-proton",
- version="%s-%d" % (_version, _release),
- author="Apache Qpid",
- author_email="dev@qpid.apache.org",
- py_modules=["proton", "cproton"],
- url="http://qpid.apache.org/",
- description="Python bindings for the Proton library",
- long_description=_long_description,
- license="Apache Software License",
- classifiers=["License :: OSI Approved :: Apache Software License",
- "Intended Audience :: Developers",
- "Programming Language :: Python"],
- ext_modules=[swig_ext])
-except:
- logging.error("setup failed!\n%s", _help_description)
- raise
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[27/35] qpid-proton git commit: PROTON-752: Provide a non-blocking
means to receive messages in Ruby.
Posted by gs...@apache.org.
PROTON-752: Provide a non-blocking means to receive messages in Ruby.
To avoid changing the APIs or their intentions, a new class method is
added:
Qpid::Proton::Receiver::receive_and_call
The method takes as arguments either an existing instance of Messenger
or else the parameters to create an instance, and also a code block to
be called with each message received.
The messenger is then put into passive mode and a new thread started. It
then monitors the messenger and, when a new message is received, passes
it to the block for processing.
To exit the messenger, the code would call Messenger#interrupt. The
thread then exits and the messenger stops processing.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/0820a372
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/0820a372
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/0820a372
Branch: refs/heads/examples
Commit: 0820a3722b6ab5c2a5a4dbfac3428de7d22c1c6e
Parents: 2335465
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Fri Nov 21 09:57:40 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Mon Nov 24 12:58:10 2014 -0500
----------------------------------------------------------------------
examples/messenger/ruby/passive_recv.rb | 122 +++---------------
.../bindings/ruby/lib/qpid_proton/messenger.rb | 128 +++++++++++++++++++
.../bindings/ruby/lib/qpid_proton/selectable.rb | 21 ++-
3 files changed, 163 insertions(+), 108 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0820a372/examples/messenger/ruby/passive_recv.rb
----------------------------------------------------------------------
diff --git a/examples/messenger/ruby/passive_recv.rb b/examples/messenger/ruby/passive_recv.rb
index a3625ac..878c801 100644
--- a/examples/messenger/ruby/passive_recv.rb
+++ b/examples/messenger/ruby/passive_recv.rb
@@ -31,110 +31,26 @@ end
addresses = ["~0.0.0.0"] if addresses.empty?
-messenger = Qpid::Proton::Messenger.new
-messenger.passive = true
-
-begin
- messenger.start
-rescue ProtonError => error
- puts "ERROR: #{error.message}"
- puts error.backtrace.join("\n")
- exit
-end
-
-addresses.each do |address|
- begin
- messenger.subscribe(address)
- rescue Qpid::Proton::ProtonError => error
- puts "ERROR: #{error.message}"
- exit
- end
-end
-
-msg = Qpid::Proton::Message.new
-
-read_array = []
-write_array = []
-selectables = {}
-
-loop do
-
- # wait for incoming messages
- sel = messenger.selectable
- while !sel.nil?
- if sel.terminal?
- selectables.delete(sel.fileno)
- read_array.delete(sel)
- write_array.delete(sel)
- sel.free
- else
- sel.capacity
- sel.pending
- if !sel.registered?
- read_array << sel
- write_array << sel
- selectables[sel.fileno] = sel
- sel.registered = true
- end
- end
- sel = messenger.selectable
+msgr = Qpid::Proton::Messenger.receive_and_call(nil, :addresses => addresses) do |message|
+ puts "Address: #{message.address}"
+ subject = message.subject || "(no subject)"
+ puts "Subject: #{subject}"
+ puts "Body: #{message.body}"
+ puts "Properties: #{message.properties}"
+ puts "Instructions: #{message.instructions}"
+ puts "Annotations: #{message.annotations}"
+
+ if message.reply_to
+ puts "=== Sending a reply to #{message.reply_to}"
+ reply = Qpid::Proton::Message.new
+ reply.address = message.reply_to
+ reply.subject = "RE: #{message.subject}"
+ reply.content = "Thanks for the message!"
+
+ messenger.put(reply)
+ messenger.send
end
- unless selectables.empty?
- rarray = []; read_array.each {|fd| rarray << fd.to_io }
- warray = []; write_array.each {|fd| warray << fd.to_io }
-
- if messenger.deadline > 0.0
- result = IO.select(rarray, warray, nil, messenger.deadline)
- else
- result = IO.select(rarray, warray)
- end
-
- unless result.nil? && result.empty?
- result.flatten.each do |io|
- sel = selectables[io.fileno]
-
- sel.writable if sel.pending > 0
- sel.readable if sel.capacity > 0
- end
- end
-
- begin
- messenger.receive(10)
- rescue Qpid::Proton::ProtonError => error
- puts "ERROR: #{error.message}"
- exit
- end
-
- while messenger.incoming.nonzero?
- begin
- messenger.get(msg)
- rescue Qpid::Proton::Error => error
- puts "ERROR: #{error.message}"
- exit
- end
-
- puts "Address: #{msg.address}"
- subject = msg.subject || "(no subject)"
- puts "Subject: #{subject}"
- puts "Body: #{msg.body}"
- puts "Properties: #{msg.properties}"
- puts "Instructions: #{msg.instructions}"
- puts "Annotations: #{msg.annotations}"
-
- if msg.reply_to
- puts "=== Sending a reply to #{msg.reply_to}"
- reply = Qpid::Proton::Message.new
- reply.address = msg.reply_to
- reply.subject = "RE: #{msg.subject}"
- reply.content = "Thanks for the message!"
-
- messenger.put(reply)
- messenger.send
- end
- end
- end
end
-messenger.stop
-
+Thread.list[1].join
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0820a372/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index 5a16c50..a8f7330 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -75,6 +75,7 @@ module Qpid # :nodoc:
#
def initialize(name = nil)
@impl = Cproton.pn_messenger(name)
+ @interrupted = false
@selectables = {}
ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
end
@@ -407,6 +408,7 @@ module Qpid # :nodoc:
# originated the interrupt.
#
def interrupt
+ @interrupted = true
Cproton.pn_messenger_interrupt(@impl)
end
@@ -695,6 +697,132 @@ module Qpid # :nodoc:
!window.nil? && [Float, Fixnum].include?(window.class)
end
+ public
+
+
+ #--
+ # The following are class methods.
+ #++
+
+ # Receives messages from the provided instance of Messenger, and then
+ # calls the supplied block for each Message received. If no instance
+ # is provided then one is created using the provided list of options.
+ #
+ # This starts a new thread which will loop, waiting for and processing
+ # incoming messages.
+ #
+ # ==== Arguments
+ #
+ # * messenger - The instance of Messenger.
+ #
+ # ==== Options
+ #
+ # * :addresses - An array of addresses to which to subscribe. Addresses
+ # are required if no Messenger was supplied.
+ #
+ # ==== Examples
+ #
+ # # create a Messenger
+ # messenger = Qpid::Proton::Messenger.new
+ # # begin receiving messages
+ # Qpid::Proton::Messenger.receive_and_call(messenger) do |message|
+ # puts "Received: #{message.body}"
+ # end
+ #
+ def self.receive_and_call(messenger, options = {}, &block)
+ # if the messenger wasn't created then create one
+ if messenger.nil?
+ # if no addresses were supplied then raise an exception
+ raise ArgumentError.new("no addresses") if options[:addresses].nil?
+ # if no block was supplied then raise an exception
+ raise ArgumentError.new("missing block") if block.nil?
+
+ messenger = Qpid::Proton::Messenger.new
+ Array(options[:addresses]).each do |address|
+ messenger.subscribe address
+ end
+ end
+
+ # set the messenger to passive mode
+ messenger.passive = true
+ messenger.start
+
+ Thread.new(messenger, block) do |messenger, &block|
+ read_array = []
+ write_array = []
+ selectables = {}
+
+ aborted = false
+
+ while !aborted do
+ # refresh the list of fds to be processed
+ sel = messenger.selectable
+ while !sel.nil?
+ if sel.terminal?
+ selectables.delete(sel.fileno)
+ read_array.delete(sel)
+ write_array.delete(sel)
+ sel.free
+ else
+ sel.capacity
+ sel.pending
+ if !sel.registered?
+ read_array << sel
+ write_array << sel
+ selectables[sel.fileno] = sel
+ sel.registered = true
+ end
+ end
+ sel = messenger.selectable
+ end
+
+ unless selectables.empty?
+ rarray = []; read_array.each {|fd| rarray << fd.to_io}
+ warray = []; write_array.each {|fd| warray << fd.to_io}
+
+ if messenger.deadline > 0.0
+ result = IO.select(rarray, warray, nil, messenger.deadline)
+ else
+ result = IO.select(rarray, warray)
+ end
+
+ unless result.nil? && result.empty?
+ result.flatten.each do |io|
+ sel = selectables[io.fileno]
+
+ sel.writable if sel.pending > 0
+ sel.readable if sel.capacity > 0
+ end
+ end
+
+ messenger.receive(10)
+
+ # if this was interrupted then exit
+ messenger.instance_eval do
+ aborted = @interrupted
+ @interrupted = false
+ end
+
+ if !aborted
+ # process each message received
+ while messenger.incoming.nonzero?
+ message = Qpid::Proton::Message.new
+ messenger.get(message)
+ yield message
+ end
+ end
+
+ end
+
+ end
+
+ end
+
+ # return the messenger
+ messenger
+
+ end
+
end
end
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0820a372/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
index 33554cd..8b1214a 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
@@ -37,6 +37,14 @@ module Qpid # :nodoc:
@impl = impl
@io = nil
@freed = false
+
+ ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
+ end
+
+ def self.finalize!(impl) # :nodoc:
+ proc {
+ impl.free
+ }
end
# Returns the underlying file descriptor.
@@ -48,7 +56,11 @@ module Qpid # :nodoc:
end
def to_io
- @io ||= IO.new(fileno)
+ if @io.nil?
+ fileno = self.fileno
+ @io = IO.new(fileno)
+ end
+ @io
end
# The number of bytes the selectable is capable of consuming.
@@ -97,15 +109,14 @@ module Qpid # :nodoc:
end
def to_s
- "fileno=#{self.fileno} registered=#{self.registered?} terminal=#{self.terminal?}"
+ return super if @freed
+ "#{super} fileno=#{self.fileno} registered=#{self.registered?} terminal=#{self.terminal?}"
end
def free
- return if @freed
@freed = true
@messenger.unregister_selectable(fileno)
- @io.close unless @io.nil?
- Cproton.pn_selectable_free(@impl)
+ @messenger = nil
@impl = nil
end
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[30/35] qpid-proton git commit: Revert "NO-JIRA: Fix protocol tracing
for transactional states."
Posted by gs...@apache.org.
Revert "NO-JIRA: Fix protocol tracing for transactional states."
This reverts commit 061da30be815467217ecb365cfc1d7581367ba32.
The fix had already been made by:
4c6f212 * PROTON-723: based on gordon's patch, added support for the coordinator target
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/36f81e09
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/36f81e09
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/36f81e09
Branch: refs/heads/examples
Commit: 36f81e0941e616b1b3ed0df4035f994ea40df159
Parents: 061da30
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Nov 25 09:44:02 2014 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 25 09:44:02 2014 -0500
----------------------------------------------------------------------
proton-c/src/protocol.py | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/36f81e09/proton-c/src/protocol.py
----------------------------------------------------------------------
diff --git a/proton-c/src/protocol.py b/proton-c/src/protocol.py
index ae65150..685e63b 100644
--- a/proton-c/src/protocol.py
+++ b/proton-c/src/protocol.py
@@ -22,7 +22,6 @@ doc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "transport.xml"))
mdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "messaging.xml"))
tdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "transactions.xml"))
sdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "security.xml"))
-tdoc = mllib.xml_parse(os.path.join(os.path.dirname(__file__), "transactions.xml"))
def eq(attr, value):
return lambda nd: nd[attr] == value
@@ -31,14 +30,12 @@ TYPES = doc.query["amqp/section/type", eq("@class", "composite")] + \
mdoc.query["amqp/section/type", eq("@class", "composite")] + \
tdoc.query["amqp/section/type", eq("@class", "composite")] + \
sdoc.query["amqp/section/type", eq("@class", "composite")] + \
- mdoc.query["amqp/section/type", eq("@provides", "section")] + \
- tdoc.query["amqp/section/type", eq("@class", "composite")]
-
+ mdoc.query["amqp/section/type", eq("@provides", "section")]
RESTRICTIONS = {}
COMPOSITES = {}
for type in doc.query["amqp/section/type"] + mdoc.query["amqp/section/type"] + \
- sdoc.query["amqp/section/type"] + tdoc.query["amqp/section/type"]:
+ sdoc.query["amqp/section/type"]:
source = type["@source"]
if source:
RESTRICTIONS[type["@name"]] = source
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[32/35] qpid-proton git commit: Merge branch 'master' into examples
Posted by gs...@apache.org.
Merge branch 'master' into examples
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d02fdad1
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d02fdad1
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d02fdad1
Branch: refs/heads/examples
Commit: d02fdad17003d17f9a6ebce71757ab39f6bdc241
Parents: 0fd8b1f 36f81e0
Author: Gordon Sim <gs...@redhat.com>
Authored: Wed Nov 26 16:03:07 2014 +0000
Committer: Gordon Sim <gs...@redhat.com>
Committed: Wed Nov 26 16:03:07 2014 +0000
----------------------------------------------------------------------
proton-c/CMakeLists.txt | 1 +
.../bindings/perl/lib/qpid/proton/Message.pm | 2 +-
proton-c/bindings/perl/lib/qpid/proton/utils.pm | 2 +-
proton-c/bindings/perl/lib/qpid_proton.pm | 1 +
proton-c/bindings/python/CMakeLists.txt | 83 +-
proton-c/bindings/python/proton.py | 3875 -----------------
proton-c/bindings/python/proton/__init__.py | 3894 ++++++++++++++++++
proton-c/bindings/python/setup.py.in | 107 -
proton-c/bindings/ruby/lib/qpid_proton.rb | 4 +-
proton-c/bindings/ruby/lib/qpid_proton/array.rb | 10 +-
proton-c/bindings/ruby/lib/qpid_proton/data.rb | 10 +-
.../bindings/ruby/lib/qpid_proton/described.rb | 4 +-
.../ruby/lib/qpid_proton/exception_handling.rb | 53 +-
.../bindings/ruby/lib/qpid_proton/exceptions.rb | 8 +-
.../bindings/ruby/lib/qpid_proton/filters.rb | 8 +-
proton-c/bindings/ruby/lib/qpid_proton/hash.rb | 6 +-
.../bindings/ruby/lib/qpid_proton/mapping.rb | 11 +-
.../bindings/ruby/lib/qpid_proton/message.rb | 8 +-
.../ruby/lib/qpid_proton/message_format.rb | 8 +-
.../bindings/ruby/lib/qpid_proton/messenger.rb | 92 +-
.../bindings/ruby/lib/qpid_proton/selectable.rb | 8 +-
.../bindings/ruby/lib/qpid_proton/strings.rb | 6 +-
.../ruby/lib/qpid_proton/subscription.rb | 8 +-
.../bindings/ruby/lib/qpid_proton/tracker.rb | 8 +-
.../ruby/lib/qpid_proton/tracker_status.rb | 8 +-
.../bindings/ruby/lib/qpid_proton/version.rb | 11 +-
.../ruby/spec/qpid/proton/messenger_spec.rb | 16 +
proton-c/include/proton/cproton.i | 2 +-
proton-c/include/proton/sasl.h | 20 +-
proton-c/include/proton/ssl.h | 6 +
proton-c/include/proton/transport.h | 20 +-
proton-c/src/engine/engine-internal.h | 36 +-
proton-c/src/messenger/messenger.c | 3 +-
proton-c/src/posix/driver.c | 8 +-
proton-c/src/proton.c | 10 +-
proton-c/src/sasl/sasl-internal.h | 6 +-
proton-c/src/sasl/sasl.c | 294 +-
proton-c/src/ssl/openssl.c | 452 +-
proton-c/src/ssl/ssl-internal.h | 6 +-
proton-c/src/ssl/ssl_stub.c | 22 +-
proton-c/src/tests/engine.c | 3 +
proton-c/src/transport/autodetect.c | 135 +
proton-c/src/transport/autodetect.h | 40 +
proton-c/src/transport/transport.c | 422 +-
proton-c/src/windows/driver.c | 8 +-
proton-c/src/windows/schannel.c | 371 +-
.../qpid/proton/amqp/messaging/Accepted.java | 3 +
.../qpid/proton/amqp/messaging/Modified.java | 3 +
.../qpid/proton/amqp/messaging/Rejected.java | 2 +
.../qpid/proton/amqp/messaging/Released.java | 3 +
.../qpid/proton/amqp/transaction/Declared.java | 3 +
.../qpid/proton/codec/impl/ArrayElement.java | 13 +
.../apache/qpid/proton/codec/impl/DataImpl.java | 10 +
.../qpid/proton/engine/impl/SaslImpl.java | 7 +-
proton-j/src/main/resources/cengine.py | 5 +-
proton-j/src/main/resources/csasl.py | 14 +-
proton-j/src/main/resources/cssl.py | 3 +
.../qpid/proton/codec/impl/DataImplTest.java | 84 +
tests/python/proton_tests/common.py | 13 +-
tests/python/proton_tests/engine.py | 3 -
tests/python/proton_tests/sasl.py | 14 +-
tests/ruby/proton_tests/smoke.rb | 4 +-
62 files changed, 5354 insertions(+), 4946 deletions(-)
----------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[06/35] qpid-proton git commit: PROTON-749: Remove transport pointer
from ssl and sasl structs - Change means that API pn_ssl_t and pn_sasl_t
pointers are really pn_transport_t pointers and need to be cast internally on
use
Posted by gs...@apache.org.
PROTON-749: Remove transport pointer from ssl and sasl structs
- Change means that API pn_ssl_t and pn_sasl_t pointers are really
pn_transport_t pointers and need to be cast internally on use
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/df029005
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/df029005
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/df029005
Branch: refs/heads/examples
Commit: df02900597cb25de9841b6d8c4763acdc0a40fad
Parents: 120639b
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Aug 14 18:22:39 2014 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 17 14:55:36 2014 -0500
----------------------------------------------------------------------
proton-c/src/engine/engine-internal.h | 7 +-
proton-c/src/sasl/sasl-internal.h | 4 +-
proton-c/src/sasl/sasl.c | 132 +++++++++------
proton-c/src/ssl/openssl.c | 258 ++++++++++++++++-------------
proton-c/src/ssl/ssl-internal.h | 4 +-
proton-c/src/transport/transport.c | 8 +-
proton-c/src/windows/schannel.c | 164 ++++++++++--------
7 files changed, 326 insertions(+), 251 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index 40a839b..3960acf 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -108,10 +108,13 @@ typedef struct pn_io_layer_t {
extern const pn_io_layer_t pni_passthru_layer;
+typedef struct pni_sasl_t pni_sasl_t;
+typedef struct pni_ssl_t pni_ssl_t;
+
struct pn_transport_t {
pn_tracer_t tracer;
- pn_sasl_t *sasl;
- pn_ssl_t *ssl;
+ pni_sasl_t *sasl;
+ pni_ssl_t *ssl;
pn_connection_t *connection; // reference counted
pn_dispatcher_t *disp;
char *remote_container;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl-internal.h b/proton-c/src/sasl/sasl-internal.h
index e362547..15fd0b1 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -48,13 +48,13 @@ ssize_t pn_sasl_input(pn_sasl_t *sasl, const char *bytes, size_t available);
*/
ssize_t pn_sasl_output(pn_sasl_t *sasl, char *bytes, size_t size);
-void pn_sasl_trace(pn_sasl_t *sasl, pn_trace_t trace);
+void pn_sasl_trace(pn_transport_t *transport, pn_trace_t trace);
/** Destructor for the given SASL layer.
*
* @param[in] sasl the SASL object to free. No longer valid on
* return.
*/
-void pn_sasl_free(pn_sasl_t *sasl);
+void pn_sasl_free(pn_transport_t *transport);
#endif /* sasl-internal.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 5034eb7..ffa310b 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -34,8 +34,7 @@
#include "util.h"
-struct pn_sasl_t {
- pn_transport_t *transport;
+struct pni_sasl_t {
pn_dispatcher_t *disp;
char *mechanisms;
char *remote_mechanisms;
@@ -53,6 +52,18 @@ struct pn_sasl_t {
bool output_bypass;
};
+static inline pn_transport_t *get_transport_internal(pn_sasl_t *sasl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ((pn_transport_t *)sasl);
+}
+
+static inline pni_sasl_t *get_sasl_internal(pn_sasl_t *sasl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return sasl ? ((pn_transport_t *)sasl)->sasl : NULL;
+}
+
static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available);
static ssize_t pn_input_read_sasl(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
static ssize_t pn_output_write_sasl_header(pn_transport_t* transport, unsigned int layer, char* bytes, size_t size);
@@ -89,7 +100,7 @@ const pn_io_layer_t sasl_layer = {
pn_sasl_t *pn_sasl(pn_transport_t *transport)
{
if (!transport->sasl) {
- pn_sasl_t *sasl = (pn_sasl_t *) malloc(sizeof(pn_sasl_t));
+ pni_sasl_t *sasl = (pni_sasl_t *) malloc(sizeof(pni_sasl_t));
sasl->disp = pn_dispatcher(1, transport);
sasl->disp->batch = false;
@@ -109,15 +120,16 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
sasl->output_bypass = false;
transport->sasl = sasl;
- sasl->transport = transport;
transport->io_layers[PN_IO_SASL] = &sasl_headers_layer;
}
- return transport->sasl;
+ // The actual external pn_sasl_t pointer is a pointer to its enclosing pn_transport_t
+ return (pn_sasl_t *)transport;
}
-pn_sasl_state_t pn_sasl_state(pn_sasl_t *sasl)
+pn_sasl_state_t pn_sasl_state(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
if (!sasl->configured) return PN_SASL_CONF;
if (sasl->outcome == PN_SASL_NONE) {
@@ -133,19 +145,22 @@ pn_sasl_state_t pn_sasl_state(pn_sasl_t *sasl)
}
}
-void pn_sasl_mechanisms(pn_sasl_t *sasl, const char *mechanisms)
+void pn_sasl_mechanisms(pn_sasl_t *sasl0, const char *mechanisms)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (!sasl) return;
sasl->mechanisms = pn_strdup(mechanisms);
}
-const char *pn_sasl_remote_mechanisms(pn_sasl_t *sasl)
+const char *pn_sasl_remote_mechanisms(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
return sasl ? sasl->remote_mechanisms : NULL;
}
-ssize_t pn_sasl_send(pn_sasl_t *sasl, const char *bytes, size_t size)
+ssize_t pn_sasl_send(pn_sasl_t *sasl0, const char *bytes, size_t size)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
if (pn_buffer_size(sasl->send_data)) {
// XXX: need better error
@@ -159,8 +174,9 @@ ssize_t pn_sasl_send(pn_sasl_t *sasl, const char *bytes, size_t size)
}
}
-size_t pn_sasl_pending(pn_sasl_t *sasl)
+size_t pn_sasl_pending(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl && pn_buffer_size(sasl->recv_data)) {
return pn_buffer_size(sasl->recv_data);
} else {
@@ -168,8 +184,9 @@ size_t pn_sasl_pending(pn_sasl_t *sasl)
}
}
-ssize_t pn_sasl_recv(pn_sasl_t *sasl, char *bytes, size_t size)
+ssize_t pn_sasl_recv(pn_sasl_t *sasl0, char *bytes, size_t size)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (!sasl) return PN_ARG_ERR;
size_t bsize = pn_buffer_size(sasl->recv_data);
@@ -183,30 +200,34 @@ ssize_t pn_sasl_recv(pn_sasl_t *sasl, char *bytes, size_t size)
}
}
-void pn_sasl_client(pn_sasl_t *sasl)
+void pn_sasl_client(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
sasl->client = true;
sasl->configured = true;
}
}
-void pn_sasl_server(pn_sasl_t *sasl)
+void pn_sasl_server(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
sasl->client = false;
sasl->configured = true;
}
}
-void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
+void pn_sasl_allow_skip(pn_sasl_t *sasl0, bool allow)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl)
sasl->allow_skip = allow;
}
-void pn_sasl_plain(pn_sasl_t *sasl, const char *username, const char *password)
+void pn_sasl_plain(pn_sasl_t *sasl0, const char *username, const char *password)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (!sasl) return;
const char *user = username ? username : "";
@@ -221,42 +242,47 @@ void pn_sasl_plain(pn_sasl_t *sasl, const char *username, const char *password)
iresp[usize + 1] = 0;
memmove(iresp + usize + 2, pass, psize);
- pn_sasl_mechanisms(sasl, "PLAIN");
- pn_sasl_send(sasl, iresp, size);
- pn_sasl_client(sasl);
+ pn_sasl_mechanisms(sasl0, "PLAIN");
+ pn_sasl_send(sasl0, iresp, size);
+ pn_sasl_client(sasl0);
free(iresp);
}
-void pn_sasl_done(pn_sasl_t *sasl, pn_sasl_outcome_t outcome)
+void pn_sasl_done(pn_sasl_t *sasl0, pn_sasl_outcome_t outcome)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
if (sasl) {
sasl->outcome = outcome;
}
}
-pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl)
+pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
return sasl ? sasl->outcome : PN_SASL_NONE;
}
-void pn_sasl_trace(pn_sasl_t *sasl, pn_trace_t trace)
+void pn_sasl_trace(pn_transport_t *transport, pn_trace_t trace)
{
- sasl->disp->trace = trace;
+ transport->sasl->disp->trace = trace;
}
-void pn_sasl_free(pn_sasl_t *sasl)
+void pn_sasl_free(pn_transport_t *transport)
{
- if (sasl) {
- free(sasl->mechanisms);
- free(sasl->remote_mechanisms);
- pn_buffer_free(sasl->send_data);
- pn_buffer_free(sasl->recv_data);
- pn_dispatcher_free(sasl->disp);
- free(sasl);
+ if (transport) {
+ pni_sasl_t *sasl = transport->sasl;
+ if (sasl) {
+ free(sasl->mechanisms);
+ free(sasl->remote_mechanisms);
+ pn_buffer_free(sasl->send_data);
+ pn_buffer_free(sasl->recv_data);
+ pn_dispatcher_free(sasl->disp);
+ free(sasl);
+ }
}
}
-void pn_client_init(pn_sasl_t *sasl)
+void pn_client_init(pni_sasl_t *sasl)
{
pn_buffer_memory_t bytes = pn_buffer_memory(sasl->send_data);
pn_post_frame(sasl->disp, 0, "DL[sz]", SASL_INIT, sasl->mechanisms,
@@ -264,7 +290,7 @@ void pn_client_init(pn_sasl_t *sasl)
pn_buffer_clear(sasl->send_data);
}
-void pn_server_init(pn_sasl_t *sasl)
+void pn_server_init(pni_sasl_t *sasl)
{
// XXX
char *mechs[16];
@@ -295,13 +321,15 @@ void pn_server_init(pn_sasl_t *sasl)
pn_post_frame(sasl->disp, 0, "DL[@T[*s]]", SASL_MECHANISMS, PN_SYMBOL, count, mechs);
}
-void pn_server_done(pn_sasl_t *sasl)
+void pn_server_done(pn_sasl_t *sasl0)
{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
pn_post_frame(sasl->disp, 0, "DL[B]", SASL_OUTCOME, sasl->outcome);
}
-void pn_sasl_process(pn_sasl_t *sasl)
+void pn_sasl_process(pn_transport_t *transport)
{
+ pni_sasl_t *sasl = transport->sasl;
if (!sasl->configured) return;
if (!sasl->sent_init) {
@@ -321,7 +349,7 @@ void pn_sasl_process(pn_sasl_t *sasl)
}
if (!sasl->client && sasl->outcome != PN_SASL_NONE && !sasl->sent_done) {
- pn_server_done(sasl);
+ pn_server_done((pn_sasl_t *)transport);
sasl->sent_done = true;
}
@@ -335,15 +363,16 @@ void pn_sasl_process(pn_sasl_t *sasl)
}
}
-ssize_t pn_sasl_input(pn_sasl_t *sasl, const char *bytes, size_t available)
+ssize_t pn_sasl_input(pn_transport_t *transport, const char *bytes, size_t available)
{
+ pni_sasl_t *sasl = transport->sasl;
ssize_t n = pn_dispatcher_input(sasl->disp, bytes, available);
if (n < 0) return n;
- pn_sasl_process(sasl);
+ pn_sasl_process(transport);
if (sasl->rcvd_done) {
- if (pn_sasl_state(sasl) == PN_SASL_PASS) {
+ if (pn_sasl_state((pn_sasl_t *)transport) == PN_SASL_PASS) {
if (n) {
return n;
} else {
@@ -358,12 +387,13 @@ ssize_t pn_sasl_input(pn_sasl_t *sasl, const char *bytes, size_t available)
}
}
-ssize_t pn_sasl_output(pn_sasl_t *sasl, char *bytes, size_t size)
+ssize_t pn_sasl_output(pn_transport_t *transport, char *bytes, size_t size)
{
- pn_sasl_process(sasl);
+ pn_sasl_process(transport);
+ pni_sasl_t *sasl = transport->sasl;
if (sasl->disp->available == 0 && sasl->sent_done) {
- if (pn_sasl_state(sasl) == PN_SASL_PASS) {
+ if (pn_sasl_state((pn_sasl_t *)transport) == PN_SASL_PASS) {
return PN_EOS;
} else {
// XXX: should probably do something better here
@@ -376,7 +406,7 @@ ssize_t pn_sasl_output(pn_sasl_t *sasl, char *bytes, size_t size)
int pn_do_init(pn_dispatcher_t *disp)
{
- pn_sasl_t *sasl = disp->transport->sasl;
+ pni_sasl_t *sasl = disp->transport->sasl;
pn_bytes_t mech;
pn_bytes_t recv;
int err = pn_scan_args(disp, "D.[sz]", &mech, &recv);
@@ -389,14 +419,14 @@ int pn_do_init(pn_dispatcher_t *disp)
int pn_do_mechanisms(pn_dispatcher_t *disp)
{
- pn_sasl_t *sasl = disp->transport->sasl;
+ pni_sasl_t *sasl = disp->transport->sasl;
sasl->rcvd_init = true;
return 0;
}
int pn_do_recv(pn_dispatcher_t *disp)
{
- pn_sasl_t *sasl = disp->transport->sasl;
+ pni_sasl_t *sasl = disp->transport->sasl;
pn_bytes_t recv;
int err = pn_scan_args(disp, "D.[z]", &recv);
if (err) return err;
@@ -416,7 +446,7 @@ int pn_do_response(pn_dispatcher_t *disp)
int pn_do_outcome(pn_dispatcher_t *disp)
{
- pn_sasl_t *sasl = disp->transport->sasl;
+ pni_sasl_t *sasl = disp->transport->sasl;
uint8_t outcome;
int err = pn_scan_args(disp, "D.[B]", &outcome);
if (err) return err;
@@ -433,7 +463,7 @@ int pn_do_outcome(pn_dispatcher_t *disp)
static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- pn_sasl_t *sasl = transport->sasl;
+ pni_sasl_t *sasl = transport->sasl;
if (available > 0) {
if (available < SASL_HEADER_LEN) {
if (memcmp(bytes, SASL_HEADER, available) == 0 ||
@@ -472,9 +502,9 @@ static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int
static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- pn_sasl_t *sasl = transport->sasl;
+ pni_sasl_t *sasl = transport->sasl;
if (!sasl->input_bypass) {
- ssize_t n = pn_sasl_input(sasl, bytes, available);
+ ssize_t n = pn_sasl_input(transport, bytes, available);
if (n != PN_EOS) return n;
sasl->input_bypass = true;
@@ -486,7 +516,7 @@ static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer,
static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t size)
{
- pn_sasl_t *sasl = transport->sasl;
+ pni_sasl_t *sasl = transport->sasl;
if (sasl->disp->trace & PN_TRACE_FRM)
pn_transport_logf(transport, " -> %s", "SASL");
assert(size >= SASL_HEADER_LEN);
@@ -501,14 +531,14 @@ static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned i
static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available)
{
- pn_sasl_t *sasl = transport->sasl;
+ pni_sasl_t *sasl = transport->sasl;
if (!sasl->output_bypass) {
// this accounts for when pn_do_error is invoked, e.g. by idle timeout
ssize_t n;
if (transport->close_sent) {
n = PN_EOS;
} else {
- n = pn_sasl_output(sasl, bytes, available);
+ n = pn_sasl_output(transport, bytes, available);
}
if (n != PN_EOS) return n;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index 7202f7a..41e36b5 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -86,8 +86,7 @@ struct pn_ssl_domain_t {
};
-struct pn_ssl_t {
- pn_transport_t *transport;
+struct pni_ssl_t {
pn_ssl_domain_t *domain;
const char *session_id;
const char *peer_hostname;
@@ -117,6 +116,18 @@ struct pn_ssl_t {
bool write_blocked; // SSL blocked until data is written to network
};
+static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ((pn_transport_t *)ssl);
+}
+
+static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ssl ? ((pn_transport_t *)ssl)->ssl : NULL;
+}
+
struct pn_ssl_session_t {
const char *id;
SSL_SESSION *session;
@@ -139,53 +150,55 @@ static ssize_t process_output_unknown( pn_transport_t *transport, unsigned int l
static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
-static int init_ssl_socket( pn_ssl_t * );
-static void release_ssl_socket( pn_ssl_t * );
+static int init_ssl_socket(pn_transport_t *, pni_ssl_t *);
+static void release_ssl_socket( pni_ssl_t * );
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
static void ssl_session_free( pn_ssl_session_t *);
static size_t buffered_output( pn_transport_t *transport );
// @todo: used to avoid littering the code with calls to printf...
-static void _log_error(pn_ssl_t *ssl, const char *fmt, ...)
+static void ssl_log(pn_transport_t *transport, const char *fmt, ...)
{
- va_list ap;
- va_start(ap, fmt);
- pn_transport_vlogf(ssl ? ssl->transport : NULL, fmt, ap);
- va_end(ap);
-}
-
-// @todo: used to avoid littering the code with calls to printf...
-static void _log(pn_ssl_t *ssl, const char *fmt, ...)
-{
- if (PN_TRACE_DRV & ssl->trace) {
+ if (PN_TRACE_DRV & transport->ssl->trace) {
va_list ap;
va_start(ap, fmt);
- pn_transport_vlogf(ssl->transport, fmt, ap);
+ pn_transport_vlogf(transport, fmt, ap);
va_end(ap);
}
}
-// log an error and dump the SSL error stack
-static void _log_ssl_error(pn_ssl_t *ssl, const char *fmt, ...)
+static void ssl_log_flush(pn_transport_t* transport)
{
char buf[128]; // see "man ERR_error_string_n()"
+ unsigned long err = ERR_get_error();
+ while (err) {
+ ERR_error_string_n(err, buf, sizeof(buf));
+ pn_transport_logf(transport, "%s", buf);
+ err = ERR_get_error();
+ }
+}
+
+// log an error and dump the SSL error stack
+static void ssl_log_error(const char *fmt, ...)
+{
va_list ap;
if (fmt) {
va_start(ap, fmt);
- pn_transport_vlogf(ssl ? ssl->transport : NULL, fmt, ap);
+ pn_transport_vlogf(NULL, fmt, ap);
va_end(ap);
}
+ char buf[128]; // see "man ERR_error_string_n()"
unsigned long err = ERR_get_error();
while (err) {
ERR_error_string_n(err, buf, sizeof(buf));
- _log_error(ssl, "%s", buf);
+ pn_transport_logf(NULL, "%s", buf);
err = ERR_get_error();
}
}
-static void _log_clear_data(pn_ssl_t *ssl, const char *data, size_t len)
+static void ssl_log_clear_data(pni_ssl_t *ssl, const char *data, size_t len)
{
if (PN_TRACE_RAW & ssl->trace) {
fprintf(stderr, "SSL decrypted data: \"");
@@ -195,9 +208,10 @@ static void _log_clear_data(pn_ssl_t *ssl, const char *data, size_t len)
}
// unrecoverable SSL failure occured, notify transport and generate error code.
-static int ssl_failed(pn_ssl_t *ssl)
+static int ssl_failed(pn_transport_t *transport)
{
- SSL_set_shutdown(ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+ pni_ssl_t *ssl = transport->ssl;
+ SSL_set_shutdown(ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
ssl->ssl_closed = true;
ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
// fake a shutdown so the i/o processing code will close properly
@@ -208,8 +222,8 @@ static int ssl_failed(pn_ssl_t *ssl)
if (ssl_err) {
ERR_error_string_n( ssl_err, buf, sizeof(buf) );
}
- _log_ssl_error(ssl, NULL); // spit out any remaining errors to the log file
- pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", buf);
+ ssl_log_flush(transport); // spit out any remaining errors to the log file
+ pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: %s", buf);
return PN_EOS;
}
@@ -280,23 +294,24 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
SSL *ssn = (SSL *) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
if (!ssn) {
- _log_error(NULL, "Error: unexpected error - SSL session info not available for peer verify!");
+ pn_transport_logf(NULL, "Error: unexpected error - SSL session info not available for peer verify!");
return 0; // fail connection
}
- pn_ssl_t *ssl = (pn_ssl_t *)SSL_get_ex_data(ssn, ssl_ex_data_index);
- if (!ssl) {
- _log_error(NULL, "Error: unexpected error - SSL context info not available for peer verify!");
+ pn_transport_t *transport = (pn_transport_t *)SSL_get_ex_data(ssn, ssl_ex_data_index);
+ if (!transport) {
+ pn_transport_logf(NULL, "Error: unexpected error - SSL context info not available for peer verify!");
return 0; // fail connection
}
+ pni_ssl_t *ssl = transport->ssl;
if (ssl->domain->verify_mode != PN_SSL_VERIFY_PEER_NAME) return preverify_ok;
if (!ssl->peer_hostname) {
- _log_error(ssl, "Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
+ pn_transport_logf(transport, "Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
return 0; // fail connection
}
- _log( ssl, "Checking identifying name in peer cert against '%s'", ssl->peer_hostname);
+ ssl_log(transport, "Checking identifying name in peer cert against '%s'", ssl->peer_hostname);
bool matched = false;
@@ -313,7 +328,7 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
unsigned char *str;
int len = ASN1_STRING_to_UTF8( &str, asn1 );
if (len >= 0) {
- _log( ssl, "SubjectAltName (dns) from peer cert = '%.*s'", len, str );
+ ssl_log(transport, "SubjectAltName (dns) from peer cert = '%.*s'", len, str );
matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
OPENSSL_free( str );
}
@@ -333,7 +348,7 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
unsigned char *str;
int len = ASN1_STRING_to_UTF8( &str, name_asn1);
if (len >= 0) {
- _log( ssl, "commonName from peer cert = '%.*s'", len, str );
+ ssl_log(transport, "commonName from peer cert = '%.*s'", len, str);
matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
OPENSSL_free(str);
}
@@ -341,14 +356,14 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
}
if (!matched) {
- _log( ssl, "Error: no name matching %s found in peer cert - rejecting handshake.",
+ ssl_log(transport, "Error: no name matching %s found in peer cert - rejecting handshake.",
ssl->peer_hostname);
preverify_ok = 0;
#ifdef X509_V_ERR_APPLICATION_VERIFICATION
X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION );
#endif
} else {
- _log( ssl, "Name from peer cert matched - peer is valid." );
+ ssl_log(transport, "Name from peer cert matched - peer is valid.");
}
return preverify_ok;
}
@@ -460,7 +475,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
case PN_SSL_MODE_CLIENT:
domain->ctx = SSL_CTX_new(SSLv23_client_method()); // and TLSv1+
if (!domain->ctx) {
- _log_ssl_error(NULL, "Unable to initialize OpenSSL context.");
+ ssl_log_error("Unable to initialize OpenSSL context.");
free(domain);
return NULL;
}
@@ -469,14 +484,14 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
case PN_SSL_MODE_SERVER:
domain->ctx = SSL_CTX_new(SSLv23_server_method()); // and TLSv1+
if (!domain->ctx) {
- _log_ssl_error(NULL, "Unable to initialize OpenSSL context.");
+ ssl_log_error("Unable to initialize OpenSSL context.");
free(domain);
return NULL;
}
break;
default:
- _log_error(NULL, "Invalid value for pn_ssl_mode_t: %d", mode);
+ pn_transport_logf(NULL, "Invalid value for pn_ssl_mode_t: %d", mode);
free(domain);
return NULL;
}
@@ -489,7 +504,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
// by default, allow anonymous ciphers so certificates are not required 'out of the box'
if (!SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_ANONYMOUS )) {
- _log_ssl_error(NULL, "Failed to set cipher list to %s", CIPHERS_ANONYMOUS);
+ ssl_log_error("Failed to set cipher list to %s", CIPHERS_ANONYMOUS);
pn_ssl_domain_free(domain);
return NULL;
}
@@ -538,7 +553,7 @@ int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
if (!domain || !domain->ctx) return -1;
if (SSL_CTX_use_certificate_chain_file(domain->ctx, certificate_file) != 1) {
- _log_ssl_error(NULL, "SSL_CTX_use_certificate_chain_file( %s ) failed", certificate_file);
+ ssl_log_error("SSL_CTX_use_certificate_chain_file( %s ) failed", certificate_file);
return -3;
}
@@ -549,12 +564,12 @@ int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
}
if (SSL_CTX_use_PrivateKey_file(domain->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
- _log_ssl_error(NULL, "SSL_CTX_use_PrivateKey_file( %s ) failed", private_key_file);
+ ssl_log_error("SSL_CTX_use_PrivateKey_file( %s ) failed", private_key_file);
return -4;
}
if (SSL_CTX_check_private_key(domain->ctx) != 1) {
- _log_ssl_error(NULL, "The key file %s is not consistent with the certificate %s",
+ ssl_log_error("The key file %s is not consistent with the certificate %s",
private_key_file, certificate_file);
return -5;
}
@@ -565,7 +580,7 @@ int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
// cipher was negotiated. TLSv1 will reject such a request. Hack: once a cert is
// configured, allow only authenticated ciphers.
if (!SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_AUTHENTICATE )) {
- _log_ssl_error(NULL, "Failed to set cipher list to %s", CIPHERS_AUTHENTICATE);
+ ssl_log_error("Failed to set cipher list to %s", CIPHERS_AUTHENTICATE);
return -6;
}
@@ -582,7 +597,7 @@ int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
// to SSL_CTX_load_verify_locations()
struct stat sbuf;
if (stat( certificate_db, &sbuf ) != 0) {
- _log_error(NULL, "stat(%s) failed: %s", certificate_db, strerror(errno));
+ pn_transport_logf(NULL, "stat(%s) failed: %s", certificate_db, strerror(errno));
return -1;
}
@@ -597,7 +612,7 @@ int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
}
if (SSL_CTX_load_verify_locations( domain->ctx, file, dir ) != 1) {
- _log_ssl_error(NULL, "SSL_CTX_load_verify_locations( %s ) failed", certificate_db);
+ ssl_log_error("SSL_CTX_load_verify_locations( %s ) failed", certificate_db);
return -1;
}
@@ -618,7 +633,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
case PN_SSL_VERIFY_PEER_NAME:
if (!domain->has_ca_db) {
- _log_error(NULL, "Error: cannot verify peer without a trusted CA configured.\n"
+ pn_transport_logf(NULL, "Error: cannot verify peer without a trusted CA configured.\n"
" Use pn_ssl_domain_set_trusted_ca_db()");
return -1;
}
@@ -627,11 +642,11 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
// openssl requires that server connections supply a list of trusted CAs which is
// sent to the client
if (!trusted_CAs) {
- _log_error(NULL, "Error: a list of trusted CAs must be provided.");
+ pn_transport_logf(NULL, "Error: a list of trusted CAs must be provided.");
return -1;
}
if (!domain->has_certificate) {
- _log_error(NULL, "Error: Server cannot verify peer without configuring a certificate.\n"
+ pn_transport_logf(NULL, "Error: Server cannot verify peer without configuring a certificate.\n"
" Use pn_ssl_domain_set_credentials()");
}
@@ -642,7 +657,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
if (cert_names != NULL)
SSL_CTX_set_client_CA_list(domain->ctx, cert_names);
else {
- _log_error(NULL, "Error: Unable to process file of trusted CAs: %s", trusted_CAs);
+ pn_transport_logf(NULL, "Error: Unable to process file of trusted CAs: %s", trusted_CAs);
return -1;
}
}
@@ -659,7 +674,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
break;
default:
- _log_error(NULL, "Invalid peer authentication mode given." );
+ pn_transport_logf(NULL, "Invalid peer authentication mode given." );
return -1;
}
@@ -702,21 +717,23 @@ const pn_io_layer_t ssl_closed_layer = {
buffered_output
};
-int pn_ssl_init( pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
+int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
{
+ pn_transport_t *transport = get_transport_internal(ssl0);
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl || !domain || ssl->domain) return -1;
ssl->domain = domain;
domain->ref_count++;
if (domain->allow_unsecured) {
- ssl->transport->io_layers[PN_IO_SSL] = &unknown_layer;
+ transport->io_layers[PN_IO_SSL] = &unknown_layer;
} else {
- ssl->transport->io_layers[PN_IO_SSL] = &ssl_layer;
+ transport->io_layers[PN_IO_SSL] = &ssl_layer;
}
if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
ssl->session_id = pn_strdup(session_id);
- return init_ssl_socket(ssl);
+ return init_ssl_socket(transport, ssl);
}
@@ -724,7 +741,7 @@ int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
{
if (!domain) return -1;
if (domain->mode != PN_SSL_MODE_SERVER) {
- _log_error(NULL, "Cannot permit unsecured clients - not a server.");
+ pn_transport_log(NULL, "Cannot permit unsecured clients - not a server.");
return -1;
}
domain->allow_unsecured = true;
@@ -732,10 +749,11 @@ int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
}
-bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size )
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
{
const SSL_CIPHER *c;
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
*buffer = '\0';
if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) {
const char *v = SSL_CIPHER_get_name(c);
@@ -747,10 +765,11 @@ bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size )
return false;
}
-bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size )
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
{
const SSL_CIPHER *c;
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
*buffer = '\0';
if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) {
const char *v = SSL_CIPHER_get_version(c);
@@ -763,10 +782,11 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size )
}
-void pn_ssl_free( pn_ssl_t *ssl)
+void pn_ssl_free(pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl) return;
- _log( ssl, "SSL socket freed." );
+ ssl_log(transport, "SSL socket freed." );
release_ssl_socket( ssl );
if (ssl->domain) pn_ssl_domain_free(ssl->domain);
if (ssl->session_id) free((void *)ssl->session_id);
@@ -779,9 +799,9 @@ void pn_ssl_free( pn_ssl_t *ssl)
pn_ssl_t *pn_ssl(pn_transport_t *transport)
{
if (!transport) return NULL;
- if (transport->ssl) return transport->ssl;
+ if (transport->ssl) return (pn_ssl_t *) transport;
- pn_ssl_t *ssl = (pn_ssl_t *) calloc(1, sizeof(pn_ssl_t));
+ pni_ssl_t *ssl = (pni_ssl_t *) calloc(1, sizeof(pni_ssl_t));
if (!ssl) return NULL;
ssl->out_size = APP_BUF_SIZE;
uint32_t max_frame = pn_transport_get_max_frame(transport);
@@ -798,14 +818,11 @@ pn_ssl_t *pn_ssl(pn_transport_t *transport)
return NULL;
}
- ssl->transport = transport;
transport->ssl = ssl;
- transport->io_layers[PN_IO_SSL] = &pni_passthru_layer;
-
ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
- return ssl;
+ return (pn_ssl_t *) transport;
}
@@ -819,10 +836,11 @@ static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata)
}
-static int start_ssl_shutdown( pn_ssl_t *ssl )
+static int start_ssl_shutdown(pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl->ssl_shutdown) {
- _log(ssl, "Shutting down SSL connection...");
+ ssl_log(transport, "Shutting down SSL connection...");
if (ssl->session_id) {
// save the negotiated credentials before we close the connection
pn_ssl_session_t *ssn = (pn_ssl_session_t *)calloc( 1, sizeof(pn_ssl_session_t));
@@ -830,7 +848,7 @@ static int start_ssl_shutdown( pn_ssl_t *ssl )
ssn->id = pn_strdup( ssl->session_id );
ssn->session = SSL_get1_session( ssl->ssl );
if (ssn->session) {
- _log( ssl, "Saving SSL session as %s", ssl->session_id );
+ ssl_log(transport, "Saving SSL session as %s", ssl->session_id );
LL_ADD( ssl->domain, ssn_cache, ssn );
} else {
ssl_session_free( ssn );
@@ -858,10 +876,10 @@ static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
// SSL socket and pass it to the application.
static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
{
- pn_ssl_t *ssl = transport->ssl;
- if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_EOS;
+ pni_ssl_t *ssl = transport->ssl;
+ if (ssl->ssl == NULL && init_ssl_socket(transport, ssl)) return PN_EOS;
- _log( ssl, "process_input_ssl( data size=%d )",available );
+ ssl_log( transport, "process_input_ssl( data size=%d )",available );
ssize_t consumed = 0;
bool work_pending;
@@ -880,12 +898,12 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer,
consumed += written;
ssl->read_blocked = false;
work_pending = (available > 0);
- _log( ssl, "Wrote %d bytes to BIO Layer, %d left over", written, available );
+ ssl_log( transport, "Wrote %d bytes to BIO Layer, %d left over", written, available );
}
} else if (shutdown_input) {
// lower layer (caller) has closed. Close the WRITE side of the BIO. This will cause
// an EOF to be passed to SSL once all pending inbound data has been consumed.
- _log( ssl, "Lower layer closed - shutting down BIO write side");
+ ssl_log( transport, "Lower layer closed - shutting down BIO write side");
(void)BIO_shutdown_wr( ssl->bio_net_io );
shutdown_input = false;
}
@@ -895,8 +913,8 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer,
if (!ssl->ssl_closed && ssl->in_count < ssl->in_size) {
int read = BIO_read( ssl->bio_ssl, &ssl->inbuf[ssl->in_count], ssl->in_size - ssl->in_count );
if (read > 0) {
- _log( ssl, "Read %d bytes from SSL socket for app", read );
- _log_clear_data( ssl, &ssl->inbuf[ssl->in_count], read );
+ ssl_log( transport, "Read %d bytes from SSL socket for app", read );
+ ssl_log_clear_data( ssl, &ssl->inbuf[ssl->in_count], read );
ssl->in_count += read;
work_pending = true;
} else {
@@ -905,22 +923,22 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer,
switch (reason) {
case SSL_ERROR_ZERO_RETURN:
// SSL closed cleanly
- _log(ssl, "SSL connection has closed");
- start_ssl_shutdown(ssl); // KAG: not sure - this may not be necessary
+ ssl_log(transport, "SSL connection has closed");
+ start_ssl_shutdown(transport); // KAG: not sure - this may not be necessary
ssl->ssl_closed = true;
break;
default:
// unexpected error
- return (ssize_t)ssl_failed(ssl);
+ return (ssize_t)ssl_failed(transport);
}
} else {
if (BIO_should_write( ssl->bio_ssl )) {
ssl->write_blocked = true;
- _log(ssl, "Detected write-blocked");
+ ssl_log(transport, "Detected write-blocked");
}
if (BIO_should_read( ssl->bio_ssl )) {
ssl->read_blocked = true;
- _log(ssl, "Detected read-blocked");
+ ssl_log(transport, "Detected read-blocked");
}
}
}
@@ -936,22 +954,22 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer,
if (ssl->in_count)
memmove( ssl->inbuf, ssl->inbuf + consumed, ssl->in_count );
work_pending = true;
- _log( ssl, "Application consumed %d bytes from peer", (int) consumed );
+ ssl_log( transport, "Application consumed %d bytes from peer", (int) consumed );
} else if (consumed < 0) {
- _log(ssl, "Application layer closed its input, error=%d (discarding %d bytes)",
+ ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)",
(int) consumed, (int)ssl->in_count);
ssl->in_count = 0; // discard any pending input
ssl->app_input_closed = consumed;
if (ssl->app_output_closed && ssl->out_count == 0) {
// both sides of app closed, and no more app output pending:
- start_ssl_shutdown(ssl);
+ start_ssl_shutdown(transport);
}
} else {
// app did not consume any bytes, must be waiting for a full frame
if (ssl->in_count == ssl->in_size) {
// but the buffer is full, not enough room for a full frame.
// can we grow the buffer?
- uint32_t max_frame = pn_transport_get_max_frame(ssl->transport);
+ uint32_t max_frame = pn_transport_get_max_frame(transport);
if (!max_frame) max_frame = ssl->in_size * 2; // no limit
if (ssl->in_size < max_frame) {
// no max frame limit - grow it.
@@ -968,7 +986,7 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer,
// the application _must_ have enough data to process. If
// this is an oversized frame, the app _must_ handle it
// by returning an error code to SSL.
- _log_error(ssl, "Error: application unable to consume input.");
+ pn_transport_log(transport, "Error: application unable to consume input.");
}
}
}
@@ -998,15 +1016,15 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer,
transport->io_layers[layer] = &ssl_input_closed_layer;
}
}
- _log(ssl, "process_input_ssl() returning %d", (int) consumed);
+ ssl_log(transport, "process_input_ssl() returning %d", (int) consumed);
return consumed;
}
static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
{
- pn_ssl_t *ssl = transport->ssl;
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl) return PN_EOS;
- if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_EOS;
+ if (ssl->ssl == NULL && init_ssl_socket(transport, ssl)) return PN_EOS;
ssize_t written = 0;
bool work_pending;
@@ -1020,10 +1038,10 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
if (app_bytes > 0) {
ssl->out_count += app_bytes;
work_pending = true;
- _log( ssl, "Gathered %d bytes from app to send to peer", app_bytes );
+ ssl_log(transport, "Gathered %d bytes from app to send to peer", app_bytes );
} else {
if (app_bytes < 0) {
- _log(ssl, "Application layer closed its output, error=%d (%d bytes pending send)",
+ ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)",
(int) app_bytes, (int) ssl->out_count);
ssl->app_output_closed = app_bytes;
}
@@ -1040,30 +1058,30 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
data += wrote;
ssl->out_count -= wrote;
work_pending = true;
- _log( ssl, "Wrote %d bytes from app to socket", wrote );
+ ssl_log( transport, "Wrote %d bytes from app to socket", wrote );
} else {
if (!BIO_should_retry(ssl->bio_ssl)) {
int reason = SSL_get_error( ssl->ssl, wrote );
switch (reason) {
case SSL_ERROR_ZERO_RETURN:
// SSL closed cleanly
- _log(ssl, "SSL connection has closed");
- start_ssl_shutdown(ssl); // KAG: not sure - this may not be necessary
+ ssl_log(transport, "SSL connection has closed");
+ start_ssl_shutdown(transport); // KAG: not sure - this may not be necessary
ssl->out_count = 0; // can no longer write to socket, so erase app output data
ssl->ssl_closed = true;
break;
default:
// unexpected error
- return (ssize_t)ssl_failed(ssl);
+ return (ssize_t)ssl_failed(transport);
}
} else {
if (BIO_should_read( ssl->bio_ssl )) {
ssl->read_blocked = true;
- _log(ssl, "Detected read-blocked");
+ ssl_log(transport, "Detected read-blocked");
}
if (BIO_should_write( ssl->bio_ssl )) {
ssl->write_blocked = true;
- _log(ssl, "Detected write-blocked");
+ ssl_log(transport, "Detected write-blocked");
}
}
}
@@ -1073,7 +1091,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
if (ssl->app_input_closed && ssl->app_output_closed) {
// application is done sending/receiving data, and all buffered output data has
// been written to the SSL socket
- start_ssl_shutdown(ssl);
+ start_ssl_shutdown(transport);
}
} else if (data != ssl->outbuf) {
memmove( ssl->outbuf, data, ssl->out_count );
@@ -1089,7 +1107,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
written += available;
ssl->write_blocked = false;
work_pending = work_pending || max_len > 0;
- _log( ssl, "Read %d bytes from BIO Layer", available );
+ ssl_log(transport, "Read %d bytes from BIO Layer", available );
}
}
@@ -1114,23 +1132,23 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
transport->io_layers[layer] = &ssl_output_closed_layer;
}
}
- _log(ssl, "process_output_ssl() returning %d", (int) written);
+ ssl_log(transport, "process_output_ssl() returning %d", (int) written);
return written;
}
-static int init_ssl_socket( pn_ssl_t *ssl )
+static int init_ssl_socket(pn_transport_t* transport, pni_ssl_t *ssl)
{
if (ssl->ssl) return 0;
if (!ssl->domain) return -1;
ssl->ssl = SSL_new(ssl->domain->ctx);
if (!ssl->ssl) {
- _log_error(ssl, "SSL socket setup failure." );
+ pn_transport_logf(transport, "SSL socket setup failure." );
return -1;
}
- // store backpointer to pn_ssl_t in SSL object:
- SSL_set_ex_data(ssl->ssl, ssl_ex_data_index, ssl);
+ // store backpointer to pn_transport_t in SSL object:
+ SSL_set_ex_data(ssl->ssl, ssl_ex_data_index, transport);
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if (ssl->peer_hostname && ssl->domain->mode == PN_SSL_MODE_CLIENT) {
@@ -1142,10 +1160,10 @@ static int init_ssl_socket( pn_ssl_t *ssl )
if (ssl->session_id) {
pn_ssl_session_t *ssn = ssn_cache_find( ssl->domain, ssl->session_id );
if (ssn) {
- _log( ssl, "Restoring previous session id=%s", ssn->id );
+ ssl_log( transport, "Restoring previous session id=%s", ssn->id );
int rc = SSL_set_session( ssl->ssl, ssn->session );
if (rc != 1) {
- _log( ssl, "Session restore failed, id=%s", ssn->id );
+ ssl_log( transport, "Session restore failed, id=%s", ssn->id );
}
LL_REMOVE( ssl->domain, ssn_cache, ssn );
ssl_session_free( ssn );
@@ -1155,14 +1173,14 @@ static int init_ssl_socket( pn_ssl_t *ssl )
// now layer a BIO over the SSL socket
ssl->bio_ssl = BIO_new(BIO_f_ssl());
if (!ssl->bio_ssl) {
- _log_error(ssl, "BIO setup failure." );
+ pn_transport_log(transport, "BIO setup failure." );
return -1;
}
(void)BIO_set_ssl(ssl->bio_ssl, ssl->ssl, BIO_NOCLOSE);
// create the "lower" BIO "pipe", and attach it below the SSL layer
if (!BIO_new_bio_pair(&ssl->bio_ssl_io, 0, &ssl->bio_net_io, 0)) {
- _log_error(ssl, "BIO setup failure." );
+ pn_transport_log(transport, "BIO setup failure." );
return -1;
}
SSL_set_bio(ssl->ssl, ssl->bio_ssl_io, ssl->bio_ssl_io);
@@ -1170,16 +1188,16 @@ static int init_ssl_socket( pn_ssl_t *ssl )
if (ssl->domain->mode == PN_SSL_MODE_SERVER) {
SSL_set_accept_state(ssl->ssl);
BIO_set_ssl_mode(ssl->bio_ssl, 0); // server mode
- _log( ssl, "Server SSL socket created." );
+ ssl_log( transport, "Server SSL socket created." );
} else { // client mode
SSL_set_connect_state(ssl->ssl);
BIO_set_ssl_mode(ssl->bio_ssl, 1); // client mode
- _log( ssl, "Client SSL socket created." );
+ ssl_log( transport, "Client SSL socket created." );
}
return 0;
}
-static void release_ssl_socket( pn_ssl_t *ssl )
+static void release_ssl_socket(pni_ssl_t *ssl)
{
if (ssl->bio_ssl) BIO_free(ssl->bio_ssl);
if (ssl->ssl) {
@@ -1206,14 +1224,13 @@ static int setup_cleartext_connection(pn_transport_t *transport, unsigned int la
static ssize_t process_input_unknown(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
{
- pn_ssl_t *ssl = transport->ssl;
switch (check_for_ssl_connection( input_data, len )) {
case SSL_CONNECTION:
- _log( ssl, "SSL connection detected.\n");
+ ssl_log( transport, "SSL connection detected.");
setup_ssl_connection(transport, layer);
break;
case CLEAR_CONNECTION:
- _log( ssl, "Cleartext connection detected.\n");
+ ssl_log( transport, "Cleartext connection detected.");
setup_cleartext_connection(transport, layer);
break;
default:
@@ -1281,14 +1298,15 @@ static connection_mode_t check_for_ssl_connection( const char *data, size_t len
return UNKNOWN_CONNECTION;
}
-void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
+void pn_ssl_trace(pn_transport_t *transport, pn_trace_t trace)
{
- ssl->trace = trace;
+ transport->ssl->trace = trace;
}
-pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
+pn_ssl_resume_status_t pn_ssl_resume_status(pn_ssl_t *ssl0)
{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
if (!ssl || !ssl->ssl) return PN_SSL_RESUME_UNKNOWN;
switch (SSL_session_reused( ssl->ssl )) {
case 0: return PN_SSL_RESUME_NEW;
@@ -1299,8 +1317,9 @@ pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
}
-int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
+int pn_ssl_set_peer_hostname(pn_ssl_t *ssl0, const char *hostname)
{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
if (!ssl) return -1;
if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
@@ -1317,8 +1336,9 @@ int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
return 0;
}
-int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
+int pn_ssl_get_peer_hostname(pn_ssl_t *ssl0, char *hostname, size_t *bufsize)
{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
if (!ssl) return -1;
if (!ssl->peer_hostname) {
*bufsize = 0;
@@ -1347,7 +1367,7 @@ static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer
static size_t buffered_output(pn_transport_t *transport)
{
size_t count = 0;
- pn_ssl_t *ssl = transport->ssl;
+ pni_ssl_t *ssl = transport->ssl;
if (ssl) {
count += ssl->out_count;
if (ssl->bio_net_io) { // pick up any bytes waiting for network io
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/ssl/ssl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl-internal.h b/proton-c/src/ssl/ssl-internal.h
index c72e513..f1cd637 100644
--- a/proton-c/src/ssl/ssl-internal.h
+++ b/proton-c/src/ssl/ssl-internal.h
@@ -29,8 +29,8 @@
*/
// release the SSL context
-void pn_ssl_free( pn_ssl_t *ssl);
+void pn_ssl_free(pn_transport_t *transport);
-void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace);
+void pn_ssl_trace(pn_transport_t *transport, pn_trace_t trace);
#endif /* ssl-internal.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index 2c086db..865f8c9 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -268,8 +268,8 @@ static void pn_transport_finalize(void *object)
{
pn_transport_t *transport = (pn_transport_t *) object;
- pn_ssl_free(transport->ssl);
- pn_sasl_free(transport->sasl);
+ pn_ssl_free(transport);
+ pn_sasl_free(transport);
pn_dispatcher_free(transport->disp);
free(transport->remote_container);
free(transport->remote_hostname);
@@ -1945,8 +1945,8 @@ ssize_t pn_transport_output(pn_transport_t *transport, char *bytes, size_t size)
void pn_transport_trace(pn_transport_t *transport, pn_trace_t trace)
{
- if (transport->sasl) pn_sasl_trace(transport->sasl, trace);
- if (transport->ssl) pn_ssl_trace(transport->ssl, trace);
+ if (transport->sasl) pn_sasl_trace(transport, trace);
+ if (transport->ssl) pn_ssl_trace(transport, trace);
transport->disp->trace = trace;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df029005/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
index 7f47745..231349c 100644
--- a/proton-c/src/windows/schannel.c
+++ b/proton-c/src/windows/schannel.c
@@ -80,8 +80,7 @@ struct pn_ssl_domain_t {
typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;
-struct pn_ssl_t {
- pn_transport_t *transport;
+struct pni_ssl_t {
pn_ssl_domain_t *domain;
const char *session_id;
const char *peer_hostname;
@@ -127,6 +126,18 @@ struct pn_ssl_t {
SecPkgContext_StreamSizes sc_sizes;
};
+static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ((pn_transport_t *)ssl);
+}
+
+static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl)
+{
+ // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+ return ssl ? ((pn_transport_t *)ssl)->ssl : NULL;
+}
+
struct pn_ssl_session_t {
const char *id;
// TODO
@@ -145,9 +156,9 @@ static connection_mode_t check_for_ssl_connection( const char *data, size_t len
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
static void ssl_session_free( pn_ssl_session_t *);
static size_t buffered_output( pn_transport_t *transport );
-static void start_ssl_shutdown(pn_ssl_t *ssl);
-static void rewind_sc_inbuf(pn_ssl_t *ssl);
-static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size);
+static void start_ssl_shutdown(pn_transport_t *transport);
+static void rewind_sc_inbuf(pni_ssl_t *ssl);
+static bool grow_inbuf2(pn_transport_t *ssl, size_t minimum_size);
// @todo: used to avoid littering the code with calls to printf...
@@ -161,7 +172,7 @@ static void ssl_log_error(const char *fmt, ...)
}
// @todo: used to avoid littering the code with calls to printf...
-static void ssl_log(pn_ssl_t *ssl, const char *fmt, ...)
+static void ssl_log(pni_ssl_t *ssl, const char *fmt, ...)
{
if (PN_TRACE_DRV & ssl->trace) {
va_list ap;
@@ -192,7 +203,7 @@ static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
fflush(stderr);
}
-static void ssl_log_clear_data(pn_ssl_t *ssl, const char *data, size_t len)
+static void ssl_log_clear_data(pni_ssl_t *ssl, const char *data, size_t len)
{
if (PN_TRACE_RAW & ssl->trace) {
fprintf(stderr, "SSL decrypted data: \"");
@@ -207,7 +218,7 @@ static size_t _pni_min(size_t a, size_t b)
}
// unrecoverable SSL failure occured, notify transport and generate error code.
-static int ssl_failed(pn_ssl_t *ssl, const char *reason)
+static int ssl_failed(pn_transport_t *transport, const char *reason)
{
char buf[512] = "Unknown error.";
if (!reason) {
@@ -217,10 +228,11 @@ static int ssl_failed(pn_ssl_t *ssl, const char *reason)
0, status, 0, buf, sizeof(buf), 0);
reason = buf;
}
+ pni_ssl_t *ssl = transport->ssl;
ssl->ssl_closed = true;
ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
ssl->state = SSL_CLOSED;
- pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
+ pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
return PN_EOS;
}
@@ -383,18 +395,20 @@ const pn_io_layer_t ssl_closed_layer = {
buffered_output
};
-int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
+int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
{
+ pn_transport_t *transport = get_transport_internal(ssl0);
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl || !domain || ssl->domain) return -1;
if (ssl->state != CREATED) return -1;
ssl->domain = domain;
domain->ref_count++;
if (domain->allow_unsecured) {
- ssl->transport->io_layers[PN_IO_SSL] = &unknown_layer;
+ transport->io_layers[PN_IO_SSL] = &unknown_layer;
}
else {
- ssl->transport->io_layers[PN_IO_SSL] = &ssl_layer;
+ transport->io_layers[PN_IO_SSL] = &ssl_layer;
}
if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
ssl->session_id = pn_strdup(session_id);
@@ -440,8 +454,9 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size )
}
-void pn_ssl_free( pn_ssl_t *ssl)
+void pn_ssl_free( pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl) return;
ssl_log( ssl, "SSL socket freed.\n" );
// clean up Windows per TLS session data before releasing the domain count
@@ -462,9 +477,9 @@ void pn_ssl_free( pn_ssl_t *ssl)
pn_ssl_t *pn_ssl(pn_transport_t *transport)
{
if (!transport) return NULL;
- if (transport->ssl) return transport->ssl;
+ if (transport->ssl) return (pn_ssl_t *)transport;
- pn_ssl_t *ssl = (pn_ssl_t *) calloc(1, sizeof(pn_ssl_t));
+ pni_ssl_t *ssl = (pni_ssl_t *) calloc(1, sizeof(pni_ssl_t));
if (!ssl) return NULL;
ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;
@@ -488,23 +503,20 @@ pn_ssl_t *pn_ssl(pn_transport_t *transport)
return NULL;
}
- ssl->transport = transport;
transport->ssl = ssl;
- transport->io_layers[PN_IO_SSL] = &pni_passthru_layer;
-
ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
SecInvalidateHandle(&ssl->cred_handle);
SecInvalidateHandle(&ssl->ctxt_handle);
ssl->state = CREATED;
ssl->decrypting = true;
- return ssl;
+ return (pn_ssl_t *)transport;
}
-void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
+void pn_ssl_trace(pn_transport_t *transport, pn_trace_t trace)
{
- ssl->trace = trace;
+ transport->ssl->trace = trace;
}
@@ -515,8 +527,9 @@ pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
}
-int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
+int pn_ssl_set_peer_hostname( pn_ssl_t *ssl0, const char *hostname )
{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
if (!ssl) return -1;
if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
@@ -528,8 +541,9 @@ int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
return 0;
}
-int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
+int pn_ssl_get_peer_hostname( pn_ssl_t *ssl0, char *hostname, size_t *bufsize )
{
+ pni_ssl_t *ssl = get_ssl_internal(ssl0);
if (!ssl) return -1;
if (!ssl->peer_hostname) {
*bufsize = 0;
@@ -548,7 +562,7 @@ int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
/** SChannel specific: */
-const char *tls_version_check(pn_ssl_t *ssl)
+const char *tls_version_check(pni_ssl_t *ssl)
{
SecPkgContext_ConnectionInfo info;
QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info);
@@ -558,7 +572,7 @@ const char *tls_version_check(pn_ssl_t *ssl)
"peer does not support TLS 1.0 security" : NULL;
}
-static void ssl_encrypt(pn_ssl_t *ssl, char *app_data, size_t count)
+static void ssl_encrypt(pni_ssl_t *ssl, char *app_data, size_t count)
{
// Get SChannel to encrypt exactly one Record.
SecBuffer buffs[4];
@@ -591,8 +605,9 @@ static void ssl_encrypt(pn_ssl_t *ssl, char *app_data, size_t count)
}
// Returns true if decryption succeeded (even for empty content)
-static bool ssl_decrypt(pn_ssl_t *ssl)
+static bool ssl_decrypt(pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
// Get SChannel to decrypt input. May have an incomplete Record,
// exactly one, or more than one. Check also for session ending,
// session renegotiation.
@@ -630,7 +645,7 @@ static bool ssl_decrypt(pn_ssl_t *ssl)
case SEC_I_RENEGOTIATE:
// TODO. Fall through for now.
default:
- ssl_failed(ssl, 0);
+ ssl_failed(transport, 0);
return false;
}
}
@@ -657,8 +672,9 @@ static bool ssl_decrypt(pn_ssl_t *ssl)
return true;
}
-static void client_handshake_init(pn_ssl_t *ssl)
+static void client_handshake_init(pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
// Tell SChannel to create the first handshake token (ClientHello)
// and place it in sc_outbuf
SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
@@ -689,11 +705,12 @@ static void client_handshake_init(pn_ssl_t *ssl)
ssl_log(ssl, "Sending client hello %d bytes\n", ssl->network_out_pending);
} else {
ssl_log_error_status(status, "InitializeSecurityContext failed");
- ssl_failed(ssl, 0);
+ ssl_failed(transport, 0);
}
}
-static void client_handshake( pn_ssl_t* ssl) {
+static void client_handshake( pn_transport_t* transport) {
+ pni_ssl_t *ssl = transport->ssl;
// Feed SChannel ongoing responses from the server until the handshake is complete.
SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
@@ -766,11 +783,11 @@ static void client_handshake( pn_ssl_t* ssl) {
return;
}
if (send_buffs[0].cbBuffer != 0) {
- ssl_failed(ssl, "unexpected final server token");
+ ssl_failed(transport, "unexpected final server token");
break;
}
if (const char *err = tls_version_check(ssl)) {
- ssl_failed(ssl, err);
+ ssl_failed(transport, err);
break;
}
if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
@@ -787,8 +804,8 @@ static void client_handshake( pn_ssl_t* ssl) {
ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
ssl->state = SHUTTING_DOWN;
ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
- start_ssl_shutdown(ssl);
- pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
+ start_ssl_shutdown(transport);
+ pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
break;
}
@@ -801,7 +818,7 @@ static void client_handshake( pn_ssl_t* ssl) {
// ended before we got going
default:
ssl_log(ssl, "client handshake failed %d\n", (int) status);
- ssl_failed(ssl, 0);
+ ssl_failed(transport, 0);
break;
}
ssl->decrypting = false;
@@ -809,28 +826,29 @@ static void client_handshake( pn_ssl_t* ssl) {
}
-static void ssl_handshake(pn_ssl_t* ssl) {
- if (ssl->domain->mode == PN_SSL_MODE_CLIENT)
- client_handshake(ssl);
+static void ssl_handshake(pn_transport_t* transport) {
+ if (transport->ssl->domain->mode == PN_SSL_MODE_CLIENT)
+ client_handshake(transport);
else {
- ssl_log( ssl, "TODO: server handshake.\n" );
- ssl_failed(ssl, "internal runtime error, not yet implemented");
+ ssl_log(transport->ssl, "TODO: server handshake.\n" );
+ ssl_failed(transport, "internal runtime error, not yet implemented");
}
}
-static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size) {
+static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
+ pni_ssl_t *ssl = transport->ssl;
size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;
while (new_capacity < minimum_size)
new_capacity *= 2;
- uint32_t max_frame = pn_transport_get_max_frame(ssl->transport);
+ uint32_t max_frame = pn_transport_get_max_frame(transport);
if (max_frame != 0) {
if (old_capacity >= max_frame) {
// already big enough
- ssl_log(ssl, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
- ssl_failed(ssl, "TLS: transport maximimum frame size error");
+ ssl_log(transport->ssl, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
+ ssl_failed(transport, "TLS: transport maximimum frame size error");
return false;
}
}
@@ -839,7 +857,7 @@ static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size) {
int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
if (err) {
ssl_log(ssl, "TLS memory allocation failed for %d bytes\n", max_frame);
- ssl_failed(ssl, "TLS memory allocation failed");
+ ssl_failed(transport, "TLS memory allocation failed");
return false;
}
return true;
@@ -851,8 +869,9 @@ static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size) {
// for the peer shutdown alert). Stop processing input immediately, and stop processing
// output once this is sent.
-static void start_ssl_shutdown(pn_ssl_t *ssl)
+static void start_ssl_shutdown(pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
assert(ssl->network_out_pending == 0);
if (ssl->queued_shutdown)
return;
@@ -871,7 +890,7 @@ static void start_ssl_shutdown(pn_ssl_t *ssl)
::ApplyControlToken(&ssl->ctxt_handle, &desc);
// Next handshake will generate the shudown alert token
- ssl_handshake(ssl);
+ ssl_handshake(transport);
}
static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
@@ -880,7 +899,7 @@ static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
return 0;
}
-static void rewind_sc_inbuf(pn_ssl_t *ssl)
+static void rewind_sc_inbuf(pni_ssl_t *ssl)
{
// Decrypted bytes have been drained or double buffered. Prepare for the next SSL Record.
assert(ssl->in_data_count == 0);
@@ -898,8 +917,9 @@ static void rewind_sc_inbuf(pn_ssl_t *ssl)
}
}
-static void app_inbytes_add(pn_ssl_t *ssl)
+static void app_inbytes_add(pn_transport_t *transport)
{
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl->app_inbytes.start) {
ssl->app_inbytes.start = ssl->in_data;
ssl->app_inbytes.size = ssl->in_data_count;
@@ -908,7 +928,7 @@ static void app_inbytes_add(pn_ssl_t *ssl)
if (ssl->double_buffered) {
if (pn_buffer_available(ssl->inbuf2) == 0) {
- if (!grow_inbuf2(ssl, 1024))
+ if (!grow_inbuf2(transport, 1024))
// could not add room
return;
}
@@ -925,8 +945,9 @@ static void app_inbytes_add(pn_ssl_t *ssl)
}
-static void app_inbytes_progress(pn_ssl_t *ssl, size_t minimum)
+static void app_inbytes_progress(pn_transport_t *transport, size_t minimum)
{
+ pni_ssl_t *ssl = transport->ssl;
// Make more decrypted data available, if possible. Otherwise, move
// unread bytes to front of inbuf2 to make room for next bulk decryption.
// SSL may have chopped up data that app layer expects to be
@@ -947,7 +968,7 @@ static void app_inbytes_progress(pn_ssl_t *ssl, size_t minimum)
pn_buffer_trim(ssl->inbuf2, 0, consumed);
}
if (!pn_buffer_available(ssl->inbuf2)) {
- if (!grow_inbuf2(ssl, minimum))
+ if (!grow_inbuf2(transport, minimum))
// could not add room
return;
}
@@ -963,7 +984,7 @@ static void app_inbytes_progress(pn_ssl_t *ssl, size_t minimum)
ssl->double_buffered = true;
pn_buffer_clear(ssl->inbuf2);
if (!pn_buffer_available(ssl->inbuf2)) {
- if (!grow_inbuf2(ssl, minimum))
+ if (!grow_inbuf2(transport, minimum))
// could not add room
return;
}
@@ -981,11 +1002,12 @@ static void app_inbytes_progress(pn_ssl_t *ssl, size_t minimum)
}
-static void app_inbytes_advance(pn_ssl_t *ssl, size_t consumed)
+static void app_inbytes_advance(pn_transport_t *transport, size_t consumed)
{
+ pni_ssl_t *ssl = transport->ssl;
if (consumed == 0) {
// more contiguous bytes required
- app_inbytes_progress(ssl, ssl->app_inbytes.size + 1);
+ app_inbytes_progress(transport, ssl->app_inbytes.size + 1);
return;
}
assert(consumed <= ssl->app_inbytes.size);
@@ -996,12 +1018,12 @@ static void app_inbytes_advance(pn_ssl_t *ssl, size_t consumed)
ssl->in_data_count -= consumed;
}
if (ssl->app_inbytes.size == 0)
- app_inbytes_progress(ssl, 0);
+ app_inbytes_progress(transport, 0);
}
static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t error)
{
- pn_ssl_t *ssl = transport->ssl;
+ pni_ssl_t *ssl = transport->ssl;
if (ssl->app_input_closed)
return;
if (ssl->state == RUNNING && !error) {
@@ -1015,7 +1037,7 @@ static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t e
// both sides of app closed, and no more app output pending:
ssl->state = SHUTTING_DOWN;
if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
- start_ssl_shutdown(ssl);
+ start_ssl_shutdown(transport);
}
}
}
@@ -1025,7 +1047,7 @@ static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t e
static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
{
- pn_ssl_t *ssl = transport->ssl;
+ pni_ssl_t *ssl = transport->ssl;
ssl_log( ssl, "process_input_ssl( data size=%d )\n",available );
ssize_t consumed = 0;
ssize_t forwarded = 0;
@@ -1091,13 +1113,13 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
if (ssl->state == NEGOTIATING) {
- ssl_handshake(ssl);
+ ssl_handshake(transport);
} else {
- if (ssl_decrypt(ssl)) {
+ if (ssl_decrypt(transport)) {
// Ignore TLS Record with 0 length data (does not mean EOS)
if (ssl->in_data_size > 0) {
new_app_input = true;
- app_inbytes_add(ssl);
+ app_inbytes_add(transport);
} else {
assert(ssl->decrypting == false);
rewind_sc_inbuf(ssl);
@@ -1109,7 +1131,7 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
if (ssl->state == SHUTTING_DOWN) {
if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
- start_ssl_shutdown(ssl);
+ start_ssl_shutdown(transport);
}
} else if (ssl->state == SSL_CLOSED) {
return consumed ? consumed : -1;
@@ -1124,11 +1146,11 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
if (count > 0) {
forwarded += count;
// advance() can increase app_inbytes.size if double buffered
- app_inbytes_advance(ssl, count);
+ app_inbytes_advance(transport, count);
ssl_log(ssl, "Application consumed %d bytes from peer\n", (int) count);
} else if (count == 0) {
size_t old_size = ssl->app_inbytes.size;
- app_inbytes_advance(ssl, 0);
+ app_inbytes_advance(transport, 0);
if (ssl->app_inbytes.size == old_size) {
break; // no additional contiguous decrypted data available, get more network data
}
@@ -1136,13 +1158,13 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
// count < 0
ssl_log(ssl, "Application layer closed its input, error=%d (discarding %d bytes)\n",
(int) count, (int)ssl->app_inbytes.size);
- app_inbytes_advance(ssl, ssl->app_inbytes.size); // discard
+ app_inbytes_advance(transport, ssl->app_inbytes.size); // discard
read_closed(transport, layer, count);
}
} else {
ssl_log(ssl, "Input closed discard %d bytes\n",
(int)ssl->app_inbytes.size);
- app_inbytes_advance(ssl, ssl->app_inbytes.size); // discard
+ app_inbytes_advance(transport, ssl->app_inbytes.size); // discard
}
}
}
@@ -1162,7 +1184,7 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
{
- pn_ssl_t *ssl = transport->ssl;
+ pni_ssl_t *ssl = transport->ssl;
if (!ssl) return PN_EOS;
ssl_log( ssl, "process_output_ssl( max_len=%d )\n",max_len );
@@ -1172,7 +1194,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
if (ssl->state == CLIENT_HELLO) {
// output buffers eclusively for internal handshake use until negotiation complete
- client_handshake_init(ssl);
+ client_handshake_init(transport);
if (ssl->state == SSL_CLOSED)
return PN_EOS;
ssl->state = NEGOTIATING;
@@ -1227,7 +1249,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
if (ssl->network_out_pending == 0 && ssl->state == SHUTTING_DOWN) {
if (!ssl->queued_shutdown) {
- start_ssl_shutdown(ssl);
+ start_ssl_shutdown(transport);
work_pending = true;
} else {
ssl->state = SSL_CLOSED;
@@ -1348,7 +1370,7 @@ static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer
static size_t buffered_output(pn_transport_t *transport)
{
size_t count = 0;
- pn_ssl_t *ssl = transport->ssl;
+ pni_ssl_t *ssl = transport->ssl;
if (ssl) {
count += ssl->network_out_pending;
if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[15/35] qpid-proton git commit: PROTON-749: Add the deprecated C APIs
back in for backward compatibility.
Posted by gs...@apache.org.
PROTON-749: Add the deprecated C APIs back in for backward compatibility.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/0fd34e83
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/0fd34e83
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/0fd34e83
Branch: refs/heads/examples
Commit: 0fd34e837db645c323fa1407c07ef41642501cbf
Parents: 1b2be03
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Nov 17 14:34:29 2014 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed Nov 19 17:50:26 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/python/proton.py | 8 ++++++++
proton-c/include/proton/cproton.i | 12 ++++++++++++
proton-c/include/proton/sasl.h | 23 +++++++++++++++++++++++
proton-c/src/sasl/sasl.c | 12 ++++++++++++
4 files changed, 55 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0fd34e83/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
index 573ec14..fce3255 100644
--- a/proton-c/bindings/python/proton.py
+++ b/proton-c/bindings/python/proton.py
@@ -3193,6 +3193,14 @@ class SASL(object):
def mechanisms(self, mechs):
pn_sasl_mechanisms(self._sasl, mechs)
+ # @deprecated
+ def client(self):
+ pn_sasl_client(self._sasl)
+
+ # @deprecated
+ def server(self):
+ pn_sasl_server(self._sasl)
+
def allow_skip(self, allow):
pn_sasl_allow_skip(self._sasl, allow)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0fd34e83/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index 3c5a1a6..3b347f2 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -995,6 +995,18 @@ typedef unsigned long int uintptr_t;
sasl != NULL;
}
+%contract pn_sasl_client(pn_sasl_t *sasl)
+{
+ require:
+ sasl != NULL;
+}
+
+%contract pn_sasl_server(pn_sasl_t *sasl)
+{
+ require:
+ sasl != NULL;
+}
+
%contract pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
{
require:
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0fd34e83/proton-c/include/proton/sasl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/sasl.h b/proton-c/include/proton/sasl.h
index ab64e13..104e156 100644
--- a/proton-c/include/proton/sasl.h
+++ b/proton-c/include/proton/sasl.h
@@ -95,6 +95,29 @@ PN_EXTERN void pn_sasl_mechanisms(pn_sasl_t *sasl, const char *mechanisms);
*/
PN_EXTERN const char *pn_sasl_remote_mechanisms(pn_sasl_t *sasl);
+/**
+ * @deprecated
+ * Configure the SASL layer to act as a SASL client.
+ *
+ * This is now unnecessary, and performs no function. The server/clientness
+ * of the sasl layer is determined from the role of the transport that is used to create
+ * it. The API is retained here so as not to break existing code.
+ *
+ * @param[in] sasl the SASL layer to configure as a client
+ */
+PN_EXTERN void pn_sasl_client(pn_sasl_t *sasl);
+
+/**
+ * @deprecated
+ * Configure the SASL layer to act as a server.
+ *
+ * This is now only necessary for backwards compatibility if creating a server pn_sasl_t
+ * from a pn_transport_t which was created implicitly as a client by pn_transport().
+ *
+ * @param[in] sasl the SASL layer to configure as a server
+ */
+PN_EXTERN void pn_sasl_server(pn_sasl_t *sasl);
+
/** Configure a SASL server layer to permit the client to skip the SASL exchange.
*
* If the peer client skips the SASL exchange (i.e. goes right to the AMQP header)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0fd34e83/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 1ee8f9b..4ed9f84 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -197,6 +197,18 @@ ssize_t pn_sasl_recv(pn_sasl_t *sasl0, char *bytes, size_t size)
}
}
+void pn_sasl_client(pn_sasl_t *sasl)
+{
+}
+
+void pn_sasl_server(pn_sasl_t *sasl0)
+{
+ pni_sasl_t *sasl = get_sasl_internal(sasl0);
+ if (sasl) {
+ sasl->client = false;
+ }
+}
+
void pn_sasl_allow_skip(pn_sasl_t *sasl0, bool allow)
{
pni_sasl_t *sasl = get_sasl_internal(sasl0);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[22/35] qpid-proton git commit: changed proton.py from a module into
a package
Posted by gs...@apache.org.
changed proton.py from a module into a package
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6a78d2f7
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6a78d2f7
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6a78d2f7
Branch: refs/heads/examples
Commit: 6a78d2f774a287070d12622556d6d5504fdfd581
Parents: 1913040
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Sat Nov 22 05:50:52 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Sat Nov 22 06:03:01 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/python/CMakeLists.txt | 2 +-
proton-c/bindings/python/proton.py | 3891 ----------------------
proton-c/bindings/python/proton/__init__.py | 3891 ++++++++++++++++++++++
3 files changed, 3892 insertions(+), 3892 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6a78d2f7/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index 6ab1e67..6be421e 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -53,7 +53,7 @@ if (NOT PYTHON_SITEARCH_PACKAGES)
endif()
set (pysrc-generated cproton.py)
-set (pysrc proton.py)
+set (pysrc proton/__init__.py)
macro (py_compile directory files)
foreach (src_file ${files})
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[08/35] qpid-proton git commit: PROTON-736: Replace missed
force_encoding with encode
Posted by gs...@apache.org.
PROTON-736: Replace missed force_encoding with encode
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d770a1ef
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d770a1ef
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d770a1ef
Branch: refs/heads/examples
Commit: d770a1ef689d859888f8cc610486b0dba4ea5fa9
Parents: 6504db6
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Tue Nov 18 09:01:33 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Tue Nov 18 09:01:33 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/ruby/lib/qpid_proton/strings.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d770a1ef/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/strings.rb b/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
index dad96ad..d8f5851 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
@@ -31,7 +31,7 @@ module Qpid # :nodoc:
# exception then we'll treat it as binary.
if RUBY_VERSION >= "1.9"
return true if (value.encoding == "UTF-8" ||
- value.force_encoding("UTF-8").valid_encoding?)
+ value.encode("UTF-8").valid_encoding?)
return false
else
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[18/35] qpid-proton git commit: PROTON-755: Update Ruby smoke tests
to use Minitest
Posted by gs...@apache.org.
PROTON-755: Update Ruby smoke tests to use Minitest
The old test framework module names have changed.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1d3a1386
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1d3a1386
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1d3a1386
Branch: refs/heads/examples
Commit: 1d3a13863117cfca5aef56244b20773760428796
Parents: b4e06d3
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Thu Nov 20 13:42:41 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Thu Nov 20 13:45:06 2014 -0500
----------------------------------------------------------------------
tests/ruby/proton-test | 2 +-
tests/ruby/proton_tests/interop.rb | 4 ++--
tests/ruby/proton_tests/smoke.rb | 8 ++++----
3 files changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d3a1386/tests/ruby/proton-test
----------------------------------------------------------------------
diff --git a/tests/ruby/proton-test b/tests/ruby/proton-test
index 748e6f0..acb0d43 100755
--- a/tests/ruby/proton-test
+++ b/tests/ruby/proton-test
@@ -1,5 +1,5 @@
#!/usr/bin/env ruby
-require 'test/unit'
+require 'minitest/autorun'
require 'proton_tests/interop.rb'
require 'proton_tests/smoke.rb'
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d3a1386/tests/ruby/proton_tests/interop.rb
----------------------------------------------------------------------
diff --git a/tests/ruby/proton_tests/interop.rb b/tests/ruby/proton_tests/interop.rb
index e14cba1..21d92d9 100755
--- a/tests/ruby/proton_tests/interop.rb
+++ b/tests/ruby/proton_tests/interop.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-require 'test/unit'
+require 'minitest/autorun'
require 'qpid_proton'
if ((RUBY_VERSION.split(".").map {|x| x.to_i} <=> [1, 9]) < 0)
@@ -12,7 +12,7 @@ if ((RUBY_VERSION.split(".").map {|x| x.to_i} <=> [1, 9]) < 0)
end
end
-class InteropTest < Test::Unit::TestCase
+class InteropTest < Minitest::Test
Data = Qpid::Proton::Data
Message = Qpid::Proton::Message
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d3a1386/tests/ruby/proton_tests/smoke.rb
----------------------------------------------------------------------
diff --git a/tests/ruby/proton_tests/smoke.rb b/tests/ruby/proton_tests/smoke.rb
index 6368283..a382a0b 100644
--- a/tests/ruby/proton_tests/smoke.rb
+++ b/tests/ruby/proton_tests/smoke.rb
@@ -1,9 +1,9 @@
#!/usr/bin/env ruby
-require 'test/unit'
+require 'minitest/autorun'
require 'qpid_proton'
-class SmokeTest < Test::Unit::TestCase
+class SmokeTest < Minitest::Test
Messenger = Qpid::Proton::Messenger
Message = Qpid::Proton::Message
@@ -29,8 +29,8 @@ class SmokeTest < Test::Unit::TestCase
pump()
- assert @client.stopped
- assert @server.stopped
+ assert @client.stopped?
+ assert @server.stopped?
end
def testSmoke(count=10)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[31/35] qpid-proton git commit: Merge branch 'master' into examples
Posted by gs...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d02fdad1/proton-c/bindings/python/proton/__init__.py
----------------------------------------------------------------------
diff --cc proton-c/bindings/python/proton/__init__.py
index 0000000,fce3255..e375723
mode 000000,100644..100644
--- a/proton-c/bindings/python/proton/__init__.py
+++ b/proton-c/bindings/python/proton/__init__.py
@@@ -1,0 -1,3891 +1,3894 @@@
+ #
+ # Licensed to the Apache Software Foundation (ASF) under one
+ # or more contributor license agreements. See the NOTICE file
+ # distributed with this work for additional information
+ # regarding copyright ownership. The ASF licenses this file
+ # to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing,
+ # software distributed under the License is distributed on an
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ # KIND, either express or implied. See the License for the
+ # specific language governing permissions and limitations
+ # under the License.
+ #
+
+ """
+ The proton module defines a suite of APIs that implement the AMQP 1.0
+ protocol.
+
+ The proton APIs consist of the following classes:
+
+ - L{Messenger} -- A messaging endpoint.
+ - L{Message} -- A class for creating and/or accessing AMQP message content.
+ - L{Data} -- A class for creating and/or accessing arbitrary AMQP encoded
+ data.
+
+ """
+
+ from cproton import *
+
+ import weakref, re, socket
+ try:
+ import uuid
+ except ImportError:
+ """
+ No 'native' UUID support. Provide a very basic UUID type that is a compatible subset of the uuid type provided by more modern python releases.
+ """
+ import struct
+ class uuid:
+ class UUID:
+ def __init__(self, hex=None, bytes=None):
+ if [hex, bytes].count(None) != 1:
+ raise TypeError("need one of hex or bytes")
+ if bytes is not None:
+ self.bytes = bytes
+ elif hex is not None:
+ fields=hex.split("-")
+ fields[4:5] = [fields[4][:4], fields[4][4:]]
+ self.bytes = struct.pack("!LHHHHL", *[int(x,16) for x in fields])
+
+ def __cmp__(self, other):
+ if isinstance(other, uuid.UUID):
+ return cmp(self.bytes, other.bytes)
+ else:
+ return -1
+
+ def __str__(self):
+ return "%08x-%04x-%04x-%04x-%04x%08x" % struct.unpack("!LHHHHL", self.bytes)
+
+ def __repr__(self):
+ return "UUID(%r)" % str(self)
+
+ def __hash__(self):
+ return self.bytes.__hash__()
+
+ import os, random, socket, time
+ rand = random.Random()
+ rand.seed((os.getpid(), time.time(), socket.gethostname()))
+ def random_uuid():
+ bytes = [rand.randint(0, 255) for i in xrange(16)]
+
+ # From RFC4122, the version bits are set to 0100
+ bytes[7] &= 0x0F
+ bytes[7] |= 0x40
+
+ # From RFC4122, the top two bits of byte 8 get set to 01
+ bytes[8] &= 0x3F
+ bytes[8] |= 0x80
+ return "".join(map(chr, bytes))
+
+ def uuid4():
+ return uuid.UUID(bytes=random_uuid())
+
++def generate_uuid():
++ return uuid.uuid4()
++
+ try:
+ bytes()
+ except NameError:
+ bytes = str
+
+ VERSION_MAJOR = PN_VERSION_MAJOR
+ VERSION_MINOR = PN_VERSION_MINOR
+ API_LANGUAGE = "C"
+ IMPLEMENTATION_LANGUAGE = "C"
+
+ class Constant(object):
+
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return self.name
+
+ class ProtonException(Exception):
+ """
+ The root of the proton exception hierarchy. All proton exception
+ classes derive from this exception.
+ """
+ pass
+
+ class Timeout(ProtonException):
+ """
+ A timeout exception indicates that a blocking operation has timed
+ out.
+ """
+ pass
+
+ class Interrupt(ProtonException):
+ """
+ An interrupt exception indicaes that a blocking operation was interrupted.
+ """
+ pass
+
+ class MessengerException(ProtonException):
+ """
+ The root of the messenger exception hierarchy. All exceptions
+ generated by the messenger class derive from this exception.
+ """
+ pass
+
+ class MessageException(ProtonException):
+ """
+ The MessageException class is the root of the message exception
+ hierarhcy. All exceptions generated by the Message class derive from
+ this exception.
+ """
+ pass
+
+ EXCEPTIONS = {
+ PN_TIMEOUT: Timeout,
+ PN_INTR: Interrupt
+ }
+
+ PENDING = Constant("PENDING")
+ ACCEPTED = Constant("ACCEPTED")
+ REJECTED = Constant("REJECTED")
+ RELEASED = Constant("RELEASED")
+ ABORTED = Constant("ABORTED")
+ SETTLED = Constant("SETTLED")
+
+ STATUSES = {
+ PN_STATUS_ABORTED: ABORTED,
+ PN_STATUS_ACCEPTED: ACCEPTED,
+ PN_STATUS_REJECTED: REJECTED,
+ PN_STATUS_RELEASED: RELEASED,
+ PN_STATUS_PENDING: PENDING,
+ PN_STATUS_SETTLED: SETTLED,
+ PN_STATUS_UNKNOWN: None
+ }
+
+ AUTOMATIC = Constant("AUTOMATIC")
+ MANUAL = Constant("MANUAL")
+
+ class Messenger(object):
+ """
+ The L{Messenger} class defines a high level interface for sending
+ and receiving L{Messages<Message>}. Every L{Messenger} contains a
+ single logical queue of incoming messages and a single logical queue
+ of outgoing messages. These messages in these queues may be destined
+ for, or originate from, a variety of addresses.
+
+ The messenger interface is single-threaded. All methods
+ except one (L{interrupt}) are intended to be used from within
+ the messenger thread.
+
+
+ Address Syntax
+ ==============
+
+ An address has the following form::
+
+ [ amqp[s]:// ] [user[:password]@] domain [/[name]]
+
+ Where domain can be one of::
+
+ host | host:port | ip | ip:port | name
+
+ The following are valid examples of addresses:
+
+ - example.org
+ - example.org:1234
+ - amqp://example.org
+ - amqps://example.org
+ - example.org/incoming
+ - amqps://example.org/outgoing
+ - amqps://fred:trustno1@example.org
+ - 127.0.0.1:1234
+ - amqps://127.0.0.1:1234
+
+ Sending & Receiving Messages
+ ============================
+
+ The L{Messenger} class works in conjuction with the L{Message} class. The
+ L{Message} class is a mutable holder of message content.
+
+ The L{put} method copies its L{Message} to the outgoing queue, and may
+ send queued messages if it can do so without blocking. The L{send}
+ method blocks until it has sent the requested number of messages,
+ or until a timeout interrupts the attempt.
+
+
+ >>> message = Message()
+ >>> for i in range(3):
+ ... message.address = "amqp://host/queue"
+ ... message.subject = "Hello World %i" % i
+ ... messenger.put(message)
+ >>> messenger.send()
+
+ Similarly, the L{recv} method receives messages into the incoming
+ queue, and may block as it attempts to receive the requested number
+ of messages, or until timeout is reached. It may receive fewer
+ than the requested number. The L{get} method pops the
+ eldest L{Message} off the incoming queue and copies it into the L{Message}
+ object that you supply. It will not block.
+
+
+ >>> message = Message()
+ >>> messenger.recv(10):
+ >>> while messenger.incoming > 0:
+ ... messenger.get(message)
+ ... print message.subject
+ Hello World 0
+ Hello World 1
+ Hello World 2
+
+ The blocking flag allows you to turn off blocking behavior entirely,
+ in which case L{send} and L{recv} will do whatever they can without
+ blocking, and then return. You can then look at the number
+ of incoming and outgoing messages to see how much outstanding work
+ still remains.
+ """
+
+ def __init__(self, name=None):
+ """
+ Construct a new L{Messenger} with the given name. The name has
+ global scope. If a NULL name is supplied, a UUID based name will
+ be chosen.
+
+ @type name: string
+ @param name: the name of the messenger or None
+
+ """
+ self._mng = pn_messenger(name)
+ self._selectables = {}
+
+ def __del__(self):
+ """
+ Destroy the L{Messenger}. This will close all connections that
+ are managed by the L{Messenger}. Call the L{stop} method before
+ destroying the L{Messenger}.
+ """
+ if hasattr(self, "_mng"):
+ pn_messenger_free(self._mng)
+ del self._mng
+
+ def _check(self, err):
+ if err < 0:
+ if (err == PN_INPROGRESS):
+ return
+ exc = EXCEPTIONS.get(err, MessengerException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_messenger_error(self._mng))))
+ else:
+ return err
+
+ @property
+ def name(self):
+ """
+ The name of the L{Messenger}.
+ """
+ return pn_messenger_name(self._mng)
+
+ def _get_certificate(self):
+ return pn_messenger_get_certificate(self._mng)
+
+ def _set_certificate(self, value):
+ self._check(pn_messenger_set_certificate(self._mng, value))
+
+ certificate = property(_get_certificate, _set_certificate,
+ doc="""
+ Path to a certificate file for the L{Messenger}. This certificate is
+ used when the L{Messenger} accepts or establishes SSL/TLS connections.
+ This property must be specified for the L{Messenger} to accept
+ incoming SSL/TLS connections and to establish client authenticated
+ outgoing SSL/TLS connection. Non client authenticated outgoing SSL/TLS
+ connections do not require this property.
+ """)
+
+ def _get_private_key(self):
+ return pn_messenger_get_private_key(self._mng)
+
+ def _set_private_key(self, value):
+ self._check(pn_messenger_set_private_key(self._mng, value))
+
+ private_key = property(_get_private_key, _set_private_key,
+ doc="""
+ Path to a private key file for the L{Messenger's<Messenger>}
+ certificate. This property must be specified for the L{Messenger} to
+ accept incoming SSL/TLS connections and to establish client
+ authenticated outgoing SSL/TLS connection. Non client authenticated
+ SSL/TLS connections do not require this property.
+ """)
+
+ def _get_password(self):
+ return pn_messenger_get_password(self._mng)
+
+ def _set_password(self, value):
+ self._check(pn_messenger_set_password(self._mng, value))
+
+ password = property(_get_password, _set_password,
+ doc="""
+ This property contains the password for the L{Messenger.private_key}
+ file, or None if the file is not encrypted.
+ """)
+
+ def _get_trusted_certificates(self):
+ return pn_messenger_get_trusted_certificates(self._mng)
+
+ def _set_trusted_certificates(self, value):
+ self._check(pn_messenger_set_trusted_certificates(self._mng, value))
+
+ trusted_certificates = property(_get_trusted_certificates,
+ _set_trusted_certificates,
+ doc="""
+ A path to a database of trusted certificates for use in verifying the
+ peer on an SSL/TLS connection. If this property is None, then the peer
+ will not be verified.
+ """)
+
+ def _get_timeout(self):
+ t = pn_messenger_get_timeout(self._mng)
+ if t == -1:
+ return None
+ else:
+ return millis2secs(t)
+
+ def _set_timeout(self, value):
+ if value is None:
+ t = -1
+ else:
+ t = secs2millis(value)
+ self._check(pn_messenger_set_timeout(self._mng, t))
+
+ timeout = property(_get_timeout, _set_timeout,
+ doc="""
+ The timeout property contains the default timeout for blocking
+ operations performed by the L{Messenger}.
+ """)
+
+ def _is_blocking(self):
+ return pn_messenger_is_blocking(self._mng)
+
+ def _set_blocking(self, b):
+ self._check(pn_messenger_set_blocking(self._mng, b))
+
+ blocking = property(_is_blocking, _set_blocking,
+ doc="""
+ Enable or disable blocking behavior during L{Message} sending
+ and receiving. This affects every blocking call, with the
+ exception of L{work}. Currently, the affected calls are
+ L{send}, L{recv}, and L{stop}.
+ """)
+
+ def _is_passive(self):
+ return pn_messenger_is_passive(self._mng)
+
+ def _set_passive(self, b):
+ self._check(pn_messenger_set_passive(self._mng, b))
+
+ passive = property(_is_passive, _set_passive,
+ doc="""
+ When passive is set to true, Messenger will not attempt to perform I/O
+ internally. In this mode it is necessary to use the selectables API to
+ drive any I/O needed to perform requested actions. In this mode
+ Messenger will never block.
+ """)
+
+ def _get_incoming_window(self):
+ return pn_messenger_get_incoming_window(self._mng)
+
+ def _set_incoming_window(self, window):
+ self._check(pn_messenger_set_incoming_window(self._mng, window))
+
+ incoming_window = property(_get_incoming_window, _set_incoming_window,
+ doc="""
+ The incoming tracking window for the messenger. The messenger will
+ track the remote status of this many incoming deliveries after they
+ have been accepted or rejected. Defaults to zero.
+
+ L{Messages<Message>} enter this window only when you take them into your application
+ using L{get}. If your incoming window size is I{n}, and you get I{n}+1 L{messages<Message>}
+ without explicitly accepting or rejecting the oldest message, then the
+ message that passes beyond the edge of the incoming window will be assigned
+ the default disposition of its link.
+ """)
+
+ def _get_outgoing_window(self):
+ return pn_messenger_get_outgoing_window(self._mng)
+
+ def _set_outgoing_window(self, window):
+ self._check(pn_messenger_set_outgoing_window(self._mng, window))
+
+ outgoing_window = property(_get_outgoing_window, _set_outgoing_window,
+ doc="""
+ The outgoing tracking window for the messenger. The messenger will
+ track the remote status of this many outgoing deliveries after calling
+ send. Defaults to zero.
+
+ A L{Message} enters this window when you call the put() method with the
+ message. If your outgoing window size is I{n}, and you call L{put} I{n}+1
+ times, status information will no longer be available for the
+ first message.
+ """)
+
+ def start(self):
+ """
+ Currently a no-op placeholder.
+ For future compatibility, do not L{send} or L{recv} messages
+ before starting the L{Messenger}.
+ """
+ self._check(pn_messenger_start(self._mng))
+
+ def stop(self):
+ """
+ Transitions the L{Messenger} to an inactive state. An inactive
+ L{Messenger} will not send or receive messages from its internal
+ queues. A L{Messenger} should be stopped before being discarded to
+ ensure a clean shutdown handshake occurs on any internally managed
+ connections.
+ """
+ self._check(pn_messenger_stop(self._mng))
+
+ @property
+ def stopped(self):
+ """
+ Returns true iff a L{Messenger} is in the stopped state.
+ This function does not block.
+ """
+ return pn_messenger_stopped(self._mng)
+
+ def subscribe(self, source):
+ """
+ Subscribes the L{Messenger} to messages originating from the
+ specified source. The source is an address as specified in the
+ L{Messenger} introduction with the following addition. If the
+ domain portion of the address begins with the '~' character, the
+ L{Messenger} will interpret the domain as host/port, bind to it,
+ and listen for incoming messages. For example "~0.0.0.0",
+ "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
+ local interface and listen for incoming messages with the last
+ variant only permitting incoming SSL connections.
+
+ @type source: string
+ @param source: the source of messages to subscribe to
+ """
+ sub_impl = pn_messenger_subscribe(self._mng, source)
+ if not sub_impl:
+ self._check(pn_error_code(pn_messenger_error(self._mng)))
+ raise MessengerException("Cannot subscribe to %s"%source)
+ return Subscription(sub_impl)
+
+ def put(self, message):
+ """
+ Places the content contained in the message onto the outgoing
+ queue of the L{Messenger}. This method will never block, however
+ it will send any unblocked L{Messages<Message>} in the outgoing
+ queue immediately and leave any blocked L{Messages<Message>}
+ remaining in the outgoing queue. The L{send} call may be used to
+ block until the outgoing queue is empty. The L{outgoing} property
+ may be used to check the depth of the outgoing queue.
+
+ When the content in a given L{Message} object is copied to the outgoing
+ message queue, you may then modify or discard the L{Message} object
+ without having any impact on the content in the outgoing queue.
+
+ This method returns an outgoing tracker for the L{Message}. The tracker
+ can be used to determine the delivery status of the L{Message}.
+
+ @type message: Message
+ @param message: the message to place in the outgoing queue
+ @return: a tracker
+ """
+ message._pre_encode()
+ self._check(pn_messenger_put(self._mng, message._msg))
+ return pn_messenger_outgoing_tracker(self._mng)
+
+ def status(self, tracker):
+ """
+ Gets the last known remote state of the delivery associated with
+ the given tracker.
+
+ @type tracker: tracker
+ @param tracker: the tracker whose status is to be retrieved
+
+ @return: one of None, PENDING, REJECTED, or ACCEPTED
+ """
+ disp = pn_messenger_status(self._mng, tracker);
+ return STATUSES.get(disp, disp)
+
+ def buffered(self, tracker):
+ """
+ Checks if the delivery associated with the given tracker is still
+ waiting to be sent.
+
+ @type tracker: tracker
+ @param tracker: the tracker whose status is to be retrieved
+
+ @return: true if delivery is still buffered
+ """
+ return pn_messenger_buffered(self._mng, tracker);
+
+ def settle(self, tracker=None):
+ """
+ Frees a L{Messenger} from tracking the status associated with a given
+ tracker. If you don't supply a tracker, all outgoing L{messages<Message>} up
+ to the most recent will be settled.
+ """
+ if tracker is None:
+ tracker = pn_messenger_outgoing_tracker(self._mng)
+ flags = PN_CUMULATIVE
+ else:
+ flags = 0
+ self._check(pn_messenger_settle(self._mng, tracker, flags))
+
+ def send(self, n=-1):
+ """
+ This call will block until the indicated number of L{messages<Message>}
+ have been sent, or until the operation times out. If n is -1 this call will
+ block until all outgoing L{messages<Message>} have been sent. If n is 0 then
+ this call will send whatever it can without blocking.
+ """
+ self._check(pn_messenger_send(self._mng, n))
+
+ def recv(self, n=None):
+ """
+ Receives up to I{n} L{messages<Message>} into the incoming queue. If no value
+ for I{n} is supplied, this call will receive as many L{messages<Message>} as it
+ can buffer internally. If the L{Messenger} is in blocking mode, this
+ call will block until at least one L{Message} is available in the
+ incoming queue.
+ """
+ if n is None:
+ n = -1
+ self._check(pn_messenger_recv(self._mng, n))
+
+ def work(self, timeout=None):
+ """
+ Sends or receives any outstanding L{messages<Message>} queued for a L{Messenger}.
+ This will block for the indicated timeout.
+ This method may also do I/O work other than sending and receiving
+ L{messages<Message>}. For example, closing connections after messenger.L{stop}()
+ has been called.
+ """
+ if timeout is None:
+ t = -1
+ else:
+ t = secs2millis(timeout)
+ err = pn_messenger_work(self._mng, t)
+ if (err == PN_TIMEOUT):
+ return False
+ else:
+ self._check(err)
+ return True
+
+ @property
+ def receiving(self):
+ return pn_messenger_receiving(self._mng)
+
+ def interrupt(self):
+ """
+ The L{Messenger} interface is single-threaded.
+ This is the only L{Messenger} function intended to be called
+ from outside of the L{Messenger} thread.
+ Call this from a non-messenger thread to interrupt
+ a L{Messenger} that is blocking.
+ This will cause any in-progress blocking call to throw
+ the L{Interrupt} exception. If there is no currently blocking
+ call, then the next blocking call will be affected, even if it
+ is within the same thread that interrupt was called from.
+ """
+ self._check(pn_messenger_interrupt(self._mng))
+
+ def get(self, message=None):
+ """
+ Moves the message from the head of the incoming message queue into
+ the supplied message object. Any content in the message will be
+ overwritten.
+
+ A tracker for the incoming L{Message} is returned. The tracker can
+ later be used to communicate your acceptance or rejection of the
+ L{Message}.
+
+ If None is passed in for the L{Message} object, the L{Message}
+ popped from the head of the queue is discarded.
+
+ @type message: Message
+ @param message: the destination message object
+ @return: a tracker
+ """
+ if message is None:
+ impl = None
+ else:
+ impl = message._msg
+ self._check(pn_messenger_get(self._mng, impl))
+ if message is not None:
+ message._post_decode()
+ return pn_messenger_incoming_tracker(self._mng)
+
+ def accept(self, tracker=None):
+ """
+ Signal the sender that you have acted on the L{Message}
+ pointed to by the tracker. If no tracker is supplied,
+ then all messages that have been returned by the L{get}
+ method are accepted, except those that have already been
+ auto-settled by passing beyond your incoming window size.
+
+ @type tracker: tracker
+ @param tracker: a tracker as returned by get
+ """
+ if tracker is None:
+ tracker = pn_messenger_incoming_tracker(self._mng)
+ flags = PN_CUMULATIVE
+ else:
+ flags = 0
+ self._check(pn_messenger_accept(self._mng, tracker, flags))
+
+ def reject(self, tracker=None):
+ """
+ Rejects the L{Message} indicated by the tracker. If no tracker
+ is supplied, all messages that have been returned by the L{get}
+ method are rejected, except those that have already been auto-settled
+ by passing beyond your outgoing window size.
+
+ @type tracker: tracker
+ @param tracker: a tracker as returned by get
+ """
+ if tracker is None:
+ tracker = pn_messenger_incoming_tracker(self._mng)
+ flags = PN_CUMULATIVE
+ else:
+ flags = 0
+ self._check(pn_messenger_reject(self._mng, tracker, flags))
+
+ @property
+ def outgoing(self):
+ """
+ The outgoing queue depth.
+ """
+ return pn_messenger_outgoing(self._mng)
+
+ @property
+ def incoming(self):
+ """
+ The incoming queue depth.
+ """
+ return pn_messenger_incoming(self._mng)
+
+ def route(self, pattern, address):
+ """
+ Adds a routing rule to a L{Messenger's<Messenger>} internal routing table.
+
+ The route procedure may be used to influence how a L{Messenger} will
+ internally treat a given address or class of addresses. Every call
+ to the route procedure will result in L{Messenger} appending a routing
+ rule to its internal routing table.
+
+ Whenever a L{Message} is presented to a L{Messenger} for delivery, it
+ will match the address of this message against the set of routing
+ rules in order. The first rule to match will be triggered, and
+ instead of routing based on the address presented in the message,
+ the L{Messenger} will route based on the address supplied in the rule.
+
+ The pattern matching syntax supports two types of matches, a '%'
+ will match any character except a '/', and a '*' will match any
+ character including a '/'.
+
+ A routing address is specified as a normal AMQP address, however it
+ may additionally use substitution variables from the pattern match
+ that triggered the rule.
+
+ Any message sent to "foo" will be routed to "amqp://foo.com":
+
+ >>> messenger.route("foo", "amqp://foo.com");
+
+ Any message sent to "foobar" will be routed to
+ "amqp://foo.com/bar":
+
+ >>> messenger.route("foobar", "amqp://foo.com/bar");
+
+ Any message sent to bar/<path> will be routed to the corresponding
+ path within the amqp://bar.com domain:
+
+ >>> messenger.route("bar/*", "amqp://bar.com/$1");
+
+ Route all L{messages<Message>} over TLS:
+
+ >>> messenger.route("amqp:*", "amqps:$1")
+
+ Supply credentials for foo.com:
+
+ >>> messenger.route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
+
+ Supply credentials for all domains:
+
+ >>> messenger.route("amqp://*", "amqp://user:password@$1");
+
+ Route all addresses through a single proxy while preserving the
+ original destination:
+
+ >>> messenger.route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
+
+ Route any address through a single broker:
+
+ >>> messenger.route("*", "amqp://user:password@broker/$1");
+ """
+ self._check(pn_messenger_route(self._mng, pattern, address))
+
+ def rewrite(self, pattern, address):
+ """
+ Similar to route(), except that the destination of
+ the L{Message} is determined before the message address is rewritten.
+
+ The outgoing address is only rewritten after routing has been
+ finalized. If a message has an outgoing address of
+ "amqp://0.0.0.0:5678", and a rewriting rule that changes its
+ outgoing address to "foo", it will still arrive at the peer that
+ is listening on "amqp://0.0.0.0:5678", but when it arrives there,
+ the receiver will see its outgoing address as "foo".
+
+ The default rewrite rule removes username and password from addresses
+ before they are transmitted.
+ """
+ self._check(pn_messenger_rewrite(self._mng, pattern, address))
+
+ def selectable(self):
+ impl = pn_messenger_selectable(self._mng)
+ if impl:
+ fd = pn_selectable_fd(impl)
+ sel = self._selectables.get(fd, None)
+ if sel is None:
+ sel = Selectable(self, impl)
+ self._selectables[fd] = sel
+ return sel
+ else:
+ return None
+
+ @property
+ def deadline(self):
+ tstamp = pn_messenger_deadline(self._mng)
+ if tstamp:
+ return millis2secs(tstamp)
+ else:
+ return None
+
+ class Message(object):
+ """The L{Message} class is a mutable holder of message content.
+
+ @ivar instructions: delivery instructions for the message
+ @type instructions: dict
+ @ivar annotations: infrastructure defined message annotations
+ @type annotations: dict
+ @ivar properties: application defined message properties
+ @type properties: dict
+ @ivar body: message body
+ @type body: bytes | unicode | dict | list | int | long | float | UUID
+ """
+
+ DATA = PN_DATA
+ TEXT = PN_TEXT
+ AMQP = PN_AMQP
+ JSON = PN_JSON
+
+ DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY
+
+ def __init__(self, **kwargs):
+ """
+ @param kwargs: Message property name/value pairs to initialise the Message
+ """
+ self._msg = pn_message()
+ self._id = Data(pn_message_id(self._msg))
+ self._correlation_id = Data(pn_message_correlation_id(self._msg))
+ self.instructions = None
+ self.annotations = None
+ self.properties = None
+ self.body = None
+ for k,v in kwargs.iteritems():
+ getattr(self, k) # Raise exception if it's not a valid attribute.
+ setattr(self, k, v)
+
+ def __del__(self):
+ if hasattr(self, "_msg"):
+ pn_message_free(self._msg)
+ del self._msg
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, MessageException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_message_error(self._msg))))
+ else:
+ return err
+
+ def _pre_encode(self):
+ inst = Data(pn_message_instructions(self._msg))
+ ann = Data(pn_message_annotations(self._msg))
+ props = Data(pn_message_properties(self._msg))
+ body = Data(pn_message_body(self._msg))
+
+ inst.clear()
+ if self.instructions is not None:
+ inst.put_object(self.instructions)
+ ann.clear()
+ if self.annotations is not None:
+ ann.put_object(self.annotations)
+ props.clear()
+ if self.properties is not None:
+ props.put_object(self.properties)
+ body.clear()
+ if self.body is not None:
+ body.put_object(self.body)
+
+ def _post_decode(self):
+ inst = Data(pn_message_instructions(self._msg))
+ ann = Data(pn_message_annotations(self._msg))
+ props = Data(pn_message_properties(self._msg))
+ body = Data(pn_message_body(self._msg))
+
+ if inst.next():
+ self.instructions = inst.get_object()
+ else:
+ self.instructions = None
+ if ann.next():
+ self.annotations = ann.get_object()
+ else:
+ self.annotations = None
+ if props.next():
+ self.properties = props.get_object()
+ else:
+ self.properties = None
+ if body.next():
+ self.body = body.get_object()
+ else:
+ self.body = None
+
+ def clear(self):
+ """
+ Clears the contents of the L{Message}. All fields will be reset to
+ their default values.
+ """
+ pn_message_clear(self._msg)
+ self.instructions = None
+ self.annotations = None
+ self.properties = None
+ self.body = None
+
+ def _is_inferred(self):
+ return pn_message_is_inferred(self._msg)
+
+ def _set_inferred(self, value):
+ self._check(pn_message_set_inferred(self._msg, bool(value)))
+
+ inferred = property(_is_inferred, _set_inferred, doc="""
+ The inferred flag for a message indicates how the message content
+ is encoded into AMQP sections. If inferred is true then binary and
+ list values in the body of the message will be encoded as AMQP DATA
+ and AMQP SEQUENCE sections, respectively. If inferred is false,
+ then all values in the body of the message will be encoded as AMQP
+ VALUE sections regardless of their type.
+ """)
+
+ def _is_durable(self):
+ return pn_message_is_durable(self._msg)
+
+ def _set_durable(self, value):
+ self._check(pn_message_set_durable(self._msg, bool(value)))
+
+ durable = property(_is_durable, _set_durable,
+ doc="""
+ The durable property indicates that the message should be held durably
+ by any intermediaries taking responsibility for the message.
+ """)
+
+ def _get_priority(self):
+ return pn_message_get_priority(self._msg)
+
+ def _set_priority(self, value):
+ self._check(pn_message_set_priority(self._msg, value))
+
+ priority = property(_get_priority, _set_priority,
+ doc="""
+ The priority of the message.
+ """)
+
+ def _get_ttl(self):
+ return millis2secs(pn_message_get_ttl(self._msg))
+
+ def _set_ttl(self, value):
+ self._check(pn_message_set_ttl(self._msg, secs2millis(value)))
+
+ ttl = property(_get_ttl, _set_ttl,
+ doc="""
+ The time to live of the message measured in seconds. Expired messages
+ may be dropped.
+ """)
+
+ def _is_first_acquirer(self):
+ return pn_message_is_first_acquirer(self._msg)
+
+ def _set_first_acquirer(self, value):
+ self._check(pn_message_set_first_acquirer(self._msg, bool(value)))
+
+ first_acquirer = property(_is_first_acquirer, _set_first_acquirer,
+ doc="""
+ True iff the recipient is the first to acquire the message.
+ """)
+
+ def _get_delivery_count(self):
+ return pn_message_get_delivery_count(self._msg)
+
+ def _set_delivery_count(self, value):
+ self._check(pn_message_set_delivery_count(self._msg, value))
+
+ delivery_count = property(_get_delivery_count, _set_delivery_count,
+ doc="""
+ The number of delivery attempts made for this message.
+ """)
+
+
+ def _get_id(self):
+ return self._id.get_object()
+ def _set_id(self, value):
+ if type(value) in (int, long):
+ value = ulong(value)
+ self._id.rewind()
+ self._id.put_object(value)
+ id = property(_get_id, _set_id,
+ doc="""
+ The id of the message.
+ """)
+
+ def _get_user_id(self):
+ return pn_message_get_user_id(self._msg)
+
+ def _set_user_id(self, value):
+ self._check(pn_message_set_user_id(self._msg, value))
+
+ user_id = property(_get_user_id, _set_user_id,
+ doc="""
+ The user id of the message creator.
+ """)
+
+ def _get_address(self):
+ return pn_message_get_address(self._msg)
+
+ def _set_address(self, value):
+ self._check(pn_message_set_address(self._msg, value))
+
+ address = property(_get_address, _set_address,
+ doc="""
+ The address of the message.
+ """)
+
+ def _get_subject(self):
+ return pn_message_get_subject(self._msg)
+
+ def _set_subject(self, value):
+ self._check(pn_message_set_subject(self._msg, value))
+
+ subject = property(_get_subject, _set_subject,
+ doc="""
+ The subject of the message.
+ """)
+
+ def _get_reply_to(self):
+ return pn_message_get_reply_to(self._msg)
+
+ def _set_reply_to(self, value):
+ self._check(pn_message_set_reply_to(self._msg, value))
+
+ reply_to = property(_get_reply_to, _set_reply_to,
+ doc="""
+ The reply-to address for the message.
+ """)
+
+ def _get_correlation_id(self):
+ return self._correlation_id.get_object()
+ def _set_correlation_id(self, value):
+ if type(value) in (int, long):
+ value = ulong(value)
+ self._correlation_id.rewind()
+ self._correlation_id.put_object(value)
+
+ correlation_id = property(_get_correlation_id, _set_correlation_id,
+ doc="""
+ The correlation-id for the message.
+ """)
+
+ def _get_content_type(self):
+ return pn_message_get_content_type(self._msg)
+
+ def _set_content_type(self, value):
+ self._check(pn_message_set_content_type(self._msg, value))
+
+ content_type = property(_get_content_type, _set_content_type,
+ doc="""
+ The content-type of the message.
+ """)
+
+ def _get_content_encoding(self):
+ return pn_message_get_content_encoding(self._msg)
+
+ def _set_content_encoding(self, value):
+ self._check(pn_message_set_content_encoding(self._msg, value))
+
+ content_encoding = property(_get_content_encoding, _set_content_encoding,
+ doc="""
+ The content-encoding of the message.
+ """)
+
+ def _get_expiry_time(self):
+ return millis2secs(pn_message_get_expiry_time(self._msg))
+
+ def _set_expiry_time(self, value):
+ self._check(pn_message_set_expiry_time(self._msg, secs2millis(value)))
+
+ expiry_time = property(_get_expiry_time, _set_expiry_time,
+ doc="""
+ The expiry time of the message.
+ """)
+
+ def _get_creation_time(self):
+ return millis2secs(pn_message_get_creation_time(self._msg))
+
+ def _set_creation_time(self, value):
+ self._check(pn_message_set_creation_time(self._msg, secs2millis(value)))
+
+ creation_time = property(_get_creation_time, _set_creation_time,
+ doc="""
+ The creation time of the message.
+ """)
+
+ def _get_group_id(self):
+ return pn_message_get_group_id(self._msg)
+
+ def _set_group_id(self, value):
+ self._check(pn_message_set_group_id(self._msg, value))
+
+ group_id = property(_get_group_id, _set_group_id,
+ doc="""
+ The group id of the message.
+ """)
+
+ def _get_group_sequence(self):
+ return pn_message_get_group_sequence(self._msg)
+
+ def _set_group_sequence(self, value):
+ self._check(pn_message_set_group_sequence(self._msg, value))
+
+ group_sequence = property(_get_group_sequence, _set_group_sequence,
+ doc="""
+ The sequence of the message within its group.
+ """)
+
+ def _get_reply_to_group_id(self):
+ return pn_message_get_reply_to_group_id(self._msg)
+
+ def _set_reply_to_group_id(self, value):
+ self._check(pn_message_set_reply_to_group_id(self._msg, value))
+
+ reply_to_group_id = property(_get_reply_to_group_id, _set_reply_to_group_id,
+ doc="""
+ The group-id for any replies.
+ """)
+
+ # XXX
+ def _get_format(self):
+ return pn_message_get_format(self._msg)
+
+ def _set_format(self, value):
+ self._check(pn_message_set_format(self._msg, value))
+
+ format = property(_get_format, _set_format,
+ doc="""
+ The format of the message.
+ """)
+
+ def encode(self):
+ self._pre_encode()
+ sz = 16
+ while True:
+ err, data = pn_message_encode(self._msg, sz)
+ if err == PN_OVERFLOW:
+ sz *= 2
+ continue
+ else:
+ self._check(err)
+ return data
+
+ def decode(self, data):
+ self._check(pn_message_decode(self._msg, data, len(data)))
+ self._post_decode()
+
+ def load(self, data):
+ self._check(pn_message_load(self._msg, data))
+
+ def save(self):
+ sz = 16
+ while True:
+ err, data = pn_message_save(self._msg, sz)
+ if err == PN_OVERFLOW:
+ sz *= 2
+ continue
+ else:
+ self._check(err)
+ return data
+
+ def __repr2__(self):
+ props = []
+ for attr in ("inferred", "address", "reply_to", "durable", "ttl",
+ "priority", "first_acquirer", "delivery_count", "id",
+ "correlation_id", "user_id", "group_id", "group_sequence",
+ "reply_to_group_id", "instructions", "annotations",
+ "properties", "body"):
+ value = getattr(self, attr)
+ if value: props.append("%s=%r" % (attr, value))
+ return "Message(%s)" % ", ".join(props)
+
+ def __repr__(self):
+ tmp = pn_string(None)
+ err = pn_inspect(self._msg, tmp)
+ result = pn_string_get(tmp)
+ pn_free(tmp)
+ self._check(err)
+ return result
+
+ class Subscription(object):
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ @property
+ def address(self):
+ return pn_subscription_address(self._impl)
+
+ class Selectable(object):
+
+ def __init__(self, messenger, impl):
+ self.messenger = messenger
+ self._impl = impl
+
+ def fileno(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_fd(self._impl)
+
+ @property
+ def capacity(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_capacity(self._impl)
+
+ @property
+ def pending(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_pending(self._impl)
+
+ @property
+ def deadline(self):
+ if not self._impl: raise ValueError("selectable freed")
+ tstamp = pn_selectable_deadline(self._impl)
+ if tstamp:
+ return millis2secs(tstamp)
+ else:
+ return None
+
+ def readable(self):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_readable(self._impl)
+
+ def writable(self):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_writable(self._impl)
+
+ def expired(self):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_expired(self._impl)
+
+ def _is_registered(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_is_registered(self._impl)
+
+ def _set_registered(self, registered):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_set_registered(self._impl, registered)
+
+ registered = property(_is_registered, _set_registered,
+ doc="""
+ The registered property may be get/set by an I/O polling system to
+ indicate whether the fd has been registered or not.
+ """)
+
+ @property
+ def is_terminal(self):
+ if not self._impl: return True
+ return pn_selectable_is_terminal(self._impl)
+
+ def free(self):
+ if self._impl:
+ del self.messenger._selectables[self.fileno()]
+ pn_selectable_free(self._impl)
+ self._impl = None
+
+ def __del__(self):
+ self.free()
+
+ class DataException(ProtonException):
+ """
+ The DataException class is the root of the Data exception hierarchy.
+ All exceptions raised by the Data class extend this exception.
+ """
+ pass
+
+ class UnmappedType:
+
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __repr__(self):
+ return "UnmappedType(%s)" % self.msg
+
+ class ulong(long):
+
+ def __repr__(self):
+ return "ulong(%s)" % long.__repr__(self)
+
+ class timestamp(long):
+
+ def __repr__(self):
+ return "timestamp(%s)" % long.__repr__(self)
+
+ class symbol(unicode):
+
+ def __repr__(self):
+ return "symbol(%s)" % unicode.__repr__(self)
+
+ class char(unicode):
+
+ def __repr__(self):
+ return "char(%s)" % unicode.__repr__(self)
+
+ class Described(object):
+
+ def __init__(self, descriptor, value):
+ self.descriptor = descriptor
+ self.value = value
+
+ def __repr__(self):
+ return "Described(%r, %r)" % (self.descriptor, self.value)
+
+ def __eq__(self, o):
+ if isinstance(o, Described):
+ return self.descriptor == o.descriptor and self.value == o.value
+ else:
+ return False
+
+ UNDESCRIBED = Constant("UNDESCRIBED")
+
+ class Array(object):
+
+ def __init__(self, descriptor, type, *elements):
+ self.descriptor = descriptor
+ self.type = type
+ self.elements = elements
+
+ def __repr__(self):
+ if self.elements:
+ els = ", %s" % (", ".join(map(repr, self.elements)))
+ else:
+ els = ""
+ return "Array(%r, %r%s)" % (self.descriptor, self.type, els)
+
+ def __eq__(self, o):
+ if isinstance(o, Array):
+ return self.descriptor == o.descriptor and \
+ self.type == o.type and self.elements == o.elements
+ else:
+ return False
+
+ class Data:
+ """
+ The L{Data} class provides an interface for decoding, extracting,
+ creating, and encoding arbitrary AMQP data. A L{Data} object
+ contains a tree of AMQP values. Leaf nodes in this tree correspond
+ to scalars in the AMQP type system such as L{ints<INT>} or
+ L{strings<STRING>}. Non-leaf nodes in this tree correspond to
+ compound values in the AMQP type system such as L{lists<LIST>},
+ L{maps<MAP>}, L{arrays<ARRAY>}, or L{described values<DESCRIBED>}.
+ The root node of the tree is the L{Data} object itself and can have
+ an arbitrary number of children.
+
+ A L{Data} object maintains the notion of the current sibling node
+ and a current parent node. Siblings are ordered within their parent.
+ Values are accessed and/or added by using the L{next}, L{prev},
+ L{enter}, and L{exit} methods to navigate to the desired location in
+ the tree and using the supplied variety of put_*/get_* methods to
+ access or add a value of the desired type.
+
+ The put_* methods will always add a value I{after} the current node
+ in the tree. If the current node has a next sibling the put_* method
+ will overwrite the value on this node. If there is no current node
+ or the current node has no next sibling then one will be added. The
+ put_* methods always set the added/modified node to the current
+ node. The get_* methods read the value of the current node and do
+ not change which node is current.
+
+ The following types of scalar values are supported:
+
+ - L{NULL}
+ - L{BOOL}
+ - L{UBYTE}
+ - L{USHORT}
+ - L{SHORT}
+ - L{UINT}
+ - L{INT}
+ - L{ULONG}
+ - L{LONG}
+ - L{FLOAT}
+ - L{DOUBLE}
+ - L{BINARY}
+ - L{STRING}
+ - L{SYMBOL}
+
+ The following types of compound values are supported:
+
+ - L{DESCRIBED}
+ - L{ARRAY}
+ - L{LIST}
+ - L{MAP}
+ """
+
+ NULL = PN_NULL; "A null value."
+ BOOL = PN_BOOL; "A boolean value."
+ UBYTE = PN_UBYTE; "An unsigned byte value."
+ BYTE = PN_BYTE; "A signed byte value."
+ USHORT = PN_USHORT; "An unsigned short value."
+ SHORT = PN_SHORT; "A short value."
+ UINT = PN_UINT; "An unsigned int value."
+ INT = PN_INT; "A signed int value."
+ CHAR = PN_CHAR; "A character value."
+ ULONG = PN_ULONG; "An unsigned long value."
+ LONG = PN_LONG; "A signed long value."
+ TIMESTAMP = PN_TIMESTAMP; "A timestamp value."
+ FLOAT = PN_FLOAT; "A float value."
+ DOUBLE = PN_DOUBLE; "A double value."
+ DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value."
+ DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value."
+ DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value."
+ UUID = PN_UUID; "A UUID value."
+ BINARY = PN_BINARY; "A binary string."
+ STRING = PN_STRING; "A unicode string."
+ SYMBOL = PN_SYMBOL; "A symbolic string."
+ DESCRIBED = PN_DESCRIBED; "A described value."
+ ARRAY = PN_ARRAY; "An array value."
+ LIST = PN_LIST; "A list value."
+ MAP = PN_MAP; "A map value."
+
+ type_names = {
+ NULL: "null",
+ BOOL: "bool",
+ BYTE: "byte",
+ UBYTE: "ubyte",
+ SHORT: "short",
+ USHORT: "ushort",
+ INT: "int",
+ UINT: "uint",
+ CHAR: "char",
+ LONG: "long",
+ ULONG: "ulong",
+ TIMESTAMP: "timestamp",
+ FLOAT: "float",
+ DOUBLE: "double",
+ DECIMAL32: "decimal32",
+ DECIMAL64: "decimal64",
+ DECIMAL128: "decimal128",
+ UUID: "uuid",
+ BINARY: "binary",
+ STRING: "string",
+ SYMBOL: "symbol",
+ DESCRIBED: "described",
+ ARRAY: "array",
+ LIST: "list",
+ MAP: "map"
+ }
+
+ @classmethod
+ def type_name(type): return Data.type_names[type]
+
+ def __init__(self, capacity=16):
+ if type(capacity) in (int, long):
+ self._data = pn_data(capacity)
+ self._free = True
+ else:
+ self._data = capacity
+ self._free = False
+
+ def __del__(self):
+ if self._free and hasattr(self, "_data"):
+ pn_data_free(self._data)
+ del self._data
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, DataException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_data_error(self._data))))
+ else:
+ return err
+
+ def clear(self):
+ """
+ Clears the data object.
+ """
+ pn_data_clear(self._data)
+
+ def rewind(self):
+ """
+ Clears current node and sets the parent to the root node. Clearing the
+ current node sets it _before_ the first node, calling next() will advance to
+ the first node.
+ """
+ assert self._data is not None
+ pn_data_rewind(self._data)
+
+ def next(self):
+ """
+ Advances the current node to its next sibling and returns its
+ type. If there is no next sibling the current node remains
+ unchanged and None is returned.
+ """
+ found = pn_data_next(self._data)
+ if found:
+ return self.type()
+ else:
+ return None
+
+ def prev(self):
+ """
+ Advances the current node to its previous sibling and returns its
+ type. If there is no previous sibling the current node remains
+ unchanged and None is returned.
+ """
+ found = pn_data_prev(self._data)
+ if found:
+ return self.type()
+ else:
+ return None
+
+ def enter(self):
+ """
+ Sets the parent node to the current node and clears the current node.
+ Clearing the current node sets it _before_ the first child,
+ call next() advances to the first child.
+ """
+ return pn_data_enter(self._data)
+
+ def exit(self):
+ """
+ Sets the current node to the parent node and the parent node to
+ its own parent.
+ """
+ return pn_data_exit(self._data)
+
+ def lookup(self, name):
+ return pn_data_lookup(self._data, name)
+
+ def narrow(self):
+ pn_data_narrow(self._data)
+
+ def widen(self):
+ pn_data_widen(self._data)
+
+ def type(self):
+ """
+ Returns the type of the current node.
+ """
+ dtype = pn_data_type(self._data)
+ if dtype == -1:
+ return None
+ else:
+ return dtype
+
+ def encode(self):
+ """
+ Returns a representation of the data encoded in AMQP format.
+ """
+ size = 1024
+ while True:
+ cd, enc = pn_data_encode(self._data, size)
+ if cd == PN_OVERFLOW:
+ size *= 2
+ elif cd >= 0:
+ return enc
+ else:
+ self._check(cd)
+
+ def decode(self, encoded):
+ """
+ Decodes the first value from supplied AMQP data and returns the
+ number of bytes consumed.
+
+ @type encoded: binary
+ @param encoded: AMQP encoded binary data
+ """
+ return self._check(pn_data_decode(self._data, encoded))
+
+ def put_list(self):
+ """
+ Puts a list value. Elements may be filled by entering the list
+ node and putting element values.
+
+ >>> data = Data()
+ >>> data.put_list()
+ >>> data.enter()
+ >>> data.put_int(1)
+ >>> data.put_int(2)
+ >>> data.put_int(3)
+ >>> data.exit()
+ """
+ self._check(pn_data_put_list(self._data))
+
+ def put_map(self):
+ """
+ Puts a map value. Elements may be filled by entering the map node
+ and putting alternating key value pairs.
+
+ >>> data = Data()
+ >>> data.put_map()
+ >>> data.enter()
+ >>> data.put_string("key")
+ >>> data.put_string("value")
+ >>> data.exit()
+ """
+ self._check(pn_data_put_map(self._data))
+
+ def put_array(self, described, element_type):
+ """
+ Puts an array value. Elements may be filled by entering the array
+ node and putting the element values. The values must all be of the
+ specified array element type. If an array is described then the
+ first child value of the array is the descriptor and may be of any
+ type.
+
+ >>> data = Data()
+ >>>
+ >>> data.put_array(False, Data.INT)
+ >>> data.enter()
+ >>> data.put_int(1)
+ >>> data.put_int(2)
+ >>> data.put_int(3)
+ >>> data.exit()
+ >>>
+ >>> data.put_array(True, Data.DOUBLE)
+ >>> data.enter()
+ >>> data.put_symbol("array-descriptor")
+ >>> data.put_double(1.1)
+ >>> data.put_double(1.2)
+ >>> data.put_double(1.3)
+ >>> data.exit()
+
+ @type described: bool
+ @param described: specifies whether the array is described
+ @type element_type: int
+ @param element_type: the type of the array elements
+ """
+ self._check(pn_data_put_array(self._data, described, element_type))
+
+ def put_described(self):
+ """
+ Puts a described value. A described node has two children, the
+ descriptor and the value. These are specified by entering the node
+ and putting the desired values.
+
+ >>> data = Data()
+ >>> data.put_described()
+ >>> data.enter()
+ >>> data.put_symbol("value-descriptor")
+ >>> data.put_string("the value")
+ >>> data.exit()
+ """
+ self._check(pn_data_put_described(self._data))
+
+ def put_null(self):
+ """
+ Puts a null value.
+ """
+ self._check(pn_data_put_null(self._data))
+
+ def put_bool(self, b):
+ """
+ Puts a boolean value.
+
+ @param b: a boolean value
+ """
+ self._check(pn_data_put_bool(self._data, b))
+
+ def put_ubyte(self, ub):
+ """
+ Puts an unsigned byte value.
+
+ @param ub: an integral value
+ """
+ self._check(pn_data_put_ubyte(self._data, ub))
+
+ def put_byte(self, b):
+ """
+ Puts a signed byte value.
+
+ @param b: an integral value
+ """
+ self._check(pn_data_put_byte(self._data, b))
+
+ def put_ushort(self, us):
+ """
+ Puts an unsigned short value.
+
+ @param us: an integral value.
+ """
+ self._check(pn_data_put_ushort(self._data, us))
+
+ def put_short(self, s):
+ """
+ Puts a signed short value.
+
+ @param s: an integral value
+ """
+ self._check(pn_data_put_short(self._data, s))
+
+ def put_uint(self, ui):
+ """
+ Puts an unsigned int value.
+
+ @param ui: an integral value
+ """
+ self._check(pn_data_put_uint(self._data, ui))
+
+ def put_int(self, i):
+ """
+ Puts a signed int value.
+
+ @param i: an integral value
+ """
+ self._check(pn_data_put_int(self._data, i))
+
+ def put_char(self, c):
+ """
+ Puts a char value.
+
+ @param c: a single character
+ """
+ self._check(pn_data_put_char(self._data, ord(c)))
+
+ def put_ulong(self, ul):
+ """
+ Puts an unsigned long value.
+
+ @param ul: an integral value
+ """
+ self._check(pn_data_put_ulong(self._data, ul))
+
+ def put_long(self, l):
+ """
+ Puts a signed long value.
+
+ @param l: an integral value
+ """
+ self._check(pn_data_put_long(self._data, l))
+
+ def put_timestamp(self, t):
+ """
+ Puts a timestamp value.
+
+ @param t: an integral value
+ """
+ self._check(pn_data_put_timestamp(self._data, t))
+
+ def put_float(self, f):
+ """
+ Puts a float value.
+
+ @param f: a floating point value
+ """
+ self._check(pn_data_put_float(self._data, f))
+
+ def put_double(self, d):
+ """
+ Puts a double value.
+
+ @param d: a floating point value.
+ """
+ self._check(pn_data_put_double(self._data, d))
+
+ def put_decimal32(self, d):
+ """
+ Puts a decimal32 value.
+
+ @param d: a decimal32 value
+ """
+ self._check(pn_data_put_decimal32(self._data, d))
+
+ def put_decimal64(self, d):
+ """
+ Puts a decimal64 value.
+
+ @param d: a decimal64 value
+ """
+ self._check(pn_data_put_decimal64(self._data, d))
+
+ def put_decimal128(self, d):
+ """
+ Puts a decimal128 value.
+
+ @param d: a decimal128 value
+ """
+ self._check(pn_data_put_decimal128(self._data, d))
+
+ def put_uuid(self, u):
+ """
+ Puts a UUID value.
+
+ @param u: a uuid value
+ """
+ self._check(pn_data_put_uuid(self._data, u.bytes))
+
+ def put_binary(self, b):
+ """
+ Puts a binary value.
+
+ @type b: binary
+ @param b: a binary value
+ """
+ self._check(pn_data_put_binary(self._data, b))
+
+ def put_string(self, s):
+ """
+ Puts a unicode value.
+
+ @type s: unicode
+ @param s: a unicode value
+ """
+ self._check(pn_data_put_string(self._data, s.encode("utf8")))
+
+ def put_symbol(self, s):
+ """
+ Puts a symbolic value.
+
+ @type s: string
+ @param s: the symbol name
+ """
+ self._check(pn_data_put_symbol(self._data, s))
+
+ def get_list(self):
+ """
+ If the current node is a list, return the number of elements,
+ otherwise return zero. List elements can be accessed by entering
+ the list.
+
+ >>> count = data.get_list()
+ >>> data.enter()
+ >>> for i in range(count):
+ ... type = data.next()
+ ... if type == Data.STRING:
+ ... print data.get_string()
+ ... elif type == ...:
+ ... ...
+ >>> data.exit()
+ """
+ return pn_data_get_list(self._data)
+
+ def get_map(self):
+ """
+ If the current node is a map, return the number of child elements,
+ otherwise return zero. Key value pairs can be accessed by entering
+ the map.
+
+ >>> count = data.get_map()
+ >>> data.enter()
+ >>> for i in range(count/2):
+ ... type = data.next()
+ ... if type == Data.STRING:
+ ... print data.get_string()
+ ... elif type == ...:
+ ... ...
+ >>> data.exit()
+ """
+ return pn_data_get_map(self._data)
+
+ def get_array(self):
+ """
+ If the current node is an array, return a tuple of the element
+ count, a boolean indicating whether the array is described, and
+ the type of each element, otherwise return (0, False, None). Array
+ data can be accessed by entering the array.
+
+ >>> # read an array of strings with a symbolic descriptor
+ >>> count, described, type = data.get_array()
+ >>> data.enter()
+ >>> data.next()
+ >>> print "Descriptor:", data.get_symbol()
+ >>> for i in range(count):
+ ... data.next()
+ ... print "Element:", data.get_string()
+ >>> data.exit()
+ """
+ count = pn_data_get_array(self._data)
+ described = pn_data_is_array_described(self._data)
+ type = pn_data_get_array_type(self._data)
+ if type == -1:
+ type = None
+ return count, described, type
+
+ def is_described(self):
+ """
+ Checks if the current node is a described value. The descriptor
+ and value may be accessed by entering the described value.
+
+ >>> # read a symbolically described string
+ >>> assert data.is_described() # will error if the current node is not described
+ >>> data.enter()
+ >>> print data.get_symbol()
+ >>> print data.get_string()
+ >>> data.exit()
+ """
+ return pn_data_is_described(self._data)
+
+ def is_null(self):
+ """
+ Checks if the current node is a null.
+ """
+ return pn_data_is_null(self._data)
+
+ def get_bool(self):
+ """
+ If the current node is a boolean, returns its value, returns False
+ otherwise.
+ """
+ return pn_data_get_bool(self._data)
+
+ def get_ubyte(self):
+ """
+ If the current node is an unsigned byte, returns its value,
+ returns 0 otherwise.
+ """
+ return pn_data_get_ubyte(self._data)
+
+ def get_byte(self):
+ """
+ If the current node is a signed byte, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_byte(self._data)
+
+ def get_ushort(self):
+ """
+ If the current node is an unsigned short, returns its value,
+ returns 0 otherwise.
+ """
+ return pn_data_get_ushort(self._data)
+
+ def get_short(self):
+ """
+ If the current node is a signed short, returns its value, returns
+ 0 otherwise.
+ """
+ return pn_data_get_short(self._data)
+
+ def get_uint(self):
+ """
+ If the current node is an unsigned int, returns its value, returns
+ 0 otherwise.
+ """
+ return pn_data_get_uint(self._data)
+
+ def get_int(self):
+ """
+ If the current node is a signed int, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_int(self._data)
+
+ def get_char(self):
+ """
+ If the current node is a char, returns its value, returns 0
+ otherwise.
+ """
+ return char(unichr(pn_data_get_char(self._data)))
+
+ def get_ulong(self):
+ """
+ If the current node is an unsigned long, returns its value,
+ returns 0 otherwise.
+ """
+ return ulong(pn_data_get_ulong(self._data))
+
+ def get_long(self):
+ """
+ If the current node is an signed long, returns its value, returns
+ 0 otherwise.
+ """
+ return pn_data_get_long(self._data)
+
+ def get_timestamp(self):
+ """
+ If the current node is a timestamp, returns its value, returns 0
+ otherwise.
+ """
+ return timestamp(pn_data_get_timestamp(self._data))
+
+ def get_float(self):
+ """
+ If the current node is a float, returns its value, raises 0
+ otherwise.
+ """
+ return pn_data_get_float(self._data)
+
+ def get_double(self):
+ """
+ If the current node is a double, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_double(self._data)
+
+ # XXX: need to convert
+ def get_decimal32(self):
+ """
+ If the current node is a decimal32, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_decimal32(self._data)
+
+ # XXX: need to convert
+ def get_decimal64(self):
+ """
+ If the current node is a decimal64, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_decimal64(self._data)
+
+ # XXX: need to convert
+ def get_decimal128(self):
+ """
+ If the current node is a decimal128, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_decimal128(self._data)
+
+ def get_uuid(self):
+ """
+ If the current node is a UUID, returns its value, returns None
+ otherwise.
+ """
+ if pn_data_type(self._data) == Data.UUID:
+ return uuid.UUID(bytes=pn_data_get_uuid(self._data))
+ else:
+ return None
+
+ def get_binary(self):
+ """
+ If the current node is binary, returns its value, returns ""
+ otherwise.
+ """
+ return pn_data_get_binary(self._data)
+
+ def get_string(self):
+ """
+ If the current node is a string, returns its value, returns ""
+ otherwise.
+ """
+ return pn_data_get_string(self._data).decode("utf8")
+
+ def get_symbol(self):
+ """
+ If the current node is a symbol, returns its value, returns ""
+ otherwise.
+ """
+ return symbol(pn_data_get_symbol(self._data))
+
+ def copy(self, src):
+ self._check(pn_data_copy(self._data, src._data))
+
+ def format(self):
+ sz = 16
+ while True:
+ err, result = pn_data_format(self._data, sz)
+ if err == PN_OVERFLOW:
+ sz *= 2
+ continue
+ else:
+ self._check(err)
+ return result
+
+ def dump(self):
+ pn_data_dump(self._data)
+
+ def put_dict(self, d):
+ self.put_map()
+ self.enter()
+ try:
+ for k, v in d.items():
+ self.put_object(k)
+ self.put_object(v)
+ finally:
+ self.exit()
+
+ def get_dict(self):
+ if self.enter():
+ try:
+ result = {}
+ while self.next():
+ k = self.get_object()
+ if self.next():
+ v = self.get_object()
+ else:
+ v = None
+ result[k] = v
+ finally:
+ self.exit()
+ return result
+
+ def put_sequence(self, s):
+ self.put_list()
+ self.enter()
+ try:
+ for o in s:
+ self.put_object(o)
+ finally:
+ self.exit()
+
+ def get_sequence(self):
+ if self.enter():
+ try:
+ result = []
+ while self.next():
+ result.append(self.get_object())
+ finally:
+ self.exit()
+ return result
+
+ def get_py_described(self):
+ if self.enter():
+ try:
+ self.next()
+ descriptor = self.get_object()
+ self.next()
+ value = self.get_object()
+ finally:
+ self.exit()
+ return Described(descriptor, value)
+
+ def put_py_described(self, d):
+ self.put_described()
+ self.enter()
+ try:
+ self.put_object(d.descriptor)
+ self.put_object(d.value)
+ finally:
+ self.exit()
+
+ def get_py_array(self):
+ """
+ If the current node is an array, return an Array object
+ representing the array and its contents. Otherwise return None.
+ This is a convenience wrapper around get_array, enter, etc.
+ """
+
+ count, described, type = self.get_array()
+ if type is None: return None
+ if self.enter():
+ try:
+ if described:
+ self.next()
+ descriptor = self.get_object()
+ else:
+ descriptor = UNDESCRIBED
+ elements = []
+ while self.next():
+ elements.append(self.get_object())
+ finally:
+ self.exit()
+ return Array(descriptor, type, *elements)
+
+ def put_py_array(self, a):
+ described = a.descriptor != UNDESCRIBED
+ self.put_array(described, a.type)
+ self.enter()
+ try:
+ if described:
+ self.put_object(a.descriptor)
+ for e in a.elements:
+ self.put_object(e)
+ finally:
+ self.exit()
+
+ put_mappings = {
+ None.__class__: lambda s, _: s.put_null(),
+ bool: put_bool,
+ dict: put_dict,
+ list: put_sequence,
+ tuple: put_sequence,
+ unicode: put_string,
+ bytes: put_binary,
+ symbol: put_symbol,
+ int: put_long,
+ char: put_char,
+ long: put_long,
+ ulong: put_ulong,
+ timestamp: put_timestamp,
+ float: put_double,
+ uuid.UUID: put_uuid,
+ Described: put_py_described,
+ Array: put_py_array
+ }
+ get_mappings = {
+ NULL: lambda s: None,
+ BOOL: get_bool,
+ BYTE: get_byte,
+ UBYTE: get_ubyte,
+ SHORT: get_short,
+ USHORT: get_ushort,
+ INT: get_int,
+ UINT: get_uint,
+ CHAR: get_char,
+ LONG: get_long,
+ ULONG: get_ulong,
+ TIMESTAMP: get_timestamp,
+ FLOAT: get_float,
+ DOUBLE: get_double,
+ DECIMAL32: get_decimal32,
+ DECIMAL64: get_decimal64,
+ DECIMAL128: get_decimal128,
+ UUID: get_uuid,
+ BINARY: get_binary,
+ STRING: get_string,
+ SYMBOL: get_symbol,
+ DESCRIBED: get_py_described,
+ ARRAY: get_py_array,
+ LIST: get_sequence,
+ MAP: get_dict
+ }
+
+
+ def put_object(self, obj):
+ putter = self.put_mappings[obj.__class__]
+ putter(self, obj)
+
+ def get_object(self):
+ type = self.type()
+ if type is None: return None
+ getter = self.get_mappings.get(type)
+ if getter:
+ return getter(self)
+ else:
+ return UnmappedType(str(type))
+
+ class ConnectionException(ProtonException):
+ pass
+
+ class Endpoint(object):
+
+ LOCAL_UNINIT = PN_LOCAL_UNINIT
+ REMOTE_UNINIT = PN_REMOTE_UNINIT
+ LOCAL_ACTIVE = PN_LOCAL_ACTIVE
+ REMOTE_ACTIVE = PN_REMOTE_ACTIVE
+ LOCAL_CLOSED = PN_LOCAL_CLOSED
+ REMOTE_CLOSED = PN_REMOTE_CLOSED
+
+ def __init__(self):
+ self.condition = None
+ self._release_invoked = False
+
+ def _release(self):
+ """Release the underlying C Engine resource."""
+ if not self._release_invoked:
+ for c in self._children:
+ c._release()
+ self._free_resource()
+ self.connection._releasing(self)
+ self._release_invoked = True
+
+ def _update_cond(self):
+ obj2cond(self.condition, self._get_cond_impl())
+
+ @property
+ def remote_condition(self):
+ return cond2obj(self._get_remote_cond_impl())
+
+ # the following must be provided by subclasses
+ def _get_cond_impl(self):
+ assert False, "Subclass must override this!"
+
+ def _get_remote_cond_impl(self):
+ assert False, "Subclass must override this!"
+
+ class Condition:
+
+ def __init__(self, name, description=None, info=None):
+ self.name = name
+ self.description = description
+ self.info = info
+
+ def __repr__(self):
+ return "Condition(%s)" % ", ".join([repr(x) for x in
+ (self.name, self.description, self.info)
+ if x])
+
+ def __eq__(self, o):
+ if not isinstance(o, Condition): return False
+ return self.name == o.name and \
+ self.description == o.description and \
+ self.info == o.info
+
+ def obj2cond(obj, cond):
+ pn_condition_clear(cond)
+ if obj:
+ pn_condition_set_name(cond, str(obj.name))
+ pn_condition_set_description(cond, obj.description)
+ info = Data(pn_condition_info(cond))
+ if obj.info:
+ info.put_object(obj.info)
+
+ def cond2obj(cond):
+ if pn_condition_is_set(cond):
+ return Condition(pn_condition_get_name(cond),
+ pn_condition_get_description(cond),
+ dat2obj(pn_condition_info(cond)))
+ else:
+ return None
+
+ def dat2obj(dimpl):
+ if dimpl:
+ d = Data(dimpl)
+ d.rewind()
+ d.next()
+ obj = d.get_object()
+ d.rewind()
+ return obj
+
+ def obj2dat(obj, dimpl):
+ if obj is not None:
+ d = Data(dimpl)
+ d.put_object(obj)
+
+ def secs2millis(secs):
+ return long(secs*1000)
+
+ def millis2secs(millis):
+ return float(millis)/1000.0
+
+ class Connection(Endpoint):
+
+ @staticmethod
+ def _wrap_connection(c_conn):
+ """Maintain only a single instance of this class for each Connection
+ object that exists in the the C Engine. This is done by storing a (weak)
+ reference to the python instance in the context field of the C object.
+ """
+ if not c_conn: return None
+ py_conn = pn_void2py(pn_connection_get_context(c_conn))
+ if py_conn: return py_conn
+ wrapper = Connection(_conn=c_conn)
+ return wrapper
+
+ def __init__(self, _conn=None):
+ Endpoint.__init__(self)
+ if _conn:
+ self._conn = _conn
+ else:
+ self._conn = pn_connection()
+ pn_connection_set_context(self._conn, pn_py2void(self))
+ self.offered_capabilities = None
+ self.desired_capabilities = None
+ self.properties = None
+ self._sessions = set()
+
+ def __del__(self):
+ if hasattr(self, "_conn") and self._conn:
+ self._release()
+
+ def free(self):
+ self._release()
+
+ @property
+ def _children(self):
+ return self._sessions
+
+ @property
+ def connection(self):
+ return self
+
+ def _free_resource(self):
+ pn_connection_free(self._conn)
+
+ def _released(self):
+ self._conn = None
+
+ def _releasing(self, child):
+ coll = getattr(self, "_collector", None)
+ if coll: coll = coll()
+ if coll:
+ coll._contexts.add(child)
+ else:
+ child._released()
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, ConnectionException)
+ raise exc("[%s]: %s" % (err, pn_connection_error(self._conn)))
+ else:
+ return err
+
+ def _get_cond_impl(self):
+ return pn_connection_condition(self._conn)
+
+ def _get_remote_cond_impl(self):
+ return pn_connection_remote_condition(self._conn)
+
+ def collect(self, collector):
+ if collector is None:
+ pn_connection_collect(self._conn, None)
+ else:
+ pn_connection_collect(self._conn, collector._impl)
+ self._collector = weakref.ref(collector)
+
+ def _get_container(self):
+ return pn_connection_get_container(self._conn)
+ def _set_container(self, name):
+ return pn_connection_set_container(self._conn, name)
+
+ container = property(_get_container, _set_container)
+
+ def _get_hostname(self):
+ return pn_connection_get_hostname(self._conn)
+ def _set_hostname(self, name):
+ return pn_connection_set_hostname(self._conn, name)
+
+ hostname = property(_get_hostname, _set_hostname)
+
+ @property
+ def remote_container(self):
+ return pn_connection_remote_container(self._conn)
+
+ @property
+ def remote_hostname(self):
+ return pn_connection_remote_hostname(self._conn)
+
+ @property
+ def remote_offered_capabilities(self):
+ return dat2obj(pn_connection_remote_offered_capabilities(self._conn))
+
+ @property
+ def remote_desired_capabilities(self):
+ return dat2obj(pn_connection_remote_desired_capabilities(self._conn))
+
+ @property
+ def remote_properties(self):
+ return dat2obj(pn_connection_remote_properties(self._conn))
+
+ def open(self):
+ obj2dat(self.offered_capabilities,
+ pn_connection_offered_capabilities(self._conn))
+ obj2dat(self.desired_capabilities,
+ pn_connection_desired_capabilities(self._conn))
+ obj2dat(self.properties, pn_connection_properties(self._conn))
+ pn_connection_open(self._conn)
+
+ def close(self):
+ self._update_cond()
+ pn_connection_close(self._conn)
+
+ @property
+ def state(self):
+ return pn_connection_state(self._conn)
+
+ def session(self):
+ return Session._wrap_session(pn_session(self._conn))
+
+ def session_head(self, mask):
+ return Session._wrap_session(pn_session_head(self._conn, mask))
+
+ def link_head(self, mask):
+ return Link._wrap_link(pn_link_head(self._conn, mask))
+
+ @property
+ def work_head(self):
+ return Delivery._wrap_delivery(pn_work_head(self._conn))
+
+ @property
+ def error(self):
+ return pn_error_code(pn_connection_error(self._conn))
+
+ class SessionException(ProtonException):
+ pass
+
+ class Session(Endpoint):
+
+ @staticmethod
+ def _wrap_session(c_ssn):
+ """Maintain only a single instance of this class for each Session object that
+ exists in the C Engine.
+ """
+ if c_ssn is None: return None
+ py_ssn = pn_void2py(pn_session_get_context(c_ssn))
+ if py_ssn: return py_ssn
+ wrapper = Session(c_ssn)
+ return wrapper
+
+ def __init__(self, ssn):
+ Endpoint.__init__(self)
+ self._ssn = ssn
+ pn_session_set_context(self._ssn, pn_py2void(self))
+ self._links = set()
+ self.connection._sessions.add(self)
+
+ @property
+ def _children(self):
+ return self._links
+
+ def _free_resource(self):
+ pn_session_free(self._ssn)
+
+ def _released(self):
+ self._ssn = None
+
+ def free(self):
+ """Release the Session, freeing its resources.
+
+ Call this when you no longer need the session. This will allow the
+ session's resources to be reclaimed. Once called, you should no longer
+ reference the session.
+
+ """
+ self.connection._sessions.remove(self)
+ self._release()
+
+ def _get_cond_impl(self):
+ return pn_session_condition(self._ssn)
+
+ def _get_remote_cond_impl(self):
+ return pn_session_remote_condition(self._ssn)
+
+ def _get_incoming_capacity(self):
+ return pn_session_get_incoming_capacity(self._ssn)
+
+ def _set_incoming_capacity(self, capacity):
+ pn_session_set_incoming_capacity(self._ssn, capacity)
+
+ incoming_capacity = property(_get_incoming_capacity, _set_incoming_capacity)
+
+ @property
+ def outgoing_bytes(self):
+ return pn_session_outgoing_bytes(self._ssn)
+
+ @property
+ def incoming_bytes(self):
+ return pn_session_incoming_bytes(self._ssn)
+
+ def open(self):
+ pn_session_open(self._ssn)
+
+ def close(self):
+ self._update_cond()
+ pn_session_close(self._ssn)
+
+ def next(self, mask):
+ return Session._wrap_session(pn_session_next(self._ssn, mask))
+
+ @property
+ def state(self):
+ return pn_session_state(self._ssn)
+
+ @property
+ def connection(self):
+ return Connection._wrap_connection(pn_session_connection(self._ssn))
+
+ def sender(self, name):
+ return Link._wrap_link(pn_sender(self._ssn, name))
+
+ def receiver(self, name):
+ return Link._wrap_link(pn_receiver(self._ssn, name))
+
+ class LinkException(ProtonException):
+ pass
+
+ class Link(Endpoint):
+
+ SND_UNSETTLED = PN_SND_UNSETTLED
+ SND_SETTLED = PN_SND_SETTLED
+ SND_MIXED = PN_SND_MIXED
+
+ RCV_FIRST = PN_RCV_FIRST
+ RCV_SECOND = PN_RCV_SECOND
+
+ @staticmethod
+ def _wrap_link(c_link):
+ """Maintain only a single instance of this class for each Session object that
+ exists in the C Engine.
+ """
+ if c_link is None: return None
+ py_link = pn_void2py(pn_link_get_context(c_link))
+ if py_link: return py_link
+ if pn_link_is_sender(c_link):
+ wrapper = Sender(c_link)
+ else:
+ wrapper = Receiver(c_link)
+ return wrapper
+
+ def __init__(self, c_link):
+ Endpoint.__init__(self)
+ self._link = c_link
+ pn_link_set_context(self._link, pn_py2void(self))
+ self._deliveries = set()
+ self.session._links.add(self)
+
+ @property
+ def _children(self):
+ return self._deliveries
+
+ def _free_resource(self):
+ pn_link_free(self._link)
+
+ def _released(self):
+ self._link = None
+
+ def free(self):
+ """Release the Link, freeing its resources"""
+ self.session._links.remove(self)
+ self._release()
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, LinkException)
+ raise exc("[%s]: %s" % (err, pn_link_error(self._link)))
+ else:
+ return err
+
+ def _get_cond_impl(self):
+ return pn_link_condition(self._link)
+
+ def _get_remote_cond_impl(self):
+ return pn_link_remote_condition(self._link)
+
+ def open(self):
+ pn_link_open(self._link)
+
+ def close(self):
+ self._update_cond()
+ pn_link_close(self._link)
+
+ @property
+ def state(self):
+ return pn_link_state(self._link)
+
+ @property
+ def source(self):
+ return Terminus(pn_link_source(self._link))
+
+ @property
+ def target(self):
+ return Terminus(pn_link_target(self._link))
+
+ @property
+ def remote_source(self):
+ return Terminus(pn_link_remote_source(self._link))
+ @property
+ def remote_target(self):
+ return Terminus(pn_link_remote_target(self._link))
+
+ @property
+ def session(self):
+ return Session._wrap_session(pn_link_session(self._link))
+
+ @property
+ def connection(self):
+ return self.session.connection
+
+ def delivery(self, tag):
+ return Delivery._wrap_delivery(pn_delivery(self._link, tag))
+
+ @property
+ def current(self):
+ return Delivery._wrap_delivery(pn_link_current(self._link))
+
+ def advance(self):
+ return pn_link_advance(self._link)
+
+ @property
+ def unsettled(self):
+ return pn_link_unsettled(self._link)
+
+ @property
+ def credit(self):
+ return pn_link_credit(self._link)
+
+ @property
+ def available(self):
+ return pn_link_available(self._link)
+
+ @property
+ def queued(self):
+ return pn_link_queued(self._link)
+
+ def next(self, mask):
+ return Link._wrap_link(pn_link_next(self._link, mask))
+
+ @property
+ def name(self):
+ return pn_link_name(self._link)
+
+ @property
+ def is_sender(self):
+ return pn_link_is_sender(self._link)
+
+ @property
+ def is_receiver(self):
+ return pn_link_is_receiver(self._link)
+
+ @property
+ def remote_snd_settle_mode(self):
+ return pn_link_remote_snd_settle_mode(self._link)
+
+ @property
+ def remote_rcv_settle_mode(self):
+ return pn_link_remote_rcv_settle_mode(self._link)
+
+ def _get_snd_settle_mode(self):
+ return pn_link_snd_settle_mode(self._link)
+ def _set_snd_settle_mode(self, mode):
+ pn_link_set_snd_settle_mode(self._link, mode)
+ snd_settle_mode = property(_get_snd_settle_mode, _set_snd_settle_mode)
+
+ def _get_rcv_settle_mode(self):
+ return pn_link_rcv_settle_mode(self._link)
+ def _set_rcv_settle_mode(self, mode):
+ pn_link_set_rcv_settle_mode(self._link, mode)
+ rcv_settle_mode = property(_get_rcv_settle_mode, _set_rcv_settle_mode)
+
+ def drained(self):
+ return pn_link_drained(self._link)
+
+ def detach(self):
+ return pn_link_detach(self._link)
+
+ class Terminus(object):
+
+ UNSPECIFIED = PN_UNSPECIFIED
+ SOURCE = PN_SOURCE
+ TARGET = PN_TARGET
+ COORDINATOR = PN_COORDINATOR
+
+ NONDURABLE = PN_NONDURABLE
+ CONFIGURATION = PN_CONFIGURATION
+ DELIVERIES = PN_DELIVERIES
+
+ DIST_MODE_UNSPECIFIED = PN_DIST_MODE_UNSPECIFIED
+ DIST_MODE_COPY = PN_DIST_MODE_COPY
+ DIST_MODE_MOVE = PN_DIST_MODE_MOVE
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, LinkException)
+ raise exc("[%s]" % err)
+ else:
+ return err
+
+ def _get_type(self):
+ return pn_terminus_get_type(self._impl)
+ def _set_type(self, type):
+ self._check(pn_terminus_set_type(self._impl, type))
+ type = property(_get_type, _set_type)
+
+ def _get_address(self):
+ return pn_terminus_get_address(self._impl)
+ def _set_address(self, address):
+ self._check(pn_terminus_set_address(self._impl, address))
+ address = property(_get_address, _set_address)
+
+ def _get_durability(self):
+ return pn_terminus_get_durability(self._impl)
+ def _set_durability(self, seconds):
+ self._check(pn_terminus_set_durability(self._impl, seconds))
+ durability = property(_get_durability, _set_durability)
+
+ def _get_expiry_policy(self):
+ return pn_terminus_get_expiry_policy(self._impl)
+ def _set_expiry_policy(self, seconds):
+ self._check(pn_terminus_set_expiry_policy(self._impl, seconds))
+ expiry_policy = property(_get_expiry_policy, _set_expiry_policy)
+
+ def _get_timeout(self):
+ return pn_terminus_get_timeout(self._impl)
+ def _set_timeout(self, seconds):
+ self._check(pn_terminus_set_timeout(self._impl, seconds))
+ timeout = property(_get_timeout, _set_timeout)
+
+ def _is_dynamic(self):
+ return pn_terminus_is_dynamic(self._impl)
+ def _set_dynamic(self, dynamic):
+ self._check(pn_terminus_set_dynamic(self._impl, dynamic))
+ dynamic = property(_is_dynamic, _set_dynamic)
+
+ def _get_distribution_mode(self):
+ return pn_terminus_get_distribution_mode(self._impl)
+ def _set_distribution_mode(self, mode):
+ self._check(pn_terminus_set_distribution_mode(self._impl, mode))
+ distribution_mode = property(_get_distribution_mode, _set_distribution_mode)
+
+ @property
+ def properties(self):
+ return Data(pn_terminus_properties(self._impl))
+
+ @property
+ def capabilities(self):
+ return Data(pn_terminus_capabilities(self._impl))
+
+ @property
+ def outcomes(self):
+ return Data(pn_terminus_outcomes(self._impl))
+
+ @property
+ def filter(self):
+ return Data(pn_terminus_filter(self._impl))
+
+ def copy(self, src):
+ self._check(pn_terminus_copy(self._impl, src._impl))
+
+ class Sender(Link):
+
+ def __init__(self, c_link):
+ super(Sender, self).__init__(c_link)
+
+ def offered(self, n):
+ pn_link_offered(self._link, n)
+
+ def send(self, bytes):
+ return self._check(pn_link_send(self._link, bytes))
+
+ class Receiver(Link):
+
+ def __init__(self, c_link):
+ super(Receiver, self).__init__(c_link)
+
+ def flow(self, n):
+ pn_link_flow(self._link, n)
+
+ def recv(self, limit):
+ n, bytes = pn_link_recv(self._link, limit)
+ if n == PN_EOS:
+ return None
+ else:
+ self._check(n)
+ return bytes
+
+ def drain(self, n):
+ pn_link_drain(self._link, n)
+
+ def draining(self):
+ return pn_link_draining(self._link)
+
+ class NamedInt(int):
+
+ values = {}
+
+ def __new__(cls, i, name):
+ ni = super(NamedInt, cls).__new__(cls, i)
+ cls.values[i] = ni
+ return ni
+
+ def __init__(self, i, name):
+ self.name = name
+
+ def __repr__(self):
+ return self.name
+
+ def __str__(self):
+ return self.name
+
+ @classmethod
+ def get(cls, i):
+ return cls.values.get(i, i)
+
+ class DispositionType(NamedInt):
+ values = {}
+
+ class Disposition(object):
+
+ RECEIVED = DispositionType(PN_RECEIVED, "RECEIVED")
+ ACCEPTED = DispositionType(PN_ACCEPTED, "ACCEPTED")
+ REJECTED = DispositionType(PN_REJECTED, "REJECTED")
+ RELEASED = DispositionType(PN_RELEASED, "RELEASED")
+ MODIFIED = DispositionType(PN_MODIFIED, "MODIFIED")
+
+ def __init__(self, impl, local):
+ self._impl = impl
+ self.local = local
+ self._data = None
+ self._condition = None
+ self._annotations = None
+
+ @property
+ def type(self):
+ return DispositionType.get(pn_disposition_type(self._impl))
+
+ def _get_section_number(self):
+ return pn_disposition_get_section_number(self._impl)
+ def _set_section_number(self, n):
+ pn_disposition_set_section_number(self._impl, n)
+ section_number = property(_get_section_number, _set_section_number)
+
+ def _get_section_offset(self):
+ return pn_disposition_get_section_offset(self._impl)
+ def _set_section_offset(self, n):
+ pn_disposition_set_section_offset(self._impl, n)
+ section_offset = property(_get_section_offset, _set_section_offset)
+
+ def _get_failed(self):
+ return pn_disposition_is_failed(self._impl)
+ def _set_failed(self, b):
+ pn_disposition_set_failed(self._impl, b)
+ failed = property(_get_failed, _set_failed)
+
+ def _get_undeliverable(self):
+ return pn_disposition_is_undeliverable(self._impl)
+ def _set_undeliverable(self, b):
+ pn_disposition_set_undeliverable(self._impl, b)
+ undeliverable = property(_get_undeliverable, _set_undeliverable)
+
+ def _get_data(self):
+ if self.local:
+ return self._data
+ else:
+ return dat2obj(pn_disposition_data(self._impl))
+ def _set_data(self, obj):
+ if self.local:
+ self._data = obj
+ else:
+ raise AttributeError("data attribute is read-only")
+ data = property(_get_data, _set_data)
+
+ def _get_annotations(self):
+ if self.local:
+ return self._annotations
+ else:
+ return dat2obj(pn_disposition_annotations(self._impl))
+ def _set_annotations(self, obj):
+ if self.local:
+ self._annotations = obj
+ else:
+ raise AttributeError("annotations attribute is read-only")
+ annotations = property(_get_annotations, _set_annotations)
+
+ def _get_condition(self):
+ if self.local:
+ return self._condition
+ else:
+ return cond2obj(pn_disposition_condition(self._impl))
+ def _set_condition(self, obj):
+ if self.local:
+ self._condition = obj
+ else:
+ raise AttributeError("condition attribute is read-only")
+ condition = property(_get_condition, _set_condition)
+
+ class Delivery(object):
+
+ RECEIVED = Disposition.RECEIVED
+ ACCEPTED = Disposition.ACCEPTED
+ REJECTED = Disposition.REJECTED
+ RELEASED = Disposition.RELEASED
+ MODIFIED = Disposition.MODIFIED
+
+ @staticmethod
+ def _wrap_delivery(c_dlv):
+ """Maintain only a single instance of this class for each Delivery object that
+ exists in the C Engine.
+ """
+ if not c_dlv: return None
+ py_dlv = pn_void2py(pn_delivery_get_context(c_dlv))
+ if py_dlv: return py_dlv
+ wrapper = Delivery(c_dlv)
+ return wrapper
+
+ def __init__(self, dlv):
+ self._dlv = dlv
+ pn_delivery_set_context(self._dlv, pn_py2void(self))
+ self.local = Disposition(pn_delivery_local(self._dlv), True)
+ self.remote = Disposition(pn_delivery_remote(self._dlv), False)
+ self.link._deliveries.add(self)
+
+ def __del__(self):
+ self._release()
+
+ def _release(self):
+ """Release the underlying C Engine resource."""
+ if self._dlv:
+ pn_delivery_set_context(self._dlv, pn_py2void(None))
+ pn_delivery_settle(self._dlv)
+ self._dlv = None
+
+ @property
+ def released(self):
+ return self._dlv is None
+
+ @property
+ def tag(self):
+ return pn_delivery_tag(self._dlv)
+
+ @property
+ def writable(self):
+ return pn_delivery_writable(self._dlv)
+
+ @property
+ def readable(self):
+ return pn_delivery_readable(self._dlv)
+
+ @property
+ def updated(self):
+ return pn_delivery_updated(self._dlv)
+
+ def update(self, state):
+ obj2dat(self.local._data, pn_disposition_data(self.local._impl))
+ obj2dat(self.local._annotations, pn_disposition_annotations(self.local._impl))
+ obj2cond(self.local._condition, pn_disposition_condition(self.local._impl))
+ pn_delivery_update(self._dlv, state)
+
+ @property
+ def pending(self):
+ return pn_delivery_pending(self._dlv)
+
+ @property
+ def partial(self):
+ return pn_delivery_partial(self._dlv)
+
+ @property
+ def local_state(self):
+ return DispositionType.get(pn_delivery_local_state(self._dlv))
+
+ @property
+ def remote_state(self):
+ return DispositionType.get(pn_delivery_remote_state(self._dlv))
+
+ @property
+ def settled(self):
+ return pn_delivery_settled(self._dlv)
+
+ def settle(self):
+ """Release the delivery"""
+ self.link._deliveries.remove(self)
+ self._release()
+
+ @property
+ def work_next(self):
+ return Delivery._wrap_delivery(pn_work_next(self._dlv))
+
+ @property
+ def link(self):
+ return Link._wrap_link(pn_delivery_link(self._dlv))
+
+ class TransportException(ProtonException):
+ pass
+
+ class Transport(object):
+
+ TRACE_OFF = PN_TRACE_OFF
+ TRACE_DRV = PN_TRACE_DRV
+ TRACE_FRM = PN_TRACE_FRM
+ TRACE_RAW = PN_TRACE_RAW
+
+ CLIENT = 1
+ SERVER = 2
+
+ @staticmethod
+ def _wrap_transport(c_trans):
+ if not c_trans: return None
+ wrapper = Transport(_trans=c_trans)
+ return
<TRUNCATED>
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d02fdad1/proton-c/src/transport/transport.c
----------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[17/35] qpid-proton git commit: PROTON-749,
PROTON-750: Merge these changes into development stream.
Posted by gs...@apache.org.
PROTON-749, PROTON-750: Merge these changes into development stream.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b4e06d34
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b4e06d34
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b4e06d34
Branch: refs/heads/examples
Commit: b4e06d34a83cd942ea88a5e19ad938be312ed2ae
Parents: 7b91e1f 0cc9134
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Nov 20 10:51:10 2014 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Nov 20 10:51:10 2014 -0500
----------------------------------------------------------------------
proton-c/CMakeLists.txt | 1 +
proton-c/bindings/python/proton.py | 35 +-
proton-c/include/proton/cproton.i | 2 +-
proton-c/include/proton/sasl.h | 20 +-
proton-c/include/proton/ssl.h | 6 +
proton-c/include/proton/transport.h | 20 +-
proton-c/src/engine/engine-internal.h | 36 +-
proton-c/src/messenger/messenger.c | 3 +-
proton-c/src/posix/driver.c | 8 +-
proton-c/src/proton.c | 10 +-
proton-c/src/sasl/sasl-internal.h | 6 +-
proton-c/src/sasl/sasl.c | 294 +++++++-----
proton-c/src/ssl/openssl.c | 452 ++++++++-----------
proton-c/src/ssl/ssl-internal.h | 6 +-
proton-c/src/ssl/ssl_stub.c | 22 +-
proton-c/src/tests/engine.c | 3 +
proton-c/src/transport/autodetect.c | 135 ++++++
proton-c/src/transport/autodetect.h | 40 ++
proton-c/src/transport/transport.c | 422 +++++++++++------
proton-c/src/windows/driver.c | 8 +-
proton-c/src/windows/schannel.c | 371 +++++++--------
.../qpid/proton/engine/impl/SaslImpl.java | 7 +-
proton-j/src/main/resources/cengine.py | 5 +-
proton-j/src/main/resources/csasl.py | 14 +-
proton-j/src/main/resources/cssl.py | 3 +
tests/python/proton_tests/common.py | 13 +-
tests/python/proton_tests/engine.py | 3 -
tests/python/proton_tests/sasl.py | 14 +-
28 files changed, 1132 insertions(+), 827 deletions(-)
----------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[19/35] qpid-proton git commit: NO-JIRA: Fix a few Ruby method names
to fit naming conventions.
Posted by gs...@apache.org.
NO-JIRA: Fix a few Ruby method names to fit naming conventions.
Messenger::receiving and Messenger::stopped renamed to
Messenger::receiving? and Messenger::stopped?
Also fixed a typo in one rdoc and added rdoc to receiving?
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b13222b8
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b13222b8
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b13222b8
Branch: refs/heads/examples
Commit: b13222b8214f4690c169eefc13354ff5f6479c2e
Parents: 1d3a138
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Thu Nov 20 13:45:15 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Thu Nov 20 13:46:17 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/ruby/lib/qpid_proton/messenger.rb | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b13222b8/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index 66a2f93..f17205d 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -208,10 +208,10 @@ module Qpid
Cproton.pn_messenger_stop(@impl)
end
- # Returns true iff a Messenger is in the stopped state.
+ # Returns true if a Messenger is in the stopped state.
# This function does not block.
#
- def stopped
+ def stopped?
Cproton.pn_messenger_stopped(@impl)
end
@@ -389,7 +389,8 @@ module Qpid
Cproton.pn_messenger_recv(@impl, limit)
end
- def receiving
+ # Returns true if the messenger is currently receiving data.
+ def receiving?
Cproton.pn_messenger_receiving(@impl)
end
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[34/35] qpid-proton git commit: moved supporting code into proton
package
Posted by gs...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/proton_reactors.py
----------------------------------------------------------------------
diff --git a/tutorial/proton_reactors.py b/tutorial/proton_reactors.py
deleted file mode 100644
index f431b24..0000000
--- a/tutorial/proton_reactors.py
+++ /dev/null
@@ -1,749 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-import heapq, os, Queue, socket, time, types
-from proton import dispatch, generate_uuid, PN_ACCEPTED, SASL, symbol, ulong, Url
-from proton import Collector, Connection, Delivery, Described, Endpoint, Event, Link, Terminus, Timeout
-from proton import Message, Handler, ProtonException, Transport, TransportException, ConnectionException
-from select import select
-from proton_handlers import nested_handlers, ScopedHandler
-
-
-class AmqpSocket(object):
-
- def __init__(self, conn, sock, events, heartbeat=None):
- self.events = events
- self.conn = conn
- self.transport = Transport()
- if heartbeat: self.transport.idle_timeout = heartbeat
- self.transport.bind(self.conn)
- self.socket = sock
- self.socket.setblocking(0)
- self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- self.write_done = False
- self.read_done = False
- self._closed = False
-
- def accept(self, force_sasl=True):
- if force_sasl:
- sasl = self.transport.sasl()
- sasl.mechanisms("ANONYMOUS")
- sasl.server()
- sasl.done(SASL.OK)
- #TODO: use SASL anyway if requested by peer
- return self
-
- def connect(self, host, port=None, username=None, password=None, force_sasl=True):
- if username and password:
- sasl = self.transport.sasl()
- sasl.plain(username, password)
- elif force_sasl:
- sasl = self.transport.sasl()
- sasl.mechanisms('ANONYMOUS')
- sasl.client()
- try:
- self.socket.connect_ex((host, port or 5672))
- except socket.gaierror, e:
- raise ConnectionException("Cannot resolve '%s': %s" % (host, e))
- return self
-
- def _closed_cleanly(self):
- return self.conn.state & Endpoint.LOCAL_CLOSED and self.conn.state & Endpoint.REMOTE_CLOSED
-
- def closed(self):
- if not self._closed and self.write_done and self.read_done:
- self.close()
- return True
- else:
- return False
-
- def close(self):
- self.socket.close()
- self._closed = True
-
- def fileno(self):
- return self.socket.fileno()
-
- def reading(self):
- if self.read_done: return False
- c = self.transport.capacity()
- if c > 0:
- return True
- elif c < 0:
- self.read_done = True
- return False
-
- def writing(self):
- if self.write_done: return False
- try:
- p = self.transport.pending()
- if p > 0:
- return True
- elif p < 0:
- self.write_done = True
- return False
- else: # p == 0
- return False
- except TransportException, e:
- self.write_done = True
- return False
-
- def readable(self):
- c = self.transport.capacity()
- if c > 0:
- try:
- data = self.socket.recv(c)
- if data:
- self.transport.push(data)
- else:
- if not self._closed_cleanly():
- self.read_done = True
- self.write_done = True
- else:
- self.transport.close_tail()
- except TransportException, e:
- print "Error on read: %s" % e
- self.read_done = True
- except socket.error, e:
- print "Error on recv: %s" % e
- self.read_done = True
- self.write_done = True
- elif c < 0:
- self.read_done = True
-
- def writable(self):
- try:
- p = self.transport.pending()
- if p > 0:
- data = self.transport.peek(p)
- n = self.socket.send(data)
- self.transport.pop(n)
- elif p < 0:
- self.write_done = True
- except TransportException, e:
- print "Error on write: %s" % e
- self.write_done = True
- except socket.error, e:
- print "Error on send: %s" % e
- self.write_done = True
-
- def removed(self):
- if not self._closed_cleanly():
- self.transport.unbind()
- self.events.dispatch(ApplicationEvent("disconnected", connection=self.conn))
-
- def tick(self):
- t = self.transport.tick(time.time())
- if t: return t - time.time()
- else: return None
-
-class Acceptor:
-
- def __init__(self, events, loop, host, port):
- self.events = events
- self.loop = loop
- self.socket = socket.socket()
- self.socket.setblocking(0)
- self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self.socket.bind((host, port))
- self.socket.listen(5)
- self.loop.add(self)
- self._closed = False
-
- def closed(self):
- if self._closed:
- self.socket.close()
- return True
- else:
- return False
-
- def close(self):
- self._closed = True
-
- def fileno(self):
- return self.socket.fileno()
-
- def reading(self):
- return not self._closed
-
- def writing(self):
- return False
-
- def readable(self):
- sock, addr = self.socket.accept()
- if sock:
- self.loop.add(AmqpSocket(self.events.connection(), sock, self.events).accept())
-
- def removed(self): pass
- def tick(self): return None
-
-class EventInjector(object):
- def __init__(self, events):
- self.events = events
- self.queue = Queue.Queue()
- self.pipe = os.pipe()
- self._closed = False
-
- def trigger(self, event):
- self.queue.put(event)
- os.write(self.pipe[1], "!")
-
- def closed(self):
- return self._closed and self.queue.empty()
-
- def close(self):
- self._closed = True
-
- def fileno(self):
- return self.pipe[0]
-
- def reading(self):
- return True
-
- def writing(self):
- return False
-
- def readable(self):
- os.read(self.pipe[0], 512)
- while not self.queue.empty():
- self.events.dispatch(self.queue.get())
-
- def removed(self): pass
- def tick(self): return None
-
-class Events(object):
- def __init__(self, *handlers):
- self.collector = Collector()
- self.handlers = handlers
-
- def connection(self):
- conn = Connection()
- conn.collect(self.collector)
- return conn
-
- def process(self):
- while True:
- ev = self.collector.peek()
- if ev:
- self.dispatch(ev)
- self.collector.pop()
- else:
- return
-
- def dispatch(self, event):
- for h in self.handlers:
- event.dispatch(h)
-
- @property
- def next_interval(self):
- return None
-
- @property
- def empty(self):
- return self.collector.peek() == None
-
-class ExtendedEventType(object):
- def __init__(self, name):
- self.name = name
- self.method = "on_%s" % name
-
-class ApplicationEvent(Event):
- def __init__(self, typename, connection=None, session=None, link=None, delivery=None, subject=None):
- self.type = ExtendedEventType(typename)
- self.subject = subject
- if delivery:
- self.context = delivery
- self.clazz = "pn_delivery"
- elif link:
- self.context = link
- self.clazz = "pn_link"
- elif session:
- self.context = session
- self.clazz = "pn_session"
- elif connection:
- self.context = connection
- self.clazz = "pn_connection"
- else:
- self.context = None
- self.clazz = "none"
-
- def __repr__(self):
- objects = [self.context, self.subject]
- return "%s(%s)" % (self.type.name,
- ", ".join([str(o) for o in objects if o is not None]))
-
-class StartEvent(ApplicationEvent):
- def __init__(self, reactor):
- super(StartEvent, self).__init__("start")
- self.reactor = reactor
-
-class ScheduledEvents(Events):
- def __init__(self, *handlers):
- super(ScheduledEvents, self).__init__(*handlers)
- self._events = []
-
- def schedule(self, deadline, event):
- heapq.heappush(self._events, (deadline, event))
-
- def process(self):
- super(ScheduledEvents, self).process()
- while self._events and self._events[0][0] <= time.time():
- self.dispatch(heapq.heappop(self._events)[1])
-
- @property
- def next_interval(self):
- if len(self._events):
- deadline = self._events[0][0]
- now = time.time()
- return deadline - now if deadline > now else 0
- else:
- return None
-
- @property
- def empty(self):
- return super(ScheduledEvents, self).empty and len(self._events) == 0
-
-def _min(a, b):
- if a and b: return min(a, b)
- elif a: return a
- else: return b
-
-class SelectLoop(object):
-
- def __init__(self, events):
- self.events = events
- self.selectables = []
- self._abort = False
-
- def abort(self):
- self._abort = True
-
- def add(self, selectable):
- self.selectables.append(selectable)
-
- def remove(self, selectable):
- self.selectables.remove(selectable)
-
- @property
- def redundant(self):
- return self.events.empty and not self.selectables
-
- @property
- def aborted(self):
- return self._abort
-
- def run(self):
- while not (self._abort or self.redundant):
- self.do_work()
-
- def do_work(self, timeout=None):
- """@return True if some work was done, False if time-out expired"""
- self.events.process()
- if self._abort: return
-
- stable = False
- while not stable:
- reading = []
- writing = []
- closed = []
- tick = None
- for s in self.selectables:
- if s.reading(): reading.append(s)
- if s.writing(): writing.append(s)
- if s.closed(): closed.append(s)
- else: tick = _min(tick, s.tick())
-
- for s in closed:
- self.selectables.remove(s)
- s.removed()
- stable = len(closed) == 0
-
- if self.redundant:
- return
-
- if timeout and timeout < 0:
- timeout = 0
- if self.events.next_interval and (timeout is None or self.events.next_interval < timeout):
- timeout = self.events.next_interval
- if tick:
- timeout = _min(tick, timeout)
- if reading or writing or timeout:
- readable, writable, _ = select(reading, writing, [], timeout)
- for s in self.selectables:
- s.tick()
- for s in readable:
- s.readable()
- for s in writable:
- s.writable()
-
- return bool(readable or writable)
- else:
- return False
-
-def delivery_tags():
- count = 1
- while True:
- yield str(count)
- count += 1
-
-def send_msg(sender, msg, tag=None, handler=None, transaction=None):
- dlv = sender.delivery(tag or next(sender.tags))
- if transaction:
- dlv.local.data = [transaction.id]
- dlv.update(0x34)
- if handler:
- dlv.context = handler
- sender.send(msg.encode())
- sender.advance()
- return dlv
-
-def _send_msg(self, msg, tag=None, handler=None, transaction=None):
- return send_msg(self, msg, tag, handler, transaction)
-
-
-class Transaction(object):
- def __init__(self, txn_ctrl, handler, settle_before_discharge=False):
- self.txn_ctrl = txn_ctrl
- self.handler = handler
- self.id = None
- self._declare = None
- self._discharge = None
- self.failed = False
- self._pending = []
- self.settle_before_discharge = settle_before_discharge
- self.declare()
-
- def commit(self):
- self.discharge(False)
-
- def abort(self):
- self.discharge(True)
-
- def declare(self):
- self._declare = self._send_ctrl(symbol(u'amqp:declare:list'), [None])
-
- def discharge(self, failed):
- self.failed = failed
- self._discharge = self._send_ctrl(symbol(u'amqp:discharge:list'), [self.id, failed])
-
- def _send_ctrl(self, descriptor, value):
- delivery = self.txn_ctrl.send_msg(Message(body=Described(descriptor, value)), handler=self.handler)
- delivery.transaction = self
- return delivery
-
- def accept(self, delivery):
- self.update(delivery, PN_ACCEPTED)
- if self.settle_before_discharge:
- delivery.settle()
- else:
- self._pending.append(delivery)
-
- def update(self, delivery, state=None):
- if state:
- delivery.local.data = [self.id, Described(ulong(state), [])]
- delivery.update(0x34)
-
- def _release_pending(self):
- for d in self._pending:
- d.update(Delivery.RELEASED)
- d.settle()
- self._clear_pending()
-
- def _clear_pending(self):
- self._pending = []
-
- def handle_outcome(self, event):
- if event.delivery == self._declare:
- if event.delivery.remote.data:
- self.id = event.delivery.remote.data[0]
- self.handler.on_transaction_declared(event)
- elif event.delivery.remote_state == Delivery.REJECTED:
- self.handler.on_transaction_declare_failed(event)
- else:
- print "Unexpected outcome for declare: %s" % event.delivery.remote_state
- self.handler.on_transaction_declare_failed(event)
- elif event.delivery == self._discharge:
- if event.delivery.remote_state == Delivery.REJECTED:
- if not self.failed:
- self.handler.on_transaction_commit_failed(event)
- self._release_pending() # make this optional?
- else:
- if self.failed:
- self.handler.on_transaction_aborted(event)
- self._release_pending()
- else:
- self.handler.on_transaction_committed(event)
- self._clear_pending()
-
-class LinkOption(object):
- def apply(self, link): pass
- def test(self, link): return True
-
-class AtMostOnce(LinkOption):
- def apply(self, link):
- link.snd_settle_mode = Link.SND_SETTLED
-
-class AtLeastOnce(LinkOption):
- def apply(self, link):
- link.snd_settle_mode = Link.SND_UNSETTLED
- link.rcv_settle_mode = Link.RCV_FIRST
-
-class SenderOption(LinkOption):
- def apply(self, sender): pass
- def test(self, link): return link.is_sender
-
-class ReceiverOption(LinkOption):
- def apply(self, receiver): pass
- def test(self, link): return link.is_receiver
-
-class Filter(ReceiverOption):
- def __init__(self, filter_set={}):
- self.filter_set = filter_set
-
- def apply(self, receiver):
- receiver.source.filter.put_dict(self.filter_set)
-
-class Selector(Filter):
- def __init__(self, value, name='selector'):
- super(Selector, self).__init__({symbol(name): Described(symbol('apache.org:selector-filter:string'), value)})
-
-def _apply_link_options(options, link):
- if options:
- if isinstance(options, list):
- for o in options:
- if o.test(link): o.apply(link)
- else:
- if options.test(link): options.apply(link)
-
-
-class MessagingContext(object):
- def __init__(self, conn, handler=None, ssn=None):
- self.conn = conn
- if handler:
- self.conn.context = handler
- self.conn._mc = self
- self.ssn = ssn
- self.txn_ctrl = None
-
- def _get_handler(self):
- return self.conn.context
-
- def _set_handler(self, value):
- self.conn.context = value
-
- handler = property(_get_handler, _set_handler)
-
- def create_sender(self, target, source=None, name=None, handler=None, tags=None, options=None):
- snd = self._get_ssn().sender(name or self._get_id(target, source))
- if source:
- snd.source.address = source
- if target:
- snd.target.address = target
- if handler:
- snd.context = handler
- snd.tags = tags or delivery_tags()
- snd.send_msg = types.MethodType(_send_msg, snd)
- _apply_link_options(options, snd)
- snd.open()
- return snd
-
- def create_receiver(self, source, target=None, name=None, dynamic=False, handler=None, options=None):
- rcv = self._get_ssn().receiver(name or self._get_id(source, target))
- if source:
- rcv.source.address = source
- if dynamic:
- rcv.source.dynamic = True
- if target:
- rcv.target.address = target
- if handler:
- rcv.context = handler
- _apply_link_options(options, rcv)
- rcv.open()
- return rcv
-
- def create_session(self):
- return MessageContext(conn=None, ssn=self._new_ssn())
-
- def declare_transaction(self, handler=None, settle_before_discharge=False):
- if not self.txn_ctrl:
- self.txn_ctrl = self.create_sender(None, name="txn-ctrl")
- self.txn_ctrl.target.type = Terminus.COORDINATOR
- self.txn_ctrl.target.capabilities.put_object(symbol(u'amqp:local-transactions'))
- return Transaction(self.txn_ctrl, handler, settle_before_discharge)
-
- def close(self):
- if self.ssn:
- self.ssn.close()
- if self.conn:
- self.conn.close()
-
- def _get_id(self, remote, local):
- if local and remote: "%s-%s-%s" % (self.conn.container, remote, local)
- elif local: return "%s-%s" % (self.conn.container, local)
- elif remote: return "%s-%s" % (self.conn.container, remote)
- else: return "%s-%s" % (self.conn.container, str(generate_uuid()))
-
- def _get_ssn(self):
- if not self.ssn:
- self.ssn = self._new_ssn()
- self.ssn.context = self
- return self.ssn
-
- def _new_ssn(self):
- ssn = self.conn.session()
- ssn.open()
- return ssn
-
- def on_session_remote_close(self, event):
- if self.conn:
- self.conn.close()
-
-class Connector(Handler):
- def attach_to(self, loop):
- self.loop = loop
-
- def _connect(self, connection):
- host, port = connection.address.next()
- #print "connecting to %s:%i" % (host, port)
- heartbeat = connection.heartbeat if hasattr(connection, 'heartbeat') else None
- self.loop.add(AmqpSocket(connection, socket.socket(), self.loop.events, heartbeat=heartbeat).connect(host, port))
-
- def on_connection_local_open(self, event):
- if hasattr(event.connection, "address"):
- self._connect(event.connection)
-
- def on_connection_remote_open(self, event):
- if hasattr(event.connection, "reconnect"):
- event.connection.reconnect.reset()
-
- def on_disconnected(self, event):
- if hasattr(event.connection, "reconnect"):
- delay = event.connection.reconnect.next()
- if delay == 0:
- print "Disconnected, reconnecting..."
- self._connect(event.connection)
- else:
- print "Disconnected will try to reconnect after %s seconds" % delay
- self.loop.schedule(time.time() + delay, connection=event.connection, subject=self)
- else:
- print "Disconnected"
-
- def on_timer(self, event):
- if event.subject == self and event.connection:
- self._connect(event.connection)
-
-class Backoff(object):
- def __init__(self):
- self.delay = 0
-
- def reset(self):
- self.delay = 0
-
- def next(self):
- current = self.delay
- if current == 0:
- self.delay = 0.1
- else:
- self.delay = min(10, 2*current)
- return current
-
-class Urls(object):
- def __init__(self, values):
- self.values = [Url(v) for v in values]
- self.i = iter(self.values)
-
- def __iter__(self):
- return self
-
- def _as_pair(self, url):
- return (url.host, url.port)
-
- def next(self):
- try:
- return self._as_pair(self.i.next())
- except StopIteration:
- self.i = iter(self.values)
- return self._as_pair(self.i.next())
-
-class EventLoop(object):
- def __init__(self, *handlers):
- self.connector = Connector()
- h = [self.connector, ScopedHandler()]
- h.extend(nested_handlers(handlers))
- self.events = ScheduledEvents(*h)
- self.loop = SelectLoop(self.events)
- self.connector.attach_to(self)
- self.trigger = None
- self.container_id = str(generate_uuid())
-
- def connect(self, url=None, urls=None, address=None, handler=None, reconnect=None, heartbeat=None):
- context = MessagingContext(self.events.connection(), handler=handler)
- context.conn.container = self.container_id or str(generate_uuid())
- context.conn.heartbeat = heartbeat
- if url: context.conn.address = Urls([url])
- elif urls: context.conn.address = Urls(urls)
- elif address: context.conn.address = address
- else: raise ValueError("One of url, urls or address required")
- if reconnect:
- context.conn.reconnect = reconnect
- elif reconnect is None:
- context.conn.reconnect = Backoff()
- context.conn.open()
- return context
-
- def listen(self, url):
- host, port = Urls([url]).next()
- return Acceptor(self.events, self, host, port)
-
- def schedule(self, deadline, connection=None, session=None, link=None, delivery=None, subject=None):
- self.events.schedule(deadline, ApplicationEvent("timer", connection, session, link, delivery, subject))
-
- def get_event_trigger(self):
- if not self.trigger or self.trigger.closed():
- self.trigger = EventInjector(self.events)
- self.add(self.trigger)
- return self.trigger
-
- def add(self, selectable):
- self.loop.add(selectable)
-
- def remove(self, selectable):
- self.loop.remove(selectable)
-
- def run(self):
- self.events.dispatch(StartEvent(self))
- self.loop.run()
-
- def stop(self):
- self.loop.abort()
-
- def do_work(self, timeout=None):
- return self.loop.do_work(timeout)
-
-EventLoop.DEFAULT = EventLoop()
-
-def connect(url=None, urls=None, address=None, handler=None, reconnect=None, eventloop=None, heartbeat=None):
- if not eventloop:
- eventloop = EventLoop.DEFAULT
- return eventloop.connect(url=url, urls=urls, address=address, handler=handler, reconnect=reconnect, heartbeat=heartbeat)
-
-def run(eventloop=None):
- if not eventloop:
- eventloop = EventLoop.DEFAULT
- eventloop.run()
-
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/proton_server.py
----------------------------------------------------------------------
diff --git a/tutorial/proton_server.py b/tutorial/proton_server.py
index 3ebf366..b2e2027 100644
--- a/tutorial/proton_server.py
+++ b/tutorial/proton_server.py
@@ -18,8 +18,8 @@
#
from proton import Message
-from proton_reactors import EventLoop
-from proton_handlers import FlowController, IncomingMessageHandler
+from proton.reactors import EventLoop
+from proton.handlers import FlowController, IncomingMessageHandler
class Server(IncomingMessageHandler):
def __init__(self, host, address):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/proton_tornado.py
----------------------------------------------------------------------
diff --git a/tutorial/proton_tornado.py b/tutorial/proton_tornado.py
index a5ec82c..e49b28e 100644
--- a/tutorial/proton_tornado.py
+++ b/tutorial/proton_tornado.py
@@ -18,7 +18,7 @@
# under the License.
#
-from proton_reactors import ApplicationEvent, EventLoop, StartEvent
+from proton.reactors import ApplicationEvent, EventLoop, StartEvent
import tornado.ioloop
class TornadoLoop(EventLoop):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/proton_utils.py
----------------------------------------------------------------------
diff --git a/tutorial/proton_utils.py b/tutorial/proton_utils.py
deleted file mode 100644
index fce0cf5..0000000
--- a/tutorial/proton_utils.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-import Queue, socket, time
-from proton import ConnectionException, Endpoint, Handler, Message, Url
-from proton_reactors import AmqpSocket, Events, MessagingContext, SelectLoop, send_msg
-from proton_handlers import ScopedHandler
-
-class BlockingLink(object):
- def __init__(self, connection, link):
- self.connection = connection
- self.link = link
- self.connection.wait(lambda: not (self.link.state & Endpoint.REMOTE_UNINIT),
- msg="Opening link %s" % link.name)
-
- def close(self):
- self.connection.wait(not (self.link.state & Endpoint.REMOTE_ACTIVE),
- msg="Closing link %s" % link.name)
-
- # Access to other link attributes.
- def __getattr__(self, name): return getattr(self.link, name)
-
-class BlockingSender(BlockingLink):
- def __init__(self, connection, sender):
- super(BlockingSender, self).__init__(connection, sender)
-
- def send_msg(self, msg):
- delivery = send_msg(self.link, msg)
- self.connection.wait(lambda: delivery.settled, msg="Sending on sender %s" % self.link.name)
-
-class BlockingReceiver(BlockingLink):
- def __init__(self, connection, receiver, credit=1):
- super(BlockingReceiver, self).__init__(connection, receiver)
- if credit: receiver.flow(credit)
-
-class BlockingConnection(Handler):
- def __init__(self, url, timeout=None):
- self.timeout = timeout
- self.events = Events(ScopedHandler())
- self.loop = SelectLoop(self.events)
- self.context = MessagingContext(self.loop.events.connection(), handler=self)
- if isinstance(url, basestring):
- self.url = Url(url)
- else:
- self.url = url
- self.loop.add(
- AmqpSocket(self.context.conn, socket.socket(), self.events).connect(self.url.host, self.url.port))
- self.context.conn.open()
- self.wait(lambda: not (self.context.conn.state & Endpoint.REMOTE_UNINIT),
- msg="Opening connection")
-
- def create_sender(self, address, handler=None):
- return BlockingSender(self, self.context.create_sender(address, handler=handler))
-
- def create_receiver(self, address, credit=1, dynamic=False, handler=None):
- return BlockingReceiver(
- self, self.context.create_receiver(address, dynamic=dynamic, handler=handler), credit=credit)
-
- def close(self):
- self.context.conn.close()
- self.wait(lambda: not (self.context.conn.state & Endpoint.REMOTE_ACTIVE),
- msg="Closing connection")
-
- def run(self):
- """ Hand control over to the event loop (e.g. if waiting indefinitely for incoming messages) """
- self.loop.run()
-
- def wait(self, condition, timeout=False, msg=None):
- """Call do_work until condition() is true"""
- if timeout is False:
- timeout = self.timeout
- if timeout is None:
- while not condition():
- self.loop.do_work()
- else:
- deadline = time.time() + timeout
- while not condition():
- if not self.loop.do_work(deadline - time.time()):
- txt = "Connection %s timed out" % self.url
- if msg: txt += ": " + msg
- raise Timeout(txt)
-
- def on_link_remote_close(self, event):
- if event.link.state & Endpoint.LOCAL_ACTIVE:
- self.closed(event.link.remote_condition)
-
- def on_connection_remote_close(self, event):
- if event.connection.state & Endpoint.LOCAL_ACTIVE:
- self.closed(event.connection.remote_condition)
-
- def on_disconnected(self, event):
- raise ConnectionException("Connection %s disconnected" % self.url);
-
- def closed(self, error=None):
- txt = "Connection %s closed" % self.url
- if error:
- txt += " due to: %s" % error
- else:
- txt += " by peer"
- raise ConnectionException(txt)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/recurring_timer.py
----------------------------------------------------------------------
diff --git a/tutorial/recurring_timer.py b/tutorial/recurring_timer.py
index 2bd7b9f..c641ec6 100755
--- a/tutorial/recurring_timer.py
+++ b/tutorial/recurring_timer.py
@@ -19,7 +19,7 @@
#
import time
-from proton_reactors import EventLoop, Handler
+from proton.reactors import EventLoop, Handler
class Recurring(Handler):
def __init__(self, period):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/selected_recv.py
----------------------------------------------------------------------
diff --git a/tutorial/selected_recv.py b/tutorial/selected_recv.py
index b31862a..8425f3d 100755
--- a/tutorial/selected_recv.py
+++ b/tutorial/selected_recv.py
@@ -18,20 +18,22 @@
# under the License.
#
-import proton_reactors
-from proton_handlers import MessagingHandler
+from proton.reactors import EventLoop, Selector
+from proton.handlers import MessagingHandler
class Recv(MessagingHandler):
def __init__(self):
super(Recv, self).__init__()
+ def on_start(self, event):
+ conn = event.reactor.connect("localhost:5672")
+ conn.create_receiver("examples", options=Selector(u"colour = 'green'"))
+
def on_message(self, event):
print event.message.body
try:
- conn = proton_reactors.connect("localhost:5672", handler=Recv())
- conn.create_receiver("examples", options=proton_reactors.Selector(u"colour = 'green'"))
- proton_reactors.run()
+ EventLoop(Recv()).run()
except KeyboardInterrupt: pass
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/server.py
----------------------------------------------------------------------
diff --git a/tutorial/server.py b/tutorial/server.py
index 3969688..6ab5671 100755
--- a/tutorial/server.py
+++ b/tutorial/server.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
-from proton_reactors import EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import EventLoop
class Server(MessagingHandler):
def __init__(self, host, address):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/server_tx.py
----------------------------------------------------------------------
diff --git a/tutorial/server_tx.py b/tutorial/server_tx.py
index 179c1c8..cda2d0b 100755
--- a/tutorial/server_tx.py
+++ b/tutorial/server_tx.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_reactors import EventLoop
-from proton_handlers import MessagingHandler, TransactionHandler
+from proton.reactors import EventLoop
+from proton.handlers import MessagingHandler, TransactionHandler
class TxRequest(TransactionHandler):
def __init__(self, response, sender, request_delivery, context):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/simple_recv.py
----------------------------------------------------------------------
diff --git a/tutorial/simple_recv.py b/tutorial/simple_recv.py
index aac549c..ea80aa6 100755
--- a/tutorial/simple_recv.py
+++ b/tutorial/simple_recv.py
@@ -18,8 +18,8 @@
# under the License.
#
-from proton_handlers import MessagingHandler
-from proton_reactors import EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import EventLoop
class Recv(MessagingHandler):
def __init__(self, host, address):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/simple_send.py
----------------------------------------------------------------------
diff --git a/tutorial/simple_send.py b/tutorial/simple_send.py
index 3af5cff..bbd30ac 100755
--- a/tutorial/simple_send.py
+++ b/tutorial/simple_send.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_handlers import MessagingHandler
-from proton_reactors import EventLoop
+from proton.handlers import MessagingHandler
+from proton.reactors import EventLoop
class Send(MessagingHandler):
def __init__(self, host, address, messages):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/sync_client.py
----------------------------------------------------------------------
diff --git a/tutorial/sync_client.py b/tutorial/sync_client.py
index eb79fc5..362385a 100755
--- a/tutorial/sync_client.py
+++ b/tutorial/sync_client.py
@@ -25,8 +25,8 @@ Demonstrates the client side of the synchronous request-response pattern
"""
from proton import Message, Url, ConnectionException, Timeout
-from proton_utils import BlockingConnection
-from proton_handlers import IncomingMessageHandler
+from proton.utils import BlockingConnection
+from proton.handlers import IncomingMessageHandler
import sys
class SyncRequestClient(IncomingMessageHandler):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/tx_recv.py
----------------------------------------------------------------------
diff --git a/tutorial/tx_recv.py b/tutorial/tx_recv.py
index 5f14fd8..a28a3df 100755
--- a/tutorial/tx_recv.py
+++ b/tutorial/tx_recv.py
@@ -18,8 +18,8 @@
# under the License.
#
-from proton_reactors import EventLoop
-from proton_handlers import TransactionalClientHandler
+from proton.reactors import EventLoop
+from proton.handlers import TransactionalClientHandler
class TxRecv(TransactionalClientHandler):
def __init__(self, batch_size):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/tx_recv_interactive.py
----------------------------------------------------------------------
diff --git a/tutorial/tx_recv_interactive.py b/tutorial/tx_recv_interactive.py
index 4e36534..a822992 100755
--- a/tutorial/tx_recv_interactive.py
+++ b/tutorial/tx_recv_interactive.py
@@ -20,8 +20,8 @@
import sys
import threading
-from proton_reactors import ApplicationEvent, EventLoop
-from proton_handlers import TransactionalClientHandler
+from proton.reactors import ApplicationEvent, EventLoop
+from proton.handlers import TransactionalClientHandler
class TxRecv(TransactionalClientHandler):
def __init__(self):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/tx_send.py
----------------------------------------------------------------------
diff --git a/tutorial/tx_send.py b/tutorial/tx_send.py
index 44c78bf..b2f12b2 100755
--- a/tutorial/tx_send.py
+++ b/tutorial/tx_send.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_reactors import EventLoop
-from proton_handlers import TransactionalClientHandler
+from proton.reactors import EventLoop
+from proton.handlers import TransactionalClientHandler
class TxSend(TransactionalClientHandler):
def __init__(self, messages, batch_size):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2f4d1ba2/tutorial/tx_send_sync.py
----------------------------------------------------------------------
diff --git a/tutorial/tx_send_sync.py b/tutorial/tx_send_sync.py
index 6e4d4d8..0c50838 100755
--- a/tutorial/tx_send_sync.py
+++ b/tutorial/tx_send_sync.py
@@ -19,8 +19,8 @@
#
from proton import Message
-from proton_reactors import EventLoop
-from proton_handlers import TransactionalClientHandler
+from proton.reactors import EventLoop
+from proton.handlers import TransactionalClientHandler
class TxSend(TransactionalClientHandler):
def __init__(self, messages, batch_size):
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[03/35] qpid-proton git commit: PROTON-750: Have explicit API to
detect ssl if present - avoids overloading other functionality for this
purpose.
Posted by gs...@apache.org.
PROTON-750: Have explicit API to detect ssl if present
- avoids overloading other functionality for this purpose.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2794da59
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2794da59
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2794da59
Branch: refs/heads/examples
Commit: 2794da59b7ee8810a88b4393dacd87a947c10fe7
Parents: b57f45d
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Oct 30 15:03:32 2014 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 17 14:50:29 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/python/proton.py | 4 ++++
proton-c/include/proton/ssl.h | 6 ++++++
proton-c/src/ssl/openssl.c | 5 +++++
proton-c/src/ssl/ssl_stub.c | 5 +++++
proton-c/src/windows/schannel.c | 7 +++++--
proton-j/src/main/resources/cssl.py | 3 +++
tests/python/proton_tests/common.py | 12 ++----------
7 files changed, 30 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
index 00c36c0..81104f0 100644
--- a/proton-c/bindings/python/proton.py
+++ b/proton-c/bindings/python/proton.py
@@ -3270,6 +3270,10 @@ class SSLDomain(object):
class SSL(object):
+ @staticmethod
+ def present():
+ return pn_ssl_present()
+
def _check(self, err):
if err < 0:
exc = EXCEPTIONS.get(err, SSLException)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/proton-c/include/proton/ssl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/ssl.h b/proton-c/include/proton/ssl.h
index 013478e..09d386b 100644
--- a/proton-c/include/proton/ssl.h
+++ b/proton-c/include/proton/ssl.h
@@ -90,6 +90,12 @@ typedef enum {
PN_SSL_RESUME_REUSED /**< Session resumed from previous session. */
} pn_ssl_resume_status_t;
+/** Tests for SSL implementation present
+ *
+ * @return true if we support SSL, false if not
+ */
+PN_EXTERN bool pn_ssl_present( void );
+
/** Create an SSL configuration domain
*
* This method allocates an SSL domain object. This object is used to hold the SSL
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index ea2bd5b..dd1b88b 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -434,6 +434,11 @@ static void ssl_session_free( pn_ssl_session_t *ssn)
/** Public API - visible to application code */
+bool pn_ssl_present(void)
+{
+ return true;
+}
+
pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
{
if (!ssl_initialized) {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/proton-c/src/ssl/ssl_stub.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl_stub.c b/proton-c/src/ssl/ssl_stub.c
index 300215a..a5fce02 100644
--- a/proton-c/src/ssl/ssl_stub.c
+++ b/proton-c/src/ssl/ssl_stub.c
@@ -31,6 +31,11 @@
* used if there is no SSL/TLS support in the system's environment.
*/
+bool pn_ssl_present(void)
+{
+ return false;
+}
+
pn_ssl_t *pn_ssl(pn_transport_t *transport)
{
return NULL;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
index 9437582..de6e117 100644
--- a/proton-c/src/windows/schannel.c
+++ b/proton-c/src/windows/schannel.c
@@ -252,10 +252,13 @@ static void ssl_session_free( pn_ssl_session_t *ssn)
/** Public API - visible to application code */
+bool pn_ssl_present(void)
+{
+ return false;
+}
+
pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
{
- if (mode == PN_SSL_MODE_SERVER)
- return NULL; // Temporary: not ready for ctest, hide from isSSLPresent()
pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
if (!domain) return NULL;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/proton-j/src/main/resources/cssl.py
----------------------------------------------------------------------
diff --git a/proton-j/src/main/resources/cssl.py b/proton-j/src/main/resources/cssl.py
index 97740e3..74497ef 100644
--- a/proton-j/src/main/resources/cssl.py
+++ b/proton-j/src/main/resources/cssl.py
@@ -44,6 +44,9 @@ PN_SSL_MODE_P2J = {
PN_SSL_MODE_SERVER: SslDomain.Mode.SERVER
}
+def pn_ssl_present():
+ return True
+
def pn_ssl_domain(mode):
domain = Proton.sslDomain()
domain.init(PN_SSL_MODE_P2J[mode])
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2794da59/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
index cfb7e3d..e0887e6 100644
--- a/tests/python/proton_tests/common.py
+++ b/tests/python/proton_tests/common.py
@@ -22,8 +22,7 @@ from threading import Thread
from socket import socket, AF_INET, SOCK_STREAM
from subprocess import Popen,PIPE,STDOUT
import sys, os, string
-from proton import Driver, Connection, Transport, SASL, Endpoint, Delivery, \
- SSLDomain, SSLUnavailable
+from proton import Driver, Connection, Transport, SASL, Endpoint, Delivery, SSL
def free_tcp_ports(count=1):
@@ -79,14 +78,7 @@ def pump(transport1, transport2, buffer_size=1024):
pass
def isSSLPresent():
- """ True if a suitable SSL library is available.
- """
- try:
- xxx = SSLDomain(SSLDomain.MODE_SERVER)
- return True
- except SSLUnavailable, e:
- # SSL libraries not installed
- return False
+ return SSL.present()
class Test(object):
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[09/35] qpid-proton git commit: NO-JIRA: Removed trailing spaces from
the Ruby Messenger class.
Posted by gs...@apache.org.
NO-JIRA: Removed trailing spaces from the Ruby Messenger class.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/0d1b8a86
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/0d1b8a86
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/0d1b8a86
Branch: refs/heads/examples
Commit: 0d1b8a8683b116dbcbe420a58f074e77f00d5570
Parents: d770a1e
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Fri Nov 14 16:27:10 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Tue Nov 18 09:09:40 2014 -0500
----------------------------------------------------------------------
.../ruby/lib/qpid_proton/exception_handling.rb | 2 +-
.../bindings/ruby/lib/qpid_proton/messenger.rb | 22 ++++++++++----------
2 files changed, 12 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d1b8a86/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb b/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
index 6789c90..f8ac8c6 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
@@ -32,7 +32,7 @@ module Qpid
raise ::ArgumentError.new("Invalid error code: #{code}") if code.nil?
- return code if code > 0
+ return code if code > 0
case(code)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0d1b8a86/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index 2581e2b..044a3ad 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -297,10 +297,10 @@ module Qpid
# Places the content contained in the message onto the outgoing
# queue of the Messenger.
#
- # This method will never block, however it will send any unblocked
+ # This method will never block, however it will send any unblocked
# Messages in the outgoing queue immediately and leave any blocked
# Messages remaining in the outgoing queue.
- # The send call may then be used to block until the outgoing queue
+ # The send call may then be used to block until the outgoing queue
# is empty. The outgoing attribute may be used to check the depth
# of the outgoing queue.
#
@@ -319,8 +319,8 @@ module Qpid
# This call will block until the indicated number of messages
# have been sent, or until the operation times out.
- # If n is -1 this call will block until all outgoing messages
- # have been sent. If n is 0 then this call will send whatever
+ # If n is -1 this call will block until all outgoing messages
+ # have been sent. If n is 0 then this call will send whatever
# it can without blocking.
#
def send(n = -1)
@@ -392,7 +392,7 @@ module Qpid
# This will block for the indicated timeout. This method may also do I/O
# other than sending and receiving messages. For example, closing
# connections after stop() has been called.
- #
+ #
def work(timeout=-1)
err = Cproton.pn_messenger_work(@impl, timeout)
if (err == Cproton::PN_TIMEOUT) then
@@ -572,9 +572,9 @@ module Qpid
end
# Gets the last known remote state of the delivery associated with
- # the given tracker, as long as the Message is still within your
- # outgoing window. (Also works on incoming messages that are still
- # within your incoming queue. See TrackerStatus for details on the
+ # the given tracker, as long as the Message is still within your
+ # outgoing window. (Also works on incoming messages that are still
+ # within your incoming queue. See TrackerStatus for details on the
# values returned.
#
# ==== Options
@@ -609,13 +609,13 @@ module Qpid
# Sets the incoming window.
#
- # The Messenger will track the remote status of this many incoming
+ # The Messenger will track the remote status of this many incoming
# deliveries after they have been accepted or rejected.
#
# Messages enter this window only when you take them into your application
# using get(). If your incoming window size is n, and you get n+1 messages
# without explicitly accepting or rejecting the oldest message, then the
- # message that passes beyond the edge of the incoming window will be
+ # message that passes beyond the edge of the incoming window will be
# assigned the default disposition of its link.
#
# ==== Options
@@ -635,7 +635,7 @@ module Qpid
# Sets the outgoing window.
#
- # The Messenger will track the remote status of this many outgoing
+ # The Messenger will track the remote status of this many outgoing
# deliveries after calling send.
# A Message enters this window when you call the put() method with the
# message. If your outgoing window size is n, and you call put n+1
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[14/35] qpid-proton git commit: PROTON-749: Server transport
autodetect: - Defer layer initialisation until first send/receive - Move
layer initialisation entirely to transport - Server transports will now
autodetect the client protocol layers talking
Posted by gs...@apache.org.
PROTON-749: Server transport autodetect:
- Defer layer initialisation until first send/receive
- Move layer initialisation entirely to transport
- Server transports will now autodetect the client protocol layers
talking to them and configure themselves automatically
- There are still some hacks in here to make SSL work.
It's not obvious why we need these hacks.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1b2be03c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1b2be03c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1b2be03c
Branch: refs/heads/examples
Commit: 1b2be03c748ef5a57cf181f8373b9b6e8f8cfd22
Parents: 9c9872b
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed Aug 20 23:39:34 2014 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed Nov 19 17:50:21 2014 -0500
----------------------------------------------------------------------
proton-c/CMakeLists.txt | 1 +
proton-c/src/engine/engine-internal.h | 8 +-
proton-c/src/sasl/sasl-internal.h | 2 +
proton-c/src/sasl/sasl.c | 55 +++----
proton-c/src/ssl/openssl.c | 112 +------------
proton-c/src/ssl/ssl-internal.h | 2 +
proton-c/src/ssl/ssl_stub.c | 17 +-
proton-c/src/transport/autodetect.c | 135 ++++++++++++++++
proton-c/src/transport/autodetect.h | 40 +++++
proton-c/src/transport/transport.c | 249 +++++++++++++++++++++++------
proton-c/src/windows/schannel.c | 113 +------------
11 files changed, 428 insertions(+), 306 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 6b6b730..b09e1c4 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -297,6 +297,7 @@ set (qpid-proton-core
src/dispatcher/dispatcher.c
src/engine/engine.c
src/events/event.c
+ src/transport/autodetect.c
src/transport/transport.c
src/message/message.c
src/sasl/sasl.c
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index ab66ef5..f53e88b 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -107,6 +107,9 @@ typedef struct pn_io_layer_t {
} pn_io_layer_t;
extern const pn_io_layer_t pni_passthru_layer;
+extern const pn_io_layer_t ssl_layer;
+extern const pn_io_layer_t sasl_header_layer;
+extern const pn_io_layer_t sasl_write_header_layer;
typedef struct pni_sasl_t pni_sasl_t;
typedef struct pni_ssl_t pni_ssl_t;
@@ -131,10 +134,7 @@ struct pn_transport_t {
pn_condition_t condition;
pn_error_t *error;
-#define PN_IO_SSL 0
-#define PN_IO_SASL 1
-#define PN_IO_AMQP 2
-#define PN_IO_LAYER_CT (PN_IO_AMQP+1)
+#define PN_IO_LAYER_CT 3
const pn_io_layer_t *io_layers[PN_IO_LAYER_CT];
/* dead remote detection */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl-internal.h b/proton-c/src/sasl/sasl-internal.h
index 15fd0b1..ca4c80e 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -57,4 +57,6 @@ void pn_sasl_trace(pn_transport_t *transport, pn_trace_t trace);
*/
void pn_sasl_free(pn_transport_t *transport);
+bool pn_sasl_skipping_allowed(pn_transport_t *transport);
+
#endif /* sasl-internal.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 90adcf6..1ee8f9b 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -32,6 +32,7 @@
#include "engine/engine-internal.h"
#include "dispatcher/dispatcher.h"
#include "util.h"
+#include "transport/autodetect.h"
struct pni_sasl_t {
@@ -68,7 +69,7 @@ static ssize_t pn_input_read_sasl(pn_transport_t *transport, unsigned int layer,
static ssize_t pn_output_write_sasl_header(pn_transport_t* transport, unsigned int layer, char* bytes, size_t size);
static ssize_t pn_output_write_sasl(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-const pn_io_layer_t sasl_headers_layer = {
+const pn_io_layer_t sasl_header_layer = {
pn_input_read_sasl_header,
pn_output_write_sasl_header,
NULL,
@@ -118,7 +119,6 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
sasl->output_bypass = false;
transport->sasl = sasl;
- transport->io_layers[PN_IO_SASL] = &sasl_headers_layer;
}
// The actual external pn_sasl_t pointer is a pointer to its enclosing pn_transport_t
@@ -204,6 +204,11 @@ void pn_sasl_allow_skip(pn_sasl_t *sasl0, bool allow)
sasl->allow_skip = allow;
}
+bool pn_sasl_skipping_allowed(pn_transport_t *transport)
+{
+ return transport && transport->sasl && transport->sasl->allow_skip;
+}
+
void pn_sasl_plain(pn_sasl_t *sasl0, const char *username, const char *password)
{
pni_sasl_t *sasl = get_sasl_internal(sasl0);
@@ -441,45 +446,33 @@ int pn_do_outcome(pn_dispatcher_t *disp)
}
#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
#define SASL_HEADER_LEN 8
static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- pni_sasl_t *sasl = transport->sasl;
- if (available > 0) {
- if (available < SASL_HEADER_LEN) {
- if (memcmp(bytes, SASL_HEADER, available) == 0 ||
- memcmp(bytes, AMQP_HEADER, available) == 0)
- return 0;
+ bool eos = pn_transport_capacity(transport)==PN_EOS;
+ pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+ switch (protocol) {
+ case PNI_PROTOCOL_AMQP_SASL:
+ if (transport->io_layers[layer] == &sasl_read_header_layer) {
+ transport->io_layers[layer] = &sasl_layer;
} else {
- if (memcmp(bytes, SASL_HEADER, SASL_HEADER_LEN) == 0) {
- if (transport->io_layers[layer] == &sasl_read_header_layer) {
- transport->io_layers[layer] = &sasl_layer;
- } else {
- transport->io_layers[layer] = &sasl_write_header_layer;
- }
- if (sasl->disp->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, " <- %s", "SASL");
- return SASL_HEADER_LEN;
- }
- if (memcmp(bytes, AMQP_HEADER, SASL_HEADER_LEN) == 0) {
- if (sasl->allow_skip) {
- sasl->outcome = PN_SASL_SKIPPED;
- transport->io_layers[layer] = &pni_passthru_layer;
- return pni_passthru_layer.process_input(transport, layer, bytes, available);
- } else {
- pn_do_error(transport, "amqp:connection:policy-error",
- "Client skipped SASL exchange - forbidden");
- return PN_EOS;
- }
- }
+ transport->io_layers[layer] = &sasl_write_header_layer;
}
+ if (transport->sasl->disp->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "SASL");
+ return SASL_HEADER_LEN;
+ case PNI_PROTOCOL_INSUFFICIENT:
+ if (!eos) return 0;
+ /* Fallthru */
+ default:
+ break;
}
char quoted[1024];
pn_quote_data(quoted, 1024, bytes, available);
pn_do_error(transport, "amqp:connection:framing-error",
- "%s header mismatch: '%s'", "SASL", quoted);
+ "%s header mismatch: %s ['%s']%s", "SASL", pni_protocol_name(protocol), quoted,
+ !eos ? "" : " (connection aborted)");
return PN_EOS;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index 41e36b5..0562cae 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -60,7 +60,6 @@
static int ssl_initialized;
static int ssl_ex_data_index;
-typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
typedef struct pn_ssl_session_t pn_ssl_session_t;
struct pn_ssl_domain_t {
@@ -145,11 +144,8 @@ struct pn_ssl_session_t {
static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata);
static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static ssize_t process_input_unknown( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
-static ssize_t process_output_unknown( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
static int init_ssl_socket(pn_transport_t *, pni_ssl_t *);
static void release_ssl_socket( pni_ssl_t * );
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
@@ -682,13 +678,6 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
return 0;
}
-const pn_io_layer_t unknown_layer = {
- process_input_unknown,
- process_output_unknown,
- NULL,
- NULL
-};
-
const pn_io_layer_t ssl_layer = {
process_input_ssl,
process_output_ssl,
@@ -725,11 +714,6 @@ int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
ssl->domain = domain;
domain->ref_count++;
- if (domain->allow_unsecured) {
- transport->io_layers[PN_IO_SSL] = &unknown_layer;
- } else {
- transport->io_layers[PN_IO_SSL] = &ssl_layer;
- }
if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
ssl->session_id = pn_strdup(session_id);
@@ -748,6 +732,10 @@ int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
return 0;
}
+bool pn_ssl_allow_unsecured(pn_transport_t *transport)
+{
+ return transport && transport->ssl && transport->ssl->domain && transport->ssl->domain->allow_unsecured;
+}
bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
{
@@ -862,13 +850,6 @@ static int start_ssl_shutdown(pn_transport_t *transport)
}
-
-static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
-{
- transport->io_layers[layer] = &ssl_layer;
- return 0;
-}
-
//////// SSL Connections
@@ -1213,91 +1194,6 @@ static void release_ssl_socket(pni_ssl_t *ssl)
}
-static int setup_cleartext_connection(pn_transport_t *transport, unsigned int layer)
-{
- transport->io_layers[layer] = &pni_passthru_layer;
- return 0;
-}
-
-
-// until we determine if the client is using SSL or not:
-
-static ssize_t process_input_unknown(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
-{
- switch (check_for_ssl_connection( input_data, len )) {
- case SSL_CONNECTION:
- ssl_log( transport, "SSL connection detected.");
- setup_ssl_connection(transport, layer);
- break;
- case CLEAR_CONNECTION:
- ssl_log( transport, "Cleartext connection detected.");
- setup_cleartext_connection(transport, layer);
- break;
- default:
- return 0;
- }
- return transport->io_layers[layer]->process_input(transport, layer, input_data, len );
-}
-
-static ssize_t process_output_unknown(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
-{
- // do not do output until we know if SSL is used or not
- return 0;
-}
-
-static connection_mode_t check_for_ssl_connection( const char *data, size_t len )
-{
- if (len >= 5) {
- const unsigned char *buf = (unsigned char *)data;
- /*
- * SSLv2 Client Hello format
- * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
- *
- * Bytes 0-1: RECORD-LENGTH
- * Byte 2: MSG-CLIENT-HELLO (1)
- * Byte 3: CLIENT-VERSION-MSB
- * Byte 4: CLIENT-VERSION-LSB
- *
- * Allowed versions:
- * 2.0 - SSLv2
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- *
- * The version sent in the Client-Hello is the latest version supported by
- * the client. NSS may send version 3.x in an SSLv2 header for
- * maximum compatibility.
- */
- int isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO
- ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
- (buf[3] == 2 && buf[4] == 0)); // SSL 2
-
- /*
- * SSLv3/TLS Client Hello format
- * RFC 2246
- *
- * Byte 0: ContentType (handshake - 22)
- * Bytes 1-2: ProtocolVersion {major, minor}
- *
- * Allowed versions:
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- */
- int isSSL3Handshake = buf[0] == 22 && // handshake
- (buf[1] == 3 && buf[2] <= 3); // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
-
- if (isSSL2Handshake || isSSL3Handshake) {
- return SSL_CONNECTION;
- } else {
- return CLEAR_CONNECTION;
- }
- }
- return UNKNOWN_CONNECTION;
-}
-
void pn_ssl_trace(pn_transport_t *transport, pn_trace_t trace)
{
transport->ssl->trace = trace;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/ssl/ssl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl-internal.h b/proton-c/src/ssl/ssl-internal.h
index f1cd637..9430af0 100644
--- a/proton-c/src/ssl/ssl-internal.h
+++ b/proton-c/src/ssl/ssl-internal.h
@@ -33,4 +33,6 @@ void pn_ssl_free(pn_transport_t *transport);
void pn_ssl_trace(pn_transport_t *transport, pn_trace_t trace);
+bool pn_ssl_allow_unsecured(pn_transport_t *transport);
+
#endif /* ssl-internal.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/ssl/ssl_stub.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl_stub.c b/proton-c/src/ssl/ssl_stub.c
index a5fce02..cea5dc4 100644
--- a/proton-c/src/ssl/ssl_stub.c
+++ b/proton-c/src/ssl/ssl_stub.c
@@ -22,6 +22,7 @@
#include <proton/ssl.h>
#include <proton/error.h>
#include <proton/transport.h>
+#include "engine/engine-internal.h"
/** @file
@@ -55,16 +56,23 @@ void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
{
}
-ssize_t pn_ssl_input(pn_ssl_t *ssl, const char *bytes, size_t available)
+ssize_t pn_ssl_input(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
{
return PN_EOS;
}
-ssize_t pn_ssl_output(pn_ssl_t *ssl, char *buffer, size_t max_size)
+ssize_t pn_ssl_output(pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_size)
{
return PN_EOS;
}
+const pn_io_layer_t ssl_layer = {
+ pn_ssl_input,
+ pn_ssl_output,
+ NULL,
+ NULL
+};
+
bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size)
{
return false;
@@ -110,6 +118,11 @@ int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
return -1;
}
+bool pn_ssl_allow_unsecured(pn_ssl_t *ssl)
+{
+ return true;
+}
+
pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *s )
{
return PN_SSL_RESUME_UNKNOWN;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/transport/autodetect.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/autodetect.c b/proton-c/src/transport/autodetect.c
new file mode 100644
index 0000000..00f6d98
--- /dev/null
+++ b/proton-c/src/transport/autodetect.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "autodetect.h"
+
+#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
+#define SSL_HEADER ("AMQP\x02\x01\x00\x00")
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
+#define SASL_HEADER_LEN 8
+
+/*
+ * SSLv2 Client Hello format
+ * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
+ *
+ * Bytes 0-1: RECORD-LENGTH
+ * Byte 2: MSG-CLIENT-HELLO (1)
+ * Byte 3: CLIENT-VERSION-MSB
+ * Byte 4: CLIENT-VERSION-LSB
+ *
+ * Allowed versions:
+ * 2.0 - SSLv2
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ *
+ * The version sent in the Client-Hello is the latest version supported by
+ * the client. NSS may send version 3.x in an SSLv2 header for
+ * maximum compatibility.
+ */
+/*
+ * SSLv3/TLS Client Hello format
+ * RFC 2246
+ *
+ * Byte 0: ContentType (handshake - 22)
+ * Bytes 1-2: ProtocolVersion {major, minor}
+ *
+ * Allowed versions:
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ */
+/*
+ * AMQP 1.0 Header
+ *
+ * Bytes 0-3: "AMQP"
+ * Byte 4: 0==AMQP, 2==SSL, 3==SASL
+ * Byte 5: 1
+ * Bytes 6-7: 0
+ */
+/*
+ * AMQP Pre 1.0 Header
+ *
+ * Bytes 0-3: 'AMQP'
+ * Byte 4: 1
+ * Byte 5: 1
+ * Byte 6: 0 (major version)
+ * Byte 7: Minor version
+ */
+pni_protocol_type_t pni_sniff_header(const char *buf, size_t len)
+{
+ if (len < 3) return PNI_PROTOCOL_INSUFFICIENT;
+ bool isSSL3Handshake = buf[0]==22 && // handshake
+ buf[1]==3 && buf[2]<=3; // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+ if (isSSL3Handshake) return PNI_PROTOCOL_SSL;
+
+ bool isFirst3AMQP = buf[0]=='A' && buf[1]=='M' && buf[2]=='Q';
+ bool isFirst3SSL2CLientHello = buf[2]==1; // Client Hello
+ if (!isFirst3AMQP && !isFirst3SSL2CLientHello) return PNI_PROTOCOL_UNKNOWN;
+
+
+ if (len < 4) return PNI_PROTOCOL_INSUFFICIENT;
+ bool isAMQP = isFirst3AMQP && buf[3]=='P';
+ bool isFirst4SSL2ClientHello = isFirst3SSL2CLientHello && (buf[3]==2 || buf[3]==3);
+ if (!isAMQP && !isFirst4SSL2ClientHello) return PNI_PROTOCOL_UNKNOWN;
+
+ if (len < 5) return PNI_PROTOCOL_INSUFFICIENT;
+ bool isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO
+ ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+ (buf[3] == 2 && buf[4] == 0)); // SSL 2
+ if (isSSL2Handshake) return PNI_PROTOCOL_SSL;
+
+ bool isFirst5OldAMQP = isAMQP && buf[4]==1;
+ bool isFirst5AMQP = isAMQP && (buf[4]==0 || buf[4]==2 || buf[4]==3);
+ if (!isFirst5AMQP && !isFirst5OldAMQP) return PNI_PROTOCOL_UNKNOWN;
+
+ if (len < 6) return PNI_PROTOCOL_INSUFFICIENT;
+
+ // Both old and new versions of AMQP have 1 in byte 5
+ if (buf[5]!=1) return PNI_PROTOCOL_UNKNOWN;
+
+ // From here on it must be some sort of AMQP
+ if (len < 8) return PNI_PROTOCOL_INSUFFICIENT;
+ if (buf[6]==0 && buf[7]==0) {
+ // AM<QP 1.0
+ if (buf[4]==0) return PNI_PROTOCOL_AMQP1;
+ if (buf[4]==2) return PNI_PROTOCOL_AMQP_SSL;
+ if (buf[4]==3) return PNI_PROTOCOL_AMQP_SASL;
+ }
+ return PNI_PROTOCOL_AMQP_OTHER;
+}
+
+const char* pni_protocol_name(pni_protocol_type_t p)
+{
+ static const char* names[] = {
+ "Insufficient data to determine protocol",
+ "Unknown protocol",
+ "SSL/TLS connection",
+ "AMQP TLS layer",
+ "AMQP SASL layer",
+ "AMQP 1.0 layer",
+ "Pre standard AMQP connection"
+ };
+ return names[p];
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/transport/autodetect.h
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/autodetect.h b/proton-c/src/transport/autodetect.h
new file mode 100644
index 0000000..12cb7d8
--- /dev/null
+++ b/proton-c/src/transport/autodetect.h
@@ -0,0 +1,40 @@
+#ifndef PROTON_AUTODETECT_H
+#define PROTON_AUTODETECT_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/types.h"
+
+typedef enum {
+ PNI_PROTOCOL_INSUFFICIENT,
+ PNI_PROTOCOL_UNKNOWN,
+ PNI_PROTOCOL_SSL,
+ PNI_PROTOCOL_AMQP_SSL,
+ PNI_PROTOCOL_AMQP_SASL,
+ PNI_PROTOCOL_AMQP1,
+ PNI_PROTOCOL_AMQP_OTHER
+} pni_protocol_type_t;
+
+pni_protocol_type_t pni_sniff_header(const char *data, size_t len);
+const char* pni_protocol_name(pni_protocol_type_t p);
+
+#endif
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index 2d5f93a..67fd3ab 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -19,22 +19,25 @@
*
*/
+#include "proton/framing.h"
+
#include "engine/engine-internal.h"
-#include <stdlib.h>
-#include <string.h>
-#include <proton/framing.h>
+#include "sasl/sasl-internal.h"
+#include "ssl/ssl-internal.h"
+
+#include "autodetect.h"
#include "protocol.h"
#include "dispatch_actions.h"
+#include "proton/event.h"
+#include "platform.h"
+#include "platform_fmt.h"
+#include <stdlib.h>
+#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
-#include "sasl/sasl-internal.h"
-#include "ssl/ssl-internal.h"
-#include "platform.h"
-#include "platform_fmt.h"
-
static ssize_t transport_consume(pn_transport_t *transport);
// delivery buffers
@@ -92,26 +95,25 @@ void pn_delivery_map_clear(pn_delivery_map_t *dm)
dm->next = 0;
}
+static void pni_default_tracer(pn_transport_t *transport, const char *message)
+{
+ fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
+}
+
static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );
static ssize_t pn_io_layer_output_passthru(pn_transport_t *, unsigned int, char *, size_t );
+static ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+
static ssize_t pn_input_read_amqp_header(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
static ssize_t pn_input_read_amqp(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
static ssize_t pn_output_write_amqp_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
static ssize_t pn_output_write_amqp(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
static pn_timestamp_t pn_tick_amqp(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now);
-static void pni_default_tracer(pn_transport_t *transport, const char *message)
-{
- fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
-}
-
-const pn_io_layer_t pni_passthru_layer = {
- pn_io_layer_input_passthru,
- pn_io_layer_output_passthru,
- NULL,
- NULL
-};
+static ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
const pn_io_layer_t amqp_header_layer = {
pn_input_read_amqp_header,
@@ -141,6 +143,158 @@ const pn_io_layer_t amqp_layer = {
NULL
};
+const pn_io_layer_t pni_setup_layer = {
+ pn_io_layer_input_setup,
+ pn_io_layer_output_setup,
+ NULL,
+ NULL
+};
+
+const pn_io_layer_t pni_autodetect_layer = {
+ pn_io_layer_input_autodetect,
+ pn_io_layer_output_null,
+ NULL,
+ NULL
+};
+
+const pn_io_layer_t pni_passthru_layer = {
+ pn_io_layer_input_passthru,
+ pn_io_layer_output_passthru,
+ NULL,
+ NULL
+};
+
+/* Set up the transport protocol layers depending on what is configured */
+static void pn_io_layer_setup(pn_transport_t *transport, unsigned int layer)
+{
+ assert(layer == 0);
+ // Figure out if we are server or not
+ if (transport->server)
+ {
+ // XXX: This is currently a large hack to work around the SSL
+ // code not handling a connection error before being set up fully
+ if (transport->ssl && pn_ssl_allow_unsecured(transport)) {
+ transport->io_layers[layer++] = &pni_autodetect_layer;
+ return;
+ }
+ }
+ if (transport->ssl) {
+ transport->io_layers[layer++] = &ssl_layer;
+ }
+ if (transport->server) {
+ transport->io_layers[layer++] = &pni_autodetect_layer;
+ return;
+ }
+ if (transport->sasl) {
+ transport->io_layers[layer++] = &sasl_header_layer;
+ }
+ transport->io_layers[layer++] = &amqp_header_layer;
+}
+
+ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
+{
+ pn_io_layer_setup(transport, layer);
+ return transport->io_layers[layer]->process_input(transport, layer, bytes, available);
+}
+
+ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
+{
+ pn_io_layer_setup(transport, layer);
+ return transport->io_layers[layer]->process_output(transport, layer, bytes, available);
+}
+
+// Autodetect the layer by reading the protocol header
+ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
+{
+ const char* error;
+ bool eos = pn_transport_capacity(transport)==PN_EOS;
+ if (eos && available==0) {
+ pn_do_error(transport, "amqp:connection:framing-error", "No valid protocol header found");
+ return PN_EOS;
+ }
+ pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+ if (transport->disp->trace & PN_TRACE_DRV)
+ pn_transport_logf(transport, "%s detected", pni_protocol_name(protocol));
+ switch (protocol) {
+ case PNI_PROTOCOL_SSL:
+ if (!transport->ssl) {
+ pn_ssl(transport);
+ }
+ transport->io_layers[layer] = &ssl_layer;
+ transport->io_layers[layer+1] = &pni_autodetect_layer;
+ return ssl_layer.process_input(transport, layer, bytes, available);
+ case PNI_PROTOCOL_AMQP_SSL:
+ if (!transport->ssl) {
+ pn_ssl(transport);
+ }
+ transport->io_layers[layer] = &ssl_layer;
+ transport->io_layers[layer+1] = &pni_autodetect_layer;
+ return 8;
+ case PNI_PROTOCOL_AMQP_SASL:
+ if (!transport->sasl) {
+ pn_sasl(transport);
+ }
+ transport->io_layers[layer] = &sasl_write_header_layer;
+ transport->io_layers[layer+1] = &pni_autodetect_layer;
+ if (transport->disp->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "SASL");
+ return 8;
+ case PNI_PROTOCOL_AMQP1:
+ if (transport->sasl && pn_sasl_state((pn_sasl_t *)transport)==PN_SASL_IDLE) {
+ if (pn_sasl_skipping_allowed(transport)) {
+ pn_sasl_done((pn_sasl_t *)transport, PN_SASL_SKIPPED);
+ } else {
+ pn_do_error(transport, "amqp:connection:policy-error",
+ "Client skipped SASL exchange - forbidden");
+ return PN_EOS;
+ }
+ }
+ transport->io_layers[layer] = &amqp_write_header_layer;
+ if (transport->disp->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "AMQP");
+ return 8;
+ case PNI_PROTOCOL_INSUFFICIENT:
+ if (!eos) return 0;
+ error = "End of input stream before protocol detection";
+ break;
+ case PNI_PROTOCOL_AMQP_OTHER:
+ error = "Incompatible AMQP connection detected";
+ break;
+ case PNI_PROTOCOL_UNKNOWN:
+ default:
+ error = "Unknown protocol detected";
+ break;
+ }
+ char quoted[1024];
+ pn_quote_data(quoted, 1024, bytes, available);
+ pn_do_error(transport, "amqp:connection:framing-error",
+ "%s: '%s'%s", error, quoted,
+ !eos ? "" : " (connection aborted)");
+ return PN_EOS;
+}
+
+// We don't know what the output should be - do nothing
+ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
+{
+ return 0;
+}
+
+/** Pass through input handler */
+ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
+{
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
+ return PN_EOS;
+}
+
+/** Pass through output handler */
+ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
+{
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
+ return PN_EOS;
+}
+
static void pn_transport_initialize(void *object)
{
pn_transport_t *transport = (pn_transport_t *)object;
@@ -157,9 +311,11 @@ static void pn_transport_initialize(void *object)
transport->connection = NULL;
for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
- transport->io_layers[layer] = &pni_passthru_layer;
+ transport->io_layers[layer] = NULL;
}
- transport->io_layers[PN_IO_AMQP] = &amqp_header_layer;
+
+ // Defer setting up the layers until the first data arrives or is sent
+ transport->io_layers[0] = &pni_setup_layer;
transport->open_sent = false;
transport->open_rcvd = false;
@@ -1127,20 +1283,12 @@ static ssize_t transport_consume(pn_transport_t *transport)
return consumed;
}
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
-
static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- unsigned readable = pn_min(8, available);
bool eos = pn_transport_capacity(transport)==PN_EOS;
- if (memcmp(bytes, AMQP_HEADER, readable) || (readable<8 && eos) ) {
- char quoted[1024];
- pn_quote_data(quoted, 1024, bytes, available);
- pn_do_error(transport, "amqp:connection:framing-error",
- "%s header mismatch: '%s'%s", "AMQP", quoted,
- !eos ? "" : " (connection aborted)");
- return PN_EOS;
- } else if (readable==8) {
+ pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+ switch (protocol) {
+ case PNI_PROTOCOL_AMQP1:
if (transport->io_layers[layer] == &amqp_read_header_layer) {
transport->io_layers[layer] = &amqp_layer;
} else {
@@ -1149,8 +1297,18 @@ static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int
if (transport->disp->trace & PN_TRACE_FRM)
pn_transport_logf(transport, " <- %s", "AMQP");
return 8;
+ case PNI_PROTOCOL_INSUFFICIENT:
+ if (!eos) return 0;
+ /* Fallthru */
+ default:
+ break;
}
- return 0;
+ char quoted[1024];
+ pn_quote_data(quoted, 1024, bytes, available);
+ pn_do_error(transport, "amqp:connection:framing-error",
+ "%s header mismatch: %s ['%s']%s", "AMQP", pni_protocol_name(protocol), quoted,
+ !eos ? "" : " (connection aborted)");
+ return PN_EOS;
}
static ssize_t pn_input_read_amqp(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
@@ -1842,6 +2000,8 @@ int pn_process(pn_transport_t *transport)
return 0;
}
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
static ssize_t pn_output_write_amqp_header(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available)
{
if (transport->disp->trace & PN_TRACE_FRM)
@@ -2061,7 +2221,7 @@ pn_timestamp_t pn_transport_tick(pn_transport_t *transport, pn_timestamp_t now)
{
pn_timestamp_t r = 0;
for (int i = 0; i<PN_IO_LAYER_CT; ++i) {
- if (transport->io_layers[i]->process_tick)
+ if (transport->io_layers[i] && transport->io_layers[i]->process_tick)
r = pn_timestamp_min(r, transport->io_layers[i]->process_tick(transport, i, now));
}
return r;
@@ -2081,24 +2241,6 @@ uint64_t pn_transport_get_frames_input(const pn_transport_t *transport)
return 0;
}
-/** Pass through input handler */
-ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
-{
- if (layer+1<PN_IO_LAYER_CT)
- return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
- return PN_EOS;
-}
-
-/** Pass through output handler */
-ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
-{
- if (layer+1<PN_IO_LAYER_CT)
- return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
- return PN_EOS;
-}
-
-///
-
// input
ssize_t pn_transport_capacity(pn_transport_t *transport) /* <0 == done */
{
@@ -2252,7 +2394,8 @@ bool pn_transport_quiesced(pn_transport_t *transport)
else if (pending > 0) return false;
// no pending at transport, but check if data is buffered in I/O layers
for (int layer = 0; layer<PN_IO_LAYER_CT; ++layer) {
- if (transport->io_layers[layer]->buffered_output &&
+ if (transport->io_layers[layer] &&
+ transport->io_layers[layer]->buffered_output &&
transport->io_layers[layer]->buffered_output( transport ))
return false;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1b2be03c/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
index 231349c..e7ef5fd 100644
--- a/proton-c/src/windows/schannel.c
+++ b/proton-c/src/windows/schannel.c
@@ -148,11 +148,8 @@ struct pn_ssl_session_t {
static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static ssize_t process_input_unknown( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
-static ssize_t process_output_unknown( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
static void ssl_session_free( pn_ssl_session_t *);
static size_t buffered_output( pn_transport_t *transport );
@@ -360,13 +357,6 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
return 0;
}
-const pn_io_layer_t unknown_layer = {
- process_input_unknown,
- process_output_unknown,
- NULL,
- NULL
-};
-
const pn_io_layer_t ssl_layer = {
process_input_ssl,
process_output_ssl,
@@ -404,12 +394,6 @@ int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
ssl->domain = domain;
domain->ref_count++;
- if (domain->allow_unsecured) {
- transport->io_layers[PN_IO_SSL] = &unknown_layer;
- }
- else {
- transport->io_layers[PN_IO_SSL] = &ssl_layer;
- }
if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
ssl->session_id = pn_strdup(session_id);
@@ -439,6 +423,11 @@ int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
}
+bool pn_ssl_allow_unsecured(pn_transport_t *transport)
+{
+ return transport && transport->ssl && transport->ssl->domain && transport->ssl->domain->allow_unsecured;
+}
+
bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size )
{
*buffer = '\0';
@@ -893,12 +882,6 @@ static void start_ssl_shutdown(pn_transport_t *transport)
ssl_handshake(transport);
}
-static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
-{
- transport->io_layers[layer] = &ssl_layer;
- return 0;
-}
-
static void rewind_sc_inbuf(pni_ssl_t *ssl)
{
// Decrypted bytes have been drained or double buffered. Prepare for the next SSL Record.
@@ -1270,92 +1253,6 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
}
-static int setup_cleartext_connection(pn_transport_t *transport, unsigned int layer)
-{
- transport->io_layers[layer] = &pni_passthru_layer;
- return 0;
-}
-
-
-// until we determine if the client is using SSL or not:
-
-static ssize_t process_input_unknown(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
-{
- pn_ssl_t *ssl = transport->ssl;
- switch (check_for_ssl_connection( input_data, len )) {
- case SSL_CONNECTION:
- ssl_log(ssl, "SSL connection detected.\n");
- setup_ssl_connection(transport, layer);
- break;
- case CLEAR_CONNECTION:
- ssl_log(ssl, "Cleartext connection detected.\n");
- setup_cleartext_connection(transport, layer);
- break;
- default:
- return 0;
- }
- return transport->io_layers[layer]->process_input(transport, layer, input_data, len);
-}
-
-static ssize_t process_output_unknown(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
-{
- // do not do output until we know if SSL is used or not
- return 0;
-}
-
-static connection_mode_t check_for_ssl_connection( const char *data, size_t len )
-{
- if (len >= 5) {
- const unsigned char *buf = (unsigned char *)data;
- /*
- * SSLv2 Client Hello format
- * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
- *
- * Bytes 0-1: RECORD-LENGTH
- * Byte 2: MSG-CLIENT-HELLO (1)
- * Byte 3: CLIENT-VERSION-MSB
- * Byte 4: CLIENT-VERSION-LSB
- *
- * Allowed versions:
- * 2.0 - SSLv2
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- *
- * The version sent in the Client-Hello is the latest version supported by
- * the client. NSS may send version 3.x in an SSLv2 header for
- * maximum compatibility.
- */
- int isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO
- ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
- (buf[3] == 2 && buf[4] == 0)); // SSL 2
-
- /*
- * SSLv3/TLS Client Hello format
- * RFC 2246
- *
- * Byte 0: ContentType (handshake - 22)
- * Bytes 1-2: ProtocolVersion {major, minor}
- *
- * Allowed versions:
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- */
- int isSSL3Handshake = buf[0] == 22 && // handshake
- (buf[1] == 3 && buf[2] <= 3); // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
-
- if (isSSL2Handshake || isSSL3Handshake) {
- return SSL_CONNECTION;
- } else {
- return CLEAR_CONNECTION;
- }
- }
- return UNKNOWN_CONNECTION;
-}
-
static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
{
return PN_EOS;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[11/35] qpid-proton git commit: NO-JIRA: Fix how Perl uses the utils
module.
Posted by gs...@apache.org.
NO-JIRA: Fix how Perl uses the utils module.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/02f1c577
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/02f1c577
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/02f1c577
Branch: refs/heads/examples
Commit: 02f1c5772128a4ca1c0d176f98e4b425a88b5e71
Parents: 66150aa
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Tue Nov 18 11:43:43 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Tue Nov 18 17:13:31 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/perl/lib/qpid/proton/Message.pm | 2 +-
proton-c/bindings/perl/lib/qpid/proton/utils.pm | 2 +-
proton-c/bindings/perl/lib/qpid_proton.pm | 1 +
3 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02f1c577/proton-c/bindings/perl/lib/qpid/proton/Message.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid/proton/Message.pm b/proton-c/bindings/perl/lib/qpid/proton/Message.pm
index 49aeccd..a46717a 100644
--- a/proton-c/bindings/perl/lib/qpid/proton/Message.pm
+++ b/proton-c/bindings/perl/lib/qpid/proton/Message.pm
@@ -448,7 +448,7 @@ sub set_body {
# if no body type was defined, then attempt to infer what it should
# be, which is going to be a best guess
if (!defined($body_type)) {
- if (qpid::proton::is_num($body)) {
+ if (qpid::proton::utils::is_num($body)) {
if (qpid::proton::is_float($body)) {
$body_type = qpid::proton::FLOAT;
} else {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02f1c577/proton-c/bindings/perl/lib/qpid/proton/utils.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid/proton/utils.pm b/proton-c/bindings/perl/lib/qpid/proton/utils.pm
index 75af498..5652535 100644
--- a/proton-c/bindings/perl/lib/qpid/proton/utils.pm
+++ b/proton-c/bindings/perl/lib/qpid/proton/utils.pm
@@ -17,7 +17,7 @@
# under the License.
#
-package qpid::proton;
+package qpid::proton::utils;
sub is_num {
my $val = $_[0];
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02f1c577/proton-c/bindings/perl/lib/qpid_proton.pm
----------------------------------------------------------------------
diff --git a/proton-c/bindings/perl/lib/qpid_proton.pm b/proton-c/bindings/perl/lib/qpid_proton.pm
index de4e224..cbee98d 100644
--- a/proton-c/bindings/perl/lib/qpid_proton.pm
+++ b/proton-c/bindings/perl/lib/qpid_proton.pm
@@ -31,6 +31,7 @@ use qpid::proton::Messenger;
use qpid::proton::Message;
use qpid::proton;
+use qpid::proton::utils;
package qpid_proton;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[20/35] qpid-proton git commit: changed proton.py from a module into
a package
Posted by gs...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6a78d2f7/proton-c/bindings/python/proton/__init__.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/__init__.py b/proton-c/bindings/python/proton/__init__.py
new file mode 100644
index 0000000..fce3255
--- /dev/null
+++ b/proton-c/bindings/python/proton/__init__.py
@@ -0,0 +1,3891 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+The proton module defines a suite of APIs that implement the AMQP 1.0
+protocol.
+
+The proton APIs consist of the following classes:
+
+ - L{Messenger} -- A messaging endpoint.
+ - L{Message} -- A class for creating and/or accessing AMQP message content.
+ - L{Data} -- A class for creating and/or accessing arbitrary AMQP encoded
+ data.
+
+"""
+
+from cproton import *
+
+import weakref, re, socket
+try:
+ import uuid
+except ImportError:
+ """
+ No 'native' UUID support. Provide a very basic UUID type that is a compatible subset of the uuid type provided by more modern python releases.
+ """
+ import struct
+ class uuid:
+ class UUID:
+ def __init__(self, hex=None, bytes=None):
+ if [hex, bytes].count(None) != 1:
+ raise TypeError("need one of hex or bytes")
+ if bytes is not None:
+ self.bytes = bytes
+ elif hex is not None:
+ fields=hex.split("-")
+ fields[4:5] = [fields[4][:4], fields[4][4:]]
+ self.bytes = struct.pack("!LHHHHL", *[int(x,16) for x in fields])
+
+ def __cmp__(self, other):
+ if isinstance(other, uuid.UUID):
+ return cmp(self.bytes, other.bytes)
+ else:
+ return -1
+
+ def __str__(self):
+ return "%08x-%04x-%04x-%04x-%04x%08x" % struct.unpack("!LHHHHL", self.bytes)
+
+ def __repr__(self):
+ return "UUID(%r)" % str(self)
+
+ def __hash__(self):
+ return self.bytes.__hash__()
+
+ import os, random, socket, time
+ rand = random.Random()
+ rand.seed((os.getpid(), time.time(), socket.gethostname()))
+ def random_uuid():
+ bytes = [rand.randint(0, 255) for i in xrange(16)]
+
+ # From RFC4122, the version bits are set to 0100
+ bytes[7] &= 0x0F
+ bytes[7] |= 0x40
+
+ # From RFC4122, the top two bits of byte 8 get set to 01
+ bytes[8] &= 0x3F
+ bytes[8] |= 0x80
+ return "".join(map(chr, bytes))
+
+ def uuid4():
+ return uuid.UUID(bytes=random_uuid())
+
+try:
+ bytes()
+except NameError:
+ bytes = str
+
+VERSION_MAJOR = PN_VERSION_MAJOR
+VERSION_MINOR = PN_VERSION_MINOR
+API_LANGUAGE = "C"
+IMPLEMENTATION_LANGUAGE = "C"
+
+class Constant(object):
+
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return self.name
+
+class ProtonException(Exception):
+ """
+ The root of the proton exception hierarchy. All proton exception
+ classes derive from this exception.
+ """
+ pass
+
+class Timeout(ProtonException):
+ """
+ A timeout exception indicates that a blocking operation has timed
+ out.
+ """
+ pass
+
+class Interrupt(ProtonException):
+ """
+ An interrupt exception indicaes that a blocking operation was interrupted.
+ """
+ pass
+
+class MessengerException(ProtonException):
+ """
+ The root of the messenger exception hierarchy. All exceptions
+ generated by the messenger class derive from this exception.
+ """
+ pass
+
+class MessageException(ProtonException):
+ """
+ The MessageException class is the root of the message exception
+ hierarhcy. All exceptions generated by the Message class derive from
+ this exception.
+ """
+ pass
+
+EXCEPTIONS = {
+ PN_TIMEOUT: Timeout,
+ PN_INTR: Interrupt
+ }
+
+PENDING = Constant("PENDING")
+ACCEPTED = Constant("ACCEPTED")
+REJECTED = Constant("REJECTED")
+RELEASED = Constant("RELEASED")
+ABORTED = Constant("ABORTED")
+SETTLED = Constant("SETTLED")
+
+STATUSES = {
+ PN_STATUS_ABORTED: ABORTED,
+ PN_STATUS_ACCEPTED: ACCEPTED,
+ PN_STATUS_REJECTED: REJECTED,
+ PN_STATUS_RELEASED: RELEASED,
+ PN_STATUS_PENDING: PENDING,
+ PN_STATUS_SETTLED: SETTLED,
+ PN_STATUS_UNKNOWN: None
+ }
+
+AUTOMATIC = Constant("AUTOMATIC")
+MANUAL = Constant("MANUAL")
+
+class Messenger(object):
+ """
+ The L{Messenger} class defines a high level interface for sending
+ and receiving L{Messages<Message>}. Every L{Messenger} contains a
+ single logical queue of incoming messages and a single logical queue
+ of outgoing messages. These messages in these queues may be destined
+ for, or originate from, a variety of addresses.
+
+ The messenger interface is single-threaded. All methods
+ except one (L{interrupt}) are intended to be used from within
+ the messenger thread.
+
+
+ Address Syntax
+ ==============
+
+ An address has the following form::
+
+ [ amqp[s]:// ] [user[:password]@] domain [/[name]]
+
+ Where domain can be one of::
+
+ host | host:port | ip | ip:port | name
+
+ The following are valid examples of addresses:
+
+ - example.org
+ - example.org:1234
+ - amqp://example.org
+ - amqps://example.org
+ - example.org/incoming
+ - amqps://example.org/outgoing
+ - amqps://fred:trustno1@example.org
+ - 127.0.0.1:1234
+ - amqps://127.0.0.1:1234
+
+ Sending & Receiving Messages
+ ============================
+
+ The L{Messenger} class works in conjuction with the L{Message} class. The
+ L{Message} class is a mutable holder of message content.
+
+ The L{put} method copies its L{Message} to the outgoing queue, and may
+ send queued messages if it can do so without blocking. The L{send}
+ method blocks until it has sent the requested number of messages,
+ or until a timeout interrupts the attempt.
+
+
+ >>> message = Message()
+ >>> for i in range(3):
+ ... message.address = "amqp://host/queue"
+ ... message.subject = "Hello World %i" % i
+ ... messenger.put(message)
+ >>> messenger.send()
+
+ Similarly, the L{recv} method receives messages into the incoming
+ queue, and may block as it attempts to receive the requested number
+ of messages, or until timeout is reached. It may receive fewer
+ than the requested number. The L{get} method pops the
+ eldest L{Message} off the incoming queue and copies it into the L{Message}
+ object that you supply. It will not block.
+
+
+ >>> message = Message()
+ >>> messenger.recv(10):
+ >>> while messenger.incoming > 0:
+ ... messenger.get(message)
+ ... print message.subject
+ Hello World 0
+ Hello World 1
+ Hello World 2
+
+ The blocking flag allows you to turn off blocking behavior entirely,
+ in which case L{send} and L{recv} will do whatever they can without
+ blocking, and then return. You can then look at the number
+ of incoming and outgoing messages to see how much outstanding work
+ still remains.
+ """
+
+ def __init__(self, name=None):
+ """
+ Construct a new L{Messenger} with the given name. The name has
+ global scope. If a NULL name is supplied, a UUID based name will
+ be chosen.
+
+ @type name: string
+ @param name: the name of the messenger or None
+
+ """
+ self._mng = pn_messenger(name)
+ self._selectables = {}
+
+ def __del__(self):
+ """
+ Destroy the L{Messenger}. This will close all connections that
+ are managed by the L{Messenger}. Call the L{stop} method before
+ destroying the L{Messenger}.
+ """
+ if hasattr(self, "_mng"):
+ pn_messenger_free(self._mng)
+ del self._mng
+
+ def _check(self, err):
+ if err < 0:
+ if (err == PN_INPROGRESS):
+ return
+ exc = EXCEPTIONS.get(err, MessengerException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_messenger_error(self._mng))))
+ else:
+ return err
+
+ @property
+ def name(self):
+ """
+ The name of the L{Messenger}.
+ """
+ return pn_messenger_name(self._mng)
+
+ def _get_certificate(self):
+ return pn_messenger_get_certificate(self._mng)
+
+ def _set_certificate(self, value):
+ self._check(pn_messenger_set_certificate(self._mng, value))
+
+ certificate = property(_get_certificate, _set_certificate,
+ doc="""
+Path to a certificate file for the L{Messenger}. This certificate is
+used when the L{Messenger} accepts or establishes SSL/TLS connections.
+This property must be specified for the L{Messenger} to accept
+incoming SSL/TLS connections and to establish client authenticated
+outgoing SSL/TLS connection. Non client authenticated outgoing SSL/TLS
+connections do not require this property.
+""")
+
+ def _get_private_key(self):
+ return pn_messenger_get_private_key(self._mng)
+
+ def _set_private_key(self, value):
+ self._check(pn_messenger_set_private_key(self._mng, value))
+
+ private_key = property(_get_private_key, _set_private_key,
+ doc="""
+Path to a private key file for the L{Messenger's<Messenger>}
+certificate. This property must be specified for the L{Messenger} to
+accept incoming SSL/TLS connections and to establish client
+authenticated outgoing SSL/TLS connection. Non client authenticated
+SSL/TLS connections do not require this property.
+""")
+
+ def _get_password(self):
+ return pn_messenger_get_password(self._mng)
+
+ def _set_password(self, value):
+ self._check(pn_messenger_set_password(self._mng, value))
+
+ password = property(_get_password, _set_password,
+ doc="""
+This property contains the password for the L{Messenger.private_key}
+file, or None if the file is not encrypted.
+""")
+
+ def _get_trusted_certificates(self):
+ return pn_messenger_get_trusted_certificates(self._mng)
+
+ def _set_trusted_certificates(self, value):
+ self._check(pn_messenger_set_trusted_certificates(self._mng, value))
+
+ trusted_certificates = property(_get_trusted_certificates,
+ _set_trusted_certificates,
+ doc="""
+A path to a database of trusted certificates for use in verifying the
+peer on an SSL/TLS connection. If this property is None, then the peer
+will not be verified.
+""")
+
+ def _get_timeout(self):
+ t = pn_messenger_get_timeout(self._mng)
+ if t == -1:
+ return None
+ else:
+ return millis2secs(t)
+
+ def _set_timeout(self, value):
+ if value is None:
+ t = -1
+ else:
+ t = secs2millis(value)
+ self._check(pn_messenger_set_timeout(self._mng, t))
+
+ timeout = property(_get_timeout, _set_timeout,
+ doc="""
+The timeout property contains the default timeout for blocking
+operations performed by the L{Messenger}.
+""")
+
+ def _is_blocking(self):
+ return pn_messenger_is_blocking(self._mng)
+
+ def _set_blocking(self, b):
+ self._check(pn_messenger_set_blocking(self._mng, b))
+
+ blocking = property(_is_blocking, _set_blocking,
+ doc="""
+Enable or disable blocking behavior during L{Message} sending
+and receiving. This affects every blocking call, with the
+exception of L{work}. Currently, the affected calls are
+L{send}, L{recv}, and L{stop}.
+""")
+
+ def _is_passive(self):
+ return pn_messenger_is_passive(self._mng)
+
+ def _set_passive(self, b):
+ self._check(pn_messenger_set_passive(self._mng, b))
+
+ passive = property(_is_passive, _set_passive,
+ doc="""
+When passive is set to true, Messenger will not attempt to perform I/O
+internally. In this mode it is necessary to use the selectables API to
+drive any I/O needed to perform requested actions. In this mode
+Messenger will never block.
+""")
+
+ def _get_incoming_window(self):
+ return pn_messenger_get_incoming_window(self._mng)
+
+ def _set_incoming_window(self, window):
+ self._check(pn_messenger_set_incoming_window(self._mng, window))
+
+ incoming_window = property(_get_incoming_window, _set_incoming_window,
+ doc="""
+The incoming tracking window for the messenger. The messenger will
+track the remote status of this many incoming deliveries after they
+have been accepted or rejected. Defaults to zero.
+
+L{Messages<Message>} enter this window only when you take them into your application
+using L{get}. If your incoming window size is I{n}, and you get I{n}+1 L{messages<Message>}
+without explicitly accepting or rejecting the oldest message, then the
+message that passes beyond the edge of the incoming window will be assigned
+the default disposition of its link.
+""")
+
+ def _get_outgoing_window(self):
+ return pn_messenger_get_outgoing_window(self._mng)
+
+ def _set_outgoing_window(self, window):
+ self._check(pn_messenger_set_outgoing_window(self._mng, window))
+
+ outgoing_window = property(_get_outgoing_window, _set_outgoing_window,
+ doc="""
+The outgoing tracking window for the messenger. The messenger will
+track the remote status of this many outgoing deliveries after calling
+send. Defaults to zero.
+
+A L{Message} enters this window when you call the put() method with the
+message. If your outgoing window size is I{n}, and you call L{put} I{n}+1
+times, status information will no longer be available for the
+first message.
+""")
+
+ def start(self):
+ """
+ Currently a no-op placeholder.
+ For future compatibility, do not L{send} or L{recv} messages
+ before starting the L{Messenger}.
+ """
+ self._check(pn_messenger_start(self._mng))
+
+ def stop(self):
+ """
+ Transitions the L{Messenger} to an inactive state. An inactive
+ L{Messenger} will not send or receive messages from its internal
+ queues. A L{Messenger} should be stopped before being discarded to
+ ensure a clean shutdown handshake occurs on any internally managed
+ connections.
+ """
+ self._check(pn_messenger_stop(self._mng))
+
+ @property
+ def stopped(self):
+ """
+ Returns true iff a L{Messenger} is in the stopped state.
+ This function does not block.
+ """
+ return pn_messenger_stopped(self._mng)
+
+ def subscribe(self, source):
+ """
+ Subscribes the L{Messenger} to messages originating from the
+ specified source. The source is an address as specified in the
+ L{Messenger} introduction with the following addition. If the
+ domain portion of the address begins with the '~' character, the
+ L{Messenger} will interpret the domain as host/port, bind to it,
+ and listen for incoming messages. For example "~0.0.0.0",
+ "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
+ local interface and listen for incoming messages with the last
+ variant only permitting incoming SSL connections.
+
+ @type source: string
+ @param source: the source of messages to subscribe to
+ """
+ sub_impl = pn_messenger_subscribe(self._mng, source)
+ if not sub_impl:
+ self._check(pn_error_code(pn_messenger_error(self._mng)))
+ raise MessengerException("Cannot subscribe to %s"%source)
+ return Subscription(sub_impl)
+
+ def put(self, message):
+ """
+ Places the content contained in the message onto the outgoing
+ queue of the L{Messenger}. This method will never block, however
+ it will send any unblocked L{Messages<Message>} in the outgoing
+ queue immediately and leave any blocked L{Messages<Message>}
+ remaining in the outgoing queue. The L{send} call may be used to
+ block until the outgoing queue is empty. The L{outgoing} property
+ may be used to check the depth of the outgoing queue.
+
+ When the content in a given L{Message} object is copied to the outgoing
+ message queue, you may then modify or discard the L{Message} object
+ without having any impact on the content in the outgoing queue.
+
+ This method returns an outgoing tracker for the L{Message}. The tracker
+ can be used to determine the delivery status of the L{Message}.
+
+ @type message: Message
+ @param message: the message to place in the outgoing queue
+ @return: a tracker
+ """
+ message._pre_encode()
+ self._check(pn_messenger_put(self._mng, message._msg))
+ return pn_messenger_outgoing_tracker(self._mng)
+
+ def status(self, tracker):
+ """
+ Gets the last known remote state of the delivery associated with
+ the given tracker.
+
+ @type tracker: tracker
+ @param tracker: the tracker whose status is to be retrieved
+
+ @return: one of None, PENDING, REJECTED, or ACCEPTED
+ """
+ disp = pn_messenger_status(self._mng, tracker);
+ return STATUSES.get(disp, disp)
+
+ def buffered(self, tracker):
+ """
+ Checks if the delivery associated with the given tracker is still
+ waiting to be sent.
+
+ @type tracker: tracker
+ @param tracker: the tracker whose status is to be retrieved
+
+ @return: true if delivery is still buffered
+ """
+ return pn_messenger_buffered(self._mng, tracker);
+
+ def settle(self, tracker=None):
+ """
+ Frees a L{Messenger} from tracking the status associated with a given
+ tracker. If you don't supply a tracker, all outgoing L{messages<Message>} up
+ to the most recent will be settled.
+ """
+ if tracker is None:
+ tracker = pn_messenger_outgoing_tracker(self._mng)
+ flags = PN_CUMULATIVE
+ else:
+ flags = 0
+ self._check(pn_messenger_settle(self._mng, tracker, flags))
+
+ def send(self, n=-1):
+ """
+ This call will block until the indicated number of L{messages<Message>}
+ have been sent, or until the operation times out. If n is -1 this call will
+ block until all outgoing L{messages<Message>} have been sent. If n is 0 then
+ this call will send whatever it can without blocking.
+ """
+ self._check(pn_messenger_send(self._mng, n))
+
+ def recv(self, n=None):
+ """
+ Receives up to I{n} L{messages<Message>} into the incoming queue. If no value
+ for I{n} is supplied, this call will receive as many L{messages<Message>} as it
+ can buffer internally. If the L{Messenger} is in blocking mode, this
+ call will block until at least one L{Message} is available in the
+ incoming queue.
+ """
+ if n is None:
+ n = -1
+ self._check(pn_messenger_recv(self._mng, n))
+
+ def work(self, timeout=None):
+ """
+ Sends or receives any outstanding L{messages<Message>} queued for a L{Messenger}.
+ This will block for the indicated timeout.
+ This method may also do I/O work other than sending and receiving
+ L{messages<Message>}. For example, closing connections after messenger.L{stop}()
+ has been called.
+ """
+ if timeout is None:
+ t = -1
+ else:
+ t = secs2millis(timeout)
+ err = pn_messenger_work(self._mng, t)
+ if (err == PN_TIMEOUT):
+ return False
+ else:
+ self._check(err)
+ return True
+
+ @property
+ def receiving(self):
+ return pn_messenger_receiving(self._mng)
+
+ def interrupt(self):
+ """
+ The L{Messenger} interface is single-threaded.
+ This is the only L{Messenger} function intended to be called
+ from outside of the L{Messenger} thread.
+ Call this from a non-messenger thread to interrupt
+ a L{Messenger} that is blocking.
+ This will cause any in-progress blocking call to throw
+ the L{Interrupt} exception. If there is no currently blocking
+ call, then the next blocking call will be affected, even if it
+ is within the same thread that interrupt was called from.
+ """
+ self._check(pn_messenger_interrupt(self._mng))
+
+ def get(self, message=None):
+ """
+ Moves the message from the head of the incoming message queue into
+ the supplied message object. Any content in the message will be
+ overwritten.
+
+ A tracker for the incoming L{Message} is returned. The tracker can
+ later be used to communicate your acceptance or rejection of the
+ L{Message}.
+
+ If None is passed in for the L{Message} object, the L{Message}
+ popped from the head of the queue is discarded.
+
+ @type message: Message
+ @param message: the destination message object
+ @return: a tracker
+ """
+ if message is None:
+ impl = None
+ else:
+ impl = message._msg
+ self._check(pn_messenger_get(self._mng, impl))
+ if message is not None:
+ message._post_decode()
+ return pn_messenger_incoming_tracker(self._mng)
+
+ def accept(self, tracker=None):
+ """
+ Signal the sender that you have acted on the L{Message}
+ pointed to by the tracker. If no tracker is supplied,
+ then all messages that have been returned by the L{get}
+ method are accepted, except those that have already been
+ auto-settled by passing beyond your incoming window size.
+
+ @type tracker: tracker
+ @param tracker: a tracker as returned by get
+ """
+ if tracker is None:
+ tracker = pn_messenger_incoming_tracker(self._mng)
+ flags = PN_CUMULATIVE
+ else:
+ flags = 0
+ self._check(pn_messenger_accept(self._mng, tracker, flags))
+
+ def reject(self, tracker=None):
+ """
+ Rejects the L{Message} indicated by the tracker. If no tracker
+ is supplied, all messages that have been returned by the L{get}
+ method are rejected, except those that have already been auto-settled
+ by passing beyond your outgoing window size.
+
+ @type tracker: tracker
+ @param tracker: a tracker as returned by get
+ """
+ if tracker is None:
+ tracker = pn_messenger_incoming_tracker(self._mng)
+ flags = PN_CUMULATIVE
+ else:
+ flags = 0
+ self._check(pn_messenger_reject(self._mng, tracker, flags))
+
+ @property
+ def outgoing(self):
+ """
+ The outgoing queue depth.
+ """
+ return pn_messenger_outgoing(self._mng)
+
+ @property
+ def incoming(self):
+ """
+ The incoming queue depth.
+ """
+ return pn_messenger_incoming(self._mng)
+
+ def route(self, pattern, address):
+ """
+ Adds a routing rule to a L{Messenger's<Messenger>} internal routing table.
+
+ The route procedure may be used to influence how a L{Messenger} will
+ internally treat a given address or class of addresses. Every call
+ to the route procedure will result in L{Messenger} appending a routing
+ rule to its internal routing table.
+
+ Whenever a L{Message} is presented to a L{Messenger} for delivery, it
+ will match the address of this message against the set of routing
+ rules in order. The first rule to match will be triggered, and
+ instead of routing based on the address presented in the message,
+ the L{Messenger} will route based on the address supplied in the rule.
+
+ The pattern matching syntax supports two types of matches, a '%'
+ will match any character except a '/', and a '*' will match any
+ character including a '/'.
+
+ A routing address is specified as a normal AMQP address, however it
+ may additionally use substitution variables from the pattern match
+ that triggered the rule.
+
+ Any message sent to "foo" will be routed to "amqp://foo.com":
+
+ >>> messenger.route("foo", "amqp://foo.com");
+
+ Any message sent to "foobar" will be routed to
+ "amqp://foo.com/bar":
+
+ >>> messenger.route("foobar", "amqp://foo.com/bar");
+
+ Any message sent to bar/<path> will be routed to the corresponding
+ path within the amqp://bar.com domain:
+
+ >>> messenger.route("bar/*", "amqp://bar.com/$1");
+
+ Route all L{messages<Message>} over TLS:
+
+ >>> messenger.route("amqp:*", "amqps:$1")
+
+ Supply credentials for foo.com:
+
+ >>> messenger.route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
+
+ Supply credentials for all domains:
+
+ >>> messenger.route("amqp://*", "amqp://user:password@$1");
+
+ Route all addresses through a single proxy while preserving the
+ original destination:
+
+ >>> messenger.route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
+
+ Route any address through a single broker:
+
+ >>> messenger.route("*", "amqp://user:password@broker/$1");
+ """
+ self._check(pn_messenger_route(self._mng, pattern, address))
+
+ def rewrite(self, pattern, address):
+ """
+ Similar to route(), except that the destination of
+ the L{Message} is determined before the message address is rewritten.
+
+ The outgoing address is only rewritten after routing has been
+ finalized. If a message has an outgoing address of
+ "amqp://0.0.0.0:5678", and a rewriting rule that changes its
+ outgoing address to "foo", it will still arrive at the peer that
+ is listening on "amqp://0.0.0.0:5678", but when it arrives there,
+ the receiver will see its outgoing address as "foo".
+
+ The default rewrite rule removes username and password from addresses
+ before they are transmitted.
+ """
+ self._check(pn_messenger_rewrite(self._mng, pattern, address))
+
+ def selectable(self):
+ impl = pn_messenger_selectable(self._mng)
+ if impl:
+ fd = pn_selectable_fd(impl)
+ sel = self._selectables.get(fd, None)
+ if sel is None:
+ sel = Selectable(self, impl)
+ self._selectables[fd] = sel
+ return sel
+ else:
+ return None
+
+ @property
+ def deadline(self):
+ tstamp = pn_messenger_deadline(self._mng)
+ if tstamp:
+ return millis2secs(tstamp)
+ else:
+ return None
+
+class Message(object):
+ """The L{Message} class is a mutable holder of message content.
+
+ @ivar instructions: delivery instructions for the message
+ @type instructions: dict
+ @ivar annotations: infrastructure defined message annotations
+ @type annotations: dict
+ @ivar properties: application defined message properties
+ @type properties: dict
+ @ivar body: message body
+ @type body: bytes | unicode | dict | list | int | long | float | UUID
+ """
+
+ DATA = PN_DATA
+ TEXT = PN_TEXT
+ AMQP = PN_AMQP
+ JSON = PN_JSON
+
+ DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY
+
+ def __init__(self, **kwargs):
+ """
+ @param kwargs: Message property name/value pairs to initialise the Message
+ """
+ self._msg = pn_message()
+ self._id = Data(pn_message_id(self._msg))
+ self._correlation_id = Data(pn_message_correlation_id(self._msg))
+ self.instructions = None
+ self.annotations = None
+ self.properties = None
+ self.body = None
+ for k,v in kwargs.iteritems():
+ getattr(self, k) # Raise exception if it's not a valid attribute.
+ setattr(self, k, v)
+
+ def __del__(self):
+ if hasattr(self, "_msg"):
+ pn_message_free(self._msg)
+ del self._msg
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, MessageException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_message_error(self._msg))))
+ else:
+ return err
+
+ def _pre_encode(self):
+ inst = Data(pn_message_instructions(self._msg))
+ ann = Data(pn_message_annotations(self._msg))
+ props = Data(pn_message_properties(self._msg))
+ body = Data(pn_message_body(self._msg))
+
+ inst.clear()
+ if self.instructions is not None:
+ inst.put_object(self.instructions)
+ ann.clear()
+ if self.annotations is not None:
+ ann.put_object(self.annotations)
+ props.clear()
+ if self.properties is not None:
+ props.put_object(self.properties)
+ body.clear()
+ if self.body is not None:
+ body.put_object(self.body)
+
+ def _post_decode(self):
+ inst = Data(pn_message_instructions(self._msg))
+ ann = Data(pn_message_annotations(self._msg))
+ props = Data(pn_message_properties(self._msg))
+ body = Data(pn_message_body(self._msg))
+
+ if inst.next():
+ self.instructions = inst.get_object()
+ else:
+ self.instructions = None
+ if ann.next():
+ self.annotations = ann.get_object()
+ else:
+ self.annotations = None
+ if props.next():
+ self.properties = props.get_object()
+ else:
+ self.properties = None
+ if body.next():
+ self.body = body.get_object()
+ else:
+ self.body = None
+
+ def clear(self):
+ """
+ Clears the contents of the L{Message}. All fields will be reset to
+ their default values.
+ """
+ pn_message_clear(self._msg)
+ self.instructions = None
+ self.annotations = None
+ self.properties = None
+ self.body = None
+
+ def _is_inferred(self):
+ return pn_message_is_inferred(self._msg)
+
+ def _set_inferred(self, value):
+ self._check(pn_message_set_inferred(self._msg, bool(value)))
+
+ inferred = property(_is_inferred, _set_inferred, doc="""
+The inferred flag for a message indicates how the message content
+is encoded into AMQP sections. If inferred is true then binary and
+list values in the body of the message will be encoded as AMQP DATA
+and AMQP SEQUENCE sections, respectively. If inferred is false,
+then all values in the body of the message will be encoded as AMQP
+VALUE sections regardless of their type.
+""")
+
+ def _is_durable(self):
+ return pn_message_is_durable(self._msg)
+
+ def _set_durable(self, value):
+ self._check(pn_message_set_durable(self._msg, bool(value)))
+
+ durable = property(_is_durable, _set_durable,
+ doc="""
+The durable property indicates that the message should be held durably
+by any intermediaries taking responsibility for the message.
+""")
+
+ def _get_priority(self):
+ return pn_message_get_priority(self._msg)
+
+ def _set_priority(self, value):
+ self._check(pn_message_set_priority(self._msg, value))
+
+ priority = property(_get_priority, _set_priority,
+ doc="""
+The priority of the message.
+""")
+
+ def _get_ttl(self):
+ return millis2secs(pn_message_get_ttl(self._msg))
+
+ def _set_ttl(self, value):
+ self._check(pn_message_set_ttl(self._msg, secs2millis(value)))
+
+ ttl = property(_get_ttl, _set_ttl,
+ doc="""
+The time to live of the message measured in seconds. Expired messages
+may be dropped.
+""")
+
+ def _is_first_acquirer(self):
+ return pn_message_is_first_acquirer(self._msg)
+
+ def _set_first_acquirer(self, value):
+ self._check(pn_message_set_first_acquirer(self._msg, bool(value)))
+
+ first_acquirer = property(_is_first_acquirer, _set_first_acquirer,
+ doc="""
+True iff the recipient is the first to acquire the message.
+""")
+
+ def _get_delivery_count(self):
+ return pn_message_get_delivery_count(self._msg)
+
+ def _set_delivery_count(self, value):
+ self._check(pn_message_set_delivery_count(self._msg, value))
+
+ delivery_count = property(_get_delivery_count, _set_delivery_count,
+ doc="""
+The number of delivery attempts made for this message.
+""")
+
+
+ def _get_id(self):
+ return self._id.get_object()
+ def _set_id(self, value):
+ if type(value) in (int, long):
+ value = ulong(value)
+ self._id.rewind()
+ self._id.put_object(value)
+ id = property(_get_id, _set_id,
+ doc="""
+The id of the message.
+""")
+
+ def _get_user_id(self):
+ return pn_message_get_user_id(self._msg)
+
+ def _set_user_id(self, value):
+ self._check(pn_message_set_user_id(self._msg, value))
+
+ user_id = property(_get_user_id, _set_user_id,
+ doc="""
+The user id of the message creator.
+""")
+
+ def _get_address(self):
+ return pn_message_get_address(self._msg)
+
+ def _set_address(self, value):
+ self._check(pn_message_set_address(self._msg, value))
+
+ address = property(_get_address, _set_address,
+ doc="""
+The address of the message.
+""")
+
+ def _get_subject(self):
+ return pn_message_get_subject(self._msg)
+
+ def _set_subject(self, value):
+ self._check(pn_message_set_subject(self._msg, value))
+
+ subject = property(_get_subject, _set_subject,
+ doc="""
+The subject of the message.
+""")
+
+ def _get_reply_to(self):
+ return pn_message_get_reply_to(self._msg)
+
+ def _set_reply_to(self, value):
+ self._check(pn_message_set_reply_to(self._msg, value))
+
+ reply_to = property(_get_reply_to, _set_reply_to,
+ doc="""
+The reply-to address for the message.
+""")
+
+ def _get_correlation_id(self):
+ return self._correlation_id.get_object()
+ def _set_correlation_id(self, value):
+ if type(value) in (int, long):
+ value = ulong(value)
+ self._correlation_id.rewind()
+ self._correlation_id.put_object(value)
+
+ correlation_id = property(_get_correlation_id, _set_correlation_id,
+ doc="""
+The correlation-id for the message.
+""")
+
+ def _get_content_type(self):
+ return pn_message_get_content_type(self._msg)
+
+ def _set_content_type(self, value):
+ self._check(pn_message_set_content_type(self._msg, value))
+
+ content_type = property(_get_content_type, _set_content_type,
+ doc="""
+The content-type of the message.
+""")
+
+ def _get_content_encoding(self):
+ return pn_message_get_content_encoding(self._msg)
+
+ def _set_content_encoding(self, value):
+ self._check(pn_message_set_content_encoding(self._msg, value))
+
+ content_encoding = property(_get_content_encoding, _set_content_encoding,
+ doc="""
+The content-encoding of the message.
+""")
+
+ def _get_expiry_time(self):
+ return millis2secs(pn_message_get_expiry_time(self._msg))
+
+ def _set_expiry_time(self, value):
+ self._check(pn_message_set_expiry_time(self._msg, secs2millis(value)))
+
+ expiry_time = property(_get_expiry_time, _set_expiry_time,
+ doc="""
+The expiry time of the message.
+""")
+
+ def _get_creation_time(self):
+ return millis2secs(pn_message_get_creation_time(self._msg))
+
+ def _set_creation_time(self, value):
+ self._check(pn_message_set_creation_time(self._msg, secs2millis(value)))
+
+ creation_time = property(_get_creation_time, _set_creation_time,
+ doc="""
+The creation time of the message.
+""")
+
+ def _get_group_id(self):
+ return pn_message_get_group_id(self._msg)
+
+ def _set_group_id(self, value):
+ self._check(pn_message_set_group_id(self._msg, value))
+
+ group_id = property(_get_group_id, _set_group_id,
+ doc="""
+The group id of the message.
+""")
+
+ def _get_group_sequence(self):
+ return pn_message_get_group_sequence(self._msg)
+
+ def _set_group_sequence(self, value):
+ self._check(pn_message_set_group_sequence(self._msg, value))
+
+ group_sequence = property(_get_group_sequence, _set_group_sequence,
+ doc="""
+The sequence of the message within its group.
+""")
+
+ def _get_reply_to_group_id(self):
+ return pn_message_get_reply_to_group_id(self._msg)
+
+ def _set_reply_to_group_id(self, value):
+ self._check(pn_message_set_reply_to_group_id(self._msg, value))
+
+ reply_to_group_id = property(_get_reply_to_group_id, _set_reply_to_group_id,
+ doc="""
+The group-id for any replies.
+""")
+
+ # XXX
+ def _get_format(self):
+ return pn_message_get_format(self._msg)
+
+ def _set_format(self, value):
+ self._check(pn_message_set_format(self._msg, value))
+
+ format = property(_get_format, _set_format,
+ doc="""
+The format of the message.
+""")
+
+ def encode(self):
+ self._pre_encode()
+ sz = 16
+ while True:
+ err, data = pn_message_encode(self._msg, sz)
+ if err == PN_OVERFLOW:
+ sz *= 2
+ continue
+ else:
+ self._check(err)
+ return data
+
+ def decode(self, data):
+ self._check(pn_message_decode(self._msg, data, len(data)))
+ self._post_decode()
+
+ def load(self, data):
+ self._check(pn_message_load(self._msg, data))
+
+ def save(self):
+ sz = 16
+ while True:
+ err, data = pn_message_save(self._msg, sz)
+ if err == PN_OVERFLOW:
+ sz *= 2
+ continue
+ else:
+ self._check(err)
+ return data
+
+ def __repr2__(self):
+ props = []
+ for attr in ("inferred", "address", "reply_to", "durable", "ttl",
+ "priority", "first_acquirer", "delivery_count", "id",
+ "correlation_id", "user_id", "group_id", "group_sequence",
+ "reply_to_group_id", "instructions", "annotations",
+ "properties", "body"):
+ value = getattr(self, attr)
+ if value: props.append("%s=%r" % (attr, value))
+ return "Message(%s)" % ", ".join(props)
+
+ def __repr__(self):
+ tmp = pn_string(None)
+ err = pn_inspect(self._msg, tmp)
+ result = pn_string_get(tmp)
+ pn_free(tmp)
+ self._check(err)
+ return result
+
+class Subscription(object):
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ @property
+ def address(self):
+ return pn_subscription_address(self._impl)
+
+class Selectable(object):
+
+ def __init__(self, messenger, impl):
+ self.messenger = messenger
+ self._impl = impl
+
+ def fileno(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_fd(self._impl)
+
+ @property
+ def capacity(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_capacity(self._impl)
+
+ @property
+ def pending(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_pending(self._impl)
+
+ @property
+ def deadline(self):
+ if not self._impl: raise ValueError("selectable freed")
+ tstamp = pn_selectable_deadline(self._impl)
+ if tstamp:
+ return millis2secs(tstamp)
+ else:
+ return None
+
+ def readable(self):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_readable(self._impl)
+
+ def writable(self):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_writable(self._impl)
+
+ def expired(self):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_expired(self._impl)
+
+ def _is_registered(self):
+ if not self._impl: raise ValueError("selectable freed")
+ return pn_selectable_is_registered(self._impl)
+
+ def _set_registered(self, registered):
+ if not self._impl: raise ValueError("selectable freed")
+ pn_selectable_set_registered(self._impl, registered)
+
+ registered = property(_is_registered, _set_registered,
+ doc="""
+The registered property may be get/set by an I/O polling system to
+indicate whether the fd has been registered or not.
+""")
+
+ @property
+ def is_terminal(self):
+ if not self._impl: return True
+ return pn_selectable_is_terminal(self._impl)
+
+ def free(self):
+ if self._impl:
+ del self.messenger._selectables[self.fileno()]
+ pn_selectable_free(self._impl)
+ self._impl = None
+
+ def __del__(self):
+ self.free()
+
+class DataException(ProtonException):
+ """
+ The DataException class is the root of the Data exception hierarchy.
+ All exceptions raised by the Data class extend this exception.
+ """
+ pass
+
+class UnmappedType:
+
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __repr__(self):
+ return "UnmappedType(%s)" % self.msg
+
+class ulong(long):
+
+ def __repr__(self):
+ return "ulong(%s)" % long.__repr__(self)
+
+class timestamp(long):
+
+ def __repr__(self):
+ return "timestamp(%s)" % long.__repr__(self)
+
+class symbol(unicode):
+
+ def __repr__(self):
+ return "symbol(%s)" % unicode.__repr__(self)
+
+class char(unicode):
+
+ def __repr__(self):
+ return "char(%s)" % unicode.__repr__(self)
+
+class Described(object):
+
+ def __init__(self, descriptor, value):
+ self.descriptor = descriptor
+ self.value = value
+
+ def __repr__(self):
+ return "Described(%r, %r)" % (self.descriptor, self.value)
+
+ def __eq__(self, o):
+ if isinstance(o, Described):
+ return self.descriptor == o.descriptor and self.value == o.value
+ else:
+ return False
+
+UNDESCRIBED = Constant("UNDESCRIBED")
+
+class Array(object):
+
+ def __init__(self, descriptor, type, *elements):
+ self.descriptor = descriptor
+ self.type = type
+ self.elements = elements
+
+ def __repr__(self):
+ if self.elements:
+ els = ", %s" % (", ".join(map(repr, self.elements)))
+ else:
+ els = ""
+ return "Array(%r, %r%s)" % (self.descriptor, self.type, els)
+
+ def __eq__(self, o):
+ if isinstance(o, Array):
+ return self.descriptor == o.descriptor and \
+ self.type == o.type and self.elements == o.elements
+ else:
+ return False
+
+class Data:
+ """
+ The L{Data} class provides an interface for decoding, extracting,
+ creating, and encoding arbitrary AMQP data. A L{Data} object
+ contains a tree of AMQP values. Leaf nodes in this tree correspond
+ to scalars in the AMQP type system such as L{ints<INT>} or
+ L{strings<STRING>}. Non-leaf nodes in this tree correspond to
+ compound values in the AMQP type system such as L{lists<LIST>},
+ L{maps<MAP>}, L{arrays<ARRAY>}, or L{described values<DESCRIBED>}.
+ The root node of the tree is the L{Data} object itself and can have
+ an arbitrary number of children.
+
+ A L{Data} object maintains the notion of the current sibling node
+ and a current parent node. Siblings are ordered within their parent.
+ Values are accessed and/or added by using the L{next}, L{prev},
+ L{enter}, and L{exit} methods to navigate to the desired location in
+ the tree and using the supplied variety of put_*/get_* methods to
+ access or add a value of the desired type.
+
+ The put_* methods will always add a value I{after} the current node
+ in the tree. If the current node has a next sibling the put_* method
+ will overwrite the value on this node. If there is no current node
+ or the current node has no next sibling then one will be added. The
+ put_* methods always set the added/modified node to the current
+ node. The get_* methods read the value of the current node and do
+ not change which node is current.
+
+ The following types of scalar values are supported:
+
+ - L{NULL}
+ - L{BOOL}
+ - L{UBYTE}
+ - L{USHORT}
+ - L{SHORT}
+ - L{UINT}
+ - L{INT}
+ - L{ULONG}
+ - L{LONG}
+ - L{FLOAT}
+ - L{DOUBLE}
+ - L{BINARY}
+ - L{STRING}
+ - L{SYMBOL}
+
+ The following types of compound values are supported:
+
+ - L{DESCRIBED}
+ - L{ARRAY}
+ - L{LIST}
+ - L{MAP}
+ """
+
+ NULL = PN_NULL; "A null value."
+ BOOL = PN_BOOL; "A boolean value."
+ UBYTE = PN_UBYTE; "An unsigned byte value."
+ BYTE = PN_BYTE; "A signed byte value."
+ USHORT = PN_USHORT; "An unsigned short value."
+ SHORT = PN_SHORT; "A short value."
+ UINT = PN_UINT; "An unsigned int value."
+ INT = PN_INT; "A signed int value."
+ CHAR = PN_CHAR; "A character value."
+ ULONG = PN_ULONG; "An unsigned long value."
+ LONG = PN_LONG; "A signed long value."
+ TIMESTAMP = PN_TIMESTAMP; "A timestamp value."
+ FLOAT = PN_FLOAT; "A float value."
+ DOUBLE = PN_DOUBLE; "A double value."
+ DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value."
+ DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value."
+ DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value."
+ UUID = PN_UUID; "A UUID value."
+ BINARY = PN_BINARY; "A binary string."
+ STRING = PN_STRING; "A unicode string."
+ SYMBOL = PN_SYMBOL; "A symbolic string."
+ DESCRIBED = PN_DESCRIBED; "A described value."
+ ARRAY = PN_ARRAY; "An array value."
+ LIST = PN_LIST; "A list value."
+ MAP = PN_MAP; "A map value."
+
+ type_names = {
+ NULL: "null",
+ BOOL: "bool",
+ BYTE: "byte",
+ UBYTE: "ubyte",
+ SHORT: "short",
+ USHORT: "ushort",
+ INT: "int",
+ UINT: "uint",
+ CHAR: "char",
+ LONG: "long",
+ ULONG: "ulong",
+ TIMESTAMP: "timestamp",
+ FLOAT: "float",
+ DOUBLE: "double",
+ DECIMAL32: "decimal32",
+ DECIMAL64: "decimal64",
+ DECIMAL128: "decimal128",
+ UUID: "uuid",
+ BINARY: "binary",
+ STRING: "string",
+ SYMBOL: "symbol",
+ DESCRIBED: "described",
+ ARRAY: "array",
+ LIST: "list",
+ MAP: "map"
+ }
+
+ @classmethod
+ def type_name(type): return Data.type_names[type]
+
+ def __init__(self, capacity=16):
+ if type(capacity) in (int, long):
+ self._data = pn_data(capacity)
+ self._free = True
+ else:
+ self._data = capacity
+ self._free = False
+
+ def __del__(self):
+ if self._free and hasattr(self, "_data"):
+ pn_data_free(self._data)
+ del self._data
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, DataException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_data_error(self._data))))
+ else:
+ return err
+
+ def clear(self):
+ """
+ Clears the data object.
+ """
+ pn_data_clear(self._data)
+
+ def rewind(self):
+ """
+ Clears current node and sets the parent to the root node. Clearing the
+ current node sets it _before_ the first node, calling next() will advance to
+ the first node.
+ """
+ assert self._data is not None
+ pn_data_rewind(self._data)
+
+ def next(self):
+ """
+ Advances the current node to its next sibling and returns its
+ type. If there is no next sibling the current node remains
+ unchanged and None is returned.
+ """
+ found = pn_data_next(self._data)
+ if found:
+ return self.type()
+ else:
+ return None
+
+ def prev(self):
+ """
+ Advances the current node to its previous sibling and returns its
+ type. If there is no previous sibling the current node remains
+ unchanged and None is returned.
+ """
+ found = pn_data_prev(self._data)
+ if found:
+ return self.type()
+ else:
+ return None
+
+ def enter(self):
+ """
+ Sets the parent node to the current node and clears the current node.
+ Clearing the current node sets it _before_ the first child,
+ call next() advances to the first child.
+ """
+ return pn_data_enter(self._data)
+
+ def exit(self):
+ """
+ Sets the current node to the parent node and the parent node to
+ its own parent.
+ """
+ return pn_data_exit(self._data)
+
+ def lookup(self, name):
+ return pn_data_lookup(self._data, name)
+
+ def narrow(self):
+ pn_data_narrow(self._data)
+
+ def widen(self):
+ pn_data_widen(self._data)
+
+ def type(self):
+ """
+ Returns the type of the current node.
+ """
+ dtype = pn_data_type(self._data)
+ if dtype == -1:
+ return None
+ else:
+ return dtype
+
+ def encode(self):
+ """
+ Returns a representation of the data encoded in AMQP format.
+ """
+ size = 1024
+ while True:
+ cd, enc = pn_data_encode(self._data, size)
+ if cd == PN_OVERFLOW:
+ size *= 2
+ elif cd >= 0:
+ return enc
+ else:
+ self._check(cd)
+
+ def decode(self, encoded):
+ """
+ Decodes the first value from supplied AMQP data and returns the
+ number of bytes consumed.
+
+ @type encoded: binary
+ @param encoded: AMQP encoded binary data
+ """
+ return self._check(pn_data_decode(self._data, encoded))
+
+ def put_list(self):
+ """
+ Puts a list value. Elements may be filled by entering the list
+ node and putting element values.
+
+ >>> data = Data()
+ >>> data.put_list()
+ >>> data.enter()
+ >>> data.put_int(1)
+ >>> data.put_int(2)
+ >>> data.put_int(3)
+ >>> data.exit()
+ """
+ self._check(pn_data_put_list(self._data))
+
+ def put_map(self):
+ """
+ Puts a map value. Elements may be filled by entering the map node
+ and putting alternating key value pairs.
+
+ >>> data = Data()
+ >>> data.put_map()
+ >>> data.enter()
+ >>> data.put_string("key")
+ >>> data.put_string("value")
+ >>> data.exit()
+ """
+ self._check(pn_data_put_map(self._data))
+
+ def put_array(self, described, element_type):
+ """
+ Puts an array value. Elements may be filled by entering the array
+ node and putting the element values. The values must all be of the
+ specified array element type. If an array is described then the
+ first child value of the array is the descriptor and may be of any
+ type.
+
+ >>> data = Data()
+ >>>
+ >>> data.put_array(False, Data.INT)
+ >>> data.enter()
+ >>> data.put_int(1)
+ >>> data.put_int(2)
+ >>> data.put_int(3)
+ >>> data.exit()
+ >>>
+ >>> data.put_array(True, Data.DOUBLE)
+ >>> data.enter()
+ >>> data.put_symbol("array-descriptor")
+ >>> data.put_double(1.1)
+ >>> data.put_double(1.2)
+ >>> data.put_double(1.3)
+ >>> data.exit()
+
+ @type described: bool
+ @param described: specifies whether the array is described
+ @type element_type: int
+ @param element_type: the type of the array elements
+ """
+ self._check(pn_data_put_array(self._data, described, element_type))
+
+ def put_described(self):
+ """
+ Puts a described value. A described node has two children, the
+ descriptor and the value. These are specified by entering the node
+ and putting the desired values.
+
+ >>> data = Data()
+ >>> data.put_described()
+ >>> data.enter()
+ >>> data.put_symbol("value-descriptor")
+ >>> data.put_string("the value")
+ >>> data.exit()
+ """
+ self._check(pn_data_put_described(self._data))
+
+ def put_null(self):
+ """
+ Puts a null value.
+ """
+ self._check(pn_data_put_null(self._data))
+
+ def put_bool(self, b):
+ """
+ Puts a boolean value.
+
+ @param b: a boolean value
+ """
+ self._check(pn_data_put_bool(self._data, b))
+
+ def put_ubyte(self, ub):
+ """
+ Puts an unsigned byte value.
+
+ @param ub: an integral value
+ """
+ self._check(pn_data_put_ubyte(self._data, ub))
+
+ def put_byte(self, b):
+ """
+ Puts a signed byte value.
+
+ @param b: an integral value
+ """
+ self._check(pn_data_put_byte(self._data, b))
+
+ def put_ushort(self, us):
+ """
+ Puts an unsigned short value.
+
+ @param us: an integral value.
+ """
+ self._check(pn_data_put_ushort(self._data, us))
+
+ def put_short(self, s):
+ """
+ Puts a signed short value.
+
+ @param s: an integral value
+ """
+ self._check(pn_data_put_short(self._data, s))
+
+ def put_uint(self, ui):
+ """
+ Puts an unsigned int value.
+
+ @param ui: an integral value
+ """
+ self._check(pn_data_put_uint(self._data, ui))
+
+ def put_int(self, i):
+ """
+ Puts a signed int value.
+
+ @param i: an integral value
+ """
+ self._check(pn_data_put_int(self._data, i))
+
+ def put_char(self, c):
+ """
+ Puts a char value.
+
+ @param c: a single character
+ """
+ self._check(pn_data_put_char(self._data, ord(c)))
+
+ def put_ulong(self, ul):
+ """
+ Puts an unsigned long value.
+
+ @param ul: an integral value
+ """
+ self._check(pn_data_put_ulong(self._data, ul))
+
+ def put_long(self, l):
+ """
+ Puts a signed long value.
+
+ @param l: an integral value
+ """
+ self._check(pn_data_put_long(self._data, l))
+
+ def put_timestamp(self, t):
+ """
+ Puts a timestamp value.
+
+ @param t: an integral value
+ """
+ self._check(pn_data_put_timestamp(self._data, t))
+
+ def put_float(self, f):
+ """
+ Puts a float value.
+
+ @param f: a floating point value
+ """
+ self._check(pn_data_put_float(self._data, f))
+
+ def put_double(self, d):
+ """
+ Puts a double value.
+
+ @param d: a floating point value.
+ """
+ self._check(pn_data_put_double(self._data, d))
+
+ def put_decimal32(self, d):
+ """
+ Puts a decimal32 value.
+
+ @param d: a decimal32 value
+ """
+ self._check(pn_data_put_decimal32(self._data, d))
+
+ def put_decimal64(self, d):
+ """
+ Puts a decimal64 value.
+
+ @param d: a decimal64 value
+ """
+ self._check(pn_data_put_decimal64(self._data, d))
+
+ def put_decimal128(self, d):
+ """
+ Puts a decimal128 value.
+
+ @param d: a decimal128 value
+ """
+ self._check(pn_data_put_decimal128(self._data, d))
+
+ def put_uuid(self, u):
+ """
+ Puts a UUID value.
+
+ @param u: a uuid value
+ """
+ self._check(pn_data_put_uuid(self._data, u.bytes))
+
+ def put_binary(self, b):
+ """
+ Puts a binary value.
+
+ @type b: binary
+ @param b: a binary value
+ """
+ self._check(pn_data_put_binary(self._data, b))
+
+ def put_string(self, s):
+ """
+ Puts a unicode value.
+
+ @type s: unicode
+ @param s: a unicode value
+ """
+ self._check(pn_data_put_string(self._data, s.encode("utf8")))
+
+ def put_symbol(self, s):
+ """
+ Puts a symbolic value.
+
+ @type s: string
+ @param s: the symbol name
+ """
+ self._check(pn_data_put_symbol(self._data, s))
+
+ def get_list(self):
+ """
+ If the current node is a list, return the number of elements,
+ otherwise return zero. List elements can be accessed by entering
+ the list.
+
+ >>> count = data.get_list()
+ >>> data.enter()
+ >>> for i in range(count):
+ ... type = data.next()
+ ... if type == Data.STRING:
+ ... print data.get_string()
+ ... elif type == ...:
+ ... ...
+ >>> data.exit()
+ """
+ return pn_data_get_list(self._data)
+
+ def get_map(self):
+ """
+ If the current node is a map, return the number of child elements,
+ otherwise return zero. Key value pairs can be accessed by entering
+ the map.
+
+ >>> count = data.get_map()
+ >>> data.enter()
+ >>> for i in range(count/2):
+ ... type = data.next()
+ ... if type == Data.STRING:
+ ... print data.get_string()
+ ... elif type == ...:
+ ... ...
+ >>> data.exit()
+ """
+ return pn_data_get_map(self._data)
+
+ def get_array(self):
+ """
+ If the current node is an array, return a tuple of the element
+ count, a boolean indicating whether the array is described, and
+ the type of each element, otherwise return (0, False, None). Array
+ data can be accessed by entering the array.
+
+ >>> # read an array of strings with a symbolic descriptor
+ >>> count, described, type = data.get_array()
+ >>> data.enter()
+ >>> data.next()
+ >>> print "Descriptor:", data.get_symbol()
+ >>> for i in range(count):
+ ... data.next()
+ ... print "Element:", data.get_string()
+ >>> data.exit()
+ """
+ count = pn_data_get_array(self._data)
+ described = pn_data_is_array_described(self._data)
+ type = pn_data_get_array_type(self._data)
+ if type == -1:
+ type = None
+ return count, described, type
+
+ def is_described(self):
+ """
+ Checks if the current node is a described value. The descriptor
+ and value may be accessed by entering the described value.
+
+ >>> # read a symbolically described string
+ >>> assert data.is_described() # will error if the current node is not described
+ >>> data.enter()
+ >>> print data.get_symbol()
+ >>> print data.get_string()
+ >>> data.exit()
+ """
+ return pn_data_is_described(self._data)
+
+ def is_null(self):
+ """
+ Checks if the current node is a null.
+ """
+ return pn_data_is_null(self._data)
+
+ def get_bool(self):
+ """
+ If the current node is a boolean, returns its value, returns False
+ otherwise.
+ """
+ return pn_data_get_bool(self._data)
+
+ def get_ubyte(self):
+ """
+ If the current node is an unsigned byte, returns its value,
+ returns 0 otherwise.
+ """
+ return pn_data_get_ubyte(self._data)
+
+ def get_byte(self):
+ """
+ If the current node is a signed byte, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_byte(self._data)
+
+ def get_ushort(self):
+ """
+ If the current node is an unsigned short, returns its value,
+ returns 0 otherwise.
+ """
+ return pn_data_get_ushort(self._data)
+
+ def get_short(self):
+ """
+ If the current node is a signed short, returns its value, returns
+ 0 otherwise.
+ """
+ return pn_data_get_short(self._data)
+
+ def get_uint(self):
+ """
+ If the current node is an unsigned int, returns its value, returns
+ 0 otherwise.
+ """
+ return pn_data_get_uint(self._data)
+
+ def get_int(self):
+ """
+ If the current node is a signed int, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_int(self._data)
+
+ def get_char(self):
+ """
+ If the current node is a char, returns its value, returns 0
+ otherwise.
+ """
+ return char(unichr(pn_data_get_char(self._data)))
+
+ def get_ulong(self):
+ """
+ If the current node is an unsigned long, returns its value,
+ returns 0 otherwise.
+ """
+ return ulong(pn_data_get_ulong(self._data))
+
+ def get_long(self):
+ """
+ If the current node is an signed long, returns its value, returns
+ 0 otherwise.
+ """
+ return pn_data_get_long(self._data)
+
+ def get_timestamp(self):
+ """
+ If the current node is a timestamp, returns its value, returns 0
+ otherwise.
+ """
+ return timestamp(pn_data_get_timestamp(self._data))
+
+ def get_float(self):
+ """
+ If the current node is a float, returns its value, raises 0
+ otherwise.
+ """
+ return pn_data_get_float(self._data)
+
+ def get_double(self):
+ """
+ If the current node is a double, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_double(self._data)
+
+ # XXX: need to convert
+ def get_decimal32(self):
+ """
+ If the current node is a decimal32, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_decimal32(self._data)
+
+ # XXX: need to convert
+ def get_decimal64(self):
+ """
+ If the current node is a decimal64, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_decimal64(self._data)
+
+ # XXX: need to convert
+ def get_decimal128(self):
+ """
+ If the current node is a decimal128, returns its value, returns 0
+ otherwise.
+ """
+ return pn_data_get_decimal128(self._data)
+
+ def get_uuid(self):
+ """
+ If the current node is a UUID, returns its value, returns None
+ otherwise.
+ """
+ if pn_data_type(self._data) == Data.UUID:
+ return uuid.UUID(bytes=pn_data_get_uuid(self._data))
+ else:
+ return None
+
+ def get_binary(self):
+ """
+ If the current node is binary, returns its value, returns ""
+ otherwise.
+ """
+ return pn_data_get_binary(self._data)
+
+ def get_string(self):
+ """
+ If the current node is a string, returns its value, returns ""
+ otherwise.
+ """
+ return pn_data_get_string(self._data).decode("utf8")
+
+ def get_symbol(self):
+ """
+ If the current node is a symbol, returns its value, returns ""
+ otherwise.
+ """
+ return symbol(pn_data_get_symbol(self._data))
+
+ def copy(self, src):
+ self._check(pn_data_copy(self._data, src._data))
+
+ def format(self):
+ sz = 16
+ while True:
+ err, result = pn_data_format(self._data, sz)
+ if err == PN_OVERFLOW:
+ sz *= 2
+ continue
+ else:
+ self._check(err)
+ return result
+
+ def dump(self):
+ pn_data_dump(self._data)
+
+ def put_dict(self, d):
+ self.put_map()
+ self.enter()
+ try:
+ for k, v in d.items():
+ self.put_object(k)
+ self.put_object(v)
+ finally:
+ self.exit()
+
+ def get_dict(self):
+ if self.enter():
+ try:
+ result = {}
+ while self.next():
+ k = self.get_object()
+ if self.next():
+ v = self.get_object()
+ else:
+ v = None
+ result[k] = v
+ finally:
+ self.exit()
+ return result
+
+ def put_sequence(self, s):
+ self.put_list()
+ self.enter()
+ try:
+ for o in s:
+ self.put_object(o)
+ finally:
+ self.exit()
+
+ def get_sequence(self):
+ if self.enter():
+ try:
+ result = []
+ while self.next():
+ result.append(self.get_object())
+ finally:
+ self.exit()
+ return result
+
+ def get_py_described(self):
+ if self.enter():
+ try:
+ self.next()
+ descriptor = self.get_object()
+ self.next()
+ value = self.get_object()
+ finally:
+ self.exit()
+ return Described(descriptor, value)
+
+ def put_py_described(self, d):
+ self.put_described()
+ self.enter()
+ try:
+ self.put_object(d.descriptor)
+ self.put_object(d.value)
+ finally:
+ self.exit()
+
+ def get_py_array(self):
+ """
+ If the current node is an array, return an Array object
+ representing the array and its contents. Otherwise return None.
+ This is a convenience wrapper around get_array, enter, etc.
+ """
+
+ count, described, type = self.get_array()
+ if type is None: return None
+ if self.enter():
+ try:
+ if described:
+ self.next()
+ descriptor = self.get_object()
+ else:
+ descriptor = UNDESCRIBED
+ elements = []
+ while self.next():
+ elements.append(self.get_object())
+ finally:
+ self.exit()
+ return Array(descriptor, type, *elements)
+
+ def put_py_array(self, a):
+ described = a.descriptor != UNDESCRIBED
+ self.put_array(described, a.type)
+ self.enter()
+ try:
+ if described:
+ self.put_object(a.descriptor)
+ for e in a.elements:
+ self.put_object(e)
+ finally:
+ self.exit()
+
+ put_mappings = {
+ None.__class__: lambda s, _: s.put_null(),
+ bool: put_bool,
+ dict: put_dict,
+ list: put_sequence,
+ tuple: put_sequence,
+ unicode: put_string,
+ bytes: put_binary,
+ symbol: put_symbol,
+ int: put_long,
+ char: put_char,
+ long: put_long,
+ ulong: put_ulong,
+ timestamp: put_timestamp,
+ float: put_double,
+ uuid.UUID: put_uuid,
+ Described: put_py_described,
+ Array: put_py_array
+ }
+ get_mappings = {
+ NULL: lambda s: None,
+ BOOL: get_bool,
+ BYTE: get_byte,
+ UBYTE: get_ubyte,
+ SHORT: get_short,
+ USHORT: get_ushort,
+ INT: get_int,
+ UINT: get_uint,
+ CHAR: get_char,
+ LONG: get_long,
+ ULONG: get_ulong,
+ TIMESTAMP: get_timestamp,
+ FLOAT: get_float,
+ DOUBLE: get_double,
+ DECIMAL32: get_decimal32,
+ DECIMAL64: get_decimal64,
+ DECIMAL128: get_decimal128,
+ UUID: get_uuid,
+ BINARY: get_binary,
+ STRING: get_string,
+ SYMBOL: get_symbol,
+ DESCRIBED: get_py_described,
+ ARRAY: get_py_array,
+ LIST: get_sequence,
+ MAP: get_dict
+ }
+
+
+ def put_object(self, obj):
+ putter = self.put_mappings[obj.__class__]
+ putter(self, obj)
+
+ def get_object(self):
+ type = self.type()
+ if type is None: return None
+ getter = self.get_mappings.get(type)
+ if getter:
+ return getter(self)
+ else:
+ return UnmappedType(str(type))
+
+class ConnectionException(ProtonException):
+ pass
+
+class Endpoint(object):
+
+ LOCAL_UNINIT = PN_LOCAL_UNINIT
+ REMOTE_UNINIT = PN_REMOTE_UNINIT
+ LOCAL_ACTIVE = PN_LOCAL_ACTIVE
+ REMOTE_ACTIVE = PN_REMOTE_ACTIVE
+ LOCAL_CLOSED = PN_LOCAL_CLOSED
+ REMOTE_CLOSED = PN_REMOTE_CLOSED
+
+ def __init__(self):
+ self.condition = None
+ self._release_invoked = False
+
+ def _release(self):
+ """Release the underlying C Engine resource."""
+ if not self._release_invoked:
+ for c in self._children:
+ c._release()
+ self._free_resource()
+ self.connection._releasing(self)
+ self._release_invoked = True
+
+ def _update_cond(self):
+ obj2cond(self.condition, self._get_cond_impl())
+
+ @property
+ def remote_condition(self):
+ return cond2obj(self._get_remote_cond_impl())
+
+ # the following must be provided by subclasses
+ def _get_cond_impl(self):
+ assert False, "Subclass must override this!"
+
+ def _get_remote_cond_impl(self):
+ assert False, "Subclass must override this!"
+
+class Condition:
+
+ def __init__(self, name, description=None, info=None):
+ self.name = name
+ self.description = description
+ self.info = info
+
+ def __repr__(self):
+ return "Condition(%s)" % ", ".join([repr(x) for x in
+ (self.name, self.description, self.info)
+ if x])
+
+ def __eq__(self, o):
+ if not isinstance(o, Condition): return False
+ return self.name == o.name and \
+ self.description == o.description and \
+ self.info == o.info
+
+def obj2cond(obj, cond):
+ pn_condition_clear(cond)
+ if obj:
+ pn_condition_set_name(cond, str(obj.name))
+ pn_condition_set_description(cond, obj.description)
+ info = Data(pn_condition_info(cond))
+ if obj.info:
+ info.put_object(obj.info)
+
+def cond2obj(cond):
+ if pn_condition_is_set(cond):
+ return Condition(pn_condition_get_name(cond),
+ pn_condition_get_description(cond),
+ dat2obj(pn_condition_info(cond)))
+ else:
+ return None
+
+def dat2obj(dimpl):
+ if dimpl:
+ d = Data(dimpl)
+ d.rewind()
+ d.next()
+ obj = d.get_object()
+ d.rewind()
+ return obj
+
+def obj2dat(obj, dimpl):
+ if obj is not None:
+ d = Data(dimpl)
+ d.put_object(obj)
+
+def secs2millis(secs):
+ return long(secs*1000)
+
+def millis2secs(millis):
+ return float(millis)/1000.0
+
+class Connection(Endpoint):
+
+ @staticmethod
+ def _wrap_connection(c_conn):
+ """Maintain only a single instance of this class for each Connection
+ object that exists in the the C Engine. This is done by storing a (weak)
+ reference to the python instance in the context field of the C object.
+ """
+ if not c_conn: return None
+ py_conn = pn_void2py(pn_connection_get_context(c_conn))
+ if py_conn: return py_conn
+ wrapper = Connection(_conn=c_conn)
+ return wrapper
+
+ def __init__(self, _conn=None):
+ Endpoint.__init__(self)
+ if _conn:
+ self._conn = _conn
+ else:
+ self._conn = pn_connection()
+ pn_connection_set_context(self._conn, pn_py2void(self))
+ self.offered_capabilities = None
+ self.desired_capabilities = None
+ self.properties = None
+ self._sessions = set()
+
+ def __del__(self):
+ if hasattr(self, "_conn") and self._conn:
+ self._release()
+
+ def free(self):
+ self._release()
+
+ @property
+ def _children(self):
+ return self._sessions
+
+ @property
+ def connection(self):
+ return self
+
+ def _free_resource(self):
+ pn_connection_free(self._conn)
+
+ def _released(self):
+ self._conn = None
+
+ def _releasing(self, child):
+ coll = getattr(self, "_collector", None)
+ if coll: coll = coll()
+ if coll:
+ coll._contexts.add(child)
+ else:
+ child._released()
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, ConnectionException)
+ raise exc("[%s]: %s" % (err, pn_connection_error(self._conn)))
+ else:
+ return err
+
+ def _get_cond_impl(self):
+ return pn_connection_condition(self._conn)
+
+ def _get_remote_cond_impl(self):
+ return pn_connection_remote_condition(self._conn)
+
+ def collect(self, collector):
+ if collector is None:
+ pn_connection_collect(self._conn, None)
+ else:
+ pn_connection_collect(self._conn, collector._impl)
+ self._collector = weakref.ref(collector)
+
+ def _get_container(self):
+ return pn_connection_get_container(self._conn)
+ def _set_container(self, name):
+ return pn_connection_set_container(self._conn, name)
+
+ container = property(_get_container, _set_container)
+
+ def _get_hostname(self):
+ return pn_connection_get_hostname(self._conn)
+ def _set_hostname(self, name):
+ return pn_connection_set_hostname(self._conn, name)
+
+ hostname = property(_get_hostname, _set_hostname)
+
+ @property
+ def remote_container(self):
+ return pn_connection_remote_container(self._conn)
+
+ @property
+ def remote_hostname(self):
+ return pn_connection_remote_hostname(self._conn)
+
+ @property
+ def remote_offered_capabilities(self):
+ return dat2obj(pn_connection_remote_offered_capabilities(self._conn))
+
+ @property
+ def remote_desired_capabilities(self):
+ return dat2obj(pn_connection_remote_desired_capabilities(self._conn))
+
+ @property
+ def remote_properties(self):
+ return dat2obj(pn_connection_remote_properties(self._conn))
+
+ def open(self):
+ obj2dat(self.offered_capabilities,
+ pn_connection_offered_capabilities(self._conn))
+ obj2dat(self.desired_capabilities,
+ pn_connection_desired_capabilities(self._conn))
+ obj2dat(self.properties, pn_connection_properties(self._conn))
+ pn_connection_open(self._conn)
+
+ def close(self):
+ self._update_cond()
+ pn_connection_close(self._conn)
+
+ @property
+ def state(self):
+ return pn_connection_state(self._conn)
+
+ def session(self):
+ return Session._wrap_session(pn_session(self._conn))
+
+ def session_head(self, mask):
+ return Session._wrap_session(pn_session_head(self._conn, mask))
+
+ def link_head(self, mask):
+ return Link._wrap_link(pn_link_head(self._conn, mask))
+
+ @property
+ def work_head(self):
+ return Delivery._wrap_delivery(pn_work_head(self._conn))
+
+ @property
+ def error(self):
+ return pn_error_code(pn_connection_error(self._conn))
+
+class SessionException(ProtonException):
+ pass
+
+class Session(Endpoint):
+
+ @staticmethod
+ def _wrap_session(c_ssn):
+ """Maintain only a single instance of this class for each Session object that
+ exists in the C Engine.
+ """
+ if c_ssn is None: return None
+ py_ssn = pn_void2py(pn_session_get_context(c_ssn))
+ if py_ssn: return py_ssn
+ wrapper = Session(c_ssn)
+ return wrapper
+
+ def __init__(self, ssn):
+ Endpoint.__init__(self)
+ self._ssn = ssn
+ pn_session_set_context(self._ssn, pn_py2void(self))
+ self._links = set()
+ self.connection._sessions.add(self)
+
+ @property
+ def _children(self):
+ return self._links
+
+ def _free_resource(self):
+ pn_session_free(self._ssn)
+
+ def _released(self):
+ self._ssn = None
+
+ def free(self):
+ """Release the Session, freeing its resources.
+
+ Call this when you no longer need the session. This will allow the
+ session's resources to be reclaimed. Once called, you should no longer
+ reference the session.
+
+ """
+ self.connection._sessions.remove(self)
+ self._release()
+
+ def _get_cond_impl(self):
+ return pn_session_condition(self._ssn)
+
+ def _get_remote_cond_impl(self):
+ return pn_session_remote_condition(self._ssn)
+
+ def _get_incoming_capacity(self):
+ return pn_session_get_incoming_capacity(self._ssn)
+
+ def _set_incoming_capacity(self, capacity):
+ pn_session_set_incoming_capacity(self._ssn, capacity)
+
+ incoming_capacity = property(_get_incoming_capacity, _set_incoming_capacity)
+
+ @property
+ def outgoing_bytes(self):
+ return pn_session_outgoing_bytes(self._ssn)
+
+ @property
+ def incoming_bytes(self):
+ return pn_session_incoming_bytes(self._ssn)
+
+ def open(self):
+ pn_session_open(self._ssn)
+
+ def close(self):
+ self._update_cond()
+ pn_session_close(self._ssn)
+
+ def next(self, mask):
+ return Session._wrap_session(pn_session_next(self._ssn, mask))
+
+ @property
+ def state(self):
+ return pn_session_state(self._ssn)
+
+ @property
+ def connection(self):
+ return Connection._wrap_connection(pn_session_connection(self._ssn))
+
+ def sender(self, name):
+ return Link._wrap_link(pn_sender(self._ssn, name))
+
+ def receiver(self, name):
+ return Link._wrap_link(pn_receiver(self._ssn, name))
+
+class LinkException(ProtonException):
+ pass
+
+class Link(Endpoint):
+
+ SND_UNSETTLED = PN_SND_UNSETTLED
+ SND_SETTLED = PN_SND_SETTLED
+ SND_MIXED = PN_SND_MIXED
+
+ RCV_FIRST = PN_RCV_FIRST
+ RCV_SECOND = PN_RCV_SECOND
+
+ @staticmethod
+ def _wrap_link(c_link):
+ """Maintain only a single instance of this class for each Session object that
+ exists in the C Engine.
+ """
+ if c_link is None: return None
+ py_link = pn_void2py(pn_link_get_context(c_link))
+ if py_link: return py_link
+ if pn_link_is_sender(c_link):
+ wrapper = Sender(c_link)
+ else:
+ wrapper = Receiver(c_link)
+ return wrapper
+
+ def __init__(self, c_link):
+ Endpoint.__init__(self)
+ self._link = c_link
+ pn_link_set_context(self._link, pn_py2void(self))
+ self._deliveries = set()
+ self.session._links.add(self)
+
+ @property
+ def _children(self):
+ return self._deliveries
+
+ def _free_resource(self):
+ pn_link_free(self._link)
+
+ def _released(self):
+ self._link = None
+
+ def free(self):
+ """Release the Link, freeing its resources"""
+ self.session._links.remove(self)
+ self._release()
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, LinkException)
+ raise exc("[%s]: %s" % (err, pn_link_error(self._link)))
+ else:
+ return err
+
+ def _get_cond_impl(self):
+ return pn_link_condition(self._link)
+
+ def _get_remote_cond_impl(self):
+ return pn_link_remote_condition(self._link)
+
+ def open(self):
+ pn_link_open(self._link)
+
+ def close(self):
+ self._update_cond()
+ pn_link_close(self._link)
+
+ @property
+ def state(self):
+ return pn_link_state(self._link)
+
+ @property
+ def source(self):
+ return Terminus(pn_link_source(self._link))
+
+ @property
+ def target(self):
+ return Terminus(pn_link_target(self._link))
+
+ @property
+ def remote_source(self):
+ return Terminus(pn_link_remote_source(self._link))
+ @property
+ def remote_target(self):
+ return Terminus(pn_link_remote_target(self._link))
+
+ @property
+ def session(self):
+ return Session._wrap_session(pn_link_session(self._link))
+
+ @property
+ def connection(self):
+ return self.session.connection
+
+ def delivery(self, tag):
+ return Delivery._wrap_delivery(pn_delivery(self._link, tag))
+
+ @property
+ def current(self):
+ return Delivery._wrap_delivery(pn_link_current(self._link))
+
+ def advance(self):
+ return pn_link_advance(self._link)
+
+ @property
+ def unsettled(self):
+ return pn_link_unsettled(self._link)
+
+ @property
+ def credit(self):
+ return pn_link_credit(self._link)
+
+ @property
+ def available(self):
+ return pn_link_available(self._link)
+
+ @property
+ def queued(self):
+ return pn_link_queued(self._link)
+
+ def next(self, mask):
+ return Link._wrap_link(pn_link_next(self._link, mask))
+
+ @property
+ def name(self):
+ return pn_link_name(self._link)
+
+ @property
+ def is_sender(self):
+ return pn_link_is_sender(self._link)
+
+ @property
+ def is_receiver(self):
+ return pn_link_is_receiver(self._link)
+
+ @property
+ def remote_snd_settle_mode(self):
+ return pn_link_remote_snd_settle_mode(self._link)
+
+ @property
+ def remote_rcv_settle_mode(self):
+ return pn_link_remote_rcv_settle_mode(self._link)
+
+ def _get_snd_settle_mode(self):
+ return pn_link_snd_settle_mode(self._link)
+ def _set_snd_settle_mode(self, mode):
+ pn_link_set_snd_settle_mode(self._link, mode)
+ snd_settle_mode = property(_get_snd_settle_mode, _set_snd_settle_mode)
+
+ def _get_rcv_settle_mode(self):
+ return pn_link_rcv_settle_mode(self._link)
+ def _set_rcv_settle_mode(self, mode):
+ pn_link_set_rcv_settle_mode(self._link, mode)
+ rcv_settle_mode = property(_get_rcv_settle_mode, _set_rcv_settle_mode)
+
+ def drained(self):
+ return pn_link_drained(self._link)
+
+ def detach(self):
+ return pn_link_detach(self._link)
+
+class Terminus(object):
+
+ UNSPECIFIED = PN_UNSPECIFIED
+ SOURCE = PN_SOURCE
+ TARGET = PN_TARGET
+ COORDINATOR = PN_COORDINATOR
+
+ NONDURABLE = PN_NONDURABLE
+ CONFIGURATION = PN_CONFIGURATION
+ DELIVERIES = PN_DELIVERIES
+
+ DIST_MODE_UNSPECIFIED = PN_DIST_MODE_UNSPECIFIED
+ DIST_MODE_COPY = PN_DIST_MODE_COPY
+ DIST_MODE_MOVE = PN_DIST_MODE_MOVE
+
+ def __init__(self, impl):
+ self._impl = impl
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, LinkException)
+ raise exc("[%s]" % err)
+ else:
+ return err
+
+ def _get_type(self):
+ return pn_terminus_get_type(self._impl)
+ def _set_type(self, type):
+ self._check(pn_terminus_set_type(self._impl, type))
+ type = property(_get_type, _set_type)
+
+ def _get_address(self):
+ return pn_terminus_get_address(self._impl)
+ def _set_address(self, address):
+ self._check(pn_terminus_set_address(self._impl, address))
+ address = property(_get_address, _set_address)
+
+ def _get_durability(self):
+ return pn_terminus_get_durability(self._impl)
+ def _set_durability(self, seconds):
+ self._check(pn_terminus_set_durability(self._impl, seconds))
+ durability = property(_get_durability, _set_durability)
+
+ def _get_expiry_policy(self):
+ return pn_terminus_get_expiry_policy(self._impl)
+ def _set_expiry_policy(self, seconds):
+ self._check(pn_terminus_set_expiry_policy(self._impl, seconds))
+ expiry_policy = property(_get_expiry_policy, _set_expiry_policy)
+
+ def _get_timeout(self):
+ return pn_terminus_get_timeout(self._impl)
+ def _set_timeout(self, seconds):
+ self._check(pn_terminus_set_timeout(self._impl, seconds))
+ timeout = property(_get_timeout, _set_timeout)
+
+ def _is_dynamic(self):
+ return pn_terminus_is_dynamic(self._impl)
+ def _set_dynamic(self, dynamic):
+ self._check(pn_terminus_set_dynamic(self._impl, dynamic))
+ dynamic = property(_is_dynamic, _set_dynamic)
+
+ def _get_distribution_mode(self):
+ return pn_terminus_get_distribution_mode(self._impl)
+ def _set_distribution_mode(self, mode):
+ self._check(pn_terminus_set_distribution_mode(self._impl, mode))
+ distribution_mode = property(_get_distribution_mode, _set_distribution_mode)
+
+ @property
+ def properties(self):
+ return Data(pn_terminus_properties(self._impl))
+
+ @property
+ def capabilities(self):
+ return Data(pn_terminus_capabilities(self._impl))
+
+ @property
+ def outcomes(self):
+ return Data(pn_terminus_outcomes(self._impl))
+
+ @property
+ def filter(self):
+ return Data(pn_terminus_filter(self._impl))
+
+ def copy(self, src):
+ self._check(pn_terminus_copy(self._impl, src._impl))
+
+class Sender(Link):
+
+ def __init__(self, c_link):
+ super(Sender, self).__init__(c_link)
+
+ def offered(self, n):
+ pn_link_offered(self._link, n)
+
+ def send(self, bytes):
+ return self._check(pn_link_send(self._link, bytes))
+
+class Receiver(Link):
+
+ def __init__(self, c_link):
+ super(Receiver, self).__init__(c_link)
+
+ def flow(self, n):
+ pn_link_flow(self._link, n)
+
+ def recv(self, limit):
+ n, bytes = pn_link_recv(self._link, limit)
+ if n == PN_EOS:
+ return None
+ else:
+ self._check(n)
+ return bytes
+
+ def drain(self, n):
+ pn_link_drain(self._link, n)
+
+ def draining(self):
+ return pn_link_draining(self._link)
+
+class NamedInt(int):
+
+ values = {}
+
+ def __new__(cls, i, name):
+ ni = super(NamedInt, cls).__new__(cls, i)
+ cls.values[i] = ni
+ return ni
+
+ def __init__(self, i, name):
+ self.name = name
+
+ def __repr__(self):
+ return self.name
+
+ def __str__(self):
+ return self.name
+
+ @classmethod
+ def get(cls, i):
+ return cls.values.get(i, i)
+
+class DispositionType(NamedInt):
+ values = {}
+
+class Disposition(object):
+
+ RECEIVED = DispositionType(PN_RECEIVED, "RECEIVED")
+ ACCEPTED = DispositionType(PN_ACCEPTED, "ACCEPTED")
+ REJECTED = DispositionType(PN_REJECTED, "REJECTED")
+ RELEASED = DispositionType(PN_RELEASED, "RELEASED")
+ MODIFIED = DispositionType(PN_MODIFIED, "MODIFIED")
+
+ def __init__(self, impl, local):
+ self._impl = impl
+ self.local = local
+ self._data = None
+ self._condition = None
+ self._annotations = None
+
+ @property
+ def type(self):
+ return DispositionType.get(pn_disposition_type(self._impl))
+
+ def _get_section_number(self):
+ return pn_disposition_get_section_number(self._impl)
+ def _set_section_number(self, n):
+ pn_disposition_set_section_number(self._impl, n)
+ section_number = property(_get_section_number, _set_section_number)
+
+ def _get_section_offset(self):
+ return pn_disposition_get_section_offset(self._impl)
+ def _set_section_offset(self, n):
+ pn_disposition_set_section_offset(self._impl, n)
+ section_offset = property(_get_section_offset, _set_section_offset)
+
+ def _get_failed(self):
+ return pn_disposition_is_failed(self._impl)
+ def _set_failed(self, b):
+ pn_disposition_set_failed(self._impl, b)
+ failed = property(_get_failed, _set_failed)
+
+ def _get_undeliverable(self):
+ return pn_disposition_is_undeliverable(self._impl)
+ def _set_undeliverable(self, b):
+ pn_disposition_set_undeliverable(self._impl, b)
+ undeliverable = property(_get_undeliverable, _set_undeliverable)
+
+ def _get_data(self):
+ if self.local:
+ return self._data
+ else:
+ return dat2obj(pn_disposition_data(self._impl))
+ def _set_data(self, obj):
+ if self.local:
+ self._data = obj
+ else:
+ raise AttributeError("data attribute is read-only")
+ data = property(_get_data, _set_data)
+
+ def _get_annotations(self):
+ if self.local:
+ return self._annotations
+ else:
+ return dat2obj(pn_disposition_annotations(self._impl))
+ def _set_annotations(self, obj):
+ if self.local:
+ self._annotations = obj
+ else:
+ raise AttributeError("annotations attribute is read-only")
+ annotations = property(_get_annotations, _set_annotations)
+
+ def _get_condition(self):
+ if self.local:
+ return self._condition
+ else:
+ return cond2obj(pn_disposition_condition(self._impl))
+ def _set_condition(self, obj):
+ if self.local:
+ self._condition = obj
+ else:
+ raise AttributeError("condition attribute is read-only")
+ condition = property(_get_condition, _set_condition)
+
+class Delivery(object):
+
+ RECEIVED = Disposition.RECEIVED
+ ACCEPTED = Disposition.ACCEPTED
+ REJECTED = Disposition.REJECTED
+ RELEASED = Disposition.RELEASED
+ MODIFIED = Disposition.MODIFIED
+
+ @staticmethod
+ def _wrap_delivery(c_dlv):
+ """Maintain only a single instance of this class for each Delivery object that
+ exists in the C Engine.
+ """
+ if not c_dlv: return None
+ py_dlv = pn_void2py(pn_delivery_get_context(c_dlv))
+ if py_dlv: return py_dlv
+ wrapper = Delivery(c_dlv)
+ return wrapper
+
+ def __init__(self, dlv):
+ self._dlv = dlv
+ pn_delivery_set_context(self._dlv, pn_py2void(self))
+ self.local = Disposition(pn_delivery_local(self._dlv), True)
+ self.remote = Disposition(pn_delivery_remote(self._dlv), False)
+ self.link._deliveries.add(self)
+
+ def __del__(self):
+ self._release()
+
+ def _release(self):
+ """Release the underlying C Engine resource."""
+ if self._dlv:
+ pn_delivery_set_context(self._dlv, pn_py2void(None))
+ pn_delivery_settle(self._dlv)
+ self._dlv = None
+
+ @property
+ def released(self):
+ return self._dlv is None
+
+ @property
+ def tag(self):
+ return pn_delivery_tag(self._dlv)
+
+ @property
+ def writable(self):
+ return pn_delivery_writable(self._dlv)
+
+ @property
+ def readable(self):
+ return pn_delivery_readable(self._dlv)
+
+ @property
+ def updated(self):
+ return pn_delivery_updated(self._dlv)
+
+ def update(self, state):
+ obj2dat(self.local._data, pn_disposition_data(self.local._impl))
+ obj2dat(self.local._annotations, pn_disposition_annotations(self.local._impl))
+ obj2cond(self.local._condition, pn_disposition_condition(self.local._impl))
+ pn_delivery_update(self._dlv, state)
+
+ @property
+ def pending(self):
+ return pn_delivery_pending(self._dlv)
+
+ @property
+ def partial(self):
+ return pn_delivery_partial(self._dlv)
+
+ @property
+ def local_state(self):
+ return DispositionType.get(pn_delivery_local_state(self._dlv))
+
+ @property
+ def remote_state(self):
+ return DispositionType.get(pn_delivery_remote_state(self._dlv))
+
+ @property
+ def settled(self):
+ return pn_delivery_settled(self._dlv)
+
+ def settle(self):
+ """Release the delivery"""
+ self.link._deliveries.remove(self)
+ self._release()
+
+ @property
+ def work_next(self):
+ return Delivery._wrap_delivery(pn_work_next(self._dlv))
+
+ @property
+ def link(self):
+ return Link._wrap_link(pn_delivery_link(self._dlv))
+
+class TransportException(ProtonException):
+ pass
+
+class Transport(object):
+
+ TRACE_OFF = PN_TRACE_OFF
+ TRACE_DRV = PN_TRACE_DRV
+ TRACE_FRM = PN_TRACE_FRM
+ TRACE_RAW = PN_TRACE_RAW
+
+ CLIENT = 1
+ SERVER = 2
+
+ @staticmethod
+ def _wrap_transport(c_trans):
+ if not c_trans: return None
+ wrapper = Transport(_trans=c_trans)
+ return wrapper
+
+ def __init__(self, mode=None, _trans=None):
+ if not mode and not _trans:
+ self._trans = pn_transport()
+ elif not mode:
+ self._shared_trans = True
+ self._trans = _trans
+ elif mode==Transport.CLIENT:
+ self._trans = pn_transport()
+ elif mode==Transport.SERVER:
+ self._trans = pn_transport()
+ pn_transport_set_server(self._trans)
+ else:
+ raise TransportException("Cannot initialise Transport from mode: %s" % str(mode))
+ self._sasl = None
+ self._ssl = None
+
+ def __del__(self):
+ if hasattr(self, "_trans"):
+ if not hasattr(self, "_shared_trans"):
+ pn_transport_free(self._trans)
+ if hasattr(self, "_sasl") and self._sasl:
+ # pn_transport_free deallocs the C sasl associated with the
+ # transport, so erase the reference if a SASL object was used.
+ self._sasl._sasl = None
+ self._sasl = None
+ if hasattr(self, "_ssl") and self._ssl:
+ # ditto the owned c SSL object
+ self._ssl._ssl = None
+ self._ssl = None
+ del self._trans
+
+ def _check(self, err):
+ if err < 0:
+ exc = EXCEPTIONS.get(err, TransportException)
+ raise exc("[%s]: %s" % (err, pn_error_text(pn_transport_error(self._trans))))
+ else:
+ return err
+
+ def bind(self, connection):
+ """Assign a connection to the transport"""
+ self._check(pn_transport_bind(self._trans, connection._conn))
+ # keep python connection from being garbage collected:
+ self._connection = connection
+
+ def unbind(self):
+ """Release the connection"""
+ self._check(pn_transport_unbind(self._trans))
+ self._connection = None
+
+ def trace(self, n):
+ pn_transport_trace(self._trans, n)
+
+ def tick(self, now):
+ """Process any timed events (like heartbeat generation).
+ now = seconds since epoch (float).
+ """
+ return millis2secs(pn_transport_tick(self._trans, secs2millis(now)))
+
+ def capacity(self):
+ c = pn_transport_capacity(self._trans)
+ if c >= PN_EOS:
+ return c
+ else:
+ return self._check(c)
+
+ def push(self, bytes):
+ n = self._check(pn_transport_push(self._trans, bytes))
+ if n != len(bytes):
+ raise OverflowError("unable to process all bytes")
+
+ def close_tail(self):
+ self._check(pn_transport_close_tail(self._trans))
+
+ def pending(self):
+ p = pn_transport_pending(self._trans)
+ if p >= PN_EOS:
+ return p
+ else:
+ return self._check(p)
+
+ def peek(self, size):
+ cd, out = pn_transport_peek(self._trans, size)
+ if cd == PN_EOS:
+ return None
+ else:
+ self._check(cd)
+ return out
+
+ def pop(self, size):
+ pn_transport_pop(self._trans, size)
+
+ def close_head(self):
+ self._check(pn_transport_close_head(self._trans))
+
+ @property
+ def closed(self):
+ return pn_transport_closed(self._trans)
+
+ # AMQP 1.0 max-frame-size
+ def _get_max_frame_size(self):
+ return pn_transport_get_max_frame(self._tra
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[10/35] qpid-proton git commit: PROTON-747: Around wrappers for Ruby
Messenger methods that raise errors
Posted by gs...@apache.org.
PROTON-747: Around wrappers for Ruby Messenger methods that raise errors
Each method that could potentially raise an exception in
Qpid::Proton::Message is now wrapped by a method which checks for, and
then raises, the appropriate runtime error based on the error code.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/66150aa7
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/66150aa7
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/66150aa7
Branch: refs/heads/examples
Commit: 66150aa7a845c2210ab7c1b0c0e011988a60de2e
Parents: 0d1b8a8
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Fri Nov 14 09:45:17 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Tue Nov 18 09:34:43 2014 -0500
----------------------------------------------------------------------
.../ruby/lib/qpid_proton/exception_handling.rb | 43 +++++++++++++++++
.../bindings/ruby/lib/qpid_proton/messenger.rb | 50 ++++++++++++++------
2 files changed, 79 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66150aa7/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb b/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
index f8ac8c6..4dce3ef 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
@@ -25,6 +25,49 @@ module Qpid
#
module ExceptionHandling
+ def self.included(base)
+ base.extend(self)
+
+ unless defined? base.to_be_wrapped
+ class << base
+ @@to_be_wrapped = []
+ end
+ end
+
+ define_method :method_added do |name|
+ if (!@@to_be_wrapped.nil?) && (@@to_be_wrapped.include? name)
+ @@to_be_wrapped.delete name
+ create_exception_handler_wrapper(name)
+ end
+ end
+ end
+
+ def can_raise_exception(method_names)
+ # coerce the names to be an array
+ Array(method_names).each do |method_name|
+ # if the method doesn't already exist then queue this aliasing
+ unless self.method_defined? method_name
+ @@to_be_wrapped ||= []
+ @@to_be_wrapped << method_name
+ else
+ create_exception_handler_wrapper(method_name)
+ end
+ end
+ end
+
+ def create_exception_handler_wrapper(method_name)
+ original_method_name = method_name.to_s
+ wrapped_method_name = "_excwrap_#{original_method_name}"
+ alias_method wrapped_method_name, original_method_name
+ define_method original_method_name do |*args, &block|
+ # need to get a reference to the method object itself since
+ # calls to Class.send interfere with Messenger.send
+ method = self.method(wrapped_method_name.to_sym)
+ rc = method.call(*args, &block)
+ check_for_error(rc)
+ end
+ end
+
# Raises an Proton-specific error if a return code is non-zero.
#
# Expects the class to provide an +error+ method.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/66150aa7/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index 044a3ad..66a2f93 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -59,6 +59,11 @@ module Qpid
include Qpid::Proton::ExceptionHandling
+ can_raise_exception [:send, :receive, :password=, :start, :stop,
+ :perform_put, :perform_get, :interrupt,
+ :route, :rewrite, :accept, :reject,
+ :incoming_window=, :outgoing_window=]
+
# Creates a new +Messenger+.
#
# The +name+ parameter is optional. If one is not provided then
@@ -94,7 +99,7 @@ module Qpid
# * password - the password
#
def password=(password)
- check_for_error(Cproton.pn_messenger_set_password(@impl, password))
+ Cproton.pn_messenger_set_password(@impl, password)
end
# Returns the password property for the Messenger.private_key file.
@@ -193,14 +198,14 @@ module Qpid
# before starting the +Messenger+.
#
def start
- check_for_error(Cproton.pn_messenger_start(@impl))
+ Cproton.pn_messenger_start(@impl)
end
# Stops the +Messenger+, preventing it from sending or receiving
# any more messages.
#
def stop
- check_for_error(Cproton.pn_messenger_stop(@impl))
+ Cproton.pn_messenger_stop(@impl)
end
# Returns true iff a Messenger is in the stopped state.
@@ -313,10 +318,19 @@ module Qpid
raise ArgumentError.new("invalid message type: #{message.class}") unless message.kind_of?(Message)
# encode the message first
message.pre_encode
- check_for_error(Cproton.pn_messenger_put(@impl, message.impl))
+ perform_put(message)
return outgoing_tracker
end
+ private
+
+ def perform_put(message) # :nodoc:
+ Cproton.pn_messenger_put(@impl, message.impl)
+ end
+
+ public
+
+
# This call will block until the indicated number of messages
# have been sent, or until the operation times out.
# If n is -1 this call will block until all outgoing messages
@@ -324,7 +338,7 @@ module Qpid
# it can without blocking.
#
def send(n = -1)
- check_for_error(Cproton.pn_messenger_send(@impl, n))
+ Cproton.pn_messenger_send(@impl, n)
end
# Moves the message from the head of the incoming message queue into
@@ -348,11 +362,19 @@ module Qpid
else
msg_impl = msg.impl
end
- check_for_error(Cproton.pn_messenger_get(@impl, msg_impl))
+ perform_get(msg_impl)
msg.post_decode unless msg.nil?
return incoming_tracker
end
+ private
+
+ def perform_get(msg) # :nodoc:
+ Cproton.pn_messenger_get(@impl, msg)
+ end
+
+ public
+
# Receives up to limit messages into the incoming queue. If no value
# for limit is supplied, this call will receive as many messages as it
# can buffer internally. If the Messenger is in blocking mode, this
@@ -364,7 +386,7 @@ module Qpid
# * limit - the maximum number of messages to receive
#
def receive(limit = -1)
- check_for_error(Cproton.pn_messenger_recv(@impl, limit))
+ Cproton.pn_messenger_recv(@impl, limit)
end
def receiving
@@ -384,7 +406,7 @@ module Qpid
# originated the interrupt.
#
def interrupt
- check_for_error(Cproton.pn_messenger_interrupt(@impl))
+ Cproton.pn_messenger_interrupt(@impl)
end
# Sends or receives any outstanding messages queued for a Messenger.
@@ -472,7 +494,7 @@ module Qpid
# messenger.route("*", "amqp://user:password@broker/$1")
#
def route(pattern, address)
- check_for_error(Cproton.pn_messenger_route(@impl, pattern, address))
+ Cproton.pn_messenger_route(@impl, pattern, address)
end
# Similar to #route, except that the destination of
@@ -494,7 +516,7 @@ module Qpid
# * address - the target address
#
def rewrite(pattern, address)
- check_for_error(Cproton.pn_messenger_rewrite(@impl, pattern, address))
+ Cproton.pn_messenger_rewrite(@impl, pattern, address)
end
def selectable
@@ -548,7 +570,7 @@ module Qpid
else
flag = 0
end
- check_for_error(Cproton.pn_messenger_accept(@impl, tracker.impl, flag))
+ Cproton.pn_messenger_accept(@impl, tracker.impl, flag)
end
# Rejects the incoming message identified by the tracker.
@@ -568,7 +590,7 @@ module Qpid
else
flag = 0
end
- check_for_error(Cproton.pn_messenger_reject(@impl, tracker.impl, flag))
+ Cproton.pn_messenger_reject(@impl, tracker.impl, flag)
end
# Gets the last known remote state of the delivery associated with
@@ -624,7 +646,7 @@ module Qpid
#
def incoming_window=(window)
raise TypeError.new("invalid window: #{window}") unless valid_window?(window)
- check_for_error(Cproton.pn_messenger_set_incoming_window(@impl, window))
+ Cproton.pn_messenger_set_incoming_window(@impl, window)
end
# Returns the incoming window.
@@ -648,7 +670,7 @@ module Qpid
#
def outgoing_window=(window)
raise TypeError.new("invalid window: #{window}") unless valid_window?(window)
- check_for_error(Cproton.pn_messenger_set_outgoing_window(@impl, window))
+ Cproton.pn_messenger_set_outgoing_window(@impl, window)
end
# Returns the outgoing window.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[04/35] qpid-proton git commit: PROTON-749: Refactoring of io layers:
- Eliminate some unnecessary stuff. - Make pn_io_layer_t a pure interface. -
Simplify amqp header code; remove header_count member from pn_transport_t
Posted by gs...@apache.org.
PROTON-749: Refactoring of io layers:
- Eliminate some unnecessary stuff.
- Make pn_io_layer_t a pure interface.
- Simplify amqp header code; remove header_count member from pn_transport_t
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/c814d5c3
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/c814d5c3
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/c814d5c3
Branch: refs/heads/examples
Commit: c814d5c39147afa642e95e1b1ad51650b04d9739
Parents: 2794da5
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed Aug 6 17:57:56 2014 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 17 14:55:03 2014 -0500
----------------------------------------------------------------------
proton-c/src/engine/engine-internal.h | 20 ++-
proton-c/src/sasl/sasl.c | 128 +++++++++++-------
proton-c/src/ssl/openssl.c | 143 +++++++++++---------
proton-c/src/transport/transport.c | 204 ++++++++++++++---------------
proton-c/src/windows/schannel.c | 155 ++++++++++++----------
5 files changed, 354 insertions(+), 296 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c814d5c3/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index dd4c44e..86f5161 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -100,18 +100,16 @@ typedef struct {
#include <proton/ssl.h>
typedef struct pn_io_layer_t {
- void *context;
- struct pn_io_layer_t *next;
- ssize_t (*process_input)(struct pn_io_layer_t *io_layer, const char *, size_t);
- ssize_t (*process_output)(struct pn_io_layer_t *io_layer, char *, size_t);
- pn_timestamp_t (*process_tick)(struct pn_io_layer_t *io_layer, pn_timestamp_t);
- size_t (*buffered_output)(struct pn_io_layer_t *); // how much output is held
- size_t (*buffered_input)(struct pn_io_layer_t *); // how much input is held
+ ssize_t (*process_input)(struct pn_transport_t *transport, unsigned int layer, const char *, size_t);
+ ssize_t (*process_output)(struct pn_transport_t *transport, unsigned int layer, char *, size_t);
+ pn_timestamp_t (*process_tick)(struct pn_transport_t *transport, unsigned int layer, pn_timestamp_t);
+ size_t (*buffered_output)(struct pn_transport_t *); // how much output is held
} pn_io_layer_t;
+extern const pn_io_layer_t pni_passthru_layer;
+
struct pn_transport_t {
pn_tracer_t tracer;
- size_t header_count;
pn_sasl_t *sasl;
pn_ssl_t *ssl;
pn_connection_t *connection; // reference counted
@@ -134,7 +132,7 @@ struct pn_transport_t {
#define PN_IO_SASL 1
#define PN_IO_AMQP 2
#define PN_IO_LAYER_CT (PN_IO_AMQP+1)
- pn_io_layer_t io_layers[PN_IO_LAYER_CT];
+ const pn_io_layer_t *io_layers[PN_IO_LAYER_CT];
/* dead remote detection */
pn_millis_t local_idle_timeout;
@@ -302,9 +300,7 @@ void pn_link_dump(pn_link_t *link);
void pn_dump(pn_connection_t *conn);
void pn_transport_sasl_init(pn_transport_t *transport);
-ssize_t pn_io_layer_input_passthru(pn_io_layer_t *, const char *, size_t );
-ssize_t pn_io_layer_output_passthru(pn_io_layer_t *, char *, size_t );
-pn_timestamp_t pn_io_layer_tick_passthru(pn_io_layer_t *, pn_timestamp_t);
+pn_timestamp_t pn_io_layer_tick_passthru(pn_transport_t *, unsigned int, pn_timestamp_t);
void pn_condition_init(pn_condition_t *condition);
void pn_condition_tini(pn_condition_t *condition);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c814d5c3/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index a82ec02..97bead4 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -36,7 +36,6 @@
struct pn_sasl_t {
pn_transport_t *transport;
- pn_io_layer_t *io_layer;
pn_dispatcher_t *disp;
char *mechanisms;
char *remote_mechanisms;
@@ -50,12 +49,42 @@ struct pn_sasl_t {
bool rcvd_init;
bool sent_done;
bool rcvd_done;
+ bool input_bypass;
+ bool output_bypass;
};
-static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *bytes, size_t available);
-static ssize_t pn_input_read_sasl(pn_io_layer_t *io_layer, const char *bytes, size_t available);
-static ssize_t pn_output_write_sasl_header(pn_io_layer_t *io_layer, char *bytes, size_t available);
-static ssize_t pn_output_write_sasl(pn_io_layer_t *io_layer, char *bytes, size_t available);
+static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available);
+static ssize_t pn_input_read_sasl(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_output_write_sasl_header(pn_transport_t* transport, unsigned int layer, char* bytes, size_t size);
+static ssize_t pn_output_write_sasl(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+
+const pn_io_layer_t sasl_headers_layer = {
+ pn_input_read_sasl_header,
+ pn_output_write_sasl_header,
+ pn_io_layer_tick_passthru,
+ NULL
+};
+
+const pn_io_layer_t sasl_write_header_layer = {
+ pn_input_read_sasl,
+ pn_output_write_sasl_header,
+ pn_io_layer_tick_passthru,
+ NULL
+};
+
+const pn_io_layer_t sasl_read_header_layer = {
+ pn_input_read_sasl_header,
+ pn_output_write_sasl,
+ pn_io_layer_tick_passthru,
+ NULL
+};
+
+const pn_io_layer_t sasl_layer = {
+ pn_input_read_sasl,
+ pn_output_write_sasl,
+ pn_io_layer_tick_passthru,
+ NULL
+};
pn_sasl_t *pn_sasl(pn_transport_t *transport)
{
@@ -76,14 +105,12 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
sasl->rcvd_init = false;
sasl->sent_done = false;
sasl->rcvd_done = false;
+ sasl->input_bypass = false;
+ sasl->output_bypass = false;
transport->sasl = sasl;
sasl->transport = transport;
- sasl->io_layer = &transport->io_layers[PN_IO_SASL];
- sasl->io_layer->context = sasl;
- sasl->io_layer->process_input = pn_input_read_sasl_header;
- sasl->io_layer->process_output = pn_output_write_sasl_header;
- sasl->io_layer->process_tick = pn_io_layer_tick_passthru;
+ transport->io_layers[PN_IO_SASL] = &sasl_headers_layer;
}
return transport->sasl;
@@ -404,9 +431,9 @@ int pn_do_outcome(pn_dispatcher_t *disp)
#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
#define SASL_HEADER_LEN 8
-static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *bytes, size_t available)
+static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
+ pn_sasl_t *sasl = transport->sasl;
if (available > 0) {
if (available < SASL_HEADER_LEN) {
if (memcmp(bytes, SASL_HEADER, available) == 0 ||
@@ -414,20 +441,22 @@ static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *by
return 0;
} else {
if (memcmp(bytes, SASL_HEADER, SASL_HEADER_LEN) == 0) {
- sasl->io_layer->process_input = pn_input_read_sasl;
+ if (transport->io_layers[layer] == &sasl_read_header_layer) {
+ transport->io_layers[layer] = &sasl_layer;
+ } else {
+ transport->io_layers[layer] = &sasl_write_header_layer;
+ }
if (sasl->disp->trace & PN_TRACE_FRM)
- pn_transport_logf(sasl->transport, " <- %s", "SASL");
+ pn_transport_logf(transport, " <- %s", "SASL");
return SASL_HEADER_LEN;
}
if (memcmp(bytes, AMQP_HEADER, SASL_HEADER_LEN) == 0) {
if (sasl->allow_skip) {
sasl->outcome = PN_SASL_SKIPPED;
- sasl->io_layer->process_input = pn_io_layer_input_passthru;
- sasl->io_layer->process_output = pn_io_layer_output_passthru;
- pn_io_layer_t *io_next = sasl->io_layer->next;
- return io_next->process_input( io_next, bytes, available );
+ transport->io_layers[layer] = &pni_passthru_layer;
+ return pni_passthru_layer.process_input(transport, layer, bytes, available);
} else {
- pn_do_error(sasl->transport, "amqp:connection:policy-error",
+ pn_do_error(transport, "amqp:connection:policy-error",
"Client skipped SASL exchange - forbidden");
return PN_EOS;
}
@@ -436,50 +465,57 @@ static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *by
}
char quoted[1024];
pn_quote_data(quoted, 1024, bytes, available);
- pn_do_error(sasl->transport, "amqp:connection:framing-error",
+ pn_do_error(transport, "amqp:connection:framing-error",
"%s header mismatch: '%s'", "SASL", quoted);
return PN_EOS;
}
-static ssize_t pn_input_read_sasl(pn_io_layer_t *io_layer, const char *bytes, size_t available)
+static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
- ssize_t n = pn_sasl_input(sasl, bytes, available);
- if (n == PN_EOS) {
- sasl->io_layer->process_input = pn_io_layer_input_passthru;
- pn_io_layer_t *io_next = sasl->io_layer->next;
- return io_next->process_input( io_next, bytes, available );
+ pn_sasl_t *sasl = transport->sasl;
+ if (!sasl->input_bypass) {
+ ssize_t n = pn_sasl_input(sasl, bytes, available);
+ if (n != PN_EOS) return n;
+
+ sasl->input_bypass = true;
+ if (sasl->output_bypass)
+ transport->io_layers[layer] = &pni_passthru_layer;
}
- return n;
+ return pni_passthru_layer.process_input(transport, layer, bytes, available );
}
-static ssize_t pn_output_write_sasl_header(pn_io_layer_t *io_layer, char *bytes, size_t size)
+static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t size)
{
- pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
+ pn_sasl_t *sasl = transport->sasl;
if (sasl->disp->trace & PN_TRACE_FRM)
- pn_transport_logf(sasl->transport, " -> %s", "SASL");
+ pn_transport_logf(transport, " -> %s", "SASL");
assert(size >= SASL_HEADER_LEN);
memmove(bytes, SASL_HEADER, SASL_HEADER_LEN);
- sasl->io_layer->process_output = pn_output_write_sasl;
+ if (transport->io_layers[layer]==&sasl_write_header_layer) {
+ transport->io_layers[layer] = &sasl_layer;
+ } else {
+ transport->io_layers[layer] = &sasl_read_header_layer;
+ }
return SASL_HEADER_LEN;
}
-static ssize_t pn_output_write_sasl(pn_io_layer_t *io_layer, char *bytes, size_t size)
+static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available)
{
- pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
- // this accounts for when pn_do_error is invoked, e.g. by idle timeout
- ssize_t n;
- if (sasl->transport->close_sent) {
- n = PN_EOS;
- } else {
- n = pn_sasl_output(sasl, bytes, size);
- }
+ pn_sasl_t *sasl = transport->sasl;
+ if (!sasl->output_bypass) {
+ // this accounts for when pn_do_error is invoked, e.g. by idle timeout
+ ssize_t n;
+ if (transport->close_sent) {
+ n = PN_EOS;
+ } else {
+ n = pn_sasl_output(sasl, bytes, available);
+ }
+ if (n != PN_EOS) return n;
- if (n == PN_EOS) {
- sasl->io_layer->process_output = pn_io_layer_output_passthru;
- pn_io_layer_t *io_next = sasl->io_layer->next;
- return io_next->process_output( io_next, bytes, size );
+ sasl->output_bypass = true;
+ if (sasl->input_bypass)
+ transport->io_layers[layer] = &pni_passthru_layer;
}
- return n;
+ return pni_passthru_layer.process_output(transport, layer, bytes, available );
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c814d5c3/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index dd1b88b..a763cfb 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -87,9 +87,7 @@ struct pn_ssl_domain_t {
struct pn_ssl_t {
-
pn_transport_t *transport;
- pn_io_layer_t *io_layer;
pn_ssl_domain_t *domain;
const char *session_id;
const char *peer_hostname;
@@ -134,19 +132,18 @@ struct pn_ssl_session_t {
/* */
static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata);
-static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t len);
-static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *input_data, size_t len);
-static ssize_t process_input_unknown( pn_io_layer_t *io_layer, const char *input_data, size_t len);
-static ssize_t process_output_unknown( pn_io_layer_t *io_layer, char *input_data, size_t len);
-static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len);
-static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len);
+static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static ssize_t process_input_unknown( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_unknown( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
static int init_ssl_socket( pn_ssl_t * );
static void release_ssl_socket( pn_ssl_t * );
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
static void ssl_session_free( pn_ssl_session_t *);
-static size_t buffered_output( pn_io_layer_t *io_layer );
-static size_t buffered_input( pn_io_layer_t *io_layer );
+static size_t buffered_output( pn_transport_t *transport );
// @todo: used to avoid littering the code with calls to printf...
static void _log_error(pn_ssl_t *ssl, const char *fmt, ...)
@@ -670,6 +667,40 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
return 0;
}
+const pn_io_layer_t unknown_layer = {
+ process_input_unknown,
+ process_output_unknown,
+ pn_io_layer_tick_passthru,
+ NULL
+};
+
+const pn_io_layer_t ssl_layer = {
+ process_input_ssl,
+ process_output_ssl,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_input_closed_layer = {
+ process_input_done,
+ process_output_ssl,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_output_closed_layer = {
+ process_input_ssl,
+ process_output_done,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_closed_layer = {
+ process_input_done,
+ process_output_done,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
int pn_ssl_init( pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
{
@@ -678,13 +709,10 @@ int pn_ssl_init( pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
ssl->domain = domain;
domain->ref_count++;
if (domain->allow_unsecured) {
- ssl->io_layer->process_input = process_input_unknown;
- ssl->io_layer->process_output = process_output_unknown;
+ ssl->transport->io_layers[PN_IO_SSL] = &unknown_layer;
} else {
- ssl->io_layer->process_input = process_input_ssl;
- ssl->io_layer->process_output = process_output_ssl;
+ ssl->transport->io_layers[PN_IO_SSL] = &ssl_layer;
}
-
if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
ssl->session_id = pn_strdup(session_id);
@@ -773,13 +801,7 @@ pn_ssl_t *pn_ssl(pn_transport_t *transport)
ssl->transport = transport;
transport->ssl = ssl;
- ssl->io_layer = &transport->io_layers[PN_IO_SSL];
- ssl->io_layer->context = ssl;
- ssl->io_layer->process_input = pn_io_layer_input_passthru;
- ssl->io_layer->process_output = pn_io_layer_output_passthru;
- ssl->io_layer->process_tick = pn_io_layer_tick_passthru;
- ssl->io_layer->buffered_output = buffered_output;
- ssl->io_layer->buffered_input = buffered_input;
+ transport->io_layers[PN_IO_SSL] = &pni_passthru_layer;
ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
@@ -823,11 +845,9 @@ static int start_ssl_shutdown( pn_ssl_t *ssl )
-static int setup_ssl_connection( pn_ssl_t *ssl )
+static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
{
- _log( ssl, "SSL connection detected.");
- ssl->io_layer->process_input = process_input_ssl;
- ssl->io_layer->process_output = process_output_ssl;
+ transport->io_layers[layer] = &ssl_layer;
return 0;
}
@@ -836,9 +856,9 @@ static int setup_ssl_connection( pn_ssl_t *ssl )
// take data from the network, and pass it into SSL. Attempt to read decrypted data from
// SSL socket and pass it to the application.
-static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t available)
+static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
{
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_EOS;
_log( ssl, "process_input_ssl( data size=%d )",available );
@@ -910,8 +930,7 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
if (!ssl->app_input_closed) {
if (ssl->in_count > 0 || ssl->ssl_closed) { /* if ssl_closed, send 0 count */
- pn_io_layer_t *io_next = ssl->io_layer->next;
- ssize_t consumed = io_next->process_input( io_next, ssl->inbuf, ssl->in_count);
+ ssize_t consumed = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->inbuf, ssl->in_count);
if (consumed > 0) {
ssl->in_count -= consumed;
if (ssl->in_count)
@@ -973,15 +992,19 @@ static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_dat
//}
if (ssl->app_input_closed && (SSL_get_shutdown(ssl->ssl) & SSL_SENT_SHUTDOWN) ) {
consumed = ssl->app_input_closed;
- ssl->io_layer->process_input = process_input_done;
+ if (transport->io_layers[layer]==&ssl_output_closed_layer) {
+ transport->io_layers[layer] = &ssl_closed_layer;
+ } else {
+ transport->io_layers[layer] = &ssl_input_closed_layer;
+ }
}
_log(ssl, "process_input_ssl() returning %d", (int) consumed);
return consumed;
}
-static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t max_len)
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
{
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
if (!ssl) return PN_EOS;
if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_EOS;
@@ -993,8 +1016,7 @@ static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t
// first, get any pending application output, if possible
if (!ssl->app_output_closed && ssl->out_count < ssl->out_size) {
- pn_io_layer_t *io_next = ssl->io_layer->next;
- ssize_t app_bytes = io_next->process_output( io_next, &ssl->outbuf[ssl->out_count], ssl->out_size - ssl->out_count);
+ ssize_t app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, &ssl->outbuf[ssl->out_count], ssl->out_size - ssl->out_count);
if (app_bytes > 0) {
ssl->out_count += app_bytes;
work_pending = true;
@@ -1086,7 +1108,11 @@ static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t
//}
if (written == 0 && (SSL_get_shutdown(ssl->ssl) & SSL_SENT_SHUTDOWN) && BIO_pending(ssl->bio_net_io) == 0) {
written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
- ssl->io_layer->process_output = process_output_done;
+ if (transport->io_layers[layer]==&ssl_input_closed_layer) {
+ transport->io_layers[layer] = &ssl_closed_layer;
+ } else {
+ transport->io_layers[layer] = &ssl_output_closed_layer;
+ }
}
_log(ssl, "process_output_ssl() returning %d", (int) written);
return written;
@@ -1169,33 +1195,34 @@ static void release_ssl_socket( pn_ssl_t *ssl )
}
-static int setup_cleartext_connection( pn_ssl_t *ssl )
+static int setup_cleartext_connection(pn_transport_t *transport, unsigned int layer)
{
- _log( ssl, "Cleartext connection detected.");
- ssl->io_layer->process_input = pn_io_layer_input_passthru;
- ssl->io_layer->process_output = pn_io_layer_output_passthru;
+ transport->io_layers[layer] = &pni_passthru_layer;
return 0;
}
// until we determine if the client is using SSL or not:
-static ssize_t process_input_unknown(pn_io_layer_t *io_layer, const char *input_data, size_t len)
+static ssize_t process_input_unknown(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
{
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
switch (check_for_ssl_connection( input_data, len )) {
case SSL_CONNECTION:
- setup_ssl_connection( ssl );
- return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
+ _log( ssl, "SSL connection detected.\n");
+ setup_ssl_connection(transport, layer);
+ break;
case CLEAR_CONNECTION:
- setup_cleartext_connection( ssl );
- return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
+ _log( ssl, "Cleartext connection detected.\n");
+ setup_cleartext_connection(transport, layer);
+ break;
default:
return 0;
}
+ return transport->io_layers[layer]->process_input(transport, layer, input_data, len );
}
-static ssize_t process_output_unknown(pn_io_layer_t *io_layer, char *input_data, size_t len)
+static ssize_t process_output_unknown(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
{
// do not do output until we know if SSL is used or not
return 0;
@@ -1307,20 +1334,20 @@ int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
return 0;
}
-static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len)
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
{
return PN_EOS;
}
-static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len)
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
{
return PN_EOS;
}
// return # output bytes sitting in this layer
-static size_t buffered_output(pn_io_layer_t *io_layer)
+static size_t buffered_output(pn_transport_t *transport)
{
size_t count = 0;
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
if (ssl) {
count += ssl->out_count;
if (ssl->bio_net_io) { // pick up any bytes waiting for network io
@@ -1329,17 +1356,3 @@ static size_t buffered_output(pn_io_layer_t *io_layer)
}
return count;
}
-
-// return # input bytes sitting in this layer
-static size_t buffered_input( pn_io_layer_t *io_layer )
-{
- size_t count = 0;
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
- if (ssl) {
- count += ssl->in_count;
- if (ssl->bio_ssl) { // pick up any bytes waiting to be read
- count += BIO_ctrl_pending(ssl->bio_ssl);
- }
- }
- return count;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c814d5c3/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index 601d6a2..d93e16f 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -92,17 +92,55 @@ void pn_delivery_map_clear(pn_delivery_map_t *dm)
dm->next = 0;
}
-static ssize_t pn_input_read_amqp_header(pn_io_layer_t *io_layer, const char *bytes, size_t available);
-static ssize_t pn_input_read_amqp(pn_io_layer_t *io_layer, const char *bytes, size_t available);
-static ssize_t pn_output_write_amqp_header(pn_io_layer_t *io_layer, char *bytes, size_t available);
-static ssize_t pn_output_write_amqp(pn_io_layer_t *io_layer, char *bytes, size_t available);
-static pn_timestamp_t pn_tick_amqp(pn_io_layer_t *io_layer, pn_timestamp_t now);
+static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );
+static ssize_t pn_io_layer_output_passthru(pn_transport_t *, unsigned int, char *, size_t );
+
+static ssize_t pn_input_read_amqp_header(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_input_read_amqp(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_output_write_amqp_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+static ssize_t pn_output_write_amqp(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+static pn_timestamp_t pn_tick_amqp(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now);
static void pni_default_tracer(pn_transport_t *transport, const char *message)
{
fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
}
+const pn_io_layer_t pni_passthru_layer = {
+ pn_io_layer_input_passthru,
+ pn_io_layer_output_passthru,
+ pn_io_layer_tick_passthru,
+ NULL
+};
+
+const pn_io_layer_t amqp_header_layer = {
+ pn_input_read_amqp_header,
+ pn_output_write_amqp_header,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t amqp_write_header_layer = {
+ pn_input_read_amqp,
+ pn_output_write_amqp_header,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t amqp_read_header_layer = {
+ pn_input_read_amqp_header,
+ pn_output_write_amqp,
+ pn_tick_amqp,
+ NULL
+};
+
+const pn_io_layer_t amqp_layer = {
+ pn_input_read_amqp,
+ pn_output_write_amqp,
+ pn_tick_amqp,
+ NULL
+};
+
static void pn_transport_initialize(void *object)
{
pn_transport_t *transport = (pn_transport_t *)object;
@@ -112,33 +150,16 @@ static void pn_transport_initialize(void *object)
transport->input_buf = NULL;
transport->input_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
transport->tracer = pni_default_tracer;
- transport->header_count = 0;
transport->sasl = NULL;
transport->ssl = NULL;
transport->scratch = pn_string(NULL);
transport->disp = pn_dispatcher(0, transport);
transport->connection = NULL;
- pn_io_layer_t *io_layer = transport->io_layers;
- while (io_layer != &transport->io_layers[PN_IO_AMQP]) {
- io_layer->context = NULL;
- io_layer->next = io_layer + 1;
- io_layer->process_input = pn_io_layer_input_passthru;
- io_layer->process_output = pn_io_layer_output_passthru;
- io_layer->process_tick = pn_io_layer_tick_passthru;
- io_layer->buffered_output = NULL;
- io_layer->buffered_input = NULL;
- ++io_layer;
- }
-
- pn_io_layer_t *amqp = &transport->io_layers[PN_IO_AMQP];
- amqp->context = transport;
- amqp->process_input = pn_input_read_amqp_header;
- amqp->process_output = pn_output_write_amqp_header;
- amqp->process_tick = pn_io_layer_tick_passthru;
- amqp->buffered_output = NULL;
- amqp->buffered_input = NULL;
- amqp->next = NULL;
+ for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
+ transport->io_layers[layer] = &pni_passthru_layer;
+ }
+ transport->io_layers[PN_IO_AMQP] = &amqp_header_layer;
transport->open_sent = false;
transport->open_rcvd = false;
@@ -550,8 +571,6 @@ int pn_do_open(pn_dispatcher_t *disp)
} else {
transport->disp->halt = true;
}
- if (transport->remote_idle_timeout)
- transport->io_layers[PN_IO_AMQP].process_tick = pn_tick_amqp; // enable timeouts
transport->open_rcvd = true;
return 0;
}
@@ -1072,14 +1091,14 @@ ssize_t pn_transport_input(pn_transport_t *transport, const char *bytes, size_t
// process pending input until none remaining or EOS
static ssize_t transport_consume(pn_transport_t *transport)
{
- pn_io_layer_t *io_layer = transport->io_layers;
size_t consumed = 0;
while (transport->input_pending || transport->tail_closed) {
ssize_t n;
- n = io_layer->process_input( io_layer,
- transport->input_buf + consumed,
- transport->input_pending );
+ n = transport->io_layers[PN_IO_SSL]->
+ process_input( transport, PN_IO_SSL,
+ transport->input_buf + consumed,
+ transport->input_pending );
if (n > 0) {
consumed += n;
transport->input_pending -= n;
@@ -1101,44 +1120,34 @@ static ssize_t transport_consume(pn_transport_t *transport)
return consumed;
}
-static ssize_t pn_input_read_header(pn_transport_t *transport, const char *bytes, size_t available,
- const char *header, size_t size, const char *protocol,
- ssize_t (*next)(pn_io_layer_t *, const char *, size_t))
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
+static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- const char *point = header + transport->header_count;
- int delta = pn_min(available, size - transport->header_count);
- if (!available || memcmp(bytes, point, delta)) {
+ unsigned readable = pn_min(8, available);
+ bool eos = pn_transport_capacity(transport)==PN_EOS;
+ if (memcmp(bytes, AMQP_HEADER, readable) || (readable<8 && eos) ) {
char quoted[1024];
pn_quote_data(quoted, 1024, bytes, available);
pn_do_error(transport, "amqp:connection:framing-error",
- "%s header mismatch: '%s'%s", protocol, quoted,
- available ? "" : " (connection aborted)");
+ "%s header mismatch: '%s'%s", "AMQP", quoted,
+ !eos ? "" : " (connection aborted)");
return PN_EOS;
- } else {
- transport->header_count += delta;
- if (transport->header_count == size) {
- transport->header_count = 0;
- transport->io_layers[PN_IO_AMQP].process_input = next;
-
- if (transport->disp->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, " <- %s", protocol);
+ } else if (readable==8) {
+ if (transport->io_layers[layer] == &amqp_read_header_layer) {
+ transport->io_layers[layer] = &amqp_layer;
+ } else {
+ transport->io_layers[layer] = &amqp_write_header_layer;
}
- return delta;
+ if (transport->disp->trace & PN_TRACE_FRM)
+ pn_transport_logf(transport, " <- %s", "AMQP");
+ return 8;
}
+ return 0;
}
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
-
-static ssize_t pn_input_read_amqp_header(pn_io_layer_t *io_layer, const char *bytes, size_t available)
-{
- pn_transport_t *transport = (pn_transport_t *)io_layer->context;
- return pn_input_read_header(transport, bytes, available, AMQP_HEADER, 8,
- "AMQP", pn_input_read_amqp);
-}
-
-static ssize_t pn_input_read_amqp(pn_io_layer_t *io_layer, const char *bytes, size_t available)
+static ssize_t pn_input_read_amqp(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
{
- pn_transport_t *transport = (pn_transport_t *)io_layer->context;
if (transport->close_rcvd) {
if (available > 0) {
pn_do_error(transport, "amqp:connection:framing-error", "data after close");
@@ -1164,10 +1173,9 @@ static ssize_t pn_input_read_amqp(pn_io_layer_t *io_layer, const char *bytes, si
}
/* process AMQP related timer events */
-static pn_timestamp_t pn_tick_amqp(pn_io_layer_t *io_layer, pn_timestamp_t now)
+static pn_timestamp_t pn_tick_amqp(pn_transport_t* transport, unsigned int layer, pn_timestamp_t now)
{
pn_timestamp_t timeout = 0;
- pn_transport_t *transport = (pn_transport_t *)io_layer->context;
if (transport->local_idle_timeout) {
if (transport->dead_remote_deadline == 0 ||
@@ -1827,30 +1835,22 @@ int pn_process(pn_transport_t *transport)
return 0;
}
-static ssize_t pn_output_write_header(pn_transport_t *transport,
- char *bytes, size_t size,
- const char *header, size_t hdrsize,
- const char *protocol,
- ssize_t (*next)(pn_io_layer_t *, char *, size_t))
+static ssize_t pn_output_write_amqp_header(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available)
{
if (transport->disp->trace & PN_TRACE_FRM)
- pn_transport_logf(transport, " -> %s", protocol);
- assert(size >= hdrsize);
- memmove(bytes, header, hdrsize);
- transport->io_layers[PN_IO_AMQP].process_output = next;
- return hdrsize;
-}
-
-static ssize_t pn_output_write_amqp_header(pn_io_layer_t *io_layer, char *bytes, size_t size)
-{
- pn_transport_t *transport = (pn_transport_t *)io_layer->context;
- return pn_output_write_header(transport, bytes, size, AMQP_HEADER, 8, "AMQP",
- pn_output_write_amqp);
+ pn_transport_logf(transport, " -> %s", "AMQP");
+ assert(available >= 8);
+ memmove(bytes, AMQP_HEADER, 8);
+ if (transport->io_layers[layer] == &amqp_write_header_layer) {
+ transport->io_layers[layer] = &amqp_layer;
+ } else {
+ transport->io_layers[layer] = &amqp_read_header_layer;
+ }
+ return 8;
}
-static ssize_t pn_output_write_amqp(pn_io_layer_t *io_layer, char *bytes, size_t size)
+static ssize_t pn_output_write_amqp(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available)
{
- pn_transport_t *transport = (pn_transport_t *)io_layer->context;
if (transport->connection && !transport->done_processing) {
int err = pn_process(transport);
if (err) {
@@ -1866,7 +1866,7 @@ static ssize_t pn_output_write_amqp(pn_io_layer_t *io_layer, char *bytes, size_t
return PN_EOS;
}
- return pn_dispatcher_output(transport->disp, bytes, size);
+ return pn_dispatcher_output(transport->disp, bytes, available);
}
static void pni_close_head(pn_transport_t *transport)
@@ -1884,7 +1884,6 @@ static ssize_t transport_produce(pn_transport_t *transport)
{
if (transport->head_closed) return PN_EOS;
- pn_io_layer_t *io_layer = transport->io_layers;
ssize_t space = transport->output_size - transport->output_pending;
if (space <= 0) { // can we expand the buffer?
@@ -1905,9 +1904,10 @@ static ssize_t transport_produce(pn_transport_t *transport)
while (space > 0) {
ssize_t n;
- n = io_layer->process_output( io_layer,
- &transport->output_buf[transport->output_pending],
- space );
+ n = transport->io_layers[PN_IO_SSL]->
+ process_output( transport, PN_IO_SSL,
+ &transport->output_buf[transport->output_pending],
+ space );
if (n > 0) {
space -= n;
transport->output_pending += n;
@@ -2043,7 +2043,6 @@ pn_millis_t pn_transport_get_idle_timeout(pn_transport_t *transport)
void pn_transport_set_idle_timeout(pn_transport_t *transport, pn_millis_t timeout)
{
transport->local_idle_timeout = timeout;
- transport->io_layers[PN_IO_AMQP].process_tick = pn_tick_amqp;
}
pn_millis_t pn_transport_get_remote_idle_timeout(pn_transport_t *transport)
@@ -2053,8 +2052,7 @@ pn_millis_t pn_transport_get_remote_idle_timeout(pn_transport_t *transport)
pn_timestamp_t pn_transport_tick(pn_transport_t *transport, pn_timestamp_t now)
{
- pn_io_layer_t *io_layer = transport->io_layers;
- return io_layer->process_tick( io_layer, now );
+ return transport->io_layers[PN_IO_SSL]->process_tick(transport, PN_IO_SSL, now);
}
uint64_t pn_transport_get_frames_output(const pn_transport_t *transport)
@@ -2072,29 +2070,26 @@ uint64_t pn_transport_get_frames_input(const pn_transport_t *transport)
}
/** Pass through input handler */
-ssize_t pn_io_layer_input_passthru(pn_io_layer_t *io_layer, const char *data, size_t available)
+ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
{
- pn_io_layer_t *next = io_layer->next;
- if (next)
- return next->process_input( next, data, available );
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
return PN_EOS;
}
/** Pass through output handler */
-ssize_t pn_io_layer_output_passthru(pn_io_layer_t *io_layer, char *bytes, size_t size)
+ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
{
- pn_io_layer_t *next = io_layer->next;
- if (next)
- return next->process_output( next, bytes, size );
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
return PN_EOS;
}
/** Pass through tick handler */
-pn_timestamp_t pn_io_layer_tick_passthru(pn_io_layer_t *io_layer, pn_timestamp_t now)
+pn_timestamp_t pn_io_layer_tick_passthru(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now)
{
- pn_io_layer_t *next = io_layer->next;
- if (next)
- return next->process_tick( next, now );
+ if (layer+1<PN_IO_LAYER_CT)
+ return transport->io_layers[layer+1]->process_tick(transport, layer+1, now);
return 0;
}
@@ -2253,11 +2248,10 @@ bool pn_transport_quiesced(pn_transport_t *transport)
if (pending < 0) return true; // output done
else if (pending > 0) return false;
// no pending at transport, but check if data is buffered in I/O layers
- pn_io_layer_t *io_layer = transport->io_layers;
- while (io_layer != &transport->io_layers[PN_IO_LAYER_CT]) {
- if (io_layer->buffered_output && io_layer->buffered_output( io_layer ))
+ for (int layer = 0; layer<PN_IO_LAYER_CT; ++layer) {
+ if (transport->io_layers[layer]->buffered_output &&
+ transport->io_layers[layer]->buffered_output( transport ))
return false;
- ++io_layer;
}
return true;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c814d5c3/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
index de6e117..397fa21 100644
--- a/proton-c/src/windows/schannel.c
+++ b/proton-c/src/windows/schannel.c
@@ -82,7 +82,6 @@ typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
struct pn_ssl_t {
pn_transport_t *transport;
- pn_io_layer_t *io_layer;
pn_ssl_domain_t *domain;
const char *session_id;
const char *peer_hostname;
@@ -136,17 +135,16 @@ struct pn_ssl_session_t {
};
-static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t len);
-static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *input_data, size_t len);
-static ssize_t process_input_unknown( pn_io_layer_t *io_layer, const char *input_data, size_t len);
-static ssize_t process_output_unknown( pn_io_layer_t *io_layer, char *input_data, size_t len);
-static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len);
-static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len);
+static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static ssize_t process_input_unknown( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_unknown( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
static void ssl_session_free( pn_ssl_session_t *);
-static size_t buffered_output( pn_io_layer_t *io_layer );
-static size_t buffered_input( pn_io_layer_t *io_layer );
+static size_t buffered_output( pn_transport_t *transport );
static void start_ssl_shutdown(pn_ssl_t *ssl);
static void rewind_sc_inbuf(pn_ssl_t *ssl);
static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size);
@@ -350,6 +348,41 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
return 0;
}
+const pn_io_layer_t unknown_layer = {
+ process_input_unknown,
+ process_output_unknown,
+ pn_io_layer_tick_passthru,
+ NULL
+};
+
+const pn_io_layer_t ssl_layer = {
+ process_input_ssl,
+ process_output_ssl,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_input_closed_layer = {
+ process_input_done,
+ process_output_ssl,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_output_closed_layer = {
+ process_input_ssl,
+ process_output_done,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
+const pn_io_layer_t ssl_closed_layer = {
+ process_input_done,
+ process_output_done,
+ pn_io_layer_tick_passthru,
+ buffered_output
+};
+
int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
{
if (!ssl || !domain || ssl->domain) return -1;
@@ -358,13 +391,11 @@ int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
ssl->domain = domain;
domain->ref_count++;
if (domain->allow_unsecured) {
- ssl->io_layer->process_input = process_input_unknown;
- ssl->io_layer->process_output = process_output_unknown;
- } else {
- ssl->io_layer->process_input = process_input_ssl;
- ssl->io_layer->process_output = process_output_ssl;
+ ssl->transport->io_layers[PN_IO_SSL] = &unknown_layer;
+ }
+ else {
+ ssl->transport->io_layers[PN_IO_SSL] = &ssl_layer;
}
-
if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
ssl->session_id = pn_strdup(session_id);
@@ -460,13 +491,7 @@ pn_ssl_t *pn_ssl(pn_transport_t *transport)
ssl->transport = transport;
transport->ssl = ssl;
- ssl->io_layer = &transport->io_layers[PN_IO_SSL];
- ssl->io_layer->context = ssl;
- ssl->io_layer->process_input = pn_io_layer_input_passthru;
- ssl->io_layer->process_output = pn_io_layer_output_passthru;
- ssl->io_layer->process_tick = pn_io_layer_tick_passthru;
- ssl->io_layer->buffered_output = buffered_output;
- ssl->io_layer->buffered_input = buffered_input;
+ transport->io_layers[PN_IO_SSL] = &pni_passthru_layer;
ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
SecInvalidateHandle(&ssl->cred_handle);
@@ -849,11 +874,9 @@ static void start_ssl_shutdown(pn_ssl_t *ssl)
ssl_handshake(ssl);
}
-static int setup_ssl_connection(pn_ssl_t *ssl)
+static int setup_ssl_connection(pn_transport_t *transport, unsigned int layer)
{
- ssl_log( ssl, "SSL connection detected.\n");
- ssl->io_layer->process_input = process_input_ssl;
- ssl->io_layer->process_output = process_output_ssl;
+ transport->io_layers[layer] = &ssl_layer;
return 0;
}
@@ -976,14 +999,14 @@ static void app_inbytes_advance(pn_ssl_t *ssl, size_t consumed)
app_inbytes_progress(ssl, 0);
}
-static void read_closed(pn_ssl_t *ssl, ssize_t error)
+static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t error)
{
+ pn_ssl_t *ssl = transport->ssl;
if (ssl->app_input_closed)
return;
if (ssl->state == RUNNING && !error) {
- pn_io_layer_t *io_next = ssl->io_layer->next;
// Signal end of stream
- ssl->app_input_closed = io_next->process_input(io_next, ssl->app_inbytes.start, 0);
+ ssl->app_input_closed = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, 0);
}
if (!ssl->app_input_closed)
ssl->app_input_closed = error ? error : PN_ERR;
@@ -1000,9 +1023,9 @@ static void read_closed(pn_ssl_t *ssl, ssize_t error)
// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.
-static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data, size_t available)
+static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
{
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
ssl_log( ssl, "process_input_ssl( data size=%d )\n",available );
ssize_t consumed = 0;
ssize_t forwarded = 0;
@@ -1010,14 +1033,14 @@ static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data
if (available == 0) {
// No more inbound network data
- read_closed(ssl,0);
+ read_closed(transport, layer, 0);
return 0;
}
do {
if (ssl->sc_input_shutdown) {
// TLS protocol shutdown detected on input
- read_closed(ssl,0);
+ read_closed(transport, layer, 0);
return consumed;
}
@@ -1097,8 +1120,7 @@ static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data
// present app_inbytes to io_next only if it has new content
while (ssl->app_inbytes.size > 0) {
if (!ssl->app_input_closed) {
- pn_io_layer_t *io_next = ssl->io_layer->next;
- ssize_t count = io_next->process_input(io_next, ssl->app_inbytes.start, ssl->app_inbytes.size);
+ ssize_t count = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, ssl->app_inbytes.size);
if (count > 0) {
forwarded += count;
// advance() can increase app_inbytes.size if double buffered
@@ -1115,7 +1137,7 @@ static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data
ssl_log(ssl, "Application layer closed its input, error=%d (discarding %d bytes)\n",
(int) count, (int)ssl->app_inbytes.size);
app_inbytes_advance(ssl, ssl->app_inbytes.size); // discard
- read_closed(ssl, count);
+ read_closed(transport, layer, count);
}
} else {
ssl_log(ssl, "Input closed discard %d bytes\n",
@@ -1128,15 +1150,19 @@ static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data
if (ssl->app_input_closed && ssl->state >= SHUTTING_DOWN) {
consumed = ssl->app_input_closed;
- ssl->io_layer->process_input = process_input_done;
+ if (transport->io_layers[layer]==&ssl_output_closed_layer) {
+ transport->io_layers[layer] = &ssl_closed_layer;
+ } else {
+ transport->io_layers[layer] = &ssl_input_closed_layer;
+ }
}
ssl_log(ssl, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
return consumed;
}
-static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t max_len)
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
{
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
if (!ssl) return PN_EOS;
ssl_log( ssl, "process_output_ssl( max_len=%d )\n",max_len );
@@ -1173,8 +1199,7 @@ static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t
size_t remaining = ssl->max_data_size;
ssize_t app_bytes;
do {
- pn_io_layer_t *io_next = ssl->io_layer->next;
- app_bytes = io_next->process_output(io_next, app_outp, remaining);
+ app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, app_outp, remaining);
if (app_bytes > 0) {
app_outp += app_bytes;
remaining -= app_bytes;
@@ -1212,40 +1237,45 @@ static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t
if (written == 0 && ssl->state == SSL_CLOSED) {
written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
- ssl->io_layer->process_output = process_output_done;
+ if (transport->io_layers[layer]==&ssl_input_closed_layer) {
+ transport->io_layers[layer] = &ssl_closed_layer;
+ } else {
+ transport->io_layers[layer] = &ssl_output_closed_layer;
+ }
}
ssl_log(ssl, "process_output_ssl() returning %d\n", (int) written);
return written;
}
-static int setup_cleartext_connection( pn_ssl_t *ssl )
+static int setup_cleartext_connection(pn_transport_t *transport, unsigned int layer)
{
- ssl_log( ssl, "Cleartext connection detected.\n");
- ssl->io_layer->process_input = pn_io_layer_input_passthru;
- ssl->io_layer->process_output = pn_io_layer_output_passthru;
+ transport->io_layers[layer] = &pni_passthru_layer;
return 0;
}
// until we determine if the client is using SSL or not:
-static ssize_t process_input_unknown(pn_io_layer_t *io_layer, const char *input_data, size_t len)
+static ssize_t process_input_unknown(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
{
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
switch (check_for_ssl_connection( input_data, len )) {
case SSL_CONNECTION:
- setup_ssl_connection( ssl );
- return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
+ ssl_log(ssl, "SSL connection detected.\n");
+ setup_ssl_connection(transport, layer);
+ break;
case CLEAR_CONNECTION:
- setup_cleartext_connection( ssl );
- return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
+ ssl_log(ssl, "Cleartext connection detected.\n");
+ setup_cleartext_connection(transport, layer);
+ break;
default:
return 0;
}
+ return transport->io_layers[layer]->process_input(transport, layer, input_data, len);
}
-static ssize_t process_output_unknown(pn_io_layer_t *io_layer, char *input_data, size_t len)
+static ssize_t process_output_unknown(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
{
// do not do output until we know if SSL is used or not
return 0;
@@ -1304,21 +1334,21 @@ static connection_mode_t check_for_ssl_connection( const char *data, size_t len
return UNKNOWN_CONNECTION;
}
-static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len)
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
{
return PN_EOS;
}
-static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len)
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
{
return PN_EOS;
}
// return # output bytes sitting in this layer
-static size_t buffered_output(pn_io_layer_t *io_layer)
+static size_t buffered_output(pn_transport_t *transport)
{
size_t count = 0;
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
+ pn_ssl_t *ssl = transport->ssl;
if (ssl) {
count += ssl->network_out_pending;
if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
@@ -1326,14 +1356,3 @@ static size_t buffered_output(pn_io_layer_t *io_layer)
}
return count;
}
-
-// return # input bytes sitting in this layer
-static size_t buffered_input( pn_io_layer_t *io_layer )
-{
- size_t count = 0;
- pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
- if (ssl) {
- count += ssl->in_data_count;
- }
- return count;
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[12/35] qpid-proton git commit: PROTON-753: add constants for the
delivery outcome symbol descriptors,
for use in setting the supported outcomes on a Source
Posted by gs...@apache.org.
PROTON-753: add constants for the delivery outcome symbol descriptors, for use in setting the supported outcomes on a Source
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/7b91e1ff
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/7b91e1ff
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/7b91e1ff
Branch: refs/heads/examples
Commit: 7b91e1ffe986c8b3f4ee9f4b6c3fe24cafedbe05
Parents: 02f1c57
Author: Robert Gemmell <ro...@apache.org>
Authored: Wed Nov 19 12:53:41 2014 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Wed Nov 19 16:31:43 2014 +0000
----------------------------------------------------------------------
.../main/java/org/apache/qpid/proton/amqp/messaging/Accepted.java | 3 +++
.../main/java/org/apache/qpid/proton/amqp/messaging/Modified.java | 3 +++
.../main/java/org/apache/qpid/proton/amqp/messaging/Rejected.java | 2 ++
.../main/java/org/apache/qpid/proton/amqp/messaging/Released.java | 3 +++
.../java/org/apache/qpid/proton/amqp/transaction/Declared.java | 3 +++
5 files changed, 14 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b91e1ff/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Accepted.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Accepted.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Accepted.java
index a2bac32..d21caaa 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Accepted.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Accepted.java
@@ -23,12 +23,15 @@
package org.apache.qpid.proton.amqp.messaging;
+import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.transport.DeliveryState;
public final class Accepted
implements DeliveryState, Outcome
{
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:accepted:list");
+
private static final Accepted INSTANCE = new Accepted();
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b91e1ff/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Modified.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Modified.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Modified.java
index d727e25..9b9a3a3 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Modified.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Modified.java
@@ -22,11 +22,14 @@
package org.apache.qpid.proton.amqp.messaging;
import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.transport.DeliveryState;
public final class Modified
implements DeliveryState, Outcome
{
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:modified:list");
private Boolean _deliveryFailed;
private Boolean _undeliverableHere;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b91e1ff/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Rejected.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Rejected.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Rejected.java
index 022c277..3ea3a5b 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Rejected.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Rejected.java
@@ -23,6 +23,7 @@
package org.apache.qpid.proton.amqp.messaging;
+import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.transport.DeliveryState;
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
@@ -30,6 +31,7 @@ import org.apache.qpid.proton.amqp.transport.ErrorCondition;
public final class Rejected
implements DeliveryState, Outcome
{
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:rejected:list");
private ErrorCondition _error;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b91e1ff/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Released.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Released.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Released.java
index a9878c1..c67917f 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Released.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/messaging/Released.java
@@ -23,12 +23,15 @@
package org.apache.qpid.proton.amqp.messaging;
+import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.transport.DeliveryState;
public final class Released
implements DeliveryState, Outcome
{
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:released:list");
+
private static final Released INSTANCE = new Released();
@Override
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b91e1ff/proton-j/src/main/java/org/apache/qpid/proton/amqp/transaction/Declared.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/transaction/Declared.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/transaction/Declared.java
index 18b508c..e049cd5 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/transaction/Declared.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/transaction/Declared.java
@@ -24,6 +24,7 @@
package org.apache.qpid.proton.amqp.transaction;
import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.messaging.Outcome;
import org.apache.qpid.proton.amqp.transport.DeliveryState;
@@ -31,6 +32,8 @@ import org.apache.qpid.proton.amqp.transport.DeliveryState;
public final class Declared
implements DeliveryState, Outcome
{
+ public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:declared:list");
+
private Binary _txnId;
public Binary getTxnId()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[02/35] qpid-proton git commit: PROTON-746: Fix encoding a Ruby
symbol into a message body.
Posted by gs...@apache.org.
PROTON-746: Fix encoding a Ruby symbol into a message body.
The symbol needs to be converted to a string before being encoded.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b57f45d3
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b57f45d3
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b57f45d3
Branch: refs/heads/examples
Commit: b57f45d30b2643e2275219c286eab79b5efa76a2
Parents: a04193d
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Fri Nov 14 16:09:52 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Fri Nov 14 17:29:11 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/ruby/lib/qpid_proton/mapping.rb | 3 +++
1 file changed, 3 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b57f45d3/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb b/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
index 778f936..836bcd9 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
@@ -112,6 +112,9 @@ module Qpid # :nodoc:
class << STRING
def put(data, value)
+ # if we have a symbol then convert it to a string
+ value = value.to_s if value.is_a?(Symbol)
+
isutf = false
if value.is_a?(Qpid::Proton::UTFString)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[28/35] qpid-proton git commit: Revert "PROTON-752: Provide a
non-blocking means to receive messages in Ruby."
Posted by gs...@apache.org.
Revert "PROTON-752: Provide a non-blocking means to receive messages in Ruby."
This reverts commit 0820a3722b6ab5c2a5a4dbfac3428de7d22c1c6e.
Reverting this change so we can have a review first.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/3ac2e3bd
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/3ac2e3bd
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/3ac2e3bd
Branch: refs/heads/examples
Commit: 3ac2e3bd34b90a7026103af47b1cb8fd2f7d5271
Parents: 0820a37
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Mon Nov 24 14:25:26 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Mon Nov 24 14:25:26 2014 -0500
----------------------------------------------------------------------
examples/messenger/ruby/passive_recv.rb | 122 +++++++++++++++---
.../bindings/ruby/lib/qpid_proton/messenger.rb | 128 -------------------
.../bindings/ruby/lib/qpid_proton/selectable.rb | 21 +--
3 files changed, 108 insertions(+), 163 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3ac2e3bd/examples/messenger/ruby/passive_recv.rb
----------------------------------------------------------------------
diff --git a/examples/messenger/ruby/passive_recv.rb b/examples/messenger/ruby/passive_recv.rb
index 878c801..a3625ac 100644
--- a/examples/messenger/ruby/passive_recv.rb
+++ b/examples/messenger/ruby/passive_recv.rb
@@ -31,26 +31,110 @@ end
addresses = ["~0.0.0.0"] if addresses.empty?
-msgr = Qpid::Proton::Messenger.receive_and_call(nil, :addresses => addresses) do |message|
- puts "Address: #{message.address}"
- subject = message.subject || "(no subject)"
- puts "Subject: #{subject}"
- puts "Body: #{message.body}"
- puts "Properties: #{message.properties}"
- puts "Instructions: #{message.instructions}"
- puts "Annotations: #{message.annotations}"
-
- if message.reply_to
- puts "=== Sending a reply to #{message.reply_to}"
- reply = Qpid::Proton::Message.new
- reply.address = message.reply_to
- reply.subject = "RE: #{message.subject}"
- reply.content = "Thanks for the message!"
-
- messenger.put(reply)
- messenger.send
+messenger = Qpid::Proton::Messenger.new
+messenger.passive = true
+
+begin
+ messenger.start
+rescue ProtonError => error
+ puts "ERROR: #{error.message}"
+ puts error.backtrace.join("\n")
+ exit
+end
+
+addresses.each do |address|
+ begin
+ messenger.subscribe(address)
+ rescue Qpid::Proton::ProtonError => error
+ puts "ERROR: #{error.message}"
+ exit
+ end
+end
+
+msg = Qpid::Proton::Message.new
+
+read_array = []
+write_array = []
+selectables = {}
+
+loop do
+
+ # wait for incoming messages
+ sel = messenger.selectable
+ while !sel.nil?
+ if sel.terminal?
+ selectables.delete(sel.fileno)
+ read_array.delete(sel)
+ write_array.delete(sel)
+ sel.free
+ else
+ sel.capacity
+ sel.pending
+ if !sel.registered?
+ read_array << sel
+ write_array << sel
+ selectables[sel.fileno] = sel
+ sel.registered = true
+ end
+ end
+ sel = messenger.selectable
end
+ unless selectables.empty?
+ rarray = []; read_array.each {|fd| rarray << fd.to_io }
+ warray = []; write_array.each {|fd| warray << fd.to_io }
+
+ if messenger.deadline > 0.0
+ result = IO.select(rarray, warray, nil, messenger.deadline)
+ else
+ result = IO.select(rarray, warray)
+ end
+
+ unless result.nil? && result.empty?
+ result.flatten.each do |io|
+ sel = selectables[io.fileno]
+
+ sel.writable if sel.pending > 0
+ sel.readable if sel.capacity > 0
+ end
+ end
+
+ begin
+ messenger.receive(10)
+ rescue Qpid::Proton::ProtonError => error
+ puts "ERROR: #{error.message}"
+ exit
+ end
+
+ while messenger.incoming.nonzero?
+ begin
+ messenger.get(msg)
+ rescue Qpid::Proton::Error => error
+ puts "ERROR: #{error.message}"
+ exit
+ end
+
+ puts "Address: #{msg.address}"
+ subject = msg.subject || "(no subject)"
+ puts "Subject: #{subject}"
+ puts "Body: #{msg.body}"
+ puts "Properties: #{msg.properties}"
+ puts "Instructions: #{msg.instructions}"
+ puts "Annotations: #{msg.annotations}"
+
+ if msg.reply_to
+ puts "=== Sending a reply to #{msg.reply_to}"
+ reply = Qpid::Proton::Message.new
+ reply.address = msg.reply_to
+ reply.subject = "RE: #{msg.subject}"
+ reply.content = "Thanks for the message!"
+
+ messenger.put(reply)
+ messenger.send
+ end
+ end
+ end
end
-Thread.list[1].join
+messenger.stop
+
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3ac2e3bd/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index a8f7330..5a16c50 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -75,7 +75,6 @@ module Qpid # :nodoc:
#
def initialize(name = nil)
@impl = Cproton.pn_messenger(name)
- @interrupted = false
@selectables = {}
ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
end
@@ -408,7 +407,6 @@ module Qpid # :nodoc:
# originated the interrupt.
#
def interrupt
- @interrupted = true
Cproton.pn_messenger_interrupt(@impl)
end
@@ -697,132 +695,6 @@ module Qpid # :nodoc:
!window.nil? && [Float, Fixnum].include?(window.class)
end
- public
-
-
- #--
- # The following are class methods.
- #++
-
- # Receives messages from the provided instance of Messenger, and then
- # calls the supplied block for each Message received. If no instance
- # is provided then one is created using the provided list of options.
- #
- # This starts a new thread which will loop, waiting for and processing
- # incoming messages.
- #
- # ==== Arguments
- #
- # * messenger - The instance of Messenger.
- #
- # ==== Options
- #
- # * :addresses - An array of addresses to which to subscribe. Addresses
- # are required if no Messenger was supplied.
- #
- # ==== Examples
- #
- # # create a Messenger
- # messenger = Qpid::Proton::Messenger.new
- # # begin receiving messages
- # Qpid::Proton::Messenger.receive_and_call(messenger) do |message|
- # puts "Received: #{message.body}"
- # end
- #
- def self.receive_and_call(messenger, options = {}, &block)
- # if the messenger wasn't created then create one
- if messenger.nil?
- # if no addresses were supplied then raise an exception
- raise ArgumentError.new("no addresses") if options[:addresses].nil?
- # if no block was supplied then raise an exception
- raise ArgumentError.new("missing block") if block.nil?
-
- messenger = Qpid::Proton::Messenger.new
- Array(options[:addresses]).each do |address|
- messenger.subscribe address
- end
- end
-
- # set the messenger to passive mode
- messenger.passive = true
- messenger.start
-
- Thread.new(messenger, block) do |messenger, &block|
- read_array = []
- write_array = []
- selectables = {}
-
- aborted = false
-
- while !aborted do
- # refresh the list of fds to be processed
- sel = messenger.selectable
- while !sel.nil?
- if sel.terminal?
- selectables.delete(sel.fileno)
- read_array.delete(sel)
- write_array.delete(sel)
- sel.free
- else
- sel.capacity
- sel.pending
- if !sel.registered?
- read_array << sel
- write_array << sel
- selectables[sel.fileno] = sel
- sel.registered = true
- end
- end
- sel = messenger.selectable
- end
-
- unless selectables.empty?
- rarray = []; read_array.each {|fd| rarray << fd.to_io}
- warray = []; write_array.each {|fd| warray << fd.to_io}
-
- if messenger.deadline > 0.0
- result = IO.select(rarray, warray, nil, messenger.deadline)
- else
- result = IO.select(rarray, warray)
- end
-
- unless result.nil? && result.empty?
- result.flatten.each do |io|
- sel = selectables[io.fileno]
-
- sel.writable if sel.pending > 0
- sel.readable if sel.capacity > 0
- end
- end
-
- messenger.receive(10)
-
- # if this was interrupted then exit
- messenger.instance_eval do
- aborted = @interrupted
- @interrupted = false
- end
-
- if !aborted
- # process each message received
- while messenger.incoming.nonzero?
- message = Qpid::Proton::Message.new
- messenger.get(message)
- yield message
- end
- end
-
- end
-
- end
-
- end
-
- # return the messenger
- messenger
-
- end
-
end
end
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3ac2e3bd/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
index 8b1214a..33554cd 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
@@ -37,14 +37,6 @@ module Qpid # :nodoc:
@impl = impl
@io = nil
@freed = false
-
- ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
- end
-
- def self.finalize!(impl) # :nodoc:
- proc {
- impl.free
- }
end
# Returns the underlying file descriptor.
@@ -56,11 +48,7 @@ module Qpid # :nodoc:
end
def to_io
- if @io.nil?
- fileno = self.fileno
- @io = IO.new(fileno)
- end
- @io
+ @io ||= IO.new(fileno)
end
# The number of bytes the selectable is capable of consuming.
@@ -109,14 +97,15 @@ module Qpid # :nodoc:
end
def to_s
- return super if @freed
- "#{super} fileno=#{self.fileno} registered=#{self.registered?} terminal=#{self.terminal?}"
+ "fileno=#{self.fileno} registered=#{self.registered?} terminal=#{self.terminal?}"
end
def free
+ return if @freed
@freed = true
@messenger.unregister_selectable(fileno)
- @messenger = nil
+ @io.close unless @io.nil?
+ Cproton.pn_selectable_free(@impl)
@impl = nil
end
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[05/35] qpid-proton git commit: PROTON-749: Change tick layer
callbacks so that they're not chained just called in sequence
Posted by gs...@apache.org.
PROTON-749: Change tick layer callbacks so that they're not chained just called in sequence
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/120639bf
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/120639bf
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/120639bf
Branch: refs/heads/examples
Commit: 120639bf6ebed39fa52c4743baf92a90df87d497
Parents: c814d5c
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri Aug 15 17:58:37 2014 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 17 14:55:18 2014 -0500
----------------------------------------------------------------------
proton-c/src/engine/engine-internal.h | 2 --
proton-c/src/sasl/sasl.c | 8 ++++----
proton-c/src/ssl/openssl.c | 10 +++++-----
proton-c/src/transport/transport.c | 26 +++++++++++---------------
proton-c/src/windows/schannel.c | 10 +++++-----
5 files changed, 25 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/120639bf/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index 86f5161..40a839b 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -300,8 +300,6 @@ void pn_link_dump(pn_link_t *link);
void pn_dump(pn_connection_t *conn);
void pn_transport_sasl_init(pn_transport_t *transport);
-pn_timestamp_t pn_io_layer_tick_passthru(pn_transport_t *, unsigned int, pn_timestamp_t);
-
void pn_condition_init(pn_condition_t *condition);
void pn_condition_tini(pn_condition_t *condition);
void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit);
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/120639bf/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 97bead4..5034eb7 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -61,28 +61,28 @@ static ssize_t pn_output_write_sasl(pn_transport_t *transport, unsigned int laye
const pn_io_layer_t sasl_headers_layer = {
pn_input_read_sasl_header,
pn_output_write_sasl_header,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
const pn_io_layer_t sasl_write_header_layer = {
pn_input_read_sasl,
pn_output_write_sasl_header,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
const pn_io_layer_t sasl_read_header_layer = {
pn_input_read_sasl_header,
pn_output_write_sasl,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
const pn_io_layer_t sasl_layer = {
pn_input_read_sasl,
pn_output_write_sasl,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/120639bf/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index a763cfb..7202f7a 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -670,35 +670,35 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
const pn_io_layer_t unknown_layer = {
process_input_unknown,
process_output_unknown,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
const pn_io_layer_t ssl_layer = {
process_input_ssl,
process_output_ssl,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
const pn_io_layer_t ssl_input_closed_layer = {
process_input_done,
process_output_ssl,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
const pn_io_layer_t ssl_output_closed_layer = {
process_input_ssl,
process_output_done,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
const pn_io_layer_t ssl_closed_layer = {
process_input_done,
process_output_done,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/120639bf/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index d93e16f..2c086db 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -109,7 +109,7 @@ static void pni_default_tracer(pn_transport_t *transport, const char *message)
const pn_io_layer_t pni_passthru_layer = {
pn_io_layer_input_passthru,
pn_io_layer_output_passthru,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
@@ -1095,8 +1095,8 @@ static ssize_t transport_consume(pn_transport_t *transport)
while (transport->input_pending || transport->tail_closed) {
ssize_t n;
- n = transport->io_layers[PN_IO_SSL]->
- process_input( transport, PN_IO_SSL,
+ n = transport->io_layers[0]->
+ process_input( transport, 0,
transport->input_buf + consumed,
transport->input_pending );
if (n > 0) {
@@ -1904,8 +1904,8 @@ static ssize_t transport_produce(pn_transport_t *transport)
while (space > 0) {
ssize_t n;
- n = transport->io_layers[PN_IO_SSL]->
- process_output( transport, PN_IO_SSL,
+ n = transport->io_layers[0]->
+ process_output( transport, 0,
&transport->output_buf[transport->output_pending],
space );
if (n > 0) {
@@ -2052,7 +2052,12 @@ pn_millis_t pn_transport_get_remote_idle_timeout(pn_transport_t *transport)
pn_timestamp_t pn_transport_tick(pn_transport_t *transport, pn_timestamp_t now)
{
- return transport->io_layers[PN_IO_SSL]->process_tick(transport, PN_IO_SSL, now);
+ pn_timestamp_t r = 0;
+ for (int i = 0; i<PN_IO_LAYER_CT; ++i) {
+ if (transport->io_layers[i]->process_tick)
+ r = pn_timestamp_min(r, transport->io_layers[i]->process_tick(transport, i, now));
+ }
+ return r;
}
uint64_t pn_transport_get_frames_output(const pn_transport_t *transport)
@@ -2085,15 +2090,6 @@ ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int laye
return PN_EOS;
}
-/** Pass through tick handler */
-pn_timestamp_t pn_io_layer_tick_passthru(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now)
-{
- if (layer+1<PN_IO_LAYER_CT)
- return transport->io_layers[layer+1]->process_tick(transport, layer+1, now);
- return 0;
-}
-
-
///
// input
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/120639bf/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
index 397fa21..7f47745 100644
--- a/proton-c/src/windows/schannel.c
+++ b/proton-c/src/windows/schannel.c
@@ -351,35 +351,35 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
const pn_io_layer_t unknown_layer = {
process_input_unknown,
process_output_unknown,
- pn_io_layer_tick_passthru,
+ NULL,
NULL
};
const pn_io_layer_t ssl_layer = {
process_input_ssl,
process_output_ssl,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
const pn_io_layer_t ssl_input_closed_layer = {
process_input_done,
process_output_ssl,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
const pn_io_layer_t ssl_output_closed_layer = {
process_input_ssl,
process_output_done,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
const pn_io_layer_t ssl_closed_layer = {
process_input_done,
process_output_done,
- pn_io_layer_tick_passthru,
+ NULL,
buffered_output
};
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[21/35] qpid-proton git commit: changed proton.py from a module into
a package
Posted by gs...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6a78d2f7/proton-c/bindings/python/proton.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py
deleted file mode 100644
index fce3255..0000000
--- a/proton-c/bindings/python/proton.py
+++ /dev/null
@@ -1,3891 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-"""
-The proton module defines a suite of APIs that implement the AMQP 1.0
-protocol.
-
-The proton APIs consist of the following classes:
-
- - L{Messenger} -- A messaging endpoint.
- - L{Message} -- A class for creating and/or accessing AMQP message content.
- - L{Data} -- A class for creating and/or accessing arbitrary AMQP encoded
- data.
-
-"""
-
-from cproton import *
-
-import weakref, re, socket
-try:
- import uuid
-except ImportError:
- """
- No 'native' UUID support. Provide a very basic UUID type that is a compatible subset of the uuid type provided by more modern python releases.
- """
- import struct
- class uuid:
- class UUID:
- def __init__(self, hex=None, bytes=None):
- if [hex, bytes].count(None) != 1:
- raise TypeError("need one of hex or bytes")
- if bytes is not None:
- self.bytes = bytes
- elif hex is not None:
- fields=hex.split("-")
- fields[4:5] = [fields[4][:4], fields[4][4:]]
- self.bytes = struct.pack("!LHHHHL", *[int(x,16) for x in fields])
-
- def __cmp__(self, other):
- if isinstance(other, uuid.UUID):
- return cmp(self.bytes, other.bytes)
- else:
- return -1
-
- def __str__(self):
- return "%08x-%04x-%04x-%04x-%04x%08x" % struct.unpack("!LHHHHL", self.bytes)
-
- def __repr__(self):
- return "UUID(%r)" % str(self)
-
- def __hash__(self):
- return self.bytes.__hash__()
-
- import os, random, socket, time
- rand = random.Random()
- rand.seed((os.getpid(), time.time(), socket.gethostname()))
- def random_uuid():
- bytes = [rand.randint(0, 255) for i in xrange(16)]
-
- # From RFC4122, the version bits are set to 0100
- bytes[7] &= 0x0F
- bytes[7] |= 0x40
-
- # From RFC4122, the top two bits of byte 8 get set to 01
- bytes[8] &= 0x3F
- bytes[8] |= 0x80
- return "".join(map(chr, bytes))
-
- def uuid4():
- return uuid.UUID(bytes=random_uuid())
-
-try:
- bytes()
-except NameError:
- bytes = str
-
-VERSION_MAJOR = PN_VERSION_MAJOR
-VERSION_MINOR = PN_VERSION_MINOR
-API_LANGUAGE = "C"
-IMPLEMENTATION_LANGUAGE = "C"
-
-class Constant(object):
-
- def __init__(self, name):
- self.name = name
-
- def __repr__(self):
- return self.name
-
-class ProtonException(Exception):
- """
- The root of the proton exception hierarchy. All proton exception
- classes derive from this exception.
- """
- pass
-
-class Timeout(ProtonException):
- """
- A timeout exception indicates that a blocking operation has timed
- out.
- """
- pass
-
-class Interrupt(ProtonException):
- """
- An interrupt exception indicaes that a blocking operation was interrupted.
- """
- pass
-
-class MessengerException(ProtonException):
- """
- The root of the messenger exception hierarchy. All exceptions
- generated by the messenger class derive from this exception.
- """
- pass
-
-class MessageException(ProtonException):
- """
- The MessageException class is the root of the message exception
- hierarhcy. All exceptions generated by the Message class derive from
- this exception.
- """
- pass
-
-EXCEPTIONS = {
- PN_TIMEOUT: Timeout,
- PN_INTR: Interrupt
- }
-
-PENDING = Constant("PENDING")
-ACCEPTED = Constant("ACCEPTED")
-REJECTED = Constant("REJECTED")
-RELEASED = Constant("RELEASED")
-ABORTED = Constant("ABORTED")
-SETTLED = Constant("SETTLED")
-
-STATUSES = {
- PN_STATUS_ABORTED: ABORTED,
- PN_STATUS_ACCEPTED: ACCEPTED,
- PN_STATUS_REJECTED: REJECTED,
- PN_STATUS_RELEASED: RELEASED,
- PN_STATUS_PENDING: PENDING,
- PN_STATUS_SETTLED: SETTLED,
- PN_STATUS_UNKNOWN: None
- }
-
-AUTOMATIC = Constant("AUTOMATIC")
-MANUAL = Constant("MANUAL")
-
-class Messenger(object):
- """
- The L{Messenger} class defines a high level interface for sending
- and receiving L{Messages<Message>}. Every L{Messenger} contains a
- single logical queue of incoming messages and a single logical queue
- of outgoing messages. These messages in these queues may be destined
- for, or originate from, a variety of addresses.
-
- The messenger interface is single-threaded. All methods
- except one (L{interrupt}) are intended to be used from within
- the messenger thread.
-
-
- Address Syntax
- ==============
-
- An address has the following form::
-
- [ amqp[s]:// ] [user[:password]@] domain [/[name]]
-
- Where domain can be one of::
-
- host | host:port | ip | ip:port | name
-
- The following are valid examples of addresses:
-
- - example.org
- - example.org:1234
- - amqp://example.org
- - amqps://example.org
- - example.org/incoming
- - amqps://example.org/outgoing
- - amqps://fred:trustno1@example.org
- - 127.0.0.1:1234
- - amqps://127.0.0.1:1234
-
- Sending & Receiving Messages
- ============================
-
- The L{Messenger} class works in conjuction with the L{Message} class. The
- L{Message} class is a mutable holder of message content.
-
- The L{put} method copies its L{Message} to the outgoing queue, and may
- send queued messages if it can do so without blocking. The L{send}
- method blocks until it has sent the requested number of messages,
- or until a timeout interrupts the attempt.
-
-
- >>> message = Message()
- >>> for i in range(3):
- ... message.address = "amqp://host/queue"
- ... message.subject = "Hello World %i" % i
- ... messenger.put(message)
- >>> messenger.send()
-
- Similarly, the L{recv} method receives messages into the incoming
- queue, and may block as it attempts to receive the requested number
- of messages, or until timeout is reached. It may receive fewer
- than the requested number. The L{get} method pops the
- eldest L{Message} off the incoming queue and copies it into the L{Message}
- object that you supply. It will not block.
-
-
- >>> message = Message()
- >>> messenger.recv(10):
- >>> while messenger.incoming > 0:
- ... messenger.get(message)
- ... print message.subject
- Hello World 0
- Hello World 1
- Hello World 2
-
- The blocking flag allows you to turn off blocking behavior entirely,
- in which case L{send} and L{recv} will do whatever they can without
- blocking, and then return. You can then look at the number
- of incoming and outgoing messages to see how much outstanding work
- still remains.
- """
-
- def __init__(self, name=None):
- """
- Construct a new L{Messenger} with the given name. The name has
- global scope. If a NULL name is supplied, a UUID based name will
- be chosen.
-
- @type name: string
- @param name: the name of the messenger or None
-
- """
- self._mng = pn_messenger(name)
- self._selectables = {}
-
- def __del__(self):
- """
- Destroy the L{Messenger}. This will close all connections that
- are managed by the L{Messenger}. Call the L{stop} method before
- destroying the L{Messenger}.
- """
- if hasattr(self, "_mng"):
- pn_messenger_free(self._mng)
- del self._mng
-
- def _check(self, err):
- if err < 0:
- if (err == PN_INPROGRESS):
- return
- exc = EXCEPTIONS.get(err, MessengerException)
- raise exc("[%s]: %s" % (err, pn_error_text(pn_messenger_error(self._mng))))
- else:
- return err
-
- @property
- def name(self):
- """
- The name of the L{Messenger}.
- """
- return pn_messenger_name(self._mng)
-
- def _get_certificate(self):
- return pn_messenger_get_certificate(self._mng)
-
- def _set_certificate(self, value):
- self._check(pn_messenger_set_certificate(self._mng, value))
-
- certificate = property(_get_certificate, _set_certificate,
- doc="""
-Path to a certificate file for the L{Messenger}. This certificate is
-used when the L{Messenger} accepts or establishes SSL/TLS connections.
-This property must be specified for the L{Messenger} to accept
-incoming SSL/TLS connections and to establish client authenticated
-outgoing SSL/TLS connection. Non client authenticated outgoing SSL/TLS
-connections do not require this property.
-""")
-
- def _get_private_key(self):
- return pn_messenger_get_private_key(self._mng)
-
- def _set_private_key(self, value):
- self._check(pn_messenger_set_private_key(self._mng, value))
-
- private_key = property(_get_private_key, _set_private_key,
- doc="""
-Path to a private key file for the L{Messenger's<Messenger>}
-certificate. This property must be specified for the L{Messenger} to
-accept incoming SSL/TLS connections and to establish client
-authenticated outgoing SSL/TLS connection. Non client authenticated
-SSL/TLS connections do not require this property.
-""")
-
- def _get_password(self):
- return pn_messenger_get_password(self._mng)
-
- def _set_password(self, value):
- self._check(pn_messenger_set_password(self._mng, value))
-
- password = property(_get_password, _set_password,
- doc="""
-This property contains the password for the L{Messenger.private_key}
-file, or None if the file is not encrypted.
-""")
-
- def _get_trusted_certificates(self):
- return pn_messenger_get_trusted_certificates(self._mng)
-
- def _set_trusted_certificates(self, value):
- self._check(pn_messenger_set_trusted_certificates(self._mng, value))
-
- trusted_certificates = property(_get_trusted_certificates,
- _set_trusted_certificates,
- doc="""
-A path to a database of trusted certificates for use in verifying the
-peer on an SSL/TLS connection. If this property is None, then the peer
-will not be verified.
-""")
-
- def _get_timeout(self):
- t = pn_messenger_get_timeout(self._mng)
- if t == -1:
- return None
- else:
- return millis2secs(t)
-
- def _set_timeout(self, value):
- if value is None:
- t = -1
- else:
- t = secs2millis(value)
- self._check(pn_messenger_set_timeout(self._mng, t))
-
- timeout = property(_get_timeout, _set_timeout,
- doc="""
-The timeout property contains the default timeout for blocking
-operations performed by the L{Messenger}.
-""")
-
- def _is_blocking(self):
- return pn_messenger_is_blocking(self._mng)
-
- def _set_blocking(self, b):
- self._check(pn_messenger_set_blocking(self._mng, b))
-
- blocking = property(_is_blocking, _set_blocking,
- doc="""
-Enable or disable blocking behavior during L{Message} sending
-and receiving. This affects every blocking call, with the
-exception of L{work}. Currently, the affected calls are
-L{send}, L{recv}, and L{stop}.
-""")
-
- def _is_passive(self):
- return pn_messenger_is_passive(self._mng)
-
- def _set_passive(self, b):
- self._check(pn_messenger_set_passive(self._mng, b))
-
- passive = property(_is_passive, _set_passive,
- doc="""
-When passive is set to true, Messenger will not attempt to perform I/O
-internally. In this mode it is necessary to use the selectables API to
-drive any I/O needed to perform requested actions. In this mode
-Messenger will never block.
-""")
-
- def _get_incoming_window(self):
- return pn_messenger_get_incoming_window(self._mng)
-
- def _set_incoming_window(self, window):
- self._check(pn_messenger_set_incoming_window(self._mng, window))
-
- incoming_window = property(_get_incoming_window, _set_incoming_window,
- doc="""
-The incoming tracking window for the messenger. The messenger will
-track the remote status of this many incoming deliveries after they
-have been accepted or rejected. Defaults to zero.
-
-L{Messages<Message>} enter this window only when you take them into your application
-using L{get}. If your incoming window size is I{n}, and you get I{n}+1 L{messages<Message>}
-without explicitly accepting or rejecting the oldest message, then the
-message that passes beyond the edge of the incoming window will be assigned
-the default disposition of its link.
-""")
-
- def _get_outgoing_window(self):
- return pn_messenger_get_outgoing_window(self._mng)
-
- def _set_outgoing_window(self, window):
- self._check(pn_messenger_set_outgoing_window(self._mng, window))
-
- outgoing_window = property(_get_outgoing_window, _set_outgoing_window,
- doc="""
-The outgoing tracking window for the messenger. The messenger will
-track the remote status of this many outgoing deliveries after calling
-send. Defaults to zero.
-
-A L{Message} enters this window when you call the put() method with the
-message. If your outgoing window size is I{n}, and you call L{put} I{n}+1
-times, status information will no longer be available for the
-first message.
-""")
-
- def start(self):
- """
- Currently a no-op placeholder.
- For future compatibility, do not L{send} or L{recv} messages
- before starting the L{Messenger}.
- """
- self._check(pn_messenger_start(self._mng))
-
- def stop(self):
- """
- Transitions the L{Messenger} to an inactive state. An inactive
- L{Messenger} will not send or receive messages from its internal
- queues. A L{Messenger} should be stopped before being discarded to
- ensure a clean shutdown handshake occurs on any internally managed
- connections.
- """
- self._check(pn_messenger_stop(self._mng))
-
- @property
- def stopped(self):
- """
- Returns true iff a L{Messenger} is in the stopped state.
- This function does not block.
- """
- return pn_messenger_stopped(self._mng)
-
- def subscribe(self, source):
- """
- Subscribes the L{Messenger} to messages originating from the
- specified source. The source is an address as specified in the
- L{Messenger} introduction with the following addition. If the
- domain portion of the address begins with the '~' character, the
- L{Messenger} will interpret the domain as host/port, bind to it,
- and listen for incoming messages. For example "~0.0.0.0",
- "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
- local interface and listen for incoming messages with the last
- variant only permitting incoming SSL connections.
-
- @type source: string
- @param source: the source of messages to subscribe to
- """
- sub_impl = pn_messenger_subscribe(self._mng, source)
- if not sub_impl:
- self._check(pn_error_code(pn_messenger_error(self._mng)))
- raise MessengerException("Cannot subscribe to %s"%source)
- return Subscription(sub_impl)
-
- def put(self, message):
- """
- Places the content contained in the message onto the outgoing
- queue of the L{Messenger}. This method will never block, however
- it will send any unblocked L{Messages<Message>} in the outgoing
- queue immediately and leave any blocked L{Messages<Message>}
- remaining in the outgoing queue. The L{send} call may be used to
- block until the outgoing queue is empty. The L{outgoing} property
- may be used to check the depth of the outgoing queue.
-
- When the content in a given L{Message} object is copied to the outgoing
- message queue, you may then modify or discard the L{Message} object
- without having any impact on the content in the outgoing queue.
-
- This method returns an outgoing tracker for the L{Message}. The tracker
- can be used to determine the delivery status of the L{Message}.
-
- @type message: Message
- @param message: the message to place in the outgoing queue
- @return: a tracker
- """
- message._pre_encode()
- self._check(pn_messenger_put(self._mng, message._msg))
- return pn_messenger_outgoing_tracker(self._mng)
-
- def status(self, tracker):
- """
- Gets the last known remote state of the delivery associated with
- the given tracker.
-
- @type tracker: tracker
- @param tracker: the tracker whose status is to be retrieved
-
- @return: one of None, PENDING, REJECTED, or ACCEPTED
- """
- disp = pn_messenger_status(self._mng, tracker);
- return STATUSES.get(disp, disp)
-
- def buffered(self, tracker):
- """
- Checks if the delivery associated with the given tracker is still
- waiting to be sent.
-
- @type tracker: tracker
- @param tracker: the tracker whose status is to be retrieved
-
- @return: true if delivery is still buffered
- """
- return pn_messenger_buffered(self._mng, tracker);
-
- def settle(self, tracker=None):
- """
- Frees a L{Messenger} from tracking the status associated with a given
- tracker. If you don't supply a tracker, all outgoing L{messages<Message>} up
- to the most recent will be settled.
- """
- if tracker is None:
- tracker = pn_messenger_outgoing_tracker(self._mng)
- flags = PN_CUMULATIVE
- else:
- flags = 0
- self._check(pn_messenger_settle(self._mng, tracker, flags))
-
- def send(self, n=-1):
- """
- This call will block until the indicated number of L{messages<Message>}
- have been sent, or until the operation times out. If n is -1 this call will
- block until all outgoing L{messages<Message>} have been sent. If n is 0 then
- this call will send whatever it can without blocking.
- """
- self._check(pn_messenger_send(self._mng, n))
-
- def recv(self, n=None):
- """
- Receives up to I{n} L{messages<Message>} into the incoming queue. If no value
- for I{n} is supplied, this call will receive as many L{messages<Message>} as it
- can buffer internally. If the L{Messenger} is in blocking mode, this
- call will block until at least one L{Message} is available in the
- incoming queue.
- """
- if n is None:
- n = -1
- self._check(pn_messenger_recv(self._mng, n))
-
- def work(self, timeout=None):
- """
- Sends or receives any outstanding L{messages<Message>} queued for a L{Messenger}.
- This will block for the indicated timeout.
- This method may also do I/O work other than sending and receiving
- L{messages<Message>}. For example, closing connections after messenger.L{stop}()
- has been called.
- """
- if timeout is None:
- t = -1
- else:
- t = secs2millis(timeout)
- err = pn_messenger_work(self._mng, t)
- if (err == PN_TIMEOUT):
- return False
- else:
- self._check(err)
- return True
-
- @property
- def receiving(self):
- return pn_messenger_receiving(self._mng)
-
- def interrupt(self):
- """
- The L{Messenger} interface is single-threaded.
- This is the only L{Messenger} function intended to be called
- from outside of the L{Messenger} thread.
- Call this from a non-messenger thread to interrupt
- a L{Messenger} that is blocking.
- This will cause any in-progress blocking call to throw
- the L{Interrupt} exception. If there is no currently blocking
- call, then the next blocking call will be affected, even if it
- is within the same thread that interrupt was called from.
- """
- self._check(pn_messenger_interrupt(self._mng))
-
- def get(self, message=None):
- """
- Moves the message from the head of the incoming message queue into
- the supplied message object. Any content in the message will be
- overwritten.
-
- A tracker for the incoming L{Message} is returned. The tracker can
- later be used to communicate your acceptance or rejection of the
- L{Message}.
-
- If None is passed in for the L{Message} object, the L{Message}
- popped from the head of the queue is discarded.
-
- @type message: Message
- @param message: the destination message object
- @return: a tracker
- """
- if message is None:
- impl = None
- else:
- impl = message._msg
- self._check(pn_messenger_get(self._mng, impl))
- if message is not None:
- message._post_decode()
- return pn_messenger_incoming_tracker(self._mng)
-
- def accept(self, tracker=None):
- """
- Signal the sender that you have acted on the L{Message}
- pointed to by the tracker. If no tracker is supplied,
- then all messages that have been returned by the L{get}
- method are accepted, except those that have already been
- auto-settled by passing beyond your incoming window size.
-
- @type tracker: tracker
- @param tracker: a tracker as returned by get
- """
- if tracker is None:
- tracker = pn_messenger_incoming_tracker(self._mng)
- flags = PN_CUMULATIVE
- else:
- flags = 0
- self._check(pn_messenger_accept(self._mng, tracker, flags))
-
- def reject(self, tracker=None):
- """
- Rejects the L{Message} indicated by the tracker. If no tracker
- is supplied, all messages that have been returned by the L{get}
- method are rejected, except those that have already been auto-settled
- by passing beyond your outgoing window size.
-
- @type tracker: tracker
- @param tracker: a tracker as returned by get
- """
- if tracker is None:
- tracker = pn_messenger_incoming_tracker(self._mng)
- flags = PN_CUMULATIVE
- else:
- flags = 0
- self._check(pn_messenger_reject(self._mng, tracker, flags))
-
- @property
- def outgoing(self):
- """
- The outgoing queue depth.
- """
- return pn_messenger_outgoing(self._mng)
-
- @property
- def incoming(self):
- """
- The incoming queue depth.
- """
- return pn_messenger_incoming(self._mng)
-
- def route(self, pattern, address):
- """
- Adds a routing rule to a L{Messenger's<Messenger>} internal routing table.
-
- The route procedure may be used to influence how a L{Messenger} will
- internally treat a given address or class of addresses. Every call
- to the route procedure will result in L{Messenger} appending a routing
- rule to its internal routing table.
-
- Whenever a L{Message} is presented to a L{Messenger} for delivery, it
- will match the address of this message against the set of routing
- rules in order. The first rule to match will be triggered, and
- instead of routing based on the address presented in the message,
- the L{Messenger} will route based on the address supplied in the rule.
-
- The pattern matching syntax supports two types of matches, a '%'
- will match any character except a '/', and a '*' will match any
- character including a '/'.
-
- A routing address is specified as a normal AMQP address, however it
- may additionally use substitution variables from the pattern match
- that triggered the rule.
-
- Any message sent to "foo" will be routed to "amqp://foo.com":
-
- >>> messenger.route("foo", "amqp://foo.com");
-
- Any message sent to "foobar" will be routed to
- "amqp://foo.com/bar":
-
- >>> messenger.route("foobar", "amqp://foo.com/bar");
-
- Any message sent to bar/<path> will be routed to the corresponding
- path within the amqp://bar.com domain:
-
- >>> messenger.route("bar/*", "amqp://bar.com/$1");
-
- Route all L{messages<Message>} over TLS:
-
- >>> messenger.route("amqp:*", "amqps:$1")
-
- Supply credentials for foo.com:
-
- >>> messenger.route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
-
- Supply credentials for all domains:
-
- >>> messenger.route("amqp://*", "amqp://user:password@$1");
-
- Route all addresses through a single proxy while preserving the
- original destination:
-
- >>> messenger.route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
-
- Route any address through a single broker:
-
- >>> messenger.route("*", "amqp://user:password@broker/$1");
- """
- self._check(pn_messenger_route(self._mng, pattern, address))
-
- def rewrite(self, pattern, address):
- """
- Similar to route(), except that the destination of
- the L{Message} is determined before the message address is rewritten.
-
- The outgoing address is only rewritten after routing has been
- finalized. If a message has an outgoing address of
- "amqp://0.0.0.0:5678", and a rewriting rule that changes its
- outgoing address to "foo", it will still arrive at the peer that
- is listening on "amqp://0.0.0.0:5678", but when it arrives there,
- the receiver will see its outgoing address as "foo".
-
- The default rewrite rule removes username and password from addresses
- before they are transmitted.
- """
- self._check(pn_messenger_rewrite(self._mng, pattern, address))
-
- def selectable(self):
- impl = pn_messenger_selectable(self._mng)
- if impl:
- fd = pn_selectable_fd(impl)
- sel = self._selectables.get(fd, None)
- if sel is None:
- sel = Selectable(self, impl)
- self._selectables[fd] = sel
- return sel
- else:
- return None
-
- @property
- def deadline(self):
- tstamp = pn_messenger_deadline(self._mng)
- if tstamp:
- return millis2secs(tstamp)
- else:
- return None
-
-class Message(object):
- """The L{Message} class is a mutable holder of message content.
-
- @ivar instructions: delivery instructions for the message
- @type instructions: dict
- @ivar annotations: infrastructure defined message annotations
- @type annotations: dict
- @ivar properties: application defined message properties
- @type properties: dict
- @ivar body: message body
- @type body: bytes | unicode | dict | list | int | long | float | UUID
- """
-
- DATA = PN_DATA
- TEXT = PN_TEXT
- AMQP = PN_AMQP
- JSON = PN_JSON
-
- DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY
-
- def __init__(self, **kwargs):
- """
- @param kwargs: Message property name/value pairs to initialise the Message
- """
- self._msg = pn_message()
- self._id = Data(pn_message_id(self._msg))
- self._correlation_id = Data(pn_message_correlation_id(self._msg))
- self.instructions = None
- self.annotations = None
- self.properties = None
- self.body = None
- for k,v in kwargs.iteritems():
- getattr(self, k) # Raise exception if it's not a valid attribute.
- setattr(self, k, v)
-
- def __del__(self):
- if hasattr(self, "_msg"):
- pn_message_free(self._msg)
- del self._msg
-
- def _check(self, err):
- if err < 0:
- exc = EXCEPTIONS.get(err, MessageException)
- raise exc("[%s]: %s" % (err, pn_error_text(pn_message_error(self._msg))))
- else:
- return err
-
- def _pre_encode(self):
- inst = Data(pn_message_instructions(self._msg))
- ann = Data(pn_message_annotations(self._msg))
- props = Data(pn_message_properties(self._msg))
- body = Data(pn_message_body(self._msg))
-
- inst.clear()
- if self.instructions is not None:
- inst.put_object(self.instructions)
- ann.clear()
- if self.annotations is not None:
- ann.put_object(self.annotations)
- props.clear()
- if self.properties is not None:
- props.put_object(self.properties)
- body.clear()
- if self.body is not None:
- body.put_object(self.body)
-
- def _post_decode(self):
- inst = Data(pn_message_instructions(self._msg))
- ann = Data(pn_message_annotations(self._msg))
- props = Data(pn_message_properties(self._msg))
- body = Data(pn_message_body(self._msg))
-
- if inst.next():
- self.instructions = inst.get_object()
- else:
- self.instructions = None
- if ann.next():
- self.annotations = ann.get_object()
- else:
- self.annotations = None
- if props.next():
- self.properties = props.get_object()
- else:
- self.properties = None
- if body.next():
- self.body = body.get_object()
- else:
- self.body = None
-
- def clear(self):
- """
- Clears the contents of the L{Message}. All fields will be reset to
- their default values.
- """
- pn_message_clear(self._msg)
- self.instructions = None
- self.annotations = None
- self.properties = None
- self.body = None
-
- def _is_inferred(self):
- return pn_message_is_inferred(self._msg)
-
- def _set_inferred(self, value):
- self._check(pn_message_set_inferred(self._msg, bool(value)))
-
- inferred = property(_is_inferred, _set_inferred, doc="""
-The inferred flag for a message indicates how the message content
-is encoded into AMQP sections. If inferred is true then binary and
-list values in the body of the message will be encoded as AMQP DATA
-and AMQP SEQUENCE sections, respectively. If inferred is false,
-then all values in the body of the message will be encoded as AMQP
-VALUE sections regardless of their type.
-""")
-
- def _is_durable(self):
- return pn_message_is_durable(self._msg)
-
- def _set_durable(self, value):
- self._check(pn_message_set_durable(self._msg, bool(value)))
-
- durable = property(_is_durable, _set_durable,
- doc="""
-The durable property indicates that the message should be held durably
-by any intermediaries taking responsibility for the message.
-""")
-
- def _get_priority(self):
- return pn_message_get_priority(self._msg)
-
- def _set_priority(self, value):
- self._check(pn_message_set_priority(self._msg, value))
-
- priority = property(_get_priority, _set_priority,
- doc="""
-The priority of the message.
-""")
-
- def _get_ttl(self):
- return millis2secs(pn_message_get_ttl(self._msg))
-
- def _set_ttl(self, value):
- self._check(pn_message_set_ttl(self._msg, secs2millis(value)))
-
- ttl = property(_get_ttl, _set_ttl,
- doc="""
-The time to live of the message measured in seconds. Expired messages
-may be dropped.
-""")
-
- def _is_first_acquirer(self):
- return pn_message_is_first_acquirer(self._msg)
-
- def _set_first_acquirer(self, value):
- self._check(pn_message_set_first_acquirer(self._msg, bool(value)))
-
- first_acquirer = property(_is_first_acquirer, _set_first_acquirer,
- doc="""
-True iff the recipient is the first to acquire the message.
-""")
-
- def _get_delivery_count(self):
- return pn_message_get_delivery_count(self._msg)
-
- def _set_delivery_count(self, value):
- self._check(pn_message_set_delivery_count(self._msg, value))
-
- delivery_count = property(_get_delivery_count, _set_delivery_count,
- doc="""
-The number of delivery attempts made for this message.
-""")
-
-
- def _get_id(self):
- return self._id.get_object()
- def _set_id(self, value):
- if type(value) in (int, long):
- value = ulong(value)
- self._id.rewind()
- self._id.put_object(value)
- id = property(_get_id, _set_id,
- doc="""
-The id of the message.
-""")
-
- def _get_user_id(self):
- return pn_message_get_user_id(self._msg)
-
- def _set_user_id(self, value):
- self._check(pn_message_set_user_id(self._msg, value))
-
- user_id = property(_get_user_id, _set_user_id,
- doc="""
-The user id of the message creator.
-""")
-
- def _get_address(self):
- return pn_message_get_address(self._msg)
-
- def _set_address(self, value):
- self._check(pn_message_set_address(self._msg, value))
-
- address = property(_get_address, _set_address,
- doc="""
-The address of the message.
-""")
-
- def _get_subject(self):
- return pn_message_get_subject(self._msg)
-
- def _set_subject(self, value):
- self._check(pn_message_set_subject(self._msg, value))
-
- subject = property(_get_subject, _set_subject,
- doc="""
-The subject of the message.
-""")
-
- def _get_reply_to(self):
- return pn_message_get_reply_to(self._msg)
-
- def _set_reply_to(self, value):
- self._check(pn_message_set_reply_to(self._msg, value))
-
- reply_to = property(_get_reply_to, _set_reply_to,
- doc="""
-The reply-to address for the message.
-""")
-
- def _get_correlation_id(self):
- return self._correlation_id.get_object()
- def _set_correlation_id(self, value):
- if type(value) in (int, long):
- value = ulong(value)
- self._correlation_id.rewind()
- self._correlation_id.put_object(value)
-
- correlation_id = property(_get_correlation_id, _set_correlation_id,
- doc="""
-The correlation-id for the message.
-""")
-
- def _get_content_type(self):
- return pn_message_get_content_type(self._msg)
-
- def _set_content_type(self, value):
- self._check(pn_message_set_content_type(self._msg, value))
-
- content_type = property(_get_content_type, _set_content_type,
- doc="""
-The content-type of the message.
-""")
-
- def _get_content_encoding(self):
- return pn_message_get_content_encoding(self._msg)
-
- def _set_content_encoding(self, value):
- self._check(pn_message_set_content_encoding(self._msg, value))
-
- content_encoding = property(_get_content_encoding, _set_content_encoding,
- doc="""
-The content-encoding of the message.
-""")
-
- def _get_expiry_time(self):
- return millis2secs(pn_message_get_expiry_time(self._msg))
-
- def _set_expiry_time(self, value):
- self._check(pn_message_set_expiry_time(self._msg, secs2millis(value)))
-
- expiry_time = property(_get_expiry_time, _set_expiry_time,
- doc="""
-The expiry time of the message.
-""")
-
- def _get_creation_time(self):
- return millis2secs(pn_message_get_creation_time(self._msg))
-
- def _set_creation_time(self, value):
- self._check(pn_message_set_creation_time(self._msg, secs2millis(value)))
-
- creation_time = property(_get_creation_time, _set_creation_time,
- doc="""
-The creation time of the message.
-""")
-
- def _get_group_id(self):
- return pn_message_get_group_id(self._msg)
-
- def _set_group_id(self, value):
- self._check(pn_message_set_group_id(self._msg, value))
-
- group_id = property(_get_group_id, _set_group_id,
- doc="""
-The group id of the message.
-""")
-
- def _get_group_sequence(self):
- return pn_message_get_group_sequence(self._msg)
-
- def _set_group_sequence(self, value):
- self._check(pn_message_set_group_sequence(self._msg, value))
-
- group_sequence = property(_get_group_sequence, _set_group_sequence,
- doc="""
-The sequence of the message within its group.
-""")
-
- def _get_reply_to_group_id(self):
- return pn_message_get_reply_to_group_id(self._msg)
-
- def _set_reply_to_group_id(self, value):
- self._check(pn_message_set_reply_to_group_id(self._msg, value))
-
- reply_to_group_id = property(_get_reply_to_group_id, _set_reply_to_group_id,
- doc="""
-The group-id for any replies.
-""")
-
- # XXX
- def _get_format(self):
- return pn_message_get_format(self._msg)
-
- def _set_format(self, value):
- self._check(pn_message_set_format(self._msg, value))
-
- format = property(_get_format, _set_format,
- doc="""
-The format of the message.
-""")
-
- def encode(self):
- self._pre_encode()
- sz = 16
- while True:
- err, data = pn_message_encode(self._msg, sz)
- if err == PN_OVERFLOW:
- sz *= 2
- continue
- else:
- self._check(err)
- return data
-
- def decode(self, data):
- self._check(pn_message_decode(self._msg, data, len(data)))
- self._post_decode()
-
- def load(self, data):
- self._check(pn_message_load(self._msg, data))
-
- def save(self):
- sz = 16
- while True:
- err, data = pn_message_save(self._msg, sz)
- if err == PN_OVERFLOW:
- sz *= 2
- continue
- else:
- self._check(err)
- return data
-
- def __repr2__(self):
- props = []
- for attr in ("inferred", "address", "reply_to", "durable", "ttl",
- "priority", "first_acquirer", "delivery_count", "id",
- "correlation_id", "user_id", "group_id", "group_sequence",
- "reply_to_group_id", "instructions", "annotations",
- "properties", "body"):
- value = getattr(self, attr)
- if value: props.append("%s=%r" % (attr, value))
- return "Message(%s)" % ", ".join(props)
-
- def __repr__(self):
- tmp = pn_string(None)
- err = pn_inspect(self._msg, tmp)
- result = pn_string_get(tmp)
- pn_free(tmp)
- self._check(err)
- return result
-
-class Subscription(object):
-
- def __init__(self, impl):
- self._impl = impl
-
- @property
- def address(self):
- return pn_subscription_address(self._impl)
-
-class Selectable(object):
-
- def __init__(self, messenger, impl):
- self.messenger = messenger
- self._impl = impl
-
- def fileno(self):
- if not self._impl: raise ValueError("selectable freed")
- return pn_selectable_fd(self._impl)
-
- @property
- def capacity(self):
- if not self._impl: raise ValueError("selectable freed")
- return pn_selectable_capacity(self._impl)
-
- @property
- def pending(self):
- if not self._impl: raise ValueError("selectable freed")
- return pn_selectable_pending(self._impl)
-
- @property
- def deadline(self):
- if not self._impl: raise ValueError("selectable freed")
- tstamp = pn_selectable_deadline(self._impl)
- if tstamp:
- return millis2secs(tstamp)
- else:
- return None
-
- def readable(self):
- if not self._impl: raise ValueError("selectable freed")
- pn_selectable_readable(self._impl)
-
- def writable(self):
- if not self._impl: raise ValueError("selectable freed")
- pn_selectable_writable(self._impl)
-
- def expired(self):
- if not self._impl: raise ValueError("selectable freed")
- pn_selectable_expired(self._impl)
-
- def _is_registered(self):
- if not self._impl: raise ValueError("selectable freed")
- return pn_selectable_is_registered(self._impl)
-
- def _set_registered(self, registered):
- if not self._impl: raise ValueError("selectable freed")
- pn_selectable_set_registered(self._impl, registered)
-
- registered = property(_is_registered, _set_registered,
- doc="""
-The registered property may be get/set by an I/O polling system to
-indicate whether the fd has been registered or not.
-""")
-
- @property
- def is_terminal(self):
- if not self._impl: return True
- return pn_selectable_is_terminal(self._impl)
-
- def free(self):
- if self._impl:
- del self.messenger._selectables[self.fileno()]
- pn_selectable_free(self._impl)
- self._impl = None
-
- def __del__(self):
- self.free()
-
-class DataException(ProtonException):
- """
- The DataException class is the root of the Data exception hierarchy.
- All exceptions raised by the Data class extend this exception.
- """
- pass
-
-class UnmappedType:
-
- def __init__(self, msg):
- self.msg = msg
-
- def __repr__(self):
- return "UnmappedType(%s)" % self.msg
-
-class ulong(long):
-
- def __repr__(self):
- return "ulong(%s)" % long.__repr__(self)
-
-class timestamp(long):
-
- def __repr__(self):
- return "timestamp(%s)" % long.__repr__(self)
-
-class symbol(unicode):
-
- def __repr__(self):
- return "symbol(%s)" % unicode.__repr__(self)
-
-class char(unicode):
-
- def __repr__(self):
- return "char(%s)" % unicode.__repr__(self)
-
-class Described(object):
-
- def __init__(self, descriptor, value):
- self.descriptor = descriptor
- self.value = value
-
- def __repr__(self):
- return "Described(%r, %r)" % (self.descriptor, self.value)
-
- def __eq__(self, o):
- if isinstance(o, Described):
- return self.descriptor == o.descriptor and self.value == o.value
- else:
- return False
-
-UNDESCRIBED = Constant("UNDESCRIBED")
-
-class Array(object):
-
- def __init__(self, descriptor, type, *elements):
- self.descriptor = descriptor
- self.type = type
- self.elements = elements
-
- def __repr__(self):
- if self.elements:
- els = ", %s" % (", ".join(map(repr, self.elements)))
- else:
- els = ""
- return "Array(%r, %r%s)" % (self.descriptor, self.type, els)
-
- def __eq__(self, o):
- if isinstance(o, Array):
- return self.descriptor == o.descriptor and \
- self.type == o.type and self.elements == o.elements
- else:
- return False
-
-class Data:
- """
- The L{Data} class provides an interface for decoding, extracting,
- creating, and encoding arbitrary AMQP data. A L{Data} object
- contains a tree of AMQP values. Leaf nodes in this tree correspond
- to scalars in the AMQP type system such as L{ints<INT>} or
- L{strings<STRING>}. Non-leaf nodes in this tree correspond to
- compound values in the AMQP type system such as L{lists<LIST>},
- L{maps<MAP>}, L{arrays<ARRAY>}, or L{described values<DESCRIBED>}.
- The root node of the tree is the L{Data} object itself and can have
- an arbitrary number of children.
-
- A L{Data} object maintains the notion of the current sibling node
- and a current parent node. Siblings are ordered within their parent.
- Values are accessed and/or added by using the L{next}, L{prev},
- L{enter}, and L{exit} methods to navigate to the desired location in
- the tree and using the supplied variety of put_*/get_* methods to
- access or add a value of the desired type.
-
- The put_* methods will always add a value I{after} the current node
- in the tree. If the current node has a next sibling the put_* method
- will overwrite the value on this node. If there is no current node
- or the current node has no next sibling then one will be added. The
- put_* methods always set the added/modified node to the current
- node. The get_* methods read the value of the current node and do
- not change which node is current.
-
- The following types of scalar values are supported:
-
- - L{NULL}
- - L{BOOL}
- - L{UBYTE}
- - L{USHORT}
- - L{SHORT}
- - L{UINT}
- - L{INT}
- - L{ULONG}
- - L{LONG}
- - L{FLOAT}
- - L{DOUBLE}
- - L{BINARY}
- - L{STRING}
- - L{SYMBOL}
-
- The following types of compound values are supported:
-
- - L{DESCRIBED}
- - L{ARRAY}
- - L{LIST}
- - L{MAP}
- """
-
- NULL = PN_NULL; "A null value."
- BOOL = PN_BOOL; "A boolean value."
- UBYTE = PN_UBYTE; "An unsigned byte value."
- BYTE = PN_BYTE; "A signed byte value."
- USHORT = PN_USHORT; "An unsigned short value."
- SHORT = PN_SHORT; "A short value."
- UINT = PN_UINT; "An unsigned int value."
- INT = PN_INT; "A signed int value."
- CHAR = PN_CHAR; "A character value."
- ULONG = PN_ULONG; "An unsigned long value."
- LONG = PN_LONG; "A signed long value."
- TIMESTAMP = PN_TIMESTAMP; "A timestamp value."
- FLOAT = PN_FLOAT; "A float value."
- DOUBLE = PN_DOUBLE; "A double value."
- DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value."
- DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value."
- DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value."
- UUID = PN_UUID; "A UUID value."
- BINARY = PN_BINARY; "A binary string."
- STRING = PN_STRING; "A unicode string."
- SYMBOL = PN_SYMBOL; "A symbolic string."
- DESCRIBED = PN_DESCRIBED; "A described value."
- ARRAY = PN_ARRAY; "An array value."
- LIST = PN_LIST; "A list value."
- MAP = PN_MAP; "A map value."
-
- type_names = {
- NULL: "null",
- BOOL: "bool",
- BYTE: "byte",
- UBYTE: "ubyte",
- SHORT: "short",
- USHORT: "ushort",
- INT: "int",
- UINT: "uint",
- CHAR: "char",
- LONG: "long",
- ULONG: "ulong",
- TIMESTAMP: "timestamp",
- FLOAT: "float",
- DOUBLE: "double",
- DECIMAL32: "decimal32",
- DECIMAL64: "decimal64",
- DECIMAL128: "decimal128",
- UUID: "uuid",
- BINARY: "binary",
- STRING: "string",
- SYMBOL: "symbol",
- DESCRIBED: "described",
- ARRAY: "array",
- LIST: "list",
- MAP: "map"
- }
-
- @classmethod
- def type_name(type): return Data.type_names[type]
-
- def __init__(self, capacity=16):
- if type(capacity) in (int, long):
- self._data = pn_data(capacity)
- self._free = True
- else:
- self._data = capacity
- self._free = False
-
- def __del__(self):
- if self._free and hasattr(self, "_data"):
- pn_data_free(self._data)
- del self._data
-
- def _check(self, err):
- if err < 0:
- exc = EXCEPTIONS.get(err, DataException)
- raise exc("[%s]: %s" % (err, pn_error_text(pn_data_error(self._data))))
- else:
- return err
-
- def clear(self):
- """
- Clears the data object.
- """
- pn_data_clear(self._data)
-
- def rewind(self):
- """
- Clears current node and sets the parent to the root node. Clearing the
- current node sets it _before_ the first node, calling next() will advance to
- the first node.
- """
- assert self._data is not None
- pn_data_rewind(self._data)
-
- def next(self):
- """
- Advances the current node to its next sibling and returns its
- type. If there is no next sibling the current node remains
- unchanged and None is returned.
- """
- found = pn_data_next(self._data)
- if found:
- return self.type()
- else:
- return None
-
- def prev(self):
- """
- Advances the current node to its previous sibling and returns its
- type. If there is no previous sibling the current node remains
- unchanged and None is returned.
- """
- found = pn_data_prev(self._data)
- if found:
- return self.type()
- else:
- return None
-
- def enter(self):
- """
- Sets the parent node to the current node and clears the current node.
- Clearing the current node sets it _before_ the first child,
- call next() advances to the first child.
- """
- return pn_data_enter(self._data)
-
- def exit(self):
- """
- Sets the current node to the parent node and the parent node to
- its own parent.
- """
- return pn_data_exit(self._data)
-
- def lookup(self, name):
- return pn_data_lookup(self._data, name)
-
- def narrow(self):
- pn_data_narrow(self._data)
-
- def widen(self):
- pn_data_widen(self._data)
-
- def type(self):
- """
- Returns the type of the current node.
- """
- dtype = pn_data_type(self._data)
- if dtype == -1:
- return None
- else:
- return dtype
-
- def encode(self):
- """
- Returns a representation of the data encoded in AMQP format.
- """
- size = 1024
- while True:
- cd, enc = pn_data_encode(self._data, size)
- if cd == PN_OVERFLOW:
- size *= 2
- elif cd >= 0:
- return enc
- else:
- self._check(cd)
-
- def decode(self, encoded):
- """
- Decodes the first value from supplied AMQP data and returns the
- number of bytes consumed.
-
- @type encoded: binary
- @param encoded: AMQP encoded binary data
- """
- return self._check(pn_data_decode(self._data, encoded))
-
- def put_list(self):
- """
- Puts a list value. Elements may be filled by entering the list
- node and putting element values.
-
- >>> data = Data()
- >>> data.put_list()
- >>> data.enter()
- >>> data.put_int(1)
- >>> data.put_int(2)
- >>> data.put_int(3)
- >>> data.exit()
- """
- self._check(pn_data_put_list(self._data))
-
- def put_map(self):
- """
- Puts a map value. Elements may be filled by entering the map node
- and putting alternating key value pairs.
-
- >>> data = Data()
- >>> data.put_map()
- >>> data.enter()
- >>> data.put_string("key")
- >>> data.put_string("value")
- >>> data.exit()
- """
- self._check(pn_data_put_map(self._data))
-
- def put_array(self, described, element_type):
- """
- Puts an array value. Elements may be filled by entering the array
- node and putting the element values. The values must all be of the
- specified array element type. If an array is described then the
- first child value of the array is the descriptor and may be of any
- type.
-
- >>> data = Data()
- >>>
- >>> data.put_array(False, Data.INT)
- >>> data.enter()
- >>> data.put_int(1)
- >>> data.put_int(2)
- >>> data.put_int(3)
- >>> data.exit()
- >>>
- >>> data.put_array(True, Data.DOUBLE)
- >>> data.enter()
- >>> data.put_symbol("array-descriptor")
- >>> data.put_double(1.1)
- >>> data.put_double(1.2)
- >>> data.put_double(1.3)
- >>> data.exit()
-
- @type described: bool
- @param described: specifies whether the array is described
- @type element_type: int
- @param element_type: the type of the array elements
- """
- self._check(pn_data_put_array(self._data, described, element_type))
-
- def put_described(self):
- """
- Puts a described value. A described node has two children, the
- descriptor and the value. These are specified by entering the node
- and putting the desired values.
-
- >>> data = Data()
- >>> data.put_described()
- >>> data.enter()
- >>> data.put_symbol("value-descriptor")
- >>> data.put_string("the value")
- >>> data.exit()
- """
- self._check(pn_data_put_described(self._data))
-
- def put_null(self):
- """
- Puts a null value.
- """
- self._check(pn_data_put_null(self._data))
-
- def put_bool(self, b):
- """
- Puts a boolean value.
-
- @param b: a boolean value
- """
- self._check(pn_data_put_bool(self._data, b))
-
- def put_ubyte(self, ub):
- """
- Puts an unsigned byte value.
-
- @param ub: an integral value
- """
- self._check(pn_data_put_ubyte(self._data, ub))
-
- def put_byte(self, b):
- """
- Puts a signed byte value.
-
- @param b: an integral value
- """
- self._check(pn_data_put_byte(self._data, b))
-
- def put_ushort(self, us):
- """
- Puts an unsigned short value.
-
- @param us: an integral value.
- """
- self._check(pn_data_put_ushort(self._data, us))
-
- def put_short(self, s):
- """
- Puts a signed short value.
-
- @param s: an integral value
- """
- self._check(pn_data_put_short(self._data, s))
-
- def put_uint(self, ui):
- """
- Puts an unsigned int value.
-
- @param ui: an integral value
- """
- self._check(pn_data_put_uint(self._data, ui))
-
- def put_int(self, i):
- """
- Puts a signed int value.
-
- @param i: an integral value
- """
- self._check(pn_data_put_int(self._data, i))
-
- def put_char(self, c):
- """
- Puts a char value.
-
- @param c: a single character
- """
- self._check(pn_data_put_char(self._data, ord(c)))
-
- def put_ulong(self, ul):
- """
- Puts an unsigned long value.
-
- @param ul: an integral value
- """
- self._check(pn_data_put_ulong(self._data, ul))
-
- def put_long(self, l):
- """
- Puts a signed long value.
-
- @param l: an integral value
- """
- self._check(pn_data_put_long(self._data, l))
-
- def put_timestamp(self, t):
- """
- Puts a timestamp value.
-
- @param t: an integral value
- """
- self._check(pn_data_put_timestamp(self._data, t))
-
- def put_float(self, f):
- """
- Puts a float value.
-
- @param f: a floating point value
- """
- self._check(pn_data_put_float(self._data, f))
-
- def put_double(self, d):
- """
- Puts a double value.
-
- @param d: a floating point value.
- """
- self._check(pn_data_put_double(self._data, d))
-
- def put_decimal32(self, d):
- """
- Puts a decimal32 value.
-
- @param d: a decimal32 value
- """
- self._check(pn_data_put_decimal32(self._data, d))
-
- def put_decimal64(self, d):
- """
- Puts a decimal64 value.
-
- @param d: a decimal64 value
- """
- self._check(pn_data_put_decimal64(self._data, d))
-
- def put_decimal128(self, d):
- """
- Puts a decimal128 value.
-
- @param d: a decimal128 value
- """
- self._check(pn_data_put_decimal128(self._data, d))
-
- def put_uuid(self, u):
- """
- Puts a UUID value.
-
- @param u: a uuid value
- """
- self._check(pn_data_put_uuid(self._data, u.bytes))
-
- def put_binary(self, b):
- """
- Puts a binary value.
-
- @type b: binary
- @param b: a binary value
- """
- self._check(pn_data_put_binary(self._data, b))
-
- def put_string(self, s):
- """
- Puts a unicode value.
-
- @type s: unicode
- @param s: a unicode value
- """
- self._check(pn_data_put_string(self._data, s.encode("utf8")))
-
- def put_symbol(self, s):
- """
- Puts a symbolic value.
-
- @type s: string
- @param s: the symbol name
- """
- self._check(pn_data_put_symbol(self._data, s))
-
- def get_list(self):
- """
- If the current node is a list, return the number of elements,
- otherwise return zero. List elements can be accessed by entering
- the list.
-
- >>> count = data.get_list()
- >>> data.enter()
- >>> for i in range(count):
- ... type = data.next()
- ... if type == Data.STRING:
- ... print data.get_string()
- ... elif type == ...:
- ... ...
- >>> data.exit()
- """
- return pn_data_get_list(self._data)
-
- def get_map(self):
- """
- If the current node is a map, return the number of child elements,
- otherwise return zero. Key value pairs can be accessed by entering
- the map.
-
- >>> count = data.get_map()
- >>> data.enter()
- >>> for i in range(count/2):
- ... type = data.next()
- ... if type == Data.STRING:
- ... print data.get_string()
- ... elif type == ...:
- ... ...
- >>> data.exit()
- """
- return pn_data_get_map(self._data)
-
- def get_array(self):
- """
- If the current node is an array, return a tuple of the element
- count, a boolean indicating whether the array is described, and
- the type of each element, otherwise return (0, False, None). Array
- data can be accessed by entering the array.
-
- >>> # read an array of strings with a symbolic descriptor
- >>> count, described, type = data.get_array()
- >>> data.enter()
- >>> data.next()
- >>> print "Descriptor:", data.get_symbol()
- >>> for i in range(count):
- ... data.next()
- ... print "Element:", data.get_string()
- >>> data.exit()
- """
- count = pn_data_get_array(self._data)
- described = pn_data_is_array_described(self._data)
- type = pn_data_get_array_type(self._data)
- if type == -1:
- type = None
- return count, described, type
-
- def is_described(self):
- """
- Checks if the current node is a described value. The descriptor
- and value may be accessed by entering the described value.
-
- >>> # read a symbolically described string
- >>> assert data.is_described() # will error if the current node is not described
- >>> data.enter()
- >>> print data.get_symbol()
- >>> print data.get_string()
- >>> data.exit()
- """
- return pn_data_is_described(self._data)
-
- def is_null(self):
- """
- Checks if the current node is a null.
- """
- return pn_data_is_null(self._data)
-
- def get_bool(self):
- """
- If the current node is a boolean, returns its value, returns False
- otherwise.
- """
- return pn_data_get_bool(self._data)
-
- def get_ubyte(self):
- """
- If the current node is an unsigned byte, returns its value,
- returns 0 otherwise.
- """
- return pn_data_get_ubyte(self._data)
-
- def get_byte(self):
- """
- If the current node is a signed byte, returns its value, returns 0
- otherwise.
- """
- return pn_data_get_byte(self._data)
-
- def get_ushort(self):
- """
- If the current node is an unsigned short, returns its value,
- returns 0 otherwise.
- """
- return pn_data_get_ushort(self._data)
-
- def get_short(self):
- """
- If the current node is a signed short, returns its value, returns
- 0 otherwise.
- """
- return pn_data_get_short(self._data)
-
- def get_uint(self):
- """
- If the current node is an unsigned int, returns its value, returns
- 0 otherwise.
- """
- return pn_data_get_uint(self._data)
-
- def get_int(self):
- """
- If the current node is a signed int, returns its value, returns 0
- otherwise.
- """
- return pn_data_get_int(self._data)
-
- def get_char(self):
- """
- If the current node is a char, returns its value, returns 0
- otherwise.
- """
- return char(unichr(pn_data_get_char(self._data)))
-
- def get_ulong(self):
- """
- If the current node is an unsigned long, returns its value,
- returns 0 otherwise.
- """
- return ulong(pn_data_get_ulong(self._data))
-
- def get_long(self):
- """
- If the current node is an signed long, returns its value, returns
- 0 otherwise.
- """
- return pn_data_get_long(self._data)
-
- def get_timestamp(self):
- """
- If the current node is a timestamp, returns its value, returns 0
- otherwise.
- """
- return timestamp(pn_data_get_timestamp(self._data))
-
- def get_float(self):
- """
- If the current node is a float, returns its value, raises 0
- otherwise.
- """
- return pn_data_get_float(self._data)
-
- def get_double(self):
- """
- If the current node is a double, returns its value, returns 0
- otherwise.
- """
- return pn_data_get_double(self._data)
-
- # XXX: need to convert
- def get_decimal32(self):
- """
- If the current node is a decimal32, returns its value, returns 0
- otherwise.
- """
- return pn_data_get_decimal32(self._data)
-
- # XXX: need to convert
- def get_decimal64(self):
- """
- If the current node is a decimal64, returns its value, returns 0
- otherwise.
- """
- return pn_data_get_decimal64(self._data)
-
- # XXX: need to convert
- def get_decimal128(self):
- """
- If the current node is a decimal128, returns its value, returns 0
- otherwise.
- """
- return pn_data_get_decimal128(self._data)
-
- def get_uuid(self):
- """
- If the current node is a UUID, returns its value, returns None
- otherwise.
- """
- if pn_data_type(self._data) == Data.UUID:
- return uuid.UUID(bytes=pn_data_get_uuid(self._data))
- else:
- return None
-
- def get_binary(self):
- """
- If the current node is binary, returns its value, returns ""
- otherwise.
- """
- return pn_data_get_binary(self._data)
-
- def get_string(self):
- """
- If the current node is a string, returns its value, returns ""
- otherwise.
- """
- return pn_data_get_string(self._data).decode("utf8")
-
- def get_symbol(self):
- """
- If the current node is a symbol, returns its value, returns ""
- otherwise.
- """
- return symbol(pn_data_get_symbol(self._data))
-
- def copy(self, src):
- self._check(pn_data_copy(self._data, src._data))
-
- def format(self):
- sz = 16
- while True:
- err, result = pn_data_format(self._data, sz)
- if err == PN_OVERFLOW:
- sz *= 2
- continue
- else:
- self._check(err)
- return result
-
- def dump(self):
- pn_data_dump(self._data)
-
- def put_dict(self, d):
- self.put_map()
- self.enter()
- try:
- for k, v in d.items():
- self.put_object(k)
- self.put_object(v)
- finally:
- self.exit()
-
- def get_dict(self):
- if self.enter():
- try:
- result = {}
- while self.next():
- k = self.get_object()
- if self.next():
- v = self.get_object()
- else:
- v = None
- result[k] = v
- finally:
- self.exit()
- return result
-
- def put_sequence(self, s):
- self.put_list()
- self.enter()
- try:
- for o in s:
- self.put_object(o)
- finally:
- self.exit()
-
- def get_sequence(self):
- if self.enter():
- try:
- result = []
- while self.next():
- result.append(self.get_object())
- finally:
- self.exit()
- return result
-
- def get_py_described(self):
- if self.enter():
- try:
- self.next()
- descriptor = self.get_object()
- self.next()
- value = self.get_object()
- finally:
- self.exit()
- return Described(descriptor, value)
-
- def put_py_described(self, d):
- self.put_described()
- self.enter()
- try:
- self.put_object(d.descriptor)
- self.put_object(d.value)
- finally:
- self.exit()
-
- def get_py_array(self):
- """
- If the current node is an array, return an Array object
- representing the array and its contents. Otherwise return None.
- This is a convenience wrapper around get_array, enter, etc.
- """
-
- count, described, type = self.get_array()
- if type is None: return None
- if self.enter():
- try:
- if described:
- self.next()
- descriptor = self.get_object()
- else:
- descriptor = UNDESCRIBED
- elements = []
- while self.next():
- elements.append(self.get_object())
- finally:
- self.exit()
- return Array(descriptor, type, *elements)
-
- def put_py_array(self, a):
- described = a.descriptor != UNDESCRIBED
- self.put_array(described, a.type)
- self.enter()
- try:
- if described:
- self.put_object(a.descriptor)
- for e in a.elements:
- self.put_object(e)
- finally:
- self.exit()
-
- put_mappings = {
- None.__class__: lambda s, _: s.put_null(),
- bool: put_bool,
- dict: put_dict,
- list: put_sequence,
- tuple: put_sequence,
- unicode: put_string,
- bytes: put_binary,
- symbol: put_symbol,
- int: put_long,
- char: put_char,
- long: put_long,
- ulong: put_ulong,
- timestamp: put_timestamp,
- float: put_double,
- uuid.UUID: put_uuid,
- Described: put_py_described,
- Array: put_py_array
- }
- get_mappings = {
- NULL: lambda s: None,
- BOOL: get_bool,
- BYTE: get_byte,
- UBYTE: get_ubyte,
- SHORT: get_short,
- USHORT: get_ushort,
- INT: get_int,
- UINT: get_uint,
- CHAR: get_char,
- LONG: get_long,
- ULONG: get_ulong,
- TIMESTAMP: get_timestamp,
- FLOAT: get_float,
- DOUBLE: get_double,
- DECIMAL32: get_decimal32,
- DECIMAL64: get_decimal64,
- DECIMAL128: get_decimal128,
- UUID: get_uuid,
- BINARY: get_binary,
- STRING: get_string,
- SYMBOL: get_symbol,
- DESCRIBED: get_py_described,
- ARRAY: get_py_array,
- LIST: get_sequence,
- MAP: get_dict
- }
-
-
- def put_object(self, obj):
- putter = self.put_mappings[obj.__class__]
- putter(self, obj)
-
- def get_object(self):
- type = self.type()
- if type is None: return None
- getter = self.get_mappings.get(type)
- if getter:
- return getter(self)
- else:
- return UnmappedType(str(type))
-
-class ConnectionException(ProtonException):
- pass
-
-class Endpoint(object):
-
- LOCAL_UNINIT = PN_LOCAL_UNINIT
- REMOTE_UNINIT = PN_REMOTE_UNINIT
- LOCAL_ACTIVE = PN_LOCAL_ACTIVE
- REMOTE_ACTIVE = PN_REMOTE_ACTIVE
- LOCAL_CLOSED = PN_LOCAL_CLOSED
- REMOTE_CLOSED = PN_REMOTE_CLOSED
-
- def __init__(self):
- self.condition = None
- self._release_invoked = False
-
- def _release(self):
- """Release the underlying C Engine resource."""
- if not self._release_invoked:
- for c in self._children:
- c._release()
- self._free_resource()
- self.connection._releasing(self)
- self._release_invoked = True
-
- def _update_cond(self):
- obj2cond(self.condition, self._get_cond_impl())
-
- @property
- def remote_condition(self):
- return cond2obj(self._get_remote_cond_impl())
-
- # the following must be provided by subclasses
- def _get_cond_impl(self):
- assert False, "Subclass must override this!"
-
- def _get_remote_cond_impl(self):
- assert False, "Subclass must override this!"
-
-class Condition:
-
- def __init__(self, name, description=None, info=None):
- self.name = name
- self.description = description
- self.info = info
-
- def __repr__(self):
- return "Condition(%s)" % ", ".join([repr(x) for x in
- (self.name, self.description, self.info)
- if x])
-
- def __eq__(self, o):
- if not isinstance(o, Condition): return False
- return self.name == o.name and \
- self.description == o.description and \
- self.info == o.info
-
-def obj2cond(obj, cond):
- pn_condition_clear(cond)
- if obj:
- pn_condition_set_name(cond, str(obj.name))
- pn_condition_set_description(cond, obj.description)
- info = Data(pn_condition_info(cond))
- if obj.info:
- info.put_object(obj.info)
-
-def cond2obj(cond):
- if pn_condition_is_set(cond):
- return Condition(pn_condition_get_name(cond),
- pn_condition_get_description(cond),
- dat2obj(pn_condition_info(cond)))
- else:
- return None
-
-def dat2obj(dimpl):
- if dimpl:
- d = Data(dimpl)
- d.rewind()
- d.next()
- obj = d.get_object()
- d.rewind()
- return obj
-
-def obj2dat(obj, dimpl):
- if obj is not None:
- d = Data(dimpl)
- d.put_object(obj)
-
-def secs2millis(secs):
- return long(secs*1000)
-
-def millis2secs(millis):
- return float(millis)/1000.0
-
-class Connection(Endpoint):
-
- @staticmethod
- def _wrap_connection(c_conn):
- """Maintain only a single instance of this class for each Connection
- object that exists in the the C Engine. This is done by storing a (weak)
- reference to the python instance in the context field of the C object.
- """
- if not c_conn: return None
- py_conn = pn_void2py(pn_connection_get_context(c_conn))
- if py_conn: return py_conn
- wrapper = Connection(_conn=c_conn)
- return wrapper
-
- def __init__(self, _conn=None):
- Endpoint.__init__(self)
- if _conn:
- self._conn = _conn
- else:
- self._conn = pn_connection()
- pn_connection_set_context(self._conn, pn_py2void(self))
- self.offered_capabilities = None
- self.desired_capabilities = None
- self.properties = None
- self._sessions = set()
-
- def __del__(self):
- if hasattr(self, "_conn") and self._conn:
- self._release()
-
- def free(self):
- self._release()
-
- @property
- def _children(self):
- return self._sessions
-
- @property
- def connection(self):
- return self
-
- def _free_resource(self):
- pn_connection_free(self._conn)
-
- def _released(self):
- self._conn = None
-
- def _releasing(self, child):
- coll = getattr(self, "_collector", None)
- if coll: coll = coll()
- if coll:
- coll._contexts.add(child)
- else:
- child._released()
-
- def _check(self, err):
- if err < 0:
- exc = EXCEPTIONS.get(err, ConnectionException)
- raise exc("[%s]: %s" % (err, pn_connection_error(self._conn)))
- else:
- return err
-
- def _get_cond_impl(self):
- return pn_connection_condition(self._conn)
-
- def _get_remote_cond_impl(self):
- return pn_connection_remote_condition(self._conn)
-
- def collect(self, collector):
- if collector is None:
- pn_connection_collect(self._conn, None)
- else:
- pn_connection_collect(self._conn, collector._impl)
- self._collector = weakref.ref(collector)
-
- def _get_container(self):
- return pn_connection_get_container(self._conn)
- def _set_container(self, name):
- return pn_connection_set_container(self._conn, name)
-
- container = property(_get_container, _set_container)
-
- def _get_hostname(self):
- return pn_connection_get_hostname(self._conn)
- def _set_hostname(self, name):
- return pn_connection_set_hostname(self._conn, name)
-
- hostname = property(_get_hostname, _set_hostname)
-
- @property
- def remote_container(self):
- return pn_connection_remote_container(self._conn)
-
- @property
- def remote_hostname(self):
- return pn_connection_remote_hostname(self._conn)
-
- @property
- def remote_offered_capabilities(self):
- return dat2obj(pn_connection_remote_offered_capabilities(self._conn))
-
- @property
- def remote_desired_capabilities(self):
- return dat2obj(pn_connection_remote_desired_capabilities(self._conn))
-
- @property
- def remote_properties(self):
- return dat2obj(pn_connection_remote_properties(self._conn))
-
- def open(self):
- obj2dat(self.offered_capabilities,
- pn_connection_offered_capabilities(self._conn))
- obj2dat(self.desired_capabilities,
- pn_connection_desired_capabilities(self._conn))
- obj2dat(self.properties, pn_connection_properties(self._conn))
- pn_connection_open(self._conn)
-
- def close(self):
- self._update_cond()
- pn_connection_close(self._conn)
-
- @property
- def state(self):
- return pn_connection_state(self._conn)
-
- def session(self):
- return Session._wrap_session(pn_session(self._conn))
-
- def session_head(self, mask):
- return Session._wrap_session(pn_session_head(self._conn, mask))
-
- def link_head(self, mask):
- return Link._wrap_link(pn_link_head(self._conn, mask))
-
- @property
- def work_head(self):
- return Delivery._wrap_delivery(pn_work_head(self._conn))
-
- @property
- def error(self):
- return pn_error_code(pn_connection_error(self._conn))
-
-class SessionException(ProtonException):
- pass
-
-class Session(Endpoint):
-
- @staticmethod
- def _wrap_session(c_ssn):
- """Maintain only a single instance of this class for each Session object that
- exists in the C Engine.
- """
- if c_ssn is None: return None
- py_ssn = pn_void2py(pn_session_get_context(c_ssn))
- if py_ssn: return py_ssn
- wrapper = Session(c_ssn)
- return wrapper
-
- def __init__(self, ssn):
- Endpoint.__init__(self)
- self._ssn = ssn
- pn_session_set_context(self._ssn, pn_py2void(self))
- self._links = set()
- self.connection._sessions.add(self)
-
- @property
- def _children(self):
- return self._links
-
- def _free_resource(self):
- pn_session_free(self._ssn)
-
- def _released(self):
- self._ssn = None
-
- def free(self):
- """Release the Session, freeing its resources.
-
- Call this when you no longer need the session. This will allow the
- session's resources to be reclaimed. Once called, you should no longer
- reference the session.
-
- """
- self.connection._sessions.remove(self)
- self._release()
-
- def _get_cond_impl(self):
- return pn_session_condition(self._ssn)
-
- def _get_remote_cond_impl(self):
- return pn_session_remote_condition(self._ssn)
-
- def _get_incoming_capacity(self):
- return pn_session_get_incoming_capacity(self._ssn)
-
- def _set_incoming_capacity(self, capacity):
- pn_session_set_incoming_capacity(self._ssn, capacity)
-
- incoming_capacity = property(_get_incoming_capacity, _set_incoming_capacity)
-
- @property
- def outgoing_bytes(self):
- return pn_session_outgoing_bytes(self._ssn)
-
- @property
- def incoming_bytes(self):
- return pn_session_incoming_bytes(self._ssn)
-
- def open(self):
- pn_session_open(self._ssn)
-
- def close(self):
- self._update_cond()
- pn_session_close(self._ssn)
-
- def next(self, mask):
- return Session._wrap_session(pn_session_next(self._ssn, mask))
-
- @property
- def state(self):
- return pn_session_state(self._ssn)
-
- @property
- def connection(self):
- return Connection._wrap_connection(pn_session_connection(self._ssn))
-
- def sender(self, name):
- return Link._wrap_link(pn_sender(self._ssn, name))
-
- def receiver(self, name):
- return Link._wrap_link(pn_receiver(self._ssn, name))
-
-class LinkException(ProtonException):
- pass
-
-class Link(Endpoint):
-
- SND_UNSETTLED = PN_SND_UNSETTLED
- SND_SETTLED = PN_SND_SETTLED
- SND_MIXED = PN_SND_MIXED
-
- RCV_FIRST = PN_RCV_FIRST
- RCV_SECOND = PN_RCV_SECOND
-
- @staticmethod
- def _wrap_link(c_link):
- """Maintain only a single instance of this class for each Session object that
- exists in the C Engine.
- """
- if c_link is None: return None
- py_link = pn_void2py(pn_link_get_context(c_link))
- if py_link: return py_link
- if pn_link_is_sender(c_link):
- wrapper = Sender(c_link)
- else:
- wrapper = Receiver(c_link)
- return wrapper
-
- def __init__(self, c_link):
- Endpoint.__init__(self)
- self._link = c_link
- pn_link_set_context(self._link, pn_py2void(self))
- self._deliveries = set()
- self.session._links.add(self)
-
- @property
- def _children(self):
- return self._deliveries
-
- def _free_resource(self):
- pn_link_free(self._link)
-
- def _released(self):
- self._link = None
-
- def free(self):
- """Release the Link, freeing its resources"""
- self.session._links.remove(self)
- self._release()
-
- def _check(self, err):
- if err < 0:
- exc = EXCEPTIONS.get(err, LinkException)
- raise exc("[%s]: %s" % (err, pn_link_error(self._link)))
- else:
- return err
-
- def _get_cond_impl(self):
- return pn_link_condition(self._link)
-
- def _get_remote_cond_impl(self):
- return pn_link_remote_condition(self._link)
-
- def open(self):
- pn_link_open(self._link)
-
- def close(self):
- self._update_cond()
- pn_link_close(self._link)
-
- @property
- def state(self):
- return pn_link_state(self._link)
-
- @property
- def source(self):
- return Terminus(pn_link_source(self._link))
-
- @property
- def target(self):
- return Terminus(pn_link_target(self._link))
-
- @property
- def remote_source(self):
- return Terminus(pn_link_remote_source(self._link))
- @property
- def remote_target(self):
- return Terminus(pn_link_remote_target(self._link))
-
- @property
- def session(self):
- return Session._wrap_session(pn_link_session(self._link))
-
- @property
- def connection(self):
- return self.session.connection
-
- def delivery(self, tag):
- return Delivery._wrap_delivery(pn_delivery(self._link, tag))
-
- @property
- def current(self):
- return Delivery._wrap_delivery(pn_link_current(self._link))
-
- def advance(self):
- return pn_link_advance(self._link)
-
- @property
- def unsettled(self):
- return pn_link_unsettled(self._link)
-
- @property
- def credit(self):
- return pn_link_credit(self._link)
-
- @property
- def available(self):
- return pn_link_available(self._link)
-
- @property
- def queued(self):
- return pn_link_queued(self._link)
-
- def next(self, mask):
- return Link._wrap_link(pn_link_next(self._link, mask))
-
- @property
- def name(self):
- return pn_link_name(self._link)
-
- @property
- def is_sender(self):
- return pn_link_is_sender(self._link)
-
- @property
- def is_receiver(self):
- return pn_link_is_receiver(self._link)
-
- @property
- def remote_snd_settle_mode(self):
- return pn_link_remote_snd_settle_mode(self._link)
-
- @property
- def remote_rcv_settle_mode(self):
- return pn_link_remote_rcv_settle_mode(self._link)
-
- def _get_snd_settle_mode(self):
- return pn_link_snd_settle_mode(self._link)
- def _set_snd_settle_mode(self, mode):
- pn_link_set_snd_settle_mode(self._link, mode)
- snd_settle_mode = property(_get_snd_settle_mode, _set_snd_settle_mode)
-
- def _get_rcv_settle_mode(self):
- return pn_link_rcv_settle_mode(self._link)
- def _set_rcv_settle_mode(self, mode):
- pn_link_set_rcv_settle_mode(self._link, mode)
- rcv_settle_mode = property(_get_rcv_settle_mode, _set_rcv_settle_mode)
-
- def drained(self):
- return pn_link_drained(self._link)
-
- def detach(self):
- return pn_link_detach(self._link)
-
-class Terminus(object):
-
- UNSPECIFIED = PN_UNSPECIFIED
- SOURCE = PN_SOURCE
- TARGET = PN_TARGET
- COORDINATOR = PN_COORDINATOR
-
- NONDURABLE = PN_NONDURABLE
- CONFIGURATION = PN_CONFIGURATION
- DELIVERIES = PN_DELIVERIES
-
- DIST_MODE_UNSPECIFIED = PN_DIST_MODE_UNSPECIFIED
- DIST_MODE_COPY = PN_DIST_MODE_COPY
- DIST_MODE_MOVE = PN_DIST_MODE_MOVE
-
- def __init__(self, impl):
- self._impl = impl
-
- def _check(self, err):
- if err < 0:
- exc = EXCEPTIONS.get(err, LinkException)
- raise exc("[%s]" % err)
- else:
- return err
-
- def _get_type(self):
- return pn_terminus_get_type(self._impl)
- def _set_type(self, type):
- self._check(pn_terminus_set_type(self._impl, type))
- type = property(_get_type, _set_type)
-
- def _get_address(self):
- return pn_terminus_get_address(self._impl)
- def _set_address(self, address):
- self._check(pn_terminus_set_address(self._impl, address))
- address = property(_get_address, _set_address)
-
- def _get_durability(self):
- return pn_terminus_get_durability(self._impl)
- def _set_durability(self, seconds):
- self._check(pn_terminus_set_durability(self._impl, seconds))
- durability = property(_get_durability, _set_durability)
-
- def _get_expiry_policy(self):
- return pn_terminus_get_expiry_policy(self._impl)
- def _set_expiry_policy(self, seconds):
- self._check(pn_terminus_set_expiry_policy(self._impl, seconds))
- expiry_policy = property(_get_expiry_policy, _set_expiry_policy)
-
- def _get_timeout(self):
- return pn_terminus_get_timeout(self._impl)
- def _set_timeout(self, seconds):
- self._check(pn_terminus_set_timeout(self._impl, seconds))
- timeout = property(_get_timeout, _set_timeout)
-
- def _is_dynamic(self):
- return pn_terminus_is_dynamic(self._impl)
- def _set_dynamic(self, dynamic):
- self._check(pn_terminus_set_dynamic(self._impl, dynamic))
- dynamic = property(_is_dynamic, _set_dynamic)
-
- def _get_distribution_mode(self):
- return pn_terminus_get_distribution_mode(self._impl)
- def _set_distribution_mode(self, mode):
- self._check(pn_terminus_set_distribution_mode(self._impl, mode))
- distribution_mode = property(_get_distribution_mode, _set_distribution_mode)
-
- @property
- def properties(self):
- return Data(pn_terminus_properties(self._impl))
-
- @property
- def capabilities(self):
- return Data(pn_terminus_capabilities(self._impl))
-
- @property
- def outcomes(self):
- return Data(pn_terminus_outcomes(self._impl))
-
- @property
- def filter(self):
- return Data(pn_terminus_filter(self._impl))
-
- def copy(self, src):
- self._check(pn_terminus_copy(self._impl, src._impl))
-
-class Sender(Link):
-
- def __init__(self, c_link):
- super(Sender, self).__init__(c_link)
-
- def offered(self, n):
- pn_link_offered(self._link, n)
-
- def send(self, bytes):
- return self._check(pn_link_send(self._link, bytes))
-
-class Receiver(Link):
-
- def __init__(self, c_link):
- super(Receiver, self).__init__(c_link)
-
- def flow(self, n):
- pn_link_flow(self._link, n)
-
- def recv(self, limit):
- n, bytes = pn_link_recv(self._link, limit)
- if n == PN_EOS:
- return None
- else:
- self._check(n)
- return bytes
-
- def drain(self, n):
- pn_link_drain(self._link, n)
-
- def draining(self):
- return pn_link_draining(self._link)
-
-class NamedInt(int):
-
- values = {}
-
- def __new__(cls, i, name):
- ni = super(NamedInt, cls).__new__(cls, i)
- cls.values[i] = ni
- return ni
-
- def __init__(self, i, name):
- self.name = name
-
- def __repr__(self):
- return self.name
-
- def __str__(self):
- return self.name
-
- @classmethod
- def get(cls, i):
- return cls.values.get(i, i)
-
-class DispositionType(NamedInt):
- values = {}
-
-class Disposition(object):
-
- RECEIVED = DispositionType(PN_RECEIVED, "RECEIVED")
- ACCEPTED = DispositionType(PN_ACCEPTED, "ACCEPTED")
- REJECTED = DispositionType(PN_REJECTED, "REJECTED")
- RELEASED = DispositionType(PN_RELEASED, "RELEASED")
- MODIFIED = DispositionType(PN_MODIFIED, "MODIFIED")
-
- def __init__(self, impl, local):
- self._impl = impl
- self.local = local
- self._data = None
- self._condition = None
- self._annotations = None
-
- @property
- def type(self):
- return DispositionType.get(pn_disposition_type(self._impl))
-
- def _get_section_number(self):
- return pn_disposition_get_section_number(self._impl)
- def _set_section_number(self, n):
- pn_disposition_set_section_number(self._impl, n)
- section_number = property(_get_section_number, _set_section_number)
-
- def _get_section_offset(self):
- return pn_disposition_get_section_offset(self._impl)
- def _set_section_offset(self, n):
- pn_disposition_set_section_offset(self._impl, n)
- section_offset = property(_get_section_offset, _set_section_offset)
-
- def _get_failed(self):
- return pn_disposition_is_failed(self._impl)
- def _set_failed(self, b):
- pn_disposition_set_failed(self._impl, b)
- failed = property(_get_failed, _set_failed)
-
- def _get_undeliverable(self):
- return pn_disposition_is_undeliverable(self._impl)
- def _set_undeliverable(self, b):
- pn_disposition_set_undeliverable(self._impl, b)
- undeliverable = property(_get_undeliverable, _set_undeliverable)
-
- def _get_data(self):
- if self.local:
- return self._data
- else:
- return dat2obj(pn_disposition_data(self._impl))
- def _set_data(self, obj):
- if self.local:
- self._data = obj
- else:
- raise AttributeError("data attribute is read-only")
- data = property(_get_data, _set_data)
-
- def _get_annotations(self):
- if self.local:
- return self._annotations
- else:
- return dat2obj(pn_disposition_annotations(self._impl))
- def _set_annotations(self, obj):
- if self.local:
- self._annotations = obj
- else:
- raise AttributeError("annotations attribute is read-only")
- annotations = property(_get_annotations, _set_annotations)
-
- def _get_condition(self):
- if self.local:
- return self._condition
- else:
- return cond2obj(pn_disposition_condition(self._impl))
- def _set_condition(self, obj):
- if self.local:
- self._condition = obj
- else:
- raise AttributeError("condition attribute is read-only")
- condition = property(_get_condition, _set_condition)
-
-class Delivery(object):
-
- RECEIVED = Disposition.RECEIVED
- ACCEPTED = Disposition.ACCEPTED
- REJECTED = Disposition.REJECTED
- RELEASED = Disposition.RELEASED
- MODIFIED = Disposition.MODIFIED
-
- @staticmethod
- def _wrap_delivery(c_dlv):
- """Maintain only a single instance of this class for each Delivery object that
- exists in the C Engine.
- """
- if not c_dlv: return None
- py_dlv = pn_void2py(pn_delivery_get_context(c_dlv))
- if py_dlv: return py_dlv
- wrapper = Delivery(c_dlv)
- return wrapper
-
- def __init__(self, dlv):
- self._dlv = dlv
- pn_delivery_set_context(self._dlv, pn_py2void(self))
- self.local = Disposition(pn_delivery_local(self._dlv), True)
- self.remote = Disposition(pn_delivery_remote(self._dlv), False)
- self.link._deliveries.add(self)
-
- def __del__(self):
- self._release()
-
- def _release(self):
- """Release the underlying C Engine resource."""
- if self._dlv:
- pn_delivery_set_context(self._dlv, pn_py2void(None))
- pn_delivery_settle(self._dlv)
- self._dlv = None
-
- @property
- def released(self):
- return self._dlv is None
-
- @property
- def tag(self):
- return pn_delivery_tag(self._dlv)
-
- @property
- def writable(self):
- return pn_delivery_writable(self._dlv)
-
- @property
- def readable(self):
- return pn_delivery_readable(self._dlv)
-
- @property
- def updated(self):
- return pn_delivery_updated(self._dlv)
-
- def update(self, state):
- obj2dat(self.local._data, pn_disposition_data(self.local._impl))
- obj2dat(self.local._annotations, pn_disposition_annotations(self.local._impl))
- obj2cond(self.local._condition, pn_disposition_condition(self.local._impl))
- pn_delivery_update(self._dlv, state)
-
- @property
- def pending(self):
- return pn_delivery_pending(self._dlv)
-
- @property
- def partial(self):
- return pn_delivery_partial(self._dlv)
-
- @property
- def local_state(self):
- return DispositionType.get(pn_delivery_local_state(self._dlv))
-
- @property
- def remote_state(self):
- return DispositionType.get(pn_delivery_remote_state(self._dlv))
-
- @property
- def settled(self):
- return pn_delivery_settled(self._dlv)
-
- def settle(self):
- """Release the delivery"""
- self.link._deliveries.remove(self)
- self._release()
-
- @property
- def work_next(self):
- return Delivery._wrap_delivery(pn_work_next(self._dlv))
-
- @property
- def link(self):
- return Link._wrap_link(pn_delivery_link(self._dlv))
-
-class TransportException(ProtonException):
- pass
-
-class Transport(object):
-
- TRACE_OFF = PN_TRACE_OFF
- TRACE_DRV = PN_TRACE_DRV
- TRACE_FRM = PN_TRACE_FRM
- TRACE_RAW = PN_TRACE_RAW
-
- CLIENT = 1
- SERVER = 2
-
- @staticmethod
- def _wrap_transport(c_trans):
- if not c_trans: return None
- wrapper = Transport(_trans=c_trans)
- return wrapper
-
- def __init__(self, mode=None, _trans=None):
- if not mode and not _trans:
- self._trans = pn_transport()
- elif not mode:
- self._shared_trans = True
- self._trans = _trans
- elif mode==Transport.CLIENT:
- self._trans = pn_transport()
- elif mode==Transport.SERVER:
- self._trans = pn_transport()
- pn_transport_set_server(self._trans)
- else:
- raise TransportException("Cannot initialise Transport from mode: %s" % str(mode))
- self._sasl = None
- self._ssl = None
-
- def __del__(self):
- if hasattr(self, "_trans"):
- if not hasattr(self, "_shared_trans"):
- pn_transport_free(self._trans)
- if hasattr(self, "_sasl") and self._sasl:
- # pn_transport_free deallocs the C sasl associated with the
- # transport, so erase the reference if a SASL object was used.
- self._sasl._sasl = None
- self._sasl = None
- if hasattr(self, "_ssl") and self._ssl:
- # ditto the owned c SSL object
- self._ssl._ssl = None
- self._ssl = None
- del self._trans
-
- def _check(self, err):
- if err < 0:
- exc = EXCEPTIONS.get(err, TransportException)
- raise exc("[%s]: %s" % (err, pn_error_text(pn_transport_error(self._trans))))
- else:
- return err
-
- def bind(self, connection):
- """Assign a connection to the transport"""
- self._check(pn_transport_bind(self._trans, connection._conn))
- # keep python connection from being garbage collected:
- self._connection = connection
-
- def unbind(self):
- """Release the connection"""
- self._check(pn_transport_unbind(self._trans))
- self._connection = None
-
- def trace(self, n):
- pn_transport_trace(self._trans, n)
-
- def tick(self, now):
- """Process any timed events (like heartbeat generation).
- now = seconds since epoch (float).
- """
- return millis2secs(pn_transport_tick(self._trans, secs2millis(now)))
-
- def capacity(self):
- c = pn_transport_capacity(self._trans)
- if c >= PN_EOS:
- return c
- else:
- return self._check(c)
-
- def push(self, bytes):
- n = self._check(pn_transport_push(self._trans, bytes))
- if n != len(bytes):
- raise OverflowError("unable to process all bytes")
-
- def close_tail(self):
- self._check(pn_transport_close_tail(self._trans))
-
- def pending(self):
- p = pn_transport_pending(self._trans)
- if p >= PN_EOS:
- return p
- else:
- return self._check(p)
-
- def peek(self, size):
- cd, out = pn_transport_peek(self._trans, size)
- if cd == PN_EOS:
- return None
- else:
- self._check(cd)
- return out
-
- def pop(self, size):
- pn_transport_pop(self._trans, size)
-
- def close_head(self):
- self._check(pn_transport_close_head(self._trans))
-
- @property
- def closed(self):
- return pn_transport_closed(self._trans)
-
- # AMQP 1.0 max-frame-size
- def _get_max_frame_size(self):
- return pn_transport_get_max_frame(self._trans)
-
- def _set_max_frame_size
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[26/35] qpid-proton git commit: NO-JIRA: More Ruby rdoc cleanup.
Posted by gs...@apache.org.
NO-JIRA: More Ruby rdoc cleanup.
Turn off including the licensing headers repeatedly in the documentation
generated.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/23354652
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/23354652
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/23354652
Branch: refs/heads/examples
Commit: 233546525867119f652d4b3ccc5b58ca64878745
Parents: 6a78d2f
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Fri Nov 21 08:33:50 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Mon Nov 24 08:16:48 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/ruby/lib/qpid_proton.rb | 4 ++--
proton-c/bindings/ruby/lib/qpid_proton/array.rb | 10 +++++-----
proton-c/bindings/ruby/lib/qpid_proton/data.rb | 10 ++++------
proton-c/bindings/ruby/lib/qpid_proton/described.rb | 4 ++--
.../bindings/ruby/lib/qpid_proton/exception_handling.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/exceptions.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/filters.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/hash.rb | 6 +++---
proton-c/bindings/ruby/lib/qpid_proton/mapping.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/message.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/message_format.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/messenger.rb | 4 ++--
proton-c/bindings/ruby/lib/qpid_proton/selectable.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/strings.rb | 4 ++--
proton-c/bindings/ruby/lib/qpid_proton/subscription.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/tracker.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/tracker_status.rb | 8 ++++----
proton-c/bindings/ruby/lib/qpid_proton/version.rb | 11 +++++++----
18 files changed, 67 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton.rb b/proton-c/bindings/ruby/lib/qpid_proton.rb
index 4da4e11..0b7e77c 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,7 +15,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
require "cproton"
require "date"
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/array.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/array.rb b/proton-c/bindings/ruby/lib/qpid_proton/array.rb
index 34e1c67..a4294a3 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/array.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/array.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,16 +15,16 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
#--
# Patch the Array class to provide methods for adding its contents
# to a Qpid::Proton::Data instance.
#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# Holds the information for an AMQP Array compound type.
#
@@ -54,7 +54,7 @@ module Qpid
end
-class Array
+class Array # :nodoc:
# Used to declare an array as an AMQP array.
#
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/data.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/data.rb b/proton-c/bindings/ruby/lib/qpid_proton/data.rb
index 1e515c8..b6b3002 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/data.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/data.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,13 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
-
-require 'cproton'
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# +DataError+ is raised when an error occurs while encoding
# or decoding data.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/described.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/described.rb b/proton-c/bindings/ruby/lib/qpid_proton/described.rb
index adb7f8c..98679c2 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/described.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/described.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,7 +15,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
module Qpid # :nodoc:
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb b/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
index 4dce3ef..fd66865 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/exception_handling.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# Provides mixin functionality for dealing with exception conditions.
#
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/exceptions.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/exceptions.rb b/proton-c/bindings/ruby/lib/qpid_proton/exceptions.rb
index 094f6fe..e3c3d19 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/exceptions.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/exceptions.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
module Error
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/filters.rb b/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
index 46c9bf7..370d017 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/filters.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
module Filters
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/hash.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/hash.rb b/proton-c/bindings/ruby/lib/qpid_proton/hash.rb
index bd7c1b5..1e19da1 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/hash.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/hash.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,14 +15,14 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
#--
# Patch the Hash class to provide methods for adding its contents
# to a Qpid::Proton::Data instance.
#++
-class Hash
+class Hash # :nodoc:
# Places the contents of the hash into the specified data object.
#
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb b/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
index 836bcd9..b2e4b86 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/mapping.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,7 +15,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
module Qpid # :nodoc:
@@ -110,7 +110,7 @@ module Qpid # :nodoc:
UTFString,
BinaryString])
- class << STRING
+ class << STRING # :nodoc:
def put(data, value)
# if we have a symbol then convert it to a string
value = value.to_s if value.is_a?(Symbol)
@@ -144,7 +144,7 @@ module Qpid # :nodoc:
LIST = Mapping.new(Cproton::PN_LIST, "list", [::Array], "get_array")
MAP = Mapping.new(Cproton::PN_MAP, "map", [::Hash], "get_map")
- class << MAP
+ class << MAP # :nodoc:
def put(data, map)
data.put_map
data.enter
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/message.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/message.rb b/proton-c/bindings/ruby/lib/qpid_proton/message.rb
index b7a4fd0..3077ab1 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/message.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/message.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# A Message represents an addressable quantity of data.
#
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/message_format.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/message_format.rb b/proton-c/bindings/ruby/lib/qpid_proton/message_format.rb
index 120ff5f..62b6f1a 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/message_format.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/message_format.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
class MessageFormat
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index f17205d..5a16c50 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -17,9 +17,9 @@
# under the License.
#
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# The +Messenger+ class defines a high level interface for
# sending and receiving Messages. Every Messenger contains
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
index 34a030f..33554cd 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/selectable.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# Selectable enables accessing the underlying file descriptors
# for Messenger.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/strings.rb b/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
index d8f5851..44eba02 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/strings.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,7 +15,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
module Qpid # :nodoc:
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/subscription.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/subscription.rb b/proton-c/bindings/ruby/lib/qpid_proton/subscription.rb
index fbfafea..21d9281 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/subscription.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/subscription.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# A +Subscription+ is an opaque object for working with a +Messenger+'s
# subscriptions.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/tracker.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/tracker.rb b/proton-c/bindings/ruby/lib/qpid_proton/tracker.rb
index bf99e30..7de271a 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/tracker.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/tracker.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# A +Tracker+ is used to track the disposition of a +Message+.
#
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/tracker_status.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/tracker_status.rb b/proton-c/bindings/ruby/lib/qpid_proton/tracker_status.rb
index b74a4c0..81c9ea3 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/tracker_status.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/tracker_status.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,11 +15,11 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
# TrackerStatus contains symbols that represent the status value for a
# Tracker.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/23354652/proton-c/bindings/ruby/lib/qpid_proton/version.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/version.rb b/proton-c/bindings/ruby/lib/qpid_proton/version.rb
index 006353c..ebc92c5 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/version.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/version.rb
@@ -1,4 +1,4 @@
-#
+#--
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,13 +15,16 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-#
+#++
-module Qpid
+module Qpid # :nodoc:
- module Proton
+ module Proton # :nodoc:
+ # The major version for the underlying Proton library.
VERSION_MAJOR = Cproton::PN_VERSION_MAJOR
+
+ # The minor version for the underlying Proton library.
VERSION_MINOR = Cproton::PN_VERSION_MINOR
end
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[07/35] qpid-proton git commit: PROTON-743: Provide a means to clear
errors in a Ruby Messenger.
Posted by gs...@apache.org.
PROTON-743: Provide a means to clear errors in a Ruby Messenger.
Added the clear_error method to allow clearing out the error state in a
Ruby Messenger object.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6504db6f
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6504db6f
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6504db6f
Branch: refs/heads/examples
Commit: 6504db6fcebc33fe57eef1b5e334b32e4b14055c
Parents: b57f45d
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Mon Nov 17 16:04:40 2014 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Mon Nov 17 16:04:40 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/ruby/lib/qpid_proton/messenger.rb | 9 +++++++++
.../ruby/spec/qpid/proton/messenger_spec.rb | 16 ++++++++++++++++
2 files changed, 25 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6504db6f/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
index 3dca86c..2581e2b 100644
--- a/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
+++ b/proton-c/bindings/ruby/lib/qpid_proton/messenger.rb
@@ -179,6 +179,15 @@ module Qpid
Cproton.pn_error_text(Cproton.pn_messenger_error(@impl))
end
+ # Clears the current error state.
+ #
+ def clear_error
+ error = Cproton.pn_messenger_error(@impl)
+ unless error.nil?
+ Cproton.pn_error_clear(error)
+ end
+ end
+
# Currently a no-op placeholder.
# For future compatibility, do not send or recv messages
# before starting the +Messenger+.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6504db6f/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb b/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
index 86050ed..1b888c1 100644
--- a/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
+++ b/proton-c/bindings/ruby/spec/qpid/proton/messenger_spec.rb
@@ -222,6 +222,22 @@ module Qpid
@messenger.passive?.should_not be_true
end
+ it "can clear non-existent errors with failing" do
+ expect {
+ @messenger.clear_error
+ }.to_not raise_error
+ end
+
+ it "can clear errors" do
+ begin
+ @messenger.accept # should cause an error
+ rescue; end
+
+ @messenger.error.should_not be_nil
+ @messenger.clear_error
+ @messenger.error.should be_nil
+ end
+
describe "once started" do
before (:each) do
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[25/35] qpid-proton git commit: restructured cmake file to support
multiple sources
Posted by gs...@apache.org.
restructured cmake file to support multiple sources
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/19130401
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/19130401
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/19130401
Branch: refs/heads/examples
Commit: 1913040155414f7fb037a0584a9dafa4a14533f0
Parents: f5cbab5
Author: Rafael Schloming <rh...@alum.mit.edu>
Authored: Sat Nov 22 05:25:57 2014 -0500
Committer: Rafael Schloming <rh...@alum.mit.edu>
Committed: Sat Nov 22 06:03:01 2014 -0500
----------------------------------------------------------------------
proton-c/bindings/python/CMakeLists.txt | 32 ++++++++++++++++------------
1 file changed, 18 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/19130401/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index c7eb4aa..6ab1e67 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -52,14 +52,23 @@ if (NOT PYTHON_SITEARCH_PACKAGES)
set (PYTHON_SITEARCH_PACKAGES ${PYTHON_SITEARCH_PACKAGES_DEFAULT})
endif()
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
-install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
+set (pysrc-generated cproton.py)
+set (pysrc proton.py)
+
+macro (py_compile directory files)
+ foreach (src_file ${files})
+ install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile ${src_file}
+ WORKING_DIRECTORY ${directory})")
+ install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile ${src_file}
+ WORKING_DIRECTORY ${directory})")
+ list(APPEND PYTHON_ARTIFACTS ${directory}/${src_file}
+ ${directory}/${src_file}c
+ ${directory}/${src_file}o)
+ endforeach (src_file)
+endmacro(py_compile)
+
+py_compile(${CMAKE_CURRENT_BINARY_DIR} ${pysrc-generated})
+py_compile(${CMAKE_CURRENT_SOURCE_DIR} ${pysrc})
find_program(EPYDOC_EXE epydoc)
mark_as_advanced (EPYDOC_EXE)
@@ -75,12 +84,7 @@ if (EPYDOC_EXE)
${OPTIONAL_ARG})
endif (EPYDOC_EXE)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py
- ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc
- ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo
- ${CMAKE_CURRENT_SOURCE_DIR}/proton.py
- ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc
- ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo
+install(FILES ${PYTHON_ARTIFACTS}
DESTINATION ${PYTHON_SITEARCH_PACKAGES}
COMPONENT Python)
install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[16/35] qpid-proton git commit: PROTON-749: Fix erroneous windows
change due to previous version to changeset.
Posted by gs...@apache.org.
PROTON-749: Fix erroneous windows change due to previous version to changeset.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/0cc91340
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/0cc91340
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/0cc91340
Branch: refs/heads/examples
Commit: 0cc91340dd8fa4701bfcf8ba55691d825a9fa03b
Parents: 0fd34e8
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Nov 20 10:46:32 2014 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Nov 20 10:46:32 2014 -0500
----------------------------------------------------------------------
proton-c/src/windows/driver.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0cc91340/proton-c/src/windows/driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/driver.c b/proton-c/src/windows/driver.c
index 013b422..d446aae 100644
--- a/proton-c/src/windows/driver.c
+++ b/proton-c/src/windows/driver.c
@@ -285,7 +285,8 @@ pn_connector_t *pn_listener_accept(pn_listener_t *l)
pn_connector_t *c = pn_connector_fd(l->driver, sock, NULL);
snprintf(c->name, PN_NAME_MAX, "%s", name);
c->listener = l;
- c->transport = pn_transport_server();
+ c->transport = pn_transport();
+ pn_transport_set_server(c->transport);
c->sasl = pn_sasl(c->transport);
return c;
}
@@ -385,7 +386,7 @@ pn_connector_t *pn_connector(pn_driver_t *driver, const char *host,
pn_socket_t sock = pn_connect(driver->io, host, port);
pn_connector_t *c = pn_connector_fd(driver, sock, context);
- c->transport = pn_transport_client();
+ c->transport = pn_transport();
c->sasl = pn_sasl(c->transport);
snprintf(c->name, PN_NAME_MAX, "%s:%s", host, port);
if (driver->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV))
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org