Re: RFC: new routing functionality for messenger
On Thu, Mar 28, 2013 at 03:11:51PM -0400, Alan Conway wrote: > I am starting to think we need a proton routing plug-in API so that > different choices of routing rules, pattern matching, configuration > files etc. can be implemented without baking one set of choices into > messenger. Such a plugin API could be fairly simple and would allow > choice and composition of functionality from different plug-ins. +1 to that -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Delivering value year after year. Red Hat ranks #1 in value among software vendors. http://www.redhat.com/promo/vendor/ pgp_Vx5mRbfTH.pgp Description: PGP signature
Re: RFC: new routing functionality for messenger
On 03/28/2013 09:11 AM, Ken Giusti wrote: At first I was a bit skeptical whether this really belongs in the messenger API, but I've come to accept that it would have to be. Internally, messenger does perform routing - mapping the 'to' address to the proper connection and link. To me, this new API provides a level of control over that mapping process. That said, the api needs a bit of fleshing out. Assuming that we support multiple routes, then most obviously the api would need to provide the ability to query the route table for a given mapping. I'd also like to see a means for walking the route table in match order. And deletions - can't forget that. And to be clear - the match precedent is determined by the order in which routes are added, correct? That may be hard to manage if the route table is modified over time. Perhaps a route should be given a priority? Or maybe we give routes precedence based on their restrictiveness - matching more restrictive first? I am starting to think we need a proton routing plug-in API so that different choices of routing rules, pattern matching, configuration files etc. can be implemented without baking one set of choices into messenger. Such a plugin API could be fairly simple and would allow choice and composition of functionality from different plug-ins. - Original Message - From: "Rafael Schloming" To: proton@qpid.apache.org Sent: Saturday, March 23, 2013 12:43:07 PM Subject: RFC: new routing functionality for messenger Hi, I've added a new API to messenger that gives the user some control over the internal routing behaviour of a messenger. Please check it out and comment. I've pasted the C API/doxygen below. This is currently only exposed through the python binding via the route method on the Messenger class. --Rafael /** Adds a routing rule to a Messenger's internal routing table. * * The route procedure may be used to influence how a messenger will * internally treat a given address or class of addresses. Every call * to the route procedure will result in messenger appending a routing * rule to its internal routing table. * * Whenever a message is presented to a 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 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": * * pn_messenger_route("foo", "amqp://foo.com"); * * Any message sent to "foobar" will be routed to * "amqp://foo.com/bar": * * pn_messenger_route("foobar", "amqp://foo.com/bar"); * * Any message sent to bar/ will be routed to the corresponding * path within the amqp://bar.com domain: * * pn_messenger_route("bar/*", "amqp://bar.com/$1"); * * Route all messages over TLS: * * pn_messenger_route("amqp:*", "amqps:$1") * * Supply credentials for foo.com: * * pn_messenger_route("amqp://foo.com/*", "amqp://user:passw...@foo.com/$1 "); * * Supply credentials for all domains: * * pn_messenger_route("amqp://*", "amqp://user:password@$1"); * * Route all addresses through a single proxy while preserving the * original destination: * * pn_messenger_route("amqp://%/*", "amqp://user:password@proxy/$1/$2"); * * Route any address through a single broker: * * pn_messenger_route("*", "amqp://user:password@broker/$1"); * * @param[in] messenger the Messenger * @param[in] pattern a glob pattern * @param[in] address an address indicating alternative routing * * @return an error code or zero on success * @see error.h * */ PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern, const char *address);
Re: RFC: new routing functionality for messenger
On Thu, Mar 28, 2013 at 8:59 AM, Ken Giusti wrote: > Not to hijack this thread, but... > > Yes, absolutely - this is a Must Have as far as I'm concerned. > Specifically: > > 1) The application should control whether Reply-to is set or not > (currently always set by messenger) > 2) The application should be able to get its local address (for reply-to) > via messenger rather than require it to configured - the ${me} in the above. > > If no objections I'm gonna JIRA these... > Please feel free. --Rafael
Re: RFC: new routing functionality for messenger
At first I was a bit skeptical whether this really belongs in the messenger API, but I've come to accept that it would have to be. Internally, messenger does perform routing - mapping the 'to' address to the proper connection and link. To me, this new API provides a level of control over that mapping process. That said, the api needs a bit of fleshing out. Assuming that we support multiple routes, then most obviously the api would need to provide the ability to query the route table for a given mapping. I'd also like to see a means for walking the route table in match order. And deletions - can't forget that. And to be clear - the match precedent is determined by the order in which routes are added, correct? That may be hard to manage if the route table is modified over time. Perhaps a route should be given a priority? Or maybe we give routes precedence based on their restrictiveness - matching more restrictive first? -K - Original Message - > From: "Rafael Schloming" > To: proton@qpid.apache.org > Sent: Saturday, March 23, 2013 12:43:07 PM > Subject: RFC: new routing functionality for messenger > > Hi, > > I've added a new API to messenger that gives the user some control > over the > internal routing behaviour of a messenger. Please check it out and > comment. > I've pasted the C API/doxygen below. This is currently only exposed > through > the python binding via the route method on the Messenger class. > > --Rafael > > /** Adds a routing rule to a Messenger's internal routing table. > * > * The route procedure may be used to influence how a messenger will > * internally treat a given address or class of addresses. Every call > * to the route procedure will result in messenger appending a > routing > * rule to its internal routing table. > * > * Whenever a message is presented to a 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 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": > * > * pn_messenger_route("foo", "amqp://foo.com"); > * > * Any message sent to "foobar" will be routed to > * "amqp://foo.com/bar": > * > * pn_messenger_route("foobar", "amqp://foo.com/bar"); > * > * Any message sent to bar/ will be routed to the corresponding > * path within the amqp://bar.com domain: > * > * pn_messenger_route("bar/*", "amqp://bar.com/$1"); > * > * Route all messages over TLS: > * > * pn_messenger_route("amqp:*", "amqps:$1") > * > * Supply credentials for foo.com: > * > * pn_messenger_route("amqp://foo.com/*", > "amqp://user:passw...@foo.com/$1 > "); > * > * Supply credentials for all domains: > * > * pn_messenger_route("amqp://*", "amqp://user:password@$1"); > * > * Route all addresses through a single proxy while preserving the > * original destination: > * > * pn_messenger_route("amqp://%/*", > "amqp://user:password@proxy/$1/$2"); > * > * Route any address through a single broker: > * > * pn_messenger_route("*", "amqp://user:password@broker/$1"); > * > * @param[in] messenger the Messenger > * @param[in] pattern a glob pattern > * @param[in] address an address indicating alternative routing > * > * @return an error code or zero on success > * @see error.h > * > */ > PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const > char > *pattern, > const char *address); > -- -K
Re: RFC: new routing functionality for messenger
Not to hijack this thread, but... - Original Message - > From: "Rafael Schloming" > To: proton@qpid.apache.org > Sent: Tuesday, March 26, 2013 10:00:23 AM > Subject: Re: RFC: new routing functionality for messenger > > On Tue, Mar 26, 2013 at 7:19 AM, Bozo Dragojevic > wrote: > > > On 3/23/13 5:43 PM, Rafael Schloming wrote: > > > >> Hi, > >> > >> I've added a new API to messenger that gives the user some control > >> over > >> the > >> internal routing behaviour of a messenger. Please check it out and > >> comment. > >> I've pasted the C API/doxygen below. This is currently only > >> exposed > >> through > >> the python binding via the route method on the Messenger class. > >> > >> --Rafael > >> > >> /** Adds a routing rule to a Messenger's internal routing table. > >> * > >> * The route procedure may be used to influence how a messenger > >> will > >> * internally treat a given address or class of addresses. Every > >> call > >> * to the route procedure will result in messenger appending a > >> routing > >> * rule to its internal routing table. > >> * > >> * Whenever a message is presented to a 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 messenger will route based on the address supplied in the > >> rule. > >> * > >> > > > > Can you help me work through this use-case: > > > > > > A 'dumb' client, sends a message, and expects a reply: > > > > // client.c > > pn_message_set_address(msg, "amqp://localhost/bla"); > > pn_messenger_put(msgr, msg); > > pn_messenger_receive(msgr,1); > > msg = pn_messenger_get(msgr); > > > > > > > > The peer it connects to uses the new route functionality: > > > > // server.c > > pn_messenger_subscribe(msgr, "~amqp://localhost/bla"); > > > > I'm assuming you mean "amqp://~localhost/blah" above. ;-) > > > > > > 1) Are routes valid to use if there's a subscribe going on. > >I assume yes. > > > > pn_messenger_route(msgr, "*", "amqp://broker/$1"); > > > > It's certainly valid to use both at the same time. > > > > > > 2) How do they interact. > >I assume they don't, routing is only applied to outgoing > >messages. > > > > Actually routing should be applied equally to both, however now that > I > think about it I suspect you need to do the route before you do the > subscribe in order for it to make a difference for the subscribe, > although > I expect that limitation to go away in the next round of changes. > > > > > > 3) Does the order of calls to route and subscribe matter. > >According to 2) it does not. > > > > Actually the order does matter (see above). I expect eventually the > implementation will evolve in such a way that the order does not > matter, > however even so you would effectively end up getting a resubscribe > when the > new route goes into place, e.g. the following sequence of events > could > occur: > > subscribe("foo.com/bar") > ... > ... if you do a recv here, messages might arrive directly from > foo.com > ... > route("foo.com/bar", "fooproxy.com/baz") > ... > ... now you get messages via the proxy > > > > > > pn_messenger_receive(msgr, 1); > > msg = pn_messenger_get(msgr); > > > > /* echo */ > > char *sender = pn_message_get_reply_to(msg); > > pn_message_set_address(msg, sender); > > pn_messenger_put(msgr, msg); > > pn_messenger_send(msgr); > > > > > > 4) What would the pn_message_get_reply_to() return. > >The value as set by the client's messenger would be > > amqp://some-uuid-value > > > > This is a very good question. I don't recall exactly why messenger > sets the > reply_to automatically as it does, it may even be an unintentional > side > effect of a couple of different changes, but I've been thinking that > it > shouldn't actually do this automatically, i.e. that you should
Re: RFC: new routing functionality for messenger
On Wed, Mar 27, 2013 at 8:55 AM, Ted Ross wrote: > > On 03/25/2013 09:30 AM, Rafael Schloming wrote: > >> On Mon, Mar 25, 2013 at 8:36 AM, Ted Ross wrote: >> >> I question the value of having this as part of the API. It seems to me >>> that the Messenger routing table should be part of the configuration of a >>> system (i.e. in a place like /etc/qpid/messenger/, or the Windows >>> Registry, >>> etc.). Eventually, it might be desirable to have an address translation >>> service that can be accessed remotely. I guess I see this translation as >>> being not the concern of the application, but more of the deployment of >>> the >>> application. >>> >>> >>> Initially I was actually going to add the functionality via some kind of >> configuration file as you say. I have a similar conceptual view of the >> functionality as you describe, i.e. it really should only be used as part >> of the deployment/configuration of the messenger, not part of the >> "application work" portion of the API. I ended up going this route for two >> reasons (no pun intended). For starters it was a bit more expedient as I >> didn't have to write some kind of file format parser, but the second, and >> perhaps more important reason, is that I wasn't sure of the implications >> of >> adding dependencies onto files/file systems. I want messenger to be usable >> from embedded devices that might not even have a file system, so I figured >> it would be safer to offer as a pure API. I do think it would be >> appropriate to layer some kind of system integration on top of this API >> just as you describe. >> >> --Rafael >> >> > I agree with your thinking on this. But... > > This brings up the old question of what the purpose of Messenger is. If > it is to be an end-user API, then I think it's too much to ask the user to > provide file parsing capability to load the routing/address-translation > table. Perhaps this should be a downstream-packaging issue, I'm not sure. > For example, Fedora, Ubuntu, Windows, etc. packages could be pre-loaded > with route table loaders appropriate for their environments. One thing we could do here is to provide some kind of pn_messenger_configure(pn_messenger_t *m, const char *path). This could be conditionally compiled and so would be unavailable if you're on some kind of embedded system that couldn't support it. A key thing here would be that it should only parse the file and call into otherwise public parts of the messenger API, i.e. we would want to ensure that there isn't anything special you could do through the config file that you couldn't also do directly through the API. This could be used for more than just the routing table. We could have a section for the messenger name, and for all the ssl cert configuration as well. We could even provide a build time option to configure some kind of search path to load a default configuration. I would expect the downstream packagers would likely build in the default location/search path that is tailored to the distro. --Rafael
Re: RFC: new routing functionality for messenger
On 03/25/2013 09:30 AM, Rafael Schloming wrote: On Mon, Mar 25, 2013 at 8:36 AM, Ted Ross wrote: I question the value of having this as part of the API. It seems to me that the Messenger routing table should be part of the configuration of a system (i.e. in a place like /etc/qpid/messenger/, or the Windows Registry, etc.). Eventually, it might be desirable to have an address translation service that can be accessed remotely. I guess I see this translation as being not the concern of the application, but more of the deployment of the application. Initially I was actually going to add the functionality via some kind of configuration file as you say. I have a similar conceptual view of the functionality as you describe, i.e. it really should only be used as part of the deployment/configuration of the messenger, not part of the "application work" portion of the API. I ended up going this route for two reasons (no pun intended). For starters it was a bit more expedient as I didn't have to write some kind of file format parser, but the second, and perhaps more important reason, is that I wasn't sure of the implications of adding dependencies onto files/file systems. I want messenger to be usable from embedded devices that might not even have a file system, so I figured it would be safer to offer as a pure API. I do think it would be appropriate to layer some kind of system integration on top of this API just as you describe. --Rafael I agree with your thinking on this. But... This brings up the old question of what the purpose of Messenger is. If it is to be an end-user API, then I think it's too much to ask the user to provide file parsing capability to load the routing/address-translation table. Perhaps this should be a downstream-packaging issue, I'm not sure. For example, Fedora, Ubuntu, Windows, etc. packages could be pre-loaded with route table loaders appropriate for their environments. -Ted
Re: RFC: new routing functionality for messenger
On Tue, Mar 26, 2013 at 2:13 PM, Alan Conway wrote: > On 03/25/2013 09:30 AM, Rafael Schloming wrote: > >> On Mon, Mar 25, 2013 at 8:36 AM, Ted Ross wrote: >> >> I generally like this translation facility, though I'll need to think >>> through some use cases to make sure there's sufficient capability in the >>> matching and substitution. >>> >>> >> I would definitely appreciate some more feedback on this area. I think >> some >> real world usage will help us out. I struggled with various options here. >> I >> didn't want to add a dependency onto a regular expression library without >> at least some kind of fallback as I think this functionality is going to >> end up being too useful to be optional. >> >> There are a number of public domain regular expression libraries out there >> (e.g. t-rex) that are basically designed to be small enough and simple >> enough to be sucked into a codebase wholesale for when you can't afford an >> external dependency. I considered grabbing one of those, but I also wasn't >> 100% sure that full on regex was the best/only option here. There is >> something nice and simple about being able to say route("*", "my-uplink") >> as opposed to writing a fullon regex. >> >> I can see possibly even wanting to support multiple syntax options >> eventually, but for starters I decided to keep it simple. I wrote a very >> small glob style matcher with substitution. It's roughly 100 lines of code >> and should work on any platform. I'm entirely open to replacing this with >> something a real regex library if we want or something else entirely, I >> just wanted something simple/portable to start with so we could actually >> play with the functionality and learn a bit more about what is >> appropriate. >> >> >> I question the value of having this as part of the API. It seems to me >>> that the Messenger routing table should be part of the configuration of a >>> system (i.e. in a place like /etc/qpid/messenger/, or the Windows >>> Registry, >>> etc.). Eventually, it might be desirable to have an address translation >>> service that can be accessed remotely. I guess I see this translation as >>> being not the concern of the application, but more of the deployment of >>> the >>> application. >>> >> > I also don't think this belongs in the API. It can be easily be provided > as a "translator" library on top of the public messenger API. In that case > the argument over regexps vs. home-brew pattern matching is less an issue > people, can write translators that use whatever patterns they like, and in > whatever languages they want. I would favour keeping the messenger API as > simple and focused as possible and provide additional services as layers on > top. Even if we want a C implementation with multiple language bindings > that can still be a separate library to the messenger. > I don't think you can provide equivalent functionality via translation. The routing table is actually influencing what the messenger is doing internally. A translation layer built on top of messenger would need to modify the message address in order to achieve a similar effect, but then the original destination of the message would be lost. Thinking about a proxy use case might illustrate why it needs to be builtin. Let's say we want to configure an app to route all of its messages through a given proxy. The proxy might do some security checks, maybe log some stuff, etc, but ultimately in the normal case it will forward the message to wherever it would originally have been sent. If we're directing everything to the proxy via a wrapper layer, then the original to address won't actually appear in the message. This will leave the proxy no way to know how to get the message to it's final destination (or to the next hop towards it's final destination in an N step scenario). --Rafael
Re: RFC: new routing functionality for messenger
On 03/25/2013 09:30 AM, Rafael Schloming wrote: On Mon, Mar 25, 2013 at 8:36 AM, Ted Ross wrote: I generally like this translation facility, though I'll need to think through some use cases to make sure there's sufficient capability in the matching and substitution. I would definitely appreciate some more feedback on this area. I think some real world usage will help us out. I struggled with various options here. I didn't want to add a dependency onto a regular expression library without at least some kind of fallback as I think this functionality is going to end up being too useful to be optional. There are a number of public domain regular expression libraries out there (e.g. t-rex) that are basically designed to be small enough and simple enough to be sucked into a codebase wholesale for when you can't afford an external dependency. I considered grabbing one of those, but I also wasn't 100% sure that full on regex was the best/only option here. There is something nice and simple about being able to say route("*", "my-uplink") as opposed to writing a fullon regex. I can see possibly even wanting to support multiple syntax options eventually, but for starters I decided to keep it simple. I wrote a very small glob style matcher with substitution. It's roughly 100 lines of code and should work on any platform. I'm entirely open to replacing this with something a real regex library if we want or something else entirely, I just wanted something simple/portable to start with so we could actually play with the functionality and learn a bit more about what is appropriate. I question the value of having this as part of the API. It seems to me that the Messenger routing table should be part of the configuration of a system (i.e. in a place like /etc/qpid/messenger/, or the Windows Registry, etc.). Eventually, it might be desirable to have an address translation service that can be accessed remotely. I guess I see this translation as being not the concern of the application, but more of the deployment of the application. I also don't think this belongs in the API. It can be easily be provided as a "translator" library on top of the public messenger API. In that case the argument over regexps vs. home-brew pattern matching is less an issue people, can write translators that use whatever patterns they like, and in whatever languages they want. I would favour keeping the messenger API as simple and focused as possible and provide additional services as layers on top. Even if we want a C implementation with multiple language bindings that can still be a separate library to the messenger. I also suspect it will be more fruitful to prototype this kind of thing in more productive languages like python or ruby before deciding if we want to bake something into a C implementation with bindings etc. Cheers, Alan.
Re: RFC: new routing functionality for messenger
On Tue, Mar 26, 2013 at 7:19 AM, Bozo Dragojevic wrote: > On 3/23/13 5:43 PM, Rafael Schloming wrote: > >> Hi, >> >> I've added a new API to messenger that gives the user some control over >> the >> internal routing behaviour of a messenger. Please check it out and >> comment. >> I've pasted the C API/doxygen below. This is currently only exposed >> through >> the python binding via the route method on the Messenger class. >> >> --Rafael >> >> /** Adds a routing rule to a Messenger's internal routing table. >> * >> * The route procedure may be used to influence how a messenger will >> * internally treat a given address or class of addresses. Every call >> * to the route procedure will result in messenger appending a routing >> * rule to its internal routing table. >> * >> * Whenever a message is presented to a 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 messenger will route based on the address supplied in the rule. >> * >> > > Can you help me work through this use-case: > > > A 'dumb' client, sends a message, and expects a reply: > > // client.c > pn_message_set_address(msg, "amqp://localhost/bla"); > pn_messenger_put(msgr, msg); > pn_messenger_receive(msgr,1); > msg = pn_messenger_get(msgr); > > > > The peer it connects to uses the new route functionality: > > // server.c > pn_messenger_subscribe(msgr, "~amqp://localhost/bla"); > I'm assuming you mean "amqp://~localhost/blah" above. ;-) > > 1) Are routes valid to use if there's a subscribe going on. >I assume yes. > > pn_messenger_route(msgr, "*", "amqp://broker/$1"); > It's certainly valid to use both at the same time. > > 2) How do they interact. >I assume they don't, routing is only applied to outgoing messages. > Actually routing should be applied equally to both, however now that I think about it I suspect you need to do the route before you do the subscribe in order for it to make a difference for the subscribe, although I expect that limitation to go away in the next round of changes. > > 3) Does the order of calls to route and subscribe matter. >According to 2) it does not. > Actually the order does matter (see above). I expect eventually the implementation will evolve in such a way that the order does not matter, however even so you would effectively end up getting a resubscribe when the new route goes into place, e.g. the following sequence of events could occur: subscribe("foo.com/bar") ... ... if you do a recv here, messages might arrive directly from foo.com ... route("foo.com/bar", "fooproxy.com/baz") ... ... now you get messages via the proxy > > pn_messenger_receive(msgr, 1); > msg = pn_messenger_get(msgr); > > /* echo */ > char *sender = pn_message_get_reply_to(msg); > pn_message_set_address(msg, sender); > pn_messenger_put(msgr, msg); > pn_messenger_send(msgr); > > > 4) What would the pn_message_get_reply_to() return. >The value as set by the client's messenger would be > amqp://some-uuid-value > This is a very good question. I don't recall exactly why messenger sets the reply_to automatically as it does, it may even be an unintentional side effect of a couple of different changes, but I've been thinking that it shouldn't actually do this automatically, i.e. that you should always set a reply_to explicitly if that's what you want. FWIW, it's not actually setting the reply_to value to some-random-uuid, it's actually setting it to amqp://the-name-of-the-messenger. It just so happens that the name of the messenger defaults to a UUID, but if you had constructed your messenger as pn_messenger("bob") rather than pn_messenger(NULL), then the reply_to would automatically get set to amqp://bob. I was also thinking that it would be convenient to have some way to actually refer to the container name in an address, that way e.g. explicitly setting the reply_to = "amqp://${me}" would give the same effect that you currently get with the automatic setting, but would also be a bit more flexible. > > 5) Would the route above apply or not to this particular outgoing reply > message. > The rules always apply, the messenger impl doesn't really know the difference between that and any other address. > > 6) If yes, how will 'broker' learn how to talk to the original client > Another very good question. Unfortunately the answer right now depends on your broker as each broker assumes a private namespace, you would need to construct a reply_to that is known to your broker, e.g. create a reply-queue called "replies" on your broker and explicitly set your reply-to to amqp://broker/replies. One of the areas that we are working on within the OASIS TC is defining an addressing standard such that this will be much more seamless, e.g. the clients
Re: RFC: new routing functionality for messenger
On 3/23/13 5:43 PM, Rafael Schloming wrote: Hi, I've added a new API to messenger that gives the user some control over the internal routing behaviour of a messenger. Please check it out and comment. I've pasted the C API/doxygen below. This is currently only exposed through the python binding via the route method on the Messenger class. --Rafael /** Adds a routing rule to a Messenger's internal routing table. * * The route procedure may be used to influence how a messenger will * internally treat a given address or class of addresses. Every call * to the route procedure will result in messenger appending a routing * rule to its internal routing table. * * Whenever a message is presented to a 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 messenger will route based on the address supplied in the rule. * Can you help me work through this use-case: A 'dumb' client, sends a message, and expects a reply: // client.c pn_message_set_address(msg, "amqp://localhost/bla"); pn_messenger_put(msgr, msg); pn_messenger_receive(msgr,1); msg = pn_messenger_get(msgr); The peer it connects to uses the new route functionality: // server.c pn_messenger_subscribe(msgr, "~amqp://localhost/bla"); 1) Are routes valid to use if there's a subscribe going on. I assume yes. pn_messenger_route(msgr, "*", "amqp://broker/$1"); 2) How do they interact. I assume they don't, routing is only applied to outgoing messages. 3) Does the order of calls to route and subscribe matter. According to 2) it does not. pn_messenger_receive(msgr, 1); msg = pn_messenger_get(msgr); /* echo */ char *sender = pn_message_get_reply_to(msg); pn_message_set_address(msg, sender); pn_messenger_put(msgr, msg); pn_messenger_send(msgr); 4) What would the pn_message_get_reply_to() return. The value as set by the client's messenger would be amqp://some-uuid-value 5) Would the route above apply or not to this particular outgoing reply message. 6) If yes, how will 'broker' learn how to talk to the original client 7) If no, how will the server.c messenger know when to apply the routes and when not Bozzo
Re: RFC: new routing functionality for messenger
On 3/25/13 8:26 PM, Rafael Schloming wrote: On Mon, Mar 25, 2013 at 3:06 PM, Bozo Dragojevic wrote: Rafael, did you consider a variant where a user can supply a rewrite object? pn_messenger_set_router(pn_**messenger_t *msgr, pn_router_t *router) Proton library can then easily supply a one or more ready-made implementations. I did consider this, but it's difficult to expose an interface like that through swig I didn't want to suggest to go that far right now. It should be enough to expose the default implementation as pn_router_t *pn_router() I agree it's difficult to expose a mechanism to define a custom pn_router_t* in a scripting language. This is a separate task and can be done later. It'd probably make sense to wait with that until the interface between the router and the messenger firms up. Bozzo
Re: RFC: new routing functionality for messenger
On Mon, Mar 25, 2013 at 3:06 PM, Bozo Dragojevic wrote: > Rafael, > > did you consider a variant where a user can supply a rewrite object? > > pn_messenger_set_router(pn_**messenger_t *msgr, pn_router_t *router) > > Proton library can then easily supply a one or more ready-made > implementations. > I did consider this, but it's difficult to expose an interface like that through swig, and I wanted to start with something that would allow all the basic scenarios to work consistently across all the different bindings. I think if we find the need for something as flexible as you suggest above, I would probably chain it together with a more basic mechanism like what is there now, e.g. the router object would have access to rewrite both before and/or after the basic translation rules are applied. Some areas I can think of where such an interface might be interesting is with dynamic routing tables, e.g. a larger AMQP network where next hop information is propagated all the way to the endpoints, or perhaps with centralized configuration management/discovery where the routing table is queried dynamically when the network is joined. Right now though I am thinking of those sorts of things as a distinct set of scenarios from endpoint configured routing rules. --Rafael
Re: RFC: new routing functionality for messenger
Rafael, did you consider a variant where a user can supply a rewrite object? pn_messenger_set_router(pn_messenger_t *msgr, pn_router_t *router) Proton library can then easily supply a one or more ready-made implementations. Bozzo On 3/23/13 5:43 PM, Rafael Schloming wrote: Hi, I've added a new API to messenger that gives the user some control over the internal routing behaviour of a messenger. Please check it out and comment. I've pasted the C API/doxygen below. This is currently only exposed through the python binding via the route method on the Messenger class. --Rafael /** Adds a routing rule to a Messenger's internal routing table. * * The route procedure may be used to influence how a messenger will * internally treat a given address or class of addresses. Every call * to the route procedure will result in messenger appending a routing * rule to its internal routing table. * * Whenever a message is presented to a 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 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": * * pn_messenger_route("foo", "amqp://foo.com"); * * Any message sent to "foobar" will be routed to * "amqp://foo.com/bar": * * pn_messenger_route("foobar", "amqp://foo.com/bar"); * * Any message sent to bar/ will be routed to the corresponding * path within the amqp://bar.com domain: * * pn_messenger_route("bar/*", "amqp://bar.com/$1"); * * Route all messages over TLS: * * pn_messenger_route("amqp:*", "amqps:$1") * * Supply credentials for foo.com: * * pn_messenger_route("amqp://foo.com/*", "amqp://user:passw...@foo.com/$1 "); * * Supply credentials for all domains: * * pn_messenger_route("amqp://*", "amqp://user:password@$1"); * * Route all addresses through a single proxy while preserving the * original destination: * * pn_messenger_route("amqp://%/*", "amqp://user:password@proxy/$1/$2"); * * Route any address through a single broker: * * pn_messenger_route("*", "amqp://user:password@broker/$1"); * * @param[in] messenger the Messenger * @param[in] pattern a glob pattern * @param[in] address an address indicating alternative routing * * @return an error code or zero on success * @see error.h * */ PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern, const char *address);
Re: RFC: new routing functionality for messenger
On Mon, Mar 25, 2013 at 11:42 AM, Rafael Schloming wrote: > On Mon, Mar 25, 2013 at 10:34 AM, Rajith Attapattu wrote: > >> For starters I would copy this email to the user list. >> (In the future we should post things like this to a more wider >> audience, especially if we are looking for feedback based on real >> world use cases.) >> > > I posted it where I intended it to go. I don't mind a broader audience > looking at it, but at this stage I'm really looking for feedback from > proton developers and people more keyed into messenger's distributed > messaging model. This is for two reasons: (1) I don't want to push out > stuff and have people start using it before it is sufficiently reviewed by > other proton developers, and (2) a lot of the people on the users list > (perhaps most of them) are quite firmly entrenched in the traditional hub > and spoke broker model, and from their perspective the primary use for this > functionality would simply be to route("*", "my-giant-hub-broker/$1") and > thereby make messenger simulate your traditional hub and spoke client, > however this functionality is about way more than that. > > I think after a round of discussion and documentation (not just API docs) > it would probably be more digestable to a broader audience. Feel free to > kick off wider discussion if you wish though, I've no objection, I'm just > explaining my thinking at this stage. Thanks for your explanation, and you do have a point about people starting to use the feature a bit prematurely and perhaps in a narrower scope than what we would have liked. Unfortunately the same holds true if we publish it even after we deem it's ready for general consumption. Changing the mindset especially after years of being conditioned to a particular approach is going to be difficult. The challenge for Proton is to educate our users and the general development community that we can do much more than the hub-spoke model. My desire to bring the discussion to a more wider audience was motivated by recent comments/observations by Fraser and Gordon. Within our user base, we do seem to have a few early adopters who seems keen to be a bit more involved in the development process than a regular user would. Perhaps a more reasonable approach would be to copy dev@ instead of user@ hoping the above crowd is on @dev. > >> I actually like the minimalistic approach you've taken here. It works >> well in an embedded context. >> Support for regex will be a welcome addition. >> I don't think we should bother with a config file for proton. To me >> it's neither here nor there. Let the application developer or the >> deployment folks who use the proton based application worry about it. >> As both you and Ted pointed out, a more sophisticated routing >> capability is best achieved outside the scope of Proton. >> > > I agree it's not the job of a library to provide system level > integration/configuration, however we should do what we can to make it easy > for system integrators to do so themselves and, to the extent that we can, > encourage them to provide as consistent an experience as possible across > systems, e.g. I considered plugging into system provided regex libraries > for providing regular expression support, but that could result in slightly > different styles of regex depending on which system you're on, so I decided > against that option. (Not saying I don't want to provide regex support, > just that if we do we should find a way that works the same regardless of > where you are.) Thats a fair point, I agree with you. > Regarding your statement on sophisticated routing capabilities being kept > outside of proton, I think it's worth pointing out that unless you're > considering just the hub and spoke topology, routing isn't something that > is contained to a single component or even a single class of component in > your network. It's something that everything, including the endpoints in > your network need to be aware of and cooperatively participate in so that > you can achieve a given overall effect. This is indeed what I meant, perhaps I should have elaborated a bit more. As you said, for complicated networks, the routing aspect will be de-centralized and achieved by the collaboration/cooperation of all kinds of nodes/services within the network that may span organizations. Therefore it's impossible for us to provide a comprehensive solution through proton, or other components (routers, bridges, brokers ..etc) we offer through the larger QPid umbrella. What we can provide is some simple basic building blocks/helper utilities that will help the end users to compose more larger complex routing strategies. In that regard what you've offered seems quite good. Anything more will be neither here nor there. Rajith > --Rafael
Re: RFC: new routing functionality for messenger
On Mon, Mar 25, 2013 at 10:34 AM, Rajith Attapattu wrote: > For starters I would copy this email to the user list. > (In the future we should post things like this to a more wider > audience, especially if we are looking for feedback based on real > world use cases.) > I posted it where I intended it to go. I don't mind a broader audience looking at it, but at this stage I'm really looking for feedback from proton developers and people more keyed into messenger's distributed messaging model. This is for two reasons: (1) I don't want to push out stuff and have people start using it before it is sufficiently reviewed by other proton developers, and (2) a lot of the people on the users list (perhaps most of them) are quite firmly entrenched in the traditional hub and spoke broker model, and from their perspective the primary use for this functionality would simply be to route("*", "my-giant-hub-broker/$1") and thereby make messenger simulate your traditional hub and spoke client, however this functionality is about way more than that. I think after a round of discussion and documentation (not just API docs) it would probably be more digestable to a broader audience. Feel free to kick off wider discussion if you wish though, I've no objection, I'm just explaining my thinking at this stage. > I actually like the minimalistic approach you've taken here. It works > well in an embedded context. > Support for regex will be a welcome addition. > I don't think we should bother with a config file for proton. To me > it's neither here nor there. Let the application developer or the > deployment folks who use the proton based application worry about it. > As both you and Ted pointed out, a more sophisticated routing > capability is best achieved outside the scope of Proton. > I agree it's not the job of a library to provide system level integration/configuration, however we should do what we can to make it easy for system integrators to do so themselves and, to the extent that we can, encourage them to provide as consistent an experience as possible across systems, e.g. I considered plugging into system provided regex libraries for providing regular expression support, but that could result in slightly different styles of regex depending on which system you're on, so I decided against that option. (Not saying I don't want to provide regex support, just that if we do we should find a way that works the same regardless of where you are.) Regarding your statement on sophisticated routing capabilities being kept outside of proton, I think it's worth pointing out that unless you're considering just the hub and spoke topology, routing isn't something that is contained to a single component or even a single class of component in your network. It's something that everything, including the endpoints in your network need to be aware of and cooperatively participate in so that you can achieve a given overall effect. --Rafael
Re: RFC: new routing functionality for messenger
For starters I would copy this email to the user list. (In the future we should post things like this to a more wider audience, especially if we are looking for feedback based on real world use cases.) I actually like the minimalistic approach you've taken here. It works well in an embedded context. Support for regex will be a welcome addition. I don't think we should bother with a config file for proton. To me it's neither here nor there. Let the application developer or the deployment folks who use the proton based application worry about it. As both you and Ted pointed out, a more sophisticated routing capability is best achieved outside the scope of Proton. Regards, Rajith On Mon, Mar 25, 2013 at 9:30 AM, Rafael Schloming wrote: > On Mon, Mar 25, 2013 at 8:36 AM, Ted Ross wrote: > >> I generally like this translation facility, though I'll need to think >> through some use cases to make sure there's sufficient capability in the >> matching and substitution. >> > > I would definitely appreciate some more feedback on this area. I think some > real world usage will help us out. I struggled with various options here. I > didn't want to add a dependency onto a regular expression library without > at least some kind of fallback as I think this functionality is going to > end up being too useful to be optional. > > There are a number of public domain regular expression libraries out there > (e.g. t-rex) that are basically designed to be small enough and simple > enough to be sucked into a codebase wholesale for when you can't afford an > external dependency. I considered grabbing one of those, but I also wasn't > 100% sure that full on regex was the best/only option here. There is > something nice and simple about being able to say route("*", "my-uplink") > as opposed to writing a fullon regex. > > I can see possibly even wanting to support multiple syntax options > eventually, but for starters I decided to keep it simple. I wrote a very > small glob style matcher with substitution. It's roughly 100 lines of code > and should work on any platform. I'm entirely open to replacing this with > something a real regex library if we want or something else entirely, I > just wanted something simple/portable to start with so we could actually > play with the functionality and learn a bit more about what is appropriate. > > >> I question the value of having this as part of the API. It seems to me >> that the Messenger routing table should be part of the configuration of a >> system (i.e. in a place like /etc/qpid/messenger/, or the Windows Registry, >> etc.). Eventually, it might be desirable to have an address translation >> service that can be accessed remotely. I guess I see this translation as >> being not the concern of the application, but more of the deployment of the >> application. >> >> > Initially I was actually going to add the functionality via some kind of > configuration file as you say. I have a similar conceptual view of the > functionality as you describe, i.e. it really should only be used as part > of the deployment/configuration of the messenger, not part of the > "application work" portion of the API. I ended up going this route for two > reasons (no pun intended). For starters it was a bit more expedient as I > didn't have to write some kind of file format parser, but the second, and > perhaps more important reason, is that I wasn't sure of the implications of > adding dependencies onto files/file systems. I want messenger to be usable > from embedded devices that might not even have a file system, so I figured > it would be safer to offer as a pure API. I do think it would be > appropriate to layer some kind of system integration on top of this API > just as you describe. > > --Rafael
Re: RFC: new routing functionality for messenger
On Mon, Mar 25, 2013 at 8:36 AM, Ted Ross wrote: > I generally like this translation facility, though I'll need to think > through some use cases to make sure there's sufficient capability in the > matching and substitution. > I would definitely appreciate some more feedback on this area. I think some real world usage will help us out. I struggled with various options here. I didn't want to add a dependency onto a regular expression library without at least some kind of fallback as I think this functionality is going to end up being too useful to be optional. There are a number of public domain regular expression libraries out there (e.g. t-rex) that are basically designed to be small enough and simple enough to be sucked into a codebase wholesale for when you can't afford an external dependency. I considered grabbing one of those, but I also wasn't 100% sure that full on regex was the best/only option here. There is something nice and simple about being able to say route("*", "my-uplink") as opposed to writing a fullon regex. I can see possibly even wanting to support multiple syntax options eventually, but for starters I decided to keep it simple. I wrote a very small glob style matcher with substitution. It's roughly 100 lines of code and should work on any platform. I'm entirely open to replacing this with something a real regex library if we want or something else entirely, I just wanted something simple/portable to start with so we could actually play with the functionality and learn a bit more about what is appropriate. > I question the value of having this as part of the API. It seems to me > that the Messenger routing table should be part of the configuration of a > system (i.e. in a place like /etc/qpid/messenger/, or the Windows Registry, > etc.). Eventually, it might be desirable to have an address translation > service that can be accessed remotely. I guess I see this translation as > being not the concern of the application, but more of the deployment of the > application. > > Initially I was actually going to add the functionality via some kind of configuration file as you say. I have a similar conceptual view of the functionality as you describe, i.e. it really should only be used as part of the deployment/configuration of the messenger, not part of the "application work" portion of the API. I ended up going this route for two reasons (no pun intended). For starters it was a bit more expedient as I didn't have to write some kind of file format parser, but the second, and perhaps more important reason, is that I wasn't sure of the implications of adding dependencies onto files/file systems. I want messenger to be usable from embedded devices that might not even have a file system, so I figured it would be safer to offer as a pure API. I do think it would be appropriate to layer some kind of system integration on top of this API just as you describe. --Rafael
Re: RFC: new routing functionality for messenger
I generally like this translation facility, though I'll need to think through some use cases to make sure there's sufficient capability in the matching and substitution. I question the value of having this as part of the API. It seems to me that the Messenger routing table should be part of the configuration of a system (i.e. in a place like /etc/qpid/messenger/, or the Windows Registry, etc.). Eventually, it might be desirable to have an address translation service that can be accessed remotely. I guess I see this translation as being not the concern of the application, but more of the deployment of the application. -Ted On 03/23/2013 12:43 PM, Rafael Schloming wrote: Hi, I've added a new API to messenger that gives the user some control over the internal routing behaviour of a messenger. Please check it out and comment. I've pasted the C API/doxygen below. This is currently only exposed through the python binding via the route method on the Messenger class. --Rafael /** Adds a routing rule to a Messenger's internal routing table. * * The route procedure may be used to influence how a messenger will * internally treat a given address or class of addresses. Every call * to the route procedure will result in messenger appending a routing * rule to its internal routing table. * * Whenever a message is presented to a 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 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": * * pn_messenger_route("foo", "amqp://foo.com"); * * Any message sent to "foobar" will be routed to * "amqp://foo.com/bar": * * pn_messenger_route("foobar", "amqp://foo.com/bar"); * * Any message sent to bar/ will be routed to the corresponding * path within the amqp://bar.com domain: * * pn_messenger_route("bar/*", "amqp://bar.com/$1"); * * Route all messages over TLS: * * pn_messenger_route("amqp:*", "amqps:$1") * * Supply credentials for foo.com: * * pn_messenger_route("amqp://foo.com/*", "amqp://user:passw...@foo.com/$1 "); * * Supply credentials for all domains: * * pn_messenger_route("amqp://*", "amqp://user:password@$1"); * * Route all addresses through a single proxy while preserving the * original destination: * * pn_messenger_route("amqp://%/*", "amqp://user:password@proxy/$1/$2"); * * Route any address through a single broker: * * pn_messenger_route("*", "amqp://user:password@broker/$1"); * * @param[in] messenger the Messenger * @param[in] pattern a glob pattern * @param[in] address an address indicating alternative routing * * @return an error code or zero on success * @see error.h * */ PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern, const char *address);
RFC: new routing functionality for messenger
Hi, I've added a new API to messenger that gives the user some control over the internal routing behaviour of a messenger. Please check it out and comment. I've pasted the C API/doxygen below. This is currently only exposed through the python binding via the route method on the Messenger class. --Rafael /** Adds a routing rule to a Messenger's internal routing table. * * The route procedure may be used to influence how a messenger will * internally treat a given address or class of addresses. Every call * to the route procedure will result in messenger appending a routing * rule to its internal routing table. * * Whenever a message is presented to a 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 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": * * pn_messenger_route("foo", "amqp://foo.com"); * * Any message sent to "foobar" will be routed to * "amqp://foo.com/bar": * * pn_messenger_route("foobar", "amqp://foo.com/bar"); * * Any message sent to bar/ will be routed to the corresponding * path within the amqp://bar.com domain: * * pn_messenger_route("bar/*", "amqp://bar.com/$1"); * * Route all messages over TLS: * * pn_messenger_route("amqp:*", "amqps:$1") * * Supply credentials for foo.com: * * pn_messenger_route("amqp://foo.com/*", "amqp://user:passw...@foo.com/$1 "); * * Supply credentials for all domains: * * pn_messenger_route("amqp://*", "amqp://user:password@$1"); * * Route all addresses through a single proxy while preserving the * original destination: * * pn_messenger_route("amqp://%/*", "amqp://user:password@proxy/$1/$2"); * * Route any address through a single broker: * * pn_messenger_route("*", "amqp://user:password@broker/$1"); * * @param[in] messenger the Messenger * @param[in] pattern a glob pattern * @param[in] address an address indicating alternative routing * * @return an error code or zero on success * @see error.h * */ PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern, const char *address);