SHARE
TWEET

blackbeard

a guest Dec 1st, 2010 460 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -module(websocketd).
  2. -compile(export_all).
  3. -author({jha, abhinav}).
  4.  
  5.  
  6. start() ->
  7.     {ok, L} = gen_tcp:listen(8000, [binary, {active, true}, {reuseaddr, true}, {packet, 0}]),
  8.     erlang:process_flag(trap_exit, true),
  9.     Pid = spawn_link(websocketd, acceptor, [L]),
  10.     receive
  11.         {'EXIT', Pid, Why} ->
  12.             io:format("Process ~p exited with ~p. ~n", [Pid, Why]);
  13.         Any ->
  14.             io:format("~p~n", [Any])
  15.     end.
  16.  
  17. % Accepts multiple connections and handles them separately.
  18. acceptor(L)->
  19.     {ok, S} = gen_tcp:accept(L),
  20.     spawn(fun()->acceptor(L) end),
  21.     handle(S).
  22.  
  23. % Not really required, just a wrapper over handle/2 in case we want to do something later.
  24. handle(S)->
  25.     handle(S, []).
  26.  
  27. handle(S, _Data)->
  28.     Pid = self(),
  29.     Child = spawn(fun() -> handshake_and_talk(Pid) end),
  30.     loop(S, Child).
  31.  
  32. loop(S, Child)->
  33.     receive
  34.         {tcp, S, Bin} ->
  35.             Child ! {self(), Bin},
  36.             loop(S, Child);
  37.         {Child, X} ->
  38.             gen_tcp:send(S, X),
  39.             loop(S, Child);
  40.         _Any ->
  41.             loop(S, Child)
  42.     end.
  43.            
  44.  
  45. % Handshake with the client and begin talking.
  46. handshake_and_talk(Ppid)->
  47.     receive
  48.         {Ppid, X} ->
  49.             % Body = the checksum comprised after processing Key1, Key2 and the Client's request body.
  50.             Body = process_client_handshake(binary_to_list(X)),
  51.  
  52.             % Send the Handshake stuff to the browser.
  53.             Ppid ! {self(), "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"},
  54.             Ppid ! {self(), "Upgrade: WebSocket\r\n"},
  55.             Ppid ! {self(), "Connection: Upgrade\r\n"},
  56.             Ppid ! {self(), "Sec-WebSocket-Origin: http://127.0.0.1:8080\r\n"},
  57.             Ppid ! {self(), "Sec-WebSocket-Location: ws://127.0.0.1:8000/\r\n"},
  58.             Ppid ! {self(), "Sec-WebSocket-Protocol: chat"},
  59.             Ppid ! {self(), "\r\n\r\n"},
  60.  
  61.             % Send the body.
  62.             Ppid ! {self(), Body},
  63.  
  64.             % Now call the talk method to do the actual talking with the browser.
  65.             talk(Ppid);
  66.  
  67.         Any -> io:format("[Child] Random stuff received:~p~n. ~p", [Any, Ppid])
  68.     end.
  69.  
  70.  
  71. % Function to actuall talk to the browser.
  72. % Dummy implementation -  Implement as reuired.
  73. talk(Browser) ->
  74.     receive
  75.     after 1000 ->
  76.             % This is the main communicator function to the Browser.
  77.             % Whatever you write instead of "Hahah" will get sent to the browser.
  78.             % the 0 and 255 is the framing ( required) - don't change that.
  79.             Browser ! {self(), [0]},
  80.             Browser ! {self(), "Hahah"},
  81.             Browser ! {self(), [255]},
  82.             talk(Browser)
  83.     end.
  84.  
  85. % Process client's handshake to retrieve information.
  86. process_client_handshake(X)->
  87.     [Body|Head] = lists:reverse(string:tokens(X, "\r\n")),
  88.     {Key1, Key2} = extract_keys(lists:reverse(Head)),
  89.     {Skey1, Skey2} = process_keys(Key1, Key2),
  90.     Bin_body = list_to_binary(Body),
  91.     Key = <<Skey1:32/big-unsigned-integer, Skey2:32/big-unsigned-integer, Bin_body/binary>>,
  92.     erlang:md5(Key).
  93.  
  94. % Extract keys from the client's handshake.
  95. extract_keys([H|T])->
  96.     Key1 = extract_key("Sec-WebSocket-Key1: ", [H|T]),
  97.     Key2 = extract_key("Sec-WebSocket-Key2: ", [H|T]),
  98.     {Key1, Key2}.
  99.  
  100. extract_key(X, [H|T])->
  101.     case string:str(H, X) of
  102.         0 -> extract_key(X, T);
  103.         _Pos -> string:substr(H, string:len(X) + 1)
  104.     end.
  105.  
  106. % Process the keys as mentioned in the handshake 76 draft of the ietf.
  107. process_keys(Key1, Key2)->
  108.     {Digits1, []} = string:to_integer(digits(Key1)),
  109.     {Digits2, []} = string:to_integer(digits(Key2)),
  110.     Spaces1 = spaces(Key1),
  111.     Spaces2 = spaces(Key2),
  112.     {Digits1 div Spaces1, Digits2 div Spaces2}.
  113.  
  114. % Concatenate digits 0-9 of a string
  115. digits(X)-> [A || A<-X, A =< 57, A >= 48].
  116.  
  117. % Count number of spaces in a string.
  118. spaces(X)-> string:len([ A || A<-X, A =:= 32]).
RAW Paste Data
Top