1 down vote favorite
share [fb] share [tw]
I have a working Ejabberd server (version 2.1.9) and my client application running just fine, but I wish to modify the way the application's XMPP client connects to Ejabberd in order to reduce the number of requests/responses between them, because its for a mobile environment and I wish to reduce the initial connection time.
I've looked up the XMPP protocol specification (RFC 6120) and some protocol extensions (XEPs), namely XEP-0305 Quickstart, but the protocol itself doesn't specify single request sign in and the Quickstart extension although aims to reduce the number of requests isn't enough for the time reduction I'm looking for.
After searching and not finding any solution I've started to modify both client and server and wish to accomplish the following for now as a proof of concept:
//Client Request
<?xml version='1.0'?>
<stream:stream ... user='user' pass='pass'>
//Server Response
<?xml version='1.0'?>
<stream:stream ... success='1'>
I've managed to modify my client accordingly and the Ejabberd server, and it seems they connect successfully, but any request the client makes after establishing the session doesn't get a response by the server. I've used Wireshark to check the TCP connection client and server side: client side its open and the request is sent, and on the server side is also open and the request is received, but when I try to send the response it is not sent.
I've modified ONLY the file ejabberd_c2s.erl and the changes are the following:
//init function
...
%% changed the first state of the fsm to point to quickstart
%% {ok, wait_for_stream, #state{socket = Socket1,
{ok, wait_for_quickstart, #state{socket = Socket1,
...
//wait_for_quickstart function
...
case resource_conflict_action(U, StateData#state.server, R) of
closenew ->
send_header(StateData, Server, "1.0", DefaultLang, "0"),
send_trailer(StateData),
{stop, normal, StateData};
{accept_resource, R2} ->
JID = jlib:make_jid(U, StateData#state.server, R2),
allow = acl:match_rule(Server,c2s,JID),
case ejabberd_auth:check_password(U, Server, P) of
true ->
send_header(StateData, Server, "1.0", DefaultLang, "1"),
change_shaper(StateData, JID),
{Fs, Ts} = ejabberd_hooks:run_fold(
roster_get_subscription_lists,
StateData#state.server,
{[], []},
[U, StateData#state.server]),
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
Fs1 = [LJID | Fs],
Ts1 = [LJID | Ts],
PrivList =
ejabberd_hooks:run_fold(
privacy_get_user_list,
StateData#state.server,
#userlist{},
[U, StateData#state.server]),
SID = {now(), self()},
Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip},
{conn, Conn},
{auth_module, StateData#state.auth_module}],
ejabberd_sm:open_session(SID, U, StateData#state.server, R, Info),
NewStateData =
StateData#state{
user = U,
resource = R2,
jid = JID,
sid = SID,
conn = Conn,
auth_module = ejabberd_auth_internal,
authenticated = true,
pres_f = ?SETS:from_list(Fs1),
pres_t = ?SETS:from_list(Ts1),
privacy_list = PrivList},
fsm_next_state_pack(session_established,
NewStateData);
_ ->
%%auth fail
end
end.
Just to clarify: the initial client authentication request and server response are being transmitted just fine, subsequent requests are also being transmitted but there is no response to them.
Edit:The problem was that the resource was not defined since I skipped the bind operation and its defined there, so I added the code:
R1 = xml:get_attr_s("r",Attrs),
R = case jlib:resourceprep(R1) of
error -> error;
"" ->
lists:concat([randoms:get_string() | tuple_to_list(now())]);
Resource -> Resource
end,
That made the server respond to my requests, but there was other thing amiss: the <presence/>
tag was breaking on server because the #state.lang
was not defined, so I had to define it in the wait_for_quickstart function and now I have a single sign in XMPP client server working proof of concept.