Subversion Repositories SE.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
12 7u83 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
 
17
listen(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
 
32
add_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
 
37
filter_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
 
47
filter_unsecure_cipher_suites(Ciphers) ->
48
    lists:filter(fun
49
                    ({_,des_cbc,_}) -> false;
50
                    ({_,_,md5}) -> false;
51
                    (_) -> true
52
                 end,
53
                 Ciphers).
54
 
55
add_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
 
64
filter_unsafe_protcol_versions(Versions) ->
65
    lists:filter(fun
66
                    (sslv3) -> false;
67
                    (_) -> true
68
                 end,
69
                 Versions).
70
 
71
%% Provided for backwards compatibility only
72
accept(ListenSocket) ->
73
    case transport_accept(ListenSocket) of
74
        {ok, Socket} ->
75
            finish_accept(Socket);
76
        {error, _} = Err ->
77
            Err
78
    end.
79
 
80
transport_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;
87
transport_accept(ListenSocket) ->
88
    gen_tcp:accept(ListenSocket, ?ACCEPT_TIMEOUT).
89
 
90
-ifdef(ssl_handshake_unavailable).
91
finish_accept({ssl, Socket}) ->
92
    case ssl:ssl_accept(Socket, ?SSL_HANDSHAKE_TIMEOUT) of
93
        ok ->
94
            {ok, {ssl, Socket}};
95
        {error, _} = Err ->
96
            Err
97
    end;
98
finish_accept(Socket) ->
99
    {ok, Socket}.
100
-else.
101
finish_accept({ssl, Socket}) ->
102
    case ssl:handshake(Socket, ?SSL_HANDSHAKE_TIMEOUT) of
103
        {ok, SslSocket} ->
104
            {ok, {ssl, SslSocket}};
105
        {error, _} = Err ->
106
            Err
107
    end;
108
finish_accept(Socket) ->
109
    {ok, Socket}.
110
-endif.
111
 
112
recv({ssl, Socket}, Length, Timeout) ->
113
    ssl:recv(Socket, Length, Timeout);
114
recv(Socket, Length, Timeout) ->
115
    gen_tcp:recv(Socket, Length, Timeout).
116
 
117
send({ssl, Socket}, Data) ->
118
    ssl:send(Socket, Data);
119
send(Socket, Data) ->
120
    gen_tcp:send(Socket, Data).
121
 
122
close({ssl, Socket}) ->
123
    ssl:close(Socket);
124
close(Socket) ->
125
    gen_tcp:close(Socket).
126
 
127
port({ssl, Socket}) ->
128
    case ssl:sockname(Socket) of
129
        {ok, {_, Port}} ->
130
            {ok, Port};
131
        {error, _} = Err ->
132
            Err
133
    end;
134
port(Socket) ->
135
    inet:port(Socket).
136
 
137
peername({ssl, Socket}) ->
138
    ssl:peername(Socket);
139
peername(Socket) ->
140
    inet:peername(Socket).
141
 
142
setopts({ssl, Socket}, Opts) ->
143
    ssl:setopts(Socket, Opts);
144
setopts(Socket, Opts) ->
145
    inet:setopts(Socket, Opts).
146
 
147
getopts({ssl, Socket}, Opts) ->
148
    ssl:getopts(Socket, Opts);
149
getopts(Socket, Opts) ->
150
    inet:getopts(Socket, Opts).
151
 
152
type({ssl, _}) ->
153
    ssl;
154
type(_) ->
155
    plain.
156
 
157
exit_if_closed({error, closed}) ->
158
    exit(normal);
159
exit_if_closed({error, einval}) ->
160
    exit(normal);
161
exit_if_closed(Res) ->
162
    Res.