%% @author YouShuxiang %% @doc @todo Add description to packet. -module(web_ssl_receiver). -include("packet.hrl"). %% ==================================================================== %% API functions %% ==================================================================== -export([start/2]). start(Socket, ConnectPid) -> Fun = fun () -> loop(Socket, ConnectPid) end, erlang:spawn_link(Fun). %% ==================================================================== %% Internal functions %% ==================================================================== loop(Socket, ConnectPid) -> case handle_packet(Socket, ConnectPid) of ok -> loop(Socket, ConnectPid); ignore -> loop(Socket, ConnectPid); {error, _Reason} -> %% ?DEBUG("tcp close: ~p~n", [Reason]), ssl:close(Socket) end. handle_packet(Socket, ConnectPid) -> case handle_head(Socket) of {ok, Args} -> handle_data(Socket, Args, ConnectPid); {web_json, Data} -> ConnectPid ! {web_json, Data}, ok; ignore -> ignore; {error, Reason} -> {error, Reason} end. handle_head(Socket) -> case ssl:recv(Socket, 2) of {ok, Bin} -> <<_Fin:1, _Rsv:3, Opcode:4, _Mask:1, Len:7>> = Bin, %% ?DEBUG("Fin:~p, Rsv:~p, Opcode:~p, Mask:~p, Len:~p~n", [Fin, Rsv, Opcode, Mask, Len]), DataLenth = get_data_lenth(Socket, Len), HeadBin = handle_head_1(Socket, DataLenth), %% ?DEBUG("DataBin: ~p~n", [HeadBin]), case Opcode of 2 -> %% <> = HeadBin, %% ?DEBUG("Cmd: ~p~n", [Cmd]); <> = HeadBin, {ok, {Cmd, Crc, Seq, Data}}; 1 -> {web_json, HeadBin}; _ -> ignore end; {error, Reason} -> %% ?DEBUG("socket error: ~p~n", [Reason]), {error, Reason} end. handle_head_1(Socket, Len) -> case ssl:recv(Socket, Len+4) of {ok, Bin} -> %% ?DEBUG("Bin: ~p~n", [Bin]), <> = Bin, %% <> = Rest, HeadBin = unmask(Payload, Masking), HeadBin; {error, Reason} -> {error, Reason} end. get_data_lenth(Socket, Len) -> case Len of 126 -> do_get_data_lenth(Socket, 2); 127 -> do_get_data_lenth(Socket, 8); _ -> Len end. do_get_data_lenth(Socket, Len) -> case ssl:recv(Socket, Len) of {ok, Bin} -> Bl = Len * 8, <> = Bin, DataLen; {error, Reason} -> %% ?DEBUG("socket error: ~p~n", [Reason]), {error, Reason} end. handle_data(_Socket, Args, ConnectPid) -> {Cmd, _Crc, _Seq, DataBin} = Args, %% ?DEBUG("Cmd = ~p, DataSize = ~p~n", [Cmd, DataSize]), unpack_data(ConnectPid, Cmd, DataBin). unpack_data(ConnectPid, Cmd, DataBin) -> case catch packet:unpack(Cmd, 0, DataBin) of {ok, Cmd, Data, Module} -> %% ?DEBUG("Cmd = ~p, Data = ~p~n", [Cmd, Data]), send_to_parent(ConnectPid, Cmd, Data, Module), ok; _Error -> ignore end. send_to_parent(PID, Cmd, Data, Module) -> Msg = {data, {Cmd, Data, Module}}, PID ! Msg. %% unmask(Payload, Masking) -> unmask(Payload, Masking, <<>>). unmask(Payload, <> = Masking, Acc) -> case size(Payload) of 0 -> Acc; 1 -> <> = Payload, <>; 2 -> <> = Payload, <>; 3 -> <> = Payload, <>; _Other -> <> = Payload, Acc1 = <>, unmask(Rest, Masking, Acc1) end.