Project

General

Profile

component handling local domains routing to c2s

Justin Karneges
Added over 5 years ago

Hi,

I have a component that overrides handlesLocalDomains() to return true, so that it receives all packets. I can use addOutPacket() to send to remote domains and all is well. However, if I try to use send packets to locally connected clients then the packet loops back into my component. Is it possible to exclude certain domains from being handled by my component? (My clients are always connecting via a domain that is reserved for clients only). Or is there a way for c2s to be prioritized so that packets only trickle down to my component if they were not already handled by all other components?

I figure SessionManager must have similar routing issues to worry about but I could not figure it out from the code.


Replies (21)

Added by Justin Karneges over 5 years ago

To clarify, it looks like addOutPacket causes the packet to be delivered to both the session manager (and therefore c2s) as well as my own component.

So all I really need to do is detect when a packet is not mine and skip it. I could also use packet addressing tricks to detect loops I guess.

However, that still leaves another problem: the session manager doesn't know how to skip packets that are mine to handle. For example, if a packet goes to a domain that I don't intend to have any clients using, my component gets the packet and can process it, but the session manager also gets the packet and will send out a delivery error stanza. It seems as if handlesLocalDomains()=true is a "there can be only one" situation.

All I'm trying to do here is write a component that can service all non-c2s vhosts of tigase. Originally I had only enabled s2s (no c2s or session manager) and everything was fine. However, now that I'm considering turning on c2s, the entire approach breaks down. I have no need for my component to handle vhosts meant for c2s, so if there's a way to make session manager explicitly handle only c2s vhosts and make my component explicitly only handl non-c2s vhosts, then that should keep the two components from tripping on each other, but I don't know if that's possible. What should I do?

Added by Justin Karneges over 5 years ago

Okay, I have a possible solution:

1) Maintain a list of special domains (the ones I intend to fully service via component).

2) Set up a preprocessor on SM that drops any packets destined for the domains in the above list.

3) My component would drop any packets destined for domains NOT in the above list.

This way, both my component and SM can have handlesLocalDomains=true without stepping on each other, as they will be sure to drop each other's packets. Does this seem sensible?

Alternative to a list would be to flag VHostItems with a custom property. Is this possible?

Thanks.

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

I think you should start with telling us what this is you want to do. Once we understand your requirements we can help you finding the best solution.

Added by Justin Karneges over 5 years ago

I want to host user-provided domains and offer special XMPP services on them. This means a user should be able to configure a domain such as "yourcompany.com" in the system, and I should be able to have code that receives packets sent to this domain, and be able to send packets outbound as coming from this domain. These domains would only be used to provide services that I write the code for. They would not accept client connections nor offer typical XMPP services like MUC or anything like that.

Separately, I want to host domains that clients can connect to. These domains would be decided by me (not user configurable), and would have standard behavior. No custom packet handling, just basic out-of-the-box c2s.

Hope this explanation makes sense.

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Ok, so the second requirement is quite simple and easy to do out of the box. You can add new domains through VHostManager via ad-hoc commands or through DB and it just works that way out of the box.

For the special domains, there is no out of the box solution I can think of but this is the case I kind of planed for within Tigase design.

If you look inside VHostItem class there is a field comps[]. This was/is supposed to keep a list of component which are responsible for processing packets addressed to that domain. Unfortunately the implementation of the idea goes as far as this class only. This field cannot be even set via ad-hoc command, only through DB. And then even if it is set is it not used. *But, again, there is actually only one place which needs to be modified to make it work: VHostManager.getComponentsForLocalDomain(...). If this method used the field to determine what component should process packet addressed to this domain it all would be much simpler to you. Because, you could specify in the domain configuration that *this particular domain is processed by your particular component.

Please let me know if this sounds like a solution to you. Also please let me know if you add new domains via ad-hoc commands or in some other way. I can make the code modifications to you but I cannot run too much tests. So if you are willing to do testing I am willing to do the coding :-)

Added by Justin Karneges over 5 years ago

Ah! Yes, if there were a way to bind the special domains to my component then that would work perfectly. And then I'd no longer need handlesLocalDomains=true ?

Currently, VHostItems either come from init.properties (there are a few that I hardcode) or from a custom vhost repository class (where all the user-provided ones come from). So as long as I can set the comps[] field in code then I should be fine, but a way to set in init.properties would be nice too. I'm not using a DB or ad-hoc commands.

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

I have just looked through the code again and I may have found a solution for your special domains which should work out of the box. Your use case is similar to an external component protocol, which can receive connections and domains bind from any external domain. This is not a local domain so SM does not process it. So normally a s2s component would get the packet to process it. However there is a way to bind a domain which is not local to a component which wants to receive packets for that domain.

If you look at the ComponentProtocol class and method: bindHostname this is where it happens. The updateRoutings call is where you have to focus on. You can put there any regex and all packets for with a destination address matches your regex will be processed by your component. Maybe this is what you are looking for. Of course you can add and remove domain this way. In a corresponding ubnindHostname a routing is removed.

Added by Justin Karneges over 5 years ago

Hmm, regex is not ideal since the domains have arbitrary names and therefore wildcard expressions cannot be used. If I have a lot of domains then that could be a very long regex.

Usage of VHostItem.comps[] seems best. And you think all that's needed is for VHostManager.getComponentsforLocalDomain() to make use of it? And to get init.properties support, probably need to add some COMPONENTS_ELEM_ATT property?

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Ah, you do not put a single regex with all domains, instead you add a new regex for each domain. The regex is necessary to cover all the cases, because the string which is matched against the regex contains also a user name (local part) - BareJID, so it is possible to have a component which handles packets for a certain domain for users starting with 'a' for example.

Alternatively to managing regexes, you can override in your component a method: isInRegexRoutings(String address) which is called to check the routings. In this method you can chech whether you want to handle packets for the address passed to it or not. If the method returns true your component gets the packet.

Added by Justin Karneges over 5 years ago

I went ahead and wrote code for the internal comps handling. How does this look: http://andbit.net/diffs/tigase_vhost_comps.diff ?

Added by Justin Karneges over 5 years ago

Oh, oops, while this code works as expected, there is still the problem that the session manager gets the packets too. I guess this is partly why you suggested the external component approach.

I like having my component run inside of the same tigase instance, so I wonder if there's a further workaround I can make. Maybe some domain blacklist for session manager?

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Justin Karneges wrote:

I went ahead and wrote code for the internal comps handling. How does this look: http://andbit.net/diffs/tigase_vhost_comps.diff ?

Code looks good but as this solution is new and has never been tested before there might something more to do to make it work.

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Justin Karneges wrote:

Oh, oops, while this code works as expected, there is still the problem that the session manager gets the packets too. I guess this is partly why you suggested the external component approach.

I suggested this approach because it is already implemented and confirmed to work. The other one is an idea which should work but has never been tested, hence may require some more digging and debugging before it is usable.

I like having my component run inside of the same tigase instance, so I wonder if there's a further workaround I can make. Maybe some domain blacklist for session manager?

You can run your component inside Tigase. I pointed you to the external component protocol implementation only because this is where the solution is implemented so you can use it as an example code for your component.

Ok, scrap the vhost changes you made and simply try to override isInRegexRoutings(String address) method in your component... When you get your special domain as argument return true and you should get the packet and SessionManager will not.

Added by Justin Karneges over 5 years ago

I tried overriding this method but it does not seem to get called?

Added by Justin Karneges over 5 years ago

Traced the code. As far as I can tell, isInRegexRoutings() is only called in one place, in MessageRouter, and this only if calling getComponentsForLocalDomain() returns null. However, since getComponentsForLocalDomain() always returns at least sess-man, the fallback to regex is never used.

Added by Justin Karneges over 5 years ago

Here's another idea, don't fallback to generic local domain processors (like session manager) if the vhost is explicitly bound to any component. Slight reworking of previous patch:

http://andbit.net/diffs/tigase_vhost_comps2.diff

This seems to have the correct effect now, though I don't know if this is how you intended tigase to work.

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Yes, this is exactly how this is supposed to work by design.

Added by Justin Karneges over 5 years ago

Great. Maybe you can merge the patch then?

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Committed your diff to the master branch.

Added by Justin Karneges over 5 years ago

As discussed separately, DisableDisco isn't working for domain-based routings. Here's another patch for that: http://andbit.net/diffs/tigase_disabledisco_fix.diff

Avatar?id=6023&size=32x32

Added by Artur Hefczyc TigaseTeam over 5 years ago

Patch committed to the master branch, thank you.

    (1-21/21)