Ejabberd custom IQ Handler: getting feature-not-im

2019-07-14 05:28发布

问题:

I stripped mod_last.erl to test the creation of a IQHandler (pasted only the part that matters):

start(Host, Opts) ->
    IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
                             one_queue),
    gen_iq_handler:add_iq_handler(ejabberd_local, Host,
                  <<"join">>, ?MODULE, process_local_iq, IQDisc).

stop(Host) ->
    gen_iq_handler:remove_iq_handler(ejabberd_local, Host,
                     <<"join">>).

process_local_iq(_From, _To,
         #iq{type = Type, sub_el = SubEl} = IQ) ->
    case Type of
      set ->
      IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
      get ->
      Sec = 60,
      IQ#iq{type = result,
        sub_el =
            [#xmlel{name = <<"query">>,
                attrs =
                [{<<"xmlns">>, <<"join">>},
                 {<<"seconds">>,
                  iolist_to_binary(integer_to_list(Sec))}],
                children = []}]}
    end.

But when I send the request:

<iq type='get' id='123'>
    <query xmlns='join'/>
</iq>

I keep getting the service-unavailable error:

<iq from='alfred@localhost' to='alfred@localhost/Alfreds-MacBook-Pro' type='error' id='123'>
<query xmlns='join'/>
<error code='503' type='cancel'>
    <service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>

A similar question wasn't helpful, since I'm not adding to.

Note: the IQHandler that I want to create is to request joining game rooms.

回答1:

If you send an IQ stanza without a to attribute, the server will "handle the stanza on behalf of the sending entity" (RFC 6120, section 10.3.3). In practice, that means that the server will treat the stanza as if the to attribute had been the bare JID of the user, in this case alfred@localhost.

When you call gen_iq_handler:add_iq_handler to register a new handler, you also specify the "scope", either ejabberd_local or ejabberd_sm ("SM" stands for "session manager"). If it's ejabberd_local, the handler will react to IQ stanzas addressed to the server itself, in this case localhost. If it's ejabberd_sm, the handler will react to IQ stanzas addressed to the bare JID of a local user, e.g. alfred@localhost.

So that's why your IQ stanza ends up not being handled. Either include to="localhost" when sending the request, or change ejabberd_local to ejabberd_sm when registering the handler.