Re: Roster module with custom MySQL requests

2014-04-29 Thread Sylvain Guglielmi

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

2014-04-01 Thread Sylvain Guglielmi

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

2014-04-01 Thread Sylvain Guglielmi

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

2014-04-01 Thread Sylvain Guglielmi

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

2014-01-17 Thread Sylvain Guglielmi

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

2014-01-10 Thread Sylvain Guglielmi

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

2013-01-07 Thread Sylvain Guglielmi

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

2013-01-04 Thread Sylvain Guglielmi

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

2012-11-09 Thread Sylvain Guglielmi

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

2012-11-08 Thread Sylvain Guglielmi

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