aboutsummaryrefslogtreecommitdiff
path: root/src/stun/ejabberd_stun.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/stun/ejabberd_stun.erl')
-rw-r--r--src/stun/ejabberd_stun.erl239
1 files changed, 0 insertions, 239 deletions
diff --git a/src/stun/ejabberd_stun.erl b/src/stun/ejabberd_stun.erl
deleted file mode 100644
index 1046fff11..000000000
--- a/src/stun/ejabberd_stun.erl
+++ /dev/null
@@ -1,239 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% File : ejabberd_stun.erl
-%%% Author : Evgeniy Khramtsov <ekhramtsov@process-one.net>
-%%% Description : RFC5389 implementation.
-%%% Currently only Binding usage is supported.
-%%%
-%%% Created : 8 Aug 2009 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-%%% 02111-1307 USA
-%%%
-%%%-------------------------------------------------------------------
--module(ejabberd_stun).
-
--behaviour(gen_fsm).
-
-%% API
--export([start_link/2, start/2, socket_type/0,
- udp_recv/5]).
-
-%% gen_fsm callbacks
--export([init/1, handle_event/3, handle_sync_event/4,
- handle_info/3, terminate/3, code_change/4]).
-
-%% gen_fsm states
--export([wait_for_tls/2, session_established/2]).
-
--include("ejabberd.hrl").
-
--include("stun.hrl").
-
--define(MAX_BUF_SIZE, 64 * 1024).
-
--define(TIMEOUT, 10000).
-
--record(state,
- {sock :: inet:socket() | tls:tls_socket(),
- sock_mod = gen_tcp :: gen_udp | gen_tcp | tls,
- certfile :: binary(),
- peer = {{0,0,0,0}, 0} :: {inet:ip_address(), inet:port_number()},
- tref = make_ref() :: reference(),
- buf = <<>> :: binary()}).
-
-%%====================================================================
-%% API
-%%====================================================================
-start({gen_tcp, Sock}, Opts) ->
- supervisor:start_child(ejabberd_stun_sup, [Sock, Opts]).
-
-start_link(Sock, Opts) ->
- gen_fsm:start_link(?MODULE, [Sock, Opts], []).
-
-socket_type() -> raw.
-
-udp_recv(Sock, Addr, Port, Data, _Opts) ->
- case stun_codec:decode(Data) of
- {ok, Msg, <<>>} ->
- ?DEBUG("got:~n~p", [Msg]),
- case process(Addr, Port, Msg) of
- RespMsg when is_record(RespMsg, stun) ->
- ?DEBUG("sent:~n~p", [RespMsg]),
- Data1 = stun_codec:encode(RespMsg),
- gen_udp:send(Sock, Addr, Port, Data1);
- _ -> ok
- end;
- _ -> ok
- end.
-
-%%====================================================================
-%% gen_fsm callbacks
-%%====================================================================
-init([Sock, Opts]) ->
- case inet:peername(Sock) of
- {ok, Addr} ->
- inet:setopts(Sock, [{active, once}]),
- TRef = erlang:start_timer(?TIMEOUT, self(), stop),
- State = #state{sock = Sock, peer = Addr, tref = TRef},
- case proplists:get_value(certfile, Opts) of
- undefined -> {ok, session_established, State};
- CertFile ->
- {ok, wait_for_tls, State#state{certfile = CertFile}}
- end;
- Err -> Err
- end.
-
-wait_for_tls(Event, State) ->
- ?INFO_MSG("unexpected event in wait_for_tls: ~p",
- [Event]),
- {next_state, wait_for_tls, State}.
-
-session_established(Msg, State)
- when is_record(Msg, stun) ->
- ?DEBUG("got:~n~p", [Msg]),
- {Addr, Port} = State#state.peer,
- case process(Addr, Port, Msg) of
- Resp when is_record(Resp, stun) ->
- ?DEBUG("sent:~n~p", [Resp]),
- Data = stun_codec:encode(Resp),
- (State#state.sock_mod):send(State#state.sock, Data);
- _ -> ok
- end,
- {next_state, session_established, State};
-session_established(Event, State) ->
- ?INFO_MSG("unexpected event in session_established: ~p",
- [Event]),
- {next_state, session_established, State}.
-
-handle_event(_Event, StateName, State) ->
- {next_state, StateName, State}.
-
-handle_sync_event(_Event, _From, StateName, State) ->
- {reply, {error, badarg}, StateName, State}.
-
-handle_info({tcp, Sock, TLSData}, wait_for_tls,
- State) ->
- Buf = <<(State#state.buf)/binary, TLSData/binary>>,
- case Buf of
- _ when byte_size(Buf) < 3 ->
- {next_state, wait_for_tls,
- update_state(State#state{buf = Buf})};
- <<_:16, 1, _/binary>> ->
- TLSOpts = [{certfile, State#state.certfile}],
- {ok, TLSSock} = tls:tcp_to_tls(Sock, TLSOpts),
- NewState = State#state{sock = TLSSock, buf = <<>>,
- sock_mod = tls},
- case tls:recv_data(TLSSock, Buf) of
- {ok, Data} ->
- process_data(session_established, NewState, Data);
- _Err -> {stop, normal, NewState}
- end;
- _ -> process_data(session_established, State, TLSData)
- end;
-handle_info({tcp, _Sock, TLSData}, StateName,
- #state{sock_mod = tls} = State) ->
- case tls:recv_data(State#state.sock, TLSData) of
- {ok, Data} -> process_data(StateName, State, Data);
- _Err -> {stop, normal, State}
- end;
-handle_info({tcp, _Sock, Data}, StateName, State) ->
- process_data(StateName, State, Data);
-handle_info({tcp_closed, _Sock}, _StateName, State) ->
- ?DEBUG("connection reset by peer", []),
- {stop, normal, State};
-handle_info({tcp_error, _Sock, Reason}, _StateName,
- State) ->
- ?DEBUG("connection error: ~p", [Reason]),
- {stop, normal, State};
-handle_info({timeout, TRef, stop}, _StateName,
- #state{tref = TRef} = State) ->
- {stop, normal, State};
-handle_info(Info, StateName, State) ->
- ?INFO_MSG("unexpected info: ~p", [Info]),
- {next_state, StateName, State}.
-
-terminate(_Reason, _StateName, State) ->
- catch (State#state.sock_mod):close(State#state.sock),
- ok.
-
-code_change(_OldVsn, StateName, State, _Extra) ->
- {ok, StateName, State}.
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-process(Addr, Port,
- #stun{class = request, unsupported = []} = Msg) ->
- Resp = prepare_response(Msg),
- if Msg#stun.method == (?STUN_METHOD_BINDING) ->
- case stun_codec:version(Msg) of
- old ->
- Resp#stun{class = response,
- 'MAPPED-ADDRESS' = {Addr, Port}};
- new ->
- Resp#stun{class = response,
- 'XOR-MAPPED-ADDRESS' = {Addr, Port}}
- end;
- true ->
- Resp#stun{class = error,
- 'ERROR-CODE' = {405, <<"Method Not Allowed">>}}
- end;
-process(_Addr, _Port, #stun{class = request} = Msg) ->
- Resp = prepare_response(Msg),
- Resp#stun{class = error,
- 'UNKNOWN-ATTRIBUTES' = Msg#stun.unsupported,
- 'ERROR-CODE' = {420, stun_codec:reason(420)}};
-process(_Addr, _Port, _Msg) -> pass.
-
-prepare_response(Msg) ->
- Version = <<"ejabberd ", (iolist_to_binary(?VERSION))/binary>>,
- #stun{method = Msg#stun.method, magic = Msg#stun.magic,
- trid = Msg#stun.trid, 'SOFTWARE' = Version}.
-
-process_data(NextStateName, #state{buf = Buf} = State,
- Data) ->
- NewBuf = <<Buf/binary, Data/binary>>,
- case stun_codec:decode(NewBuf) of
- {ok, Msg, Tail} ->
- gen_fsm:send_event(self(), Msg),
- process_data(NextStateName, State#state{buf = <<>>},
- Tail);
- empty ->
- NewState = State#state{buf = <<>>},
- {next_state, NextStateName, update_state(NewState)};
- more when byte_size(NewBuf) < (?MAX_BUF_SIZE) ->
- NewState = State#state{buf = NewBuf},
- {next_state, NextStateName, update_state(NewState)};
- _ -> {stop, normal, State}
- end.
-
-update_state(#state{sock = Sock} = State) ->
- case State#state.sock_mod of
- gen_tcp -> inet:setopts(Sock, [{active, once}]);
- SockMod -> SockMod:setopts(Sock, [{active, once}])
- end,
- cancel_timer(State#state.tref),
- TRef = erlang:start_timer(?TIMEOUT, self(), stop),
- State#state{tref = TRef}.
-
-cancel_timer(TRef) ->
- case erlang:cancel_timer(TRef) of
- false ->
- receive {timeout, TRef, _} -> ok after 0 -> ok end;
- _ -> ok
- end.