PageRenderTime 178ms CodeModel.GetById 163ms app.highlight 13ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mochiweb_socket.erl

http://github.com/basho/mochiweb
Erlang | 148 lines | 122 code | 23 blank | 3 comment | 0 complexity | e62fad1da692ad878a22a9c92335583b MD5 | raw file
  1%% @copyright 2010 Mochi Media, Inc.
  2
  3%% @doc MochiWeb socket - wrapper for plain and ssl sockets.
  4
  5-module(mochiweb_socket).
  6
  7-export([listen/4,
  8         accept/1, transport_accept/1, finish_accept/1,
  9         recv/3, send/2, close/1, port/1, peername/1,
 10         setopts/2, getopts/2, type/1, exit_if_closed/1]).
 11
 12-define(ACCEPT_TIMEOUT, 2000).
 13-define(SSL_TIMEOUT, 10000).
 14-define(SSL_HANDSHAKE_TIMEOUT, 20000).
 15
 16
 17listen(Ssl, Port, Opts, SslOpts) ->
 18    case Ssl of
 19        true ->
 20            Opts1 = add_unbroken_ciphers_default(Opts ++ SslOpts),
 21            Opts2 = add_safe_protocol_versions(Opts1),
 22            case ssl:listen(Port, Opts2) of
 23                {ok, ListenSocket} ->
 24                    {ok, {ssl, ListenSocket}};
 25                {error, _} = Err ->
 26                    Err
 27            end;
 28        false ->
 29            gen_tcp:listen(Port, Opts)
 30    end.
 31
 32add_unbroken_ciphers_default(Opts) ->
 33    Default = filter_unsecure_cipher_suites(ssl:cipher_suites()),
 34    Ciphers = filter_broken_cipher_suites(proplists:get_value(ciphers, Opts, Default)),
 35    [{ciphers, Ciphers} | proplists:delete(ciphers, Opts)].
 36
 37filter_broken_cipher_suites(Ciphers) ->
 38	case proplists:get_value(ssl_app, ssl:versions()) of
 39		"5.3" ++ _ ->
 40            lists:filter(fun(Suite) ->
 41                                 string:left(atom_to_list(element(1, Suite)), 4) =/= "ecdh"
 42                         end, Ciphers);
 43        _ ->
 44            Ciphers
 45    end.
 46
 47filter_unsecure_cipher_suites(Ciphers) ->
 48    lists:filter(fun
 49                    ({_,des_cbc,_}) -> false;
 50                    ({_,_,md5}) -> false;
 51                    (_) -> true
 52                 end,
 53                 Ciphers).
 54
 55add_safe_protocol_versions(Opts) ->
 56    case proplists:is_defined(versions, Opts) of
 57        true ->
 58            Opts;
 59        false ->
 60            Versions = filter_unsafe_protcol_versions(proplists:get_value(available, ssl:versions())),
 61            [{versions, Versions} | Opts]
 62    end.
 63
 64filter_unsafe_protcol_versions(Versions) ->
 65    lists:filter(fun
 66                    (sslv3) -> false;
 67                    (_) -> true
 68                 end,
 69                 Versions).
 70
 71%% Provided for backwards compatibility only
 72accept(ListenSocket) ->
 73    case transport_accept(ListenSocket) of
 74        {ok, Socket} ->
 75            finish_accept(Socket);
 76        {error, _} = Err ->
 77            Err
 78    end.
 79
 80transport_accept({ssl, ListenSocket}) ->
 81    case ssl:transport_accept(ListenSocket, ?SSL_TIMEOUT) of
 82        {ok, Socket} ->
 83            {ok, {ssl, Socket}};
 84        {error, _} = Err ->
 85            Err
 86    end;
 87transport_accept(ListenSocket) ->
 88    gen_tcp:accept(ListenSocket, ?ACCEPT_TIMEOUT).
 89
 90finish_accept({ssl, Socket}) ->
 91    case ssl:ssl_accept(Socket, ?SSL_HANDSHAKE_TIMEOUT) of
 92        ok ->
 93            {ok, {ssl, Socket}};
 94        {error, _} = Err ->
 95            Err
 96    end;
 97finish_accept(Socket) ->
 98    {ok, Socket}.
 99
100recv({ssl, Socket}, Length, Timeout) ->
101    ssl:recv(Socket, Length, Timeout);
102recv(Socket, Length, Timeout) ->
103    gen_tcp:recv(Socket, Length, Timeout).
104
105send({ssl, Socket}, Data) ->
106    ssl:send(Socket, Data);
107send(Socket, Data) ->
108    gen_tcp:send(Socket, Data).
109
110close({ssl, Socket}) ->
111    ssl:close(Socket);
112close(Socket) ->
113    gen_tcp:close(Socket).
114
115port({ssl, Socket}) ->
116    case ssl:sockname(Socket) of
117        {ok, {_, Port}} ->
118            {ok, Port};
119        {error, _} = Err ->
120            Err
121    end;
122port(Socket) ->
123    inet:port(Socket).
124
125peername({ssl, Socket}) ->
126    ssl:peername(Socket);
127peername(Socket) ->
128    inet:peername(Socket).
129
130setopts({ssl, Socket}, Opts) ->
131    ssl:setopts(Socket, Opts);
132setopts(Socket, Opts) ->
133    inet:setopts(Socket, Opts).
134
135getopts({ssl, Socket}, Opts) ->
136    ssl:getopts(Socket, Opts);
137getopts(Socket, Opts) ->
138    inet:getopts(Socket, Opts).
139
140type({ssl, _}) ->
141    ssl;
142type(_) ->
143    plain.
144
145exit_if_closed({error, closed}) ->
146    exit(normal);
147exit_if_closed(Res) ->
148    Res.