Re: Roster module with custom MySQL requests
Le 01/04/2014 14:23, Tomasz Sterna a écrit : Dnia 2014-04-01, wto o godzinie 12:14 +0200, Sylvain Guglielmi pisze: The problem is : - When an user connects to jabberd2 for the first time, the active,logout... tables are empty, and the roster is already filled. - The code in dispatch.c : 130 states that if one of the user_load module fails, an unsuscribed-packet will be sent, presumably to clean the user's rosters on every session by removing this unknown contact. Just remove 'active' module from 'user-load' chain in your sm.xml. Unfortunately it does not work : When I remove 'active' module from 'user-load' chain, the auto-create in sess.c does not trigger since user_load returned sucessfully. user_create is never called for new users. This causes other issues (For example, active is never filled for the user. My search module relies on it, and you said that offline messages checked that too, and I'd not be surprised if others modules do too). It seems to me that it's related to something you stated earlier : there should be differents chains for user_load, the one when an user connects (called from sess.c) and a quicker one called from dispatch and other locations too (which should not load roster, but only plain info such as active or routing info). Sadly, I have not the time now for doing all that. I think my best option is to disable the presence unsubscribed in dispatch.c (via a config option). I'd gladly accept any better solution. When I'll have more time, I'll get back on doing the right thing. Thanks in advance for any insight. -- Sylvain Gugli Guglielmi Gamedev@Nadeo@Ubisoft
Re: Roster module with custom MySQL requests
Hello again everyone, I have some questions concerning dispatch.c, but first a short recap of the plugin I'm working on : - the plugin replaces roster and allows to write custom sql requests for accessing data (instead of the storage component). The purpose is to be able to use our already-existing buddies database, read-and-write. - I enabled auto-create/ : the server's other tables (active, logout...) get populated at the user's first connection The problem is : - When an user connects to jabberd2 for the first time, the active,logout... tables are empty, and the roster is already filled. - The code in dispatch.c : 130 states that if one of the user_load module fails, an unsuscribed-packet will be sent, presumably to clean the user's rosters on every session by removing this unknown contact. - In my case, when an user connects but one of his buddies has never been connected yet, the active module fails to user_load. The unsuscribed packet is generated, and the buddy-relationship is erased from the roster, unfortunately losing the relationship. I see three solutions here : - using the template-roster module, or adapting it, i could maybe recreate the buddies-relationships after they are deleted. But it would mean i have to keep two tables : roster-before-first-connection, and roster-after-first-connexion(=real roster), which seems weird. Also, it would mean a lot of unneeded operations on first connection. - populate all the tables of the server (active, status...) in advance (i.e before the first connection to XMPP is even possible). It makes more sense, because it avoid to have half-created sessions (with only a valid roster but nothing else). But it's also a certain amount of work for me, and server load on the future (to keep every table of the SM's database up-to-date regarding account creations). - add a config flag in sm : allow relationship to not-yet-existing buddies that would prevent the unsuscribed packet form being sent. I think the most sensible way is the last one, but I may miss some issues. Any insight would be greatly welcome, as usual. Thanks for reading me, and in advance for any answer ^_^. Le 17/01/2014 11:59, Sylvain Guglielmi a écrit : Le 10/01/2014 18:23, Tomasz Sterna a écrit You could have a separate cron component pinging 'sm' in regular intervals with special route packet, and handle this special packet in 'in-router' chain of your module. Having that it could even be done not in regular intervals, but on-demand, when your component gets triggered by web frontend. This works very well ! Thanks for the advice. My cron component is a short php script. I was unsure about how to answer disco#info queries that I get from other components, but it seems to work without answering anything. I'll read the XEP-0030 : Service Discovery RFC later and try to make a more compliant cron component. If anyone is interested in the php simple DIGEST-MD5 auth, code can be found here (It's not robust and exhaustive, but it can be useful I guess) : https://github.com/Gugli/jabberd2/blob/master/tools/sendupdatepacket.php I've been scratching my head for the last couple of days on another issue : our legacy contact system does not allow asymetrical relationships (as XMPP does). It would be very complicated to change that to a more XMPP-compliant system. The solution I came up with is to make a symmetrical mode for my roster module. In this mode : - whenever a user sends a presence subscription, the sm also consider the user allows subscription to the same contact. - whenever a user allows a contact to subscribe to his presence, the sm also consider that the user subscribe back to the same contact's presence. The session that requests the change has to be informed of this additional change with a push as any other session. Basically, item-from and item-to are linked, they always are the same value. This makes a kind of restricted XMPP protocol. It's not great, but it's the only sensible way I found to go on. Has anyone already done something approaching ? Is it bad ? Thanks very much again for all the help you provide :) -- Sylvain Gugli Guglielmi -- Sylvain Gugli Guglielmi
Re: Roster module with custom MySQL requests
Le 01/04/2014 14:23, Tomasz Sterna a écrit : Just remove 'active' module from 'user-load' chain in your sm.xml. Oh, haven't thought of that. *dumb me* (I wrongly assumed all the modules would fail to user_load without calling user_create first. Didn't think it was the purpose of the active module and that all the others should do fine xD). I found only one other module relying on the active status : roster-publish. I need to deactivate roster-publish (it relies on roster-items and roster-group that are not used when using my custom roster plugin, and i don't use ldap). Is it safe/better/not a good idea to deactivate the active plugin from every chain (user_load; user_create; user_delete) ? The sm.xml seems to indicate that the deliver plugin also use the active status, but I couldn't find any of this in the code. You may want to implement the fail-if-not-exist function in your own roster module in this chain. For now, I think it's ok : users can not connect to any c2s without existing and can not register through XMPP. But I take good note of this advice if ever I need it. Thank you very much for your time. -- Sylvain Gugli Guglielmi
Re: Roster module with custom MySQL requests
Le 01/04/2014 16:40, Tomasz Sterna a écrit : Dnia 2014-04-01, wto o godzinie 15:56 +0200, Sylvain Guglielmi pisze: Is it safe/better/not a good idea to deactivate the active plugin from every chain (user_load; user_create; user_delete) ? It's main function is to drop messages to unexisting users instead of storing them in offline messages store. If you remove it, you are potentially vulnerable to DoS attack filling your offline storage database with messages for bogus users. Ok, good to know. I'll remove it form the user_load chain and let it be in the others. Thanks again. -- Sylvain Gugli Guglielmi
Re: Roster module with custom MySQL requests
Le 10/01/2014 18:23, Tomasz Sterna a écrit You could have a separate cron component pinging 'sm' in regular intervals with special route packet, and handle this special packet in 'in-router' chain of your module. Having that it could even be done not in regular intervals, but on-demand, when your component gets triggered by web frontend. This works very well ! Thanks for the advice. My cron component is a short php script. I was unsure about how to answer disco#info queries that I get from other components, but it seems to work without answering anything. I'll read the XEP-0030 : Service Discovery RFC later and try to make a more compliant cron component. If anyone is interested in the php simple DIGEST-MD5 auth, code can be found here (It's not robust and exhaustive, but it can be useful I guess) : https://github.com/Gugli/jabberd2/blob/master/tools/sendupdatepacket.php I've been scratching my head for the last couple of days on another issue : our legacy contact system does not allow asymetrical relationships (as XMPP does). It would be very complicated to change that to a more XMPP-compliant system. The solution I came up with is to make a symmetrical mode for my roster module. In this mode : - whenever a user sends a presence subscription, the sm also consider the user allows subscription to the same contact. - whenever a user allows a contact to subscribe to his presence, the sm also consider that the user subscribe back to the same contact's presence. The session that requests the change has to be informed of this additional change with a push as any other session. Basically, item-from and item-to are linked, they always are the same value. This makes a kind of restricted XMPP protocol. It's not great, but it's the only sensible way I found to go on. Has anyone already done something approaching ? Is it bad ? Thanks very much again for all the help you provide :) -- Sylvain Gugli Guglielmi
Re: Roster module with custom MySQL requests
Another issue I'm facing : I need my module to be able to detect changes in the database and report it to the connected users if necessary. (Use case : the person adds a friend with something else than a XMPP client, like a web page interface or a webservice API, while she's connected). The way I choose to do that is : - the session manager looks for a syncro='out_of_sync' field in the database - set syncro to 'syncing' for some rows - then change the memory roster items and push packets to the user's sessions with selected changes - then set syncro to 'ok'. (In order to make this case simpler, I will do as if there were no row deletions, but there are ^_^) I'm wondering when is the best way to call this function : - I can make a per-user function, looking only for changes in rows concerning a specific user, and call it at the beginning of the mod-in_sess and mod-pkt_user functions. - I can call it on a regular interval (something like 5 seconds) and look for changes for any user. Then, if the user is loaded, apply changes, and if the user has at least one opened session, send the packets. For now, I've implemented the first solution. But my feeling is that the 2nd solution would be better performance-wise (too many requests with the 1st). I'm only stopped by the regular interval thing. My question : *Should I add a timetick chain to the SM (called every second for example), and add my module to this chain (with a rate_t check) ?* I'm not thrilled by this solution, because for now, I haven't changed any code from jabberd2 except from the new module, which make it easier to test or get in production. *Is there another, better way ?* Thanks for reading, and I'm grateful in advance for any useful insight. :) On a side note : the 5s interval could lead to some race conditions, but I think we can avoid any inconststencies (by using INSERT ... ON DUPLICATE KEY UPDATE ... instead of UPDATE ... for one). The behavior being undetermined if a user issues 2 conflicting commands at the same time through differents means is not an issue, if the resulting state is the result of one of the user's commands. -- Sylvain Gugli Guglielmi Gamedev@Nadeo@Ubisoft
Re: Silent (0 packets) connections staying established
Le 06/01/2013 18:14, Tomasz Sterna a écrit : Dnia 2013-01-04, pią o godzinie 14:31 +0100, Sylvain Guglielmi pisze: At first, we had to face ghost connections (from users not properly disconnecting). To solve that, I changed c2s.xml to have check interval600/interval idle0/idle keepalive600/keepalive /check So unplugged connections will be closed correctly after 10min. It solved the problem. My problem is that I still can see the 500 established connections (netstat -n | grep 'XXX.XXX.XXX.XXX'). Even if this connection spam occurred yesterday (long enough for keepalive to do its job) Are you sure this is a problem with jabberd, not your TCP stack configuration? It's usually the job of TCP layer to detect and close torn-down connections and using user level protocol layer keepalives to enforce this is just for convenience to the users, so they won't write to the vacuum (instead just one whitespace gets lost). If you are on Linux take a look at: https://www.linux.com/learn/docs/ldp/768-tcp-keepalive-howto http://www.speedguide.net/articles/linux-tweaking-121 It seems that my TCP stack is configured to send keepalive probes after 2h (default linux timers : 7200s / 75s / 9probes). If I understand correctly the link you sent (https://www.linux.com/learn/docs/ldp/768-tcp-keepalive-howto), the system-wide keepalive parameters are not used (*) unless setsockopt is called after socket creation (in this case, I guess it's the accept call in mio_impl.h[150] : _mio_accept(...)). Adding the following code at mio_impl.h[168] may be a way to test if it solves things : optval = 1; if(setsockopt(newfd, SOL_SOCKET, SO_KEEPALIVE, optval, sizeof(optval)) 0) { close(newfd); return; } Unfortunately, I've not yet managed to get a proper dev environement for jabberd2 (coding under Windows does not help, I guess -_-'... But I got most of the libs working : I'm probably not that far from making it work). Due to deadlines, I'm not sure I'll be able to do it before the end of January. I'll keep you updated as soon as I've managed to run some tests. If this solves the issue, maybe it can be envisioned to add an option for that in c2s.xml. It seems that setsockopt can also set keepalive probes timers to override system-wide config. It could probably be added to c2s.xml too, to complete or supersede the keepalive by sending space thing. (*) : I've had a hard time to find the default value for the SO_KEEPALIVE option. On windows, it seem to be false [http://msdn.microsoft.com/en-us/library/windows/desktop/ee470551%28v=vs.85%29.aspx] , but I'm not yet sure about the default value on Linux... Also, I've not yet found any way to force system-wide use of keepalive for TCP streams. -- Sylvain Gugli Guglielmi Gamedev@Nadeo@Ubisoft
Silent (0 packets) connections staying established
Hello. I have one XMPP server in production (approx 1.5k simultaneous connections from 170k users), running the latest jabberd2 from Ubuntu's repos (this one : http://packages.ubuntu.com/precise/net/jabberd2). At first, we had to face ghost connections (from users not properly disconnecting). To solve that, I changed c2s.xml to have check interval600/interval idle0/idle keepalive600/keepalive /check So unplugged connections will be closed correctly after 10min. It solved the problem. But yesterday, in our system logs, I saw a step in established connections : +500 connections in a few seconds. In c2s.log I found approx. 500 connections from one IP (probably a bug in client or malicious attempt), with 500 lines like : Thu Jan 3 20:24:41 2013 [notice] [700] [XXX.XXX.XXX.XXX, port=2090] connect Thu Jan 3 20:24:41 2013 [notice] [737] [XXX.XXX.XXX.XXX, port=2091] connect Thu Jan 3 20:24:41 2013 [notice] [786] [XXX.XXX.XXX.XXX, port=2092] connect Thu Jan 3 20:24:41 2013 [notice] [794] [XXX.XXX.XXX.XXX, port=2093] connect Thu Jan 3 20:24:41 2013 [notice] [796] [XXX.XXX.XXX.XXX, port=2094] connect Thu Jan 3 20:24:41 2013 [notice] [798] [XXX.XXX.XXX.XXX, port=2095] connect Is goes on for 10s, then stops 10s, then they all disconnect : Thu Jan 3 20:25:03 2013 [notice] [1482] [XXX.XXX.XXX.XXX, port=2740] disconnect jid=unbound, packets: 0 Thu Jan 3 20:25:03 2013 [notice] [1486] [XXX.XXX.XXX.XXX, port=2744] disconnect jid=unbound, packets: 0 Thu Jan 3 20:25:03 2013 [notice] [1490] [XXX.XXX.XXX.XXX, port=2748] disconnect jid=unbound, packets: 0 Thu Jan 3 20:25:03 2013 [notice] [1494] [XXX.XXX.XXX.XXX, port=2752] disconnect jid=unbound, packets: 0 Thu Jan 3 20:25:03 2013 [notice] [1498] [XXX.XXX.XXX.XXX, port=2756] disconnect jid=unbound, packets: 0 Thu Jan 3 20:25:03 2013 [notice] [1502] [XXX.XXX.XXX.XXX, port=2760] disconnect jid=unbound, packets: 0 My problem is that I still can see the 500 established connections (netstat -n | grep 'XXX.XXX.XXX.XXX'). Even if this connection spam occurred yesterday (long enough for keepalive to do its job) To prevent this to happen again, I have changed c2s.xml to io limits connects10/connects /limits /io But if I understand correctly, it should only decrease the number of created connections, and it would not prevent them from being kept established even when unnecessary. I've looked at the code, and I think 0-packet connections are properly added to c2s-dead_sess (and thus should be cleaned). I couldn't find any problem, but yet I'm not very familiar with this code. Is there a configuration item that I missed to prevent that ? Is it a bug that has been fixed since but not yet corrected in Ubuntu's repos ? Thanks in advance for any help. Apart from that, the server is doing great : very low resources consumption. ^_^ -- Sylvain Gugli Guglielmi Gamedev@Nadeo@Ubisoft
Re: mod_roster : read only roster
Thanks for your quick answer. Le 08/11/2012 17:04, Tomasz Sterna a écrit : This is exactly what chains were created for. You can write your own special case module and use it. You may create a feature request [1] if you do not want to write this module yourself. I think I'll be able to write such a module. I'll push or send he code when it's usable. If you need to, you may write a component that impersonates as a user and changes its roster using standard XMPP packets. Alternatively you may extend command port [2] with support for editing user roster. I'll look further into command port to see what I can do. Thanks again. -- Sylvain Gugli Guglielmi
mod_roster : read only roster
Hello, First of all, thanks to anyone involved for the really good job done on jabberd2. I've been trying to add an Xmpp compatibility to some pre-existing services : I already have an user-list, passwords, and a roster-like buddy list. I choose to use MySql storage, for authreg and for sessions. To ensure consistency, I'd like to prevent changes to auth data and roster from any IM client. Users will use the old system to add or remove contacts or change password, and the system will update the authreg or roster-items table directly upon changes through SQL. mod_authreg allows that : I disabled registration, without activating password changes, and I use my out-of-band registration/password changes (using id configuration attributes). But I have not yet found any easy way to have a read only mod_roster. - I've tried to revoke rights from the SM user on the table roster-items. It seems to work server-side, but I think the server does not report a failure to the client when modifying the roster, and it seems some clients will update their local copy of the roster. Since some clients will rely on this local list (it seem to be the case with MirandaIM for example, even if it should not, according to http://tools.ietf.org/html/rfc6121#section-2.2 ), this situation leads to inconsistencies. It's not a major issue : if the clients start to face problems, they can remove the account from their IM client, and then re-add it. It should then fetch the correct roster form jabberd2 server. So even if this solution is acceptable, it's not very clean. Also, I'm not sure about the consequences on sm when having fine-grained database rights. At this time, I can see 2 other solutions, yet to try. - creating my own module mod_preventrosterchanges. This module would only handle roster changes by dropping them, and pass everything else. It would be added to the in-session chain, just before mod roster. - Adding new options roster.disablesubscriptions and roster.disablechanges, loaded from sm.xml. For now, I think only option in mod_roster is roster.maxitems (mod_roster.c : 839). with roster.disablesubscriptions enabled, mod_roster would report an error to the client when before calling _roster_in_sess_s10n, or in _roster_pkt_user and with roster.disablechanges enabled, mod_roster would report an error in case of Roster Set. (Inside _roster_in_sess. mod_roster.c : 557) Such an error message seem to be described in http://tools.ietf.org/html/rfc6121#section-2.3.3 with the not-allowed/ mark-up. I guess those 2 solutions should behave nicely overall, and prevent the clients form updating their local roster on a failed add/set/delete. The only problem would be that clients will not get a Roster Push (http://tools.ietf.org/html/rfc6121#section-2.1.6) when the roster is updated using the previous system. This could probably be fixed with another component sending Roster Push stanzas at sess_start when updating roster from the existing database. I'd be very grateful to hear any advice from people more aware of Xmpp and jabberd2 constraints. Since I've been tinkering with jabberd2 for a few days only, I'm probably overlooking other ingenious solutions. I'd be glad to contribute to the project if alternate-solution #2 seems to everyone a good thing to add. Thanks to anyone who took the time needed to read my shameful wall-of-text... And many thanks in advance for any answer/hint/advice... -- Sylvain Gugli Guglielmi