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