|
| 1 | +%%%---------------------------------------------------------------------- |
| 2 | +%%% File : ejabberd_c2s.erl |
| 3 | +%%% Author : Alexey Shchepin <alexey@sevcom.net> |
| 4 | +%%% Purpose : |
| 5 | +%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@sevcom.net> |
| 6 | +%%% Id : $Id$ |
| 7 | +%%%---------------------------------------------------------------------- |
| 8 | + |
| 9 | +-module(ejabberd_c2s). |
| 10 | +-author('alexey@sevcom.net'). |
| 11 | +-vsn('$Revision$ '). |
| 12 | + |
| 13 | +-behaviour(gen_fsm). |
| 14 | + |
| 15 | +%% External exports |
| 16 | +-export([start/1, receiver/2, sender/1, send_text/2]). |
| 17 | + |
| 18 | +%% gen_fsm callbacks |
| 19 | +%-export([init/1, state_name/2, state_name/3, handle_event/3, |
| 20 | +% handle_sync_event/4, handle_info/3, terminate/3]). |
| 21 | +% |
| 22 | +-export([init/1, wait_for_stream/2, wait_for_auth/2, terminate/3]). |
| 23 | + |
| 24 | +-record(state, {socket, sender, receiver}). |
| 25 | + |
| 26 | +-include("ejabberd.hrl"). |
| 27 | + |
| 28 | +%start_old(Socket) -> |
| 29 | +% spawn(?MODULE, init, [Socket]). |
| 30 | + |
| 31 | +%init_old(Socket) -> |
| 32 | +% SenderPid = spawn(?MODULE, sender, [Socket]), |
| 33 | +% ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]), |
| 34 | +% loop_old(Socket, SenderPid, ReceiverPid). |
| 35 | +% |
| 36 | +%loop_old(Socket, SenderPid, ReceiverPid) -> |
| 37 | +% receive |
| 38 | +% {xmlstreamstart, Name, Attrs} -> |
| 39 | +% ?DEBUG("Socket(~p) -> XML Stream start~n" |
| 40 | +% " Name: ~s~n" |
| 41 | +% " Attrs: ~p~n", [Socket, Name, Attrs]), |
| 42 | +% loop_old(Socket, SenderPid, ReceiverPid); |
| 43 | +% {xmlstreamend, Name} -> |
| 44 | +% ?DEBUG("Socket(~p) -> XML Stream end~n" |
| 45 | +% " Name: ~s~n", [Socket, Name]), |
| 46 | +% loop_old(Socket, SenderPid, ReceiverPid); |
| 47 | +% {xmlstreamelement, El} -> |
| 48 | +% ?DEBUG("Socket(~p) -> XML Stream element~n" |
| 49 | +% " Element: ~p~n", [Socket, El]), |
| 50 | +% loop_old(Socket, SenderPid, ReceiverPid); |
| 51 | +% {xmlstreamerror, Err} -> |
| 52 | +% ?DEBUG("Socket(~p) -> XML Stream error~n" |
| 53 | +% " Error: ~p~n", [Socket, Err]), |
| 54 | +% loop_old(Socket, SenderPid, ReceiverPid) |
| 55 | +% end. |
| 56 | + |
| 57 | + |
| 58 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 59 | + |
| 60 | +-define(DBGFSM, true). |
| 61 | + |
| 62 | +-ifdef(DBGFSM). |
| 63 | +-define(FSMOPTS, [{debug, [trace]}]). |
| 64 | +-else. |
| 65 | +-define(FSMOPTS, []). |
| 66 | +-endif. |
| 67 | + |
| 68 | +-define(STREAM_HEADER, |
| 69 | + "<stream:stream xmlns='jabber:client' " |
| 70 | + "xmlns:stream='http://etherx.jabber.org/streams' " |
| 71 | + "id='~s' from='~s'>" |
| 72 | + ). |
| 73 | + |
| 74 | +%%%---------------------------------------------------------------------- |
| 75 | +%%% API |
| 76 | +%%%---------------------------------------------------------------------- |
| 77 | +start(Socket) -> |
| 78 | + gen_fsm:start(ejabberd_c2s, [Socket], ?FSMOPTS). |
| 79 | +%start_old(Socket) -> |
| 80 | +% spawn(?MODULE, init, [Socket]). |
| 81 | + |
| 82 | +%%%---------------------------------------------------------------------- |
| 83 | +%%% Callback functions from gen_fsm |
| 84 | +%%%---------------------------------------------------------------------- |
| 85 | + |
| 86 | +%%---------------------------------------------------------------------- |
| 87 | +%% Func: init/1 |
| 88 | +%% Returns: {ok, StateName, StateData} | |
| 89 | +%% {ok, StateName, StateData, Timeout} | |
| 90 | +%% ignore | |
| 91 | +%% {stop, StopReason} |
| 92 | +%%---------------------------------------------------------------------- |
| 93 | +init([Socket]) -> |
| 94 | + SenderPid = spawn(?MODULE, sender, [Socket]), |
| 95 | + ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]), |
| 96 | + {ok, wait_for_stream, #state{socket = Socket, |
| 97 | + receiver = ReceiverPid, |
| 98 | + sender = SenderPid}}. |
| 99 | + |
| 100 | +%%---------------------------------------------------------------------- |
| 101 | +%% Func: StateName/2 |
| 102 | +%% Returns: {next_state, NextStateName, NextStateData} | |
| 103 | +%% {next_state, NextStateName, NextStateData, Timeout} | |
| 104 | +%% {stop, Reason, NewStateData} |
| 105 | +%%---------------------------------------------------------------------- |
| 106 | +state_name(Event, StateData) -> |
| 107 | + {next_state, state_name, StateData}. |
| 108 | + |
| 109 | +wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> |
| 110 | + case lists:keysearch("xmlns:stream", 1, Attrs) of |
| 111 | + {value, {"xmlns:stream", "http://etherx.jabber.org/streams"}} -> |
| 112 | + % TODO |
| 113 | + Header = io_lib:format(?STREAM_HEADER, ["SID", "localhost"]), |
| 114 | + StateData#state.sender ! {text, Header}, |
| 115 | + {next_state, wait_for_auth, StateData}; |
| 116 | + _ -> |
| 117 | + {stop, error, StateData} |
| 118 | + end; |
| 119 | + |
| 120 | +wait_for_stream(closed, StateData) -> |
| 121 | + {stop, normal, StateData}. |
| 122 | + |
| 123 | + |
| 124 | +wait_for_auth({xmlstreamelement, El}, StateData) -> |
| 125 | + % TODO |
| 126 | + {next_state, wait_for_auth, StateData}; |
| 127 | + |
| 128 | +wait_for_auth({xmlstreamend, Name}, StateData) -> |
| 129 | + % TODO |
| 130 | + {stop, normal, StateData}; |
| 131 | + |
| 132 | +wait_for_auth(closed, StateData) -> |
| 133 | + {stop, normal, StateData}. |
| 134 | + |
| 135 | + |
| 136 | + |
| 137 | + |
| 138 | +%%---------------------------------------------------------------------- |
| 139 | +%% Func: StateName/3 |
| 140 | +%% Returns: {next_state, NextStateName, NextStateData} | |
| 141 | +%% {next_state, NextStateName, NextStateData, Timeout} | |
| 142 | +%% {reply, Reply, NextStateName, NextStateData} | |
| 143 | +%% {reply, Reply, NextStateName, NextStateData, Timeout} | |
| 144 | +%% {stop, Reason, NewStateData} | |
| 145 | +%% {stop, Reason, Reply, NewStateData} |
| 146 | +%%---------------------------------------------------------------------- |
| 147 | +state_name(Event, From, StateData) -> |
| 148 | + Reply = ok, |
| 149 | + {reply, Reply, state_name, StateData}. |
| 150 | + |
| 151 | +%%---------------------------------------------------------------------- |
| 152 | +%% Func: handle_event/3 |
| 153 | +%% Returns: {next_state, NextStateName, NextStateData} | |
| 154 | +%% {next_state, NextStateName, NextStateData, Timeout} | |
| 155 | +%% {stop, Reason, NewStateData} |
| 156 | +%%---------------------------------------------------------------------- |
| 157 | +handle_event(Event, StateName, StateData) -> |
| 158 | + {next_state, StateName, StateData}. |
| 159 | + |
| 160 | +%%---------------------------------------------------------------------- |
| 161 | +%% Func: handle_sync_event/4 |
| 162 | +%% Returns: {next_state, NextStateName, NextStateData} | |
| 163 | +%% {next_state, NextStateName, NextStateData, Timeout} | |
| 164 | +%% {reply, Reply, NextStateName, NextStateData} | |
| 165 | +%% {reply, Reply, NextStateName, NextStateData, Timeout} | |
| 166 | +%% {stop, Reason, NewStateData} | |
| 167 | +%% {stop, Reason, Reply, NewStateData} |
| 168 | +%%---------------------------------------------------------------------- |
| 169 | +handle_sync_event(Event, From, StateName, StateData) -> |
| 170 | + Reply = ok, |
| 171 | + {reply, Reply, StateName, StateData}. |
| 172 | + |
| 173 | +%%---------------------------------------------------------------------- |
| 174 | +%% Func: handle_info/3 |
| 175 | +%% Returns: {next_state, NextStateName, NextStateData} | |
| 176 | +%% {next_state, NextStateName, NextStateData, Timeout} | |
| 177 | +%% {stop, Reason, NewStateData} |
| 178 | +%%---------------------------------------------------------------------- |
| 179 | +handle_info(Info, StateName, StateData) -> |
| 180 | + {next_state, StateName, StateData}. |
| 181 | + |
| 182 | +%%---------------------------------------------------------------------- |
| 183 | +%% Func: terminate/3 |
| 184 | +%% Purpose: Shutdown the fsm |
| 185 | +%% Returns: any |
| 186 | +%%---------------------------------------------------------------------- |
| 187 | +terminate(Reason, StateName, StatData) -> |
| 188 | + ok. |
| 189 | + |
| 190 | +%%%---------------------------------------------------------------------- |
| 191 | +%%% Internal functions |
| 192 | +%%%---------------------------------------------------------------------- |
| 193 | + |
| 194 | +receiver(Socket, C2SPid) -> |
| 195 | + XMLStreamPid = xml_stream:start(C2SPid), |
| 196 | + receiver(Socket, C2SPid, XMLStreamPid). |
| 197 | + |
| 198 | +receiver(Socket, C2SPid, XMLStreamPid) -> |
| 199 | + case gen_tcp:recv(Socket, 0) of |
| 200 | + {ok, Text} -> |
| 201 | + xml_stream:send_text(XMLStreamPid, Text), |
| 202 | + receiver(Socket, C2SPid, XMLStreamPid); |
| 203 | + {error, closed} -> |
| 204 | + gen_fsm:send_event(C2SPid, closed), |
| 205 | + ok |
| 206 | + end. |
| 207 | + |
| 208 | +sender(Socket) -> |
| 209 | + receive |
| 210 | + {text, Text} -> |
| 211 | + gen_tcp:send(Socket,Text), |
| 212 | + sender(Socket); |
| 213 | + closed -> |
| 214 | + ok |
| 215 | + end. |
| 216 | + |
| 217 | +send_text(Pid, Text) -> |
| 218 | + Pid ! {text, Text}. |
| 219 | + |
0 commit comments