PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/socket.erl

https://github.com/pedroaxl/gen_smtp
Erlang | 610 lines | 530 code | 39 blank | 41 comment | 1 complexity | 51c098efb44c804115ad9e88b7f1d93d MD5 | raw file
  1. %%% Copyright 2009 Jack Danger Canty <code@jackcanty.com>. All rights reserved.
  2. %%%
  3. %%% Permission is hereby granted, free of charge, to any person obtaining
  4. %%% a copy of this software and associated documentation files (the
  5. %%% "Software"), to deal in the Software without restriction, including
  6. %%% without limitation the rights to use, copy, modify, merge, publish,
  7. %%% distribute, sublicense, and/or sell copies of the Software, and to
  8. %%% permit persons to whom the Software is furnished to do so, subject to
  9. %%% the following conditions:
  10. %%%
  11. %%% The above copyright notice and this permission notice shall be
  12. %%% included in all copies or substantial portions of the Software.
  13. %%%
  14. %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. %%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. %%% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. %%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. %%% LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. %%% OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. %%% WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. %% @doc Facilitates transparent gen_tcp/ssl socket handling
  22. -module(socket).
  23. -define(TCP_LISTEN_OPTIONS,[ {active, false},
  24. {backlog, 30},
  25. {ip,{0,0,0,0}},
  26. {keepalive, true},
  27. {packet, line},
  28. {reuseaddr, true}]).
  29. -define(TCP_CONNECT_OPTIONS,[ {active, false},
  30. {packet, line}]).
  31. -define(SSL_LISTEN_OPTIONS, [ {active, false},
  32. {backlog, 30},
  33. {certfile, "server.crt"},
  34. {depth, 0},
  35. {keepalive, true},
  36. {keyfile, "server.key"},
  37. {packet, line},
  38. {reuse_sessions, false},
  39. {reuseaddr, true},
  40. {ssl_imp, new}]).
  41. -define(SSL_CONNECT_OPTIONS,[ {active, false},
  42. {depth, 0},
  43. {packet, line},
  44. {ssl_imp, new}]).
  45. -ifdef(TEST).
  46. -include_lib("eunit/include/eunit.hrl").
  47. -endif.
  48. %% API
  49. -export([connect/3, connect/4, connect/5]).
  50. -export([listen/2, listen/3, accept/1, accept/2]).
  51. -export([send/2, recv/2, recv/3]).
  52. -export([controlling_process/2]).
  53. -export([peername/1]).
  54. -export([close/1, shutdown/2]).
  55. -export([active_once/1]).
  56. -export([setopts/2]).
  57. -export([get_proto/1]).
  58. -export([begin_inet_async/1]).
  59. -export([handle_inet_async/1, handle_inet_async/2]).
  60. -export([extract_port_from_socket/1]).
  61. -export([to_ssl_server/1,to_ssl_server/2,to_ssl_server/3]).
  62. -export([to_ssl_client/1,to_ssl_client/2,to_ssl_client/3]).
  63. -export([type/1]).
  64. %%%-----------------------------------------------------------------
  65. %%% API
  66. %%%-----------------------------------------------------------------
  67. connect(Protocol, Address, Port) ->
  68. connect(Protocol, Address, Port, [], infinity).
  69. connect(Protocol, Address, Port, Opts) ->
  70. connect(Protocol, Address, Port, Opts, infinity).
  71. connect(tcp, Address, Port, Opts, Time) ->
  72. gen_tcp:connect(Address, Port, tcp_connect_options(Opts), Time);
  73. connect(ssl, Address, Port, Opts, Time) ->
  74. application:start(crypto),
  75. application:start(public_key),
  76. application:start(ssl),
  77. ssl:connect(Address, Port, ssl_connect_options(Opts), Time).
  78. listen(Protocol, Port) ->
  79. listen(Protocol, Port, []).
  80. listen(ssl, Port, Options) ->
  81. application:start(crypto),
  82. application:start(public_key),
  83. application:start(ssl),
  84. ssl:listen(Port, ssl_listen_options(Options));
  85. listen(tcp, Port, Options) ->
  86. gen_tcp:listen(Port, tcp_listen_options(Options)).
  87. accept(Socket) ->
  88. accept(Socket, infinity).
  89. accept(Socket, Timeout) when is_port(Socket) ->
  90. case gen_tcp:accept(Socket, Timeout) of
  91. {ok, NewSocket} ->
  92. {ok, Opts} = inet:getopts(Socket, [active,keepalive,packet,reuseaddr]),
  93. inet:setopts(NewSocket, Opts),
  94. {ok, NewSocket};
  95. Error ->
  96. Error
  97. end;
  98. accept(Socket, Timeout) ->
  99. case ssl:transport_accept(Socket, Timeout) of
  100. {ok, NewSocket} ->
  101. ssl:ssl_accept(NewSocket),
  102. {ok, NewSocket};
  103. Error -> Error
  104. end.
  105. send(Socket, Data) when is_port(Socket) ->
  106. gen_tcp:send(Socket, Data);
  107. send(Socket, Data) ->
  108. ssl:send(Socket, Data).
  109. recv(Socket, Length) ->
  110. recv(Socket, Length, infinity).
  111. recv(Socket, Length, Timeout) when is_port(Socket) ->
  112. gen_tcp:recv(Socket, Length, Timeout);
  113. recv(Socket, Length, Timeout) ->
  114. ssl:recv(Socket, Length, Timeout).
  115. controlling_process(Socket, NewOwner) when is_port(Socket) ->
  116. gen_tcp:controlling_process(Socket, NewOwner);
  117. controlling_process(Socket, NewOwner) ->
  118. ssl:controlling_process(Socket, NewOwner).
  119. peername(Socket) when is_port(Socket) ->
  120. inet:peername(Socket);
  121. peername(Socket) ->
  122. ssl:peername(Socket).
  123. close(Socket) when is_port(Socket) ->
  124. gen_tcp:close(Socket);
  125. close(Socket) ->
  126. ssl:close(Socket).
  127. shutdown(Socket, How) when is_port(Socket) ->
  128. gen_tcp:shutdown(Socket, How);
  129. shutdown(Socket, How) ->
  130. ssl:shutdown(Socket, How).
  131. active_once(Socket) when is_port(Socket) ->
  132. inet:setopts(Socket, [{active, once}]);
  133. active_once(Socket) ->
  134. ssl:setopts(Socket, [{active, once}]).
  135. setopts(Socket, Options) when is_port(Socket) ->
  136. inet:setopts(Socket, Options);
  137. setopts(Socket, Options) ->
  138. ssl:setopts(Socket, Options).
  139. -spec(get_proto/1 :: (Socket :: any()) -> 'tcp' | 'ssl').
  140. get_proto(Socket) when is_port(Socket) ->
  141. tcp;
  142. get_proto(_Socket) ->
  143. ssl.
  144. %% @doc {inet_async,...} will be sent to current process when a client connects
  145. begin_inet_async(Socket) when is_port(Socket) ->
  146. prim_inet:async_accept(Socket, -1);
  147. begin_inet_async(Socket) ->
  148. Port = extract_port_from_socket(Socket),
  149. begin_inet_async(Port).
  150. %% @doc handle the {inet_async,...} message
  151. handle_inet_async({inet_async, ListenSocket, _, {ok,ClientSocket}}) ->
  152. handle_inet_async(ListenSocket, ClientSocket).
  153. handle_inet_async(ListenObject, ClientSocket) ->
  154. ListenSocket = extract_port_from_socket(ListenObject),
  155. case set_sockopt(ListenSocket, ClientSocket) of
  156. ok -> ok;
  157. Error -> erlang:error(set_sockopt, Error)
  158. end,
  159. %% Signal the network driver that we are ready to accept another connection
  160. begin_inet_async(ListenSocket),
  161. %% If the listening socket is SSL then negotiate the client socket
  162. case is_port(ListenObject) of
  163. true ->
  164. {ok, ClientSocket};
  165. false ->
  166. {ok, UpgradedClientSocket} = to_ssl_server(ClientSocket),
  167. {ok, UpgradedClientSocket}
  168. end.
  169. %% @doc Upgrade a TCP connection to SSL
  170. to_ssl_server(Socket) ->
  171. to_ssl_server(Socket, []).
  172. to_ssl_server(Socket, Options) ->
  173. to_ssl_server(Socket, Options, infinity).
  174. to_ssl_server(Socket, Options, Timeout) when is_port(Socket) ->
  175. ssl:ssl_accept(Socket, ssl_listen_options(Options), Timeout);
  176. to_ssl_server(_Socket, _Options, _Timeout) ->
  177. erlang:error(ssl_connected, "Socket is already using SSL").
  178. to_ssl_client(Socket) ->
  179. to_ssl_client(Socket, []).
  180. to_ssl_client(Socket, Options) ->
  181. to_ssl_client(Socket, Options, infinity).
  182. to_ssl_client(Socket, Options, Timeout) when is_port(Socket) ->
  183. ssl:connect(Socket, ssl_connect_options(Options), Timeout);
  184. to_ssl_client(_Socket, _Options, _Timeout) ->
  185. erlang:error(ssl_connected, "Socket is already using SSL").
  186. type(Socket) when is_port(Socket) ->
  187. tcp;
  188. type(_Socket) ->
  189. ssl.
  190. %%%-----------------------------------------------------------------
  191. %%% Internal functions (OS_Mon configuration)
  192. %%%-----------------------------------------------------------------
  193. tcp_listen_options([Format|Options]) when Format =:= list; Format =:= binary ->
  194. tcp_listen_options(Options, Format);
  195. tcp_listen_options(Options) ->
  196. tcp_listen_options(Options, list).
  197. tcp_listen_options(Options, Format) ->
  198. [Format|proplist_merge(Options, ?TCP_LISTEN_OPTIONS)].
  199. ssl_listen_options([Format|Options]) when Format =:= list; Format =:= binary ->
  200. ssl_listen_options(Options, Format);
  201. ssl_listen_options(Options) ->
  202. ssl_listen_options(Options, list).
  203. ssl_listen_options(Options, Format) ->
  204. [Format|proplist_merge(Options, ?SSL_LISTEN_OPTIONS)].
  205. tcp_connect_options([Format|Options]) when Format =:= list; Format =:= binary ->
  206. tcp_connect_options(Options, Format);
  207. tcp_connect_options(Options) ->
  208. tcp_connect_options(Options, list).
  209. tcp_connect_options(Options, Format) ->
  210. [Format|proplist_merge(Options, ?TCP_CONNECT_OPTIONS)].
  211. ssl_connect_options([Format|Options]) when Format =:= list; Format =:= binary ->
  212. ssl_connect_options(Options, Format);
  213. ssl_connect_options(Options) ->
  214. ssl_connect_options(Options, list).
  215. ssl_connect_options(Options, Format) ->
  216. [Format|proplist_merge(Options, ?SSL_CONNECT_OPTIONS)].
  217. proplist_merge(PrimaryList, DefaultList) ->
  218. Merged = lists:ukeymerge(1,
  219. lists:keysort(1, PrimaryList),
  220. lists:keysort(1, DefaultList)
  221. ),
  222. %% remove all the values that don't belong here
  223. [Option || Option = {Key, _} <- Merged, proplists:is_defined(Key, DefaultList)].
  224. extract_port_from_socket({sslsocket,_,{SSLPort,_}}) ->
  225. SSLPort;
  226. extract_port_from_socket(Socket) ->
  227. Socket.
  228. -spec(set_sockopt/2 :: (ListSock :: port(), CliSocket :: port()) -> 'ok' | any()).
  229. set_sockopt(ListenObject, ClientSocket) ->
  230. ListenSocket = extract_port_from_socket(ListenObject),
  231. true = inet_db:register_socket(ClientSocket, inet_tcp),
  232. case prim_inet:getopts(ListenSocket, [active, nodelay, keepalive, delay_send, priority, tos]) of
  233. {ok, Opts} ->
  234. case prim_inet:setopts(ClientSocket, Opts) of
  235. ok -> ok;
  236. Error -> socket:close(ClientSocket), Error
  237. end;
  238. Error -> socket:close(ClientSocket), Error
  239. end.
  240. -ifdef(TEST).
  241. -define(TEST_PORT, 7586).
  242. connect_test_() ->
  243. [
  244. {"listen and connect via tcp",
  245. fun() ->
  246. Self = self(),
  247. spawn(fun() ->
  248. {ok, ListenSocket} = listen(tcp, ?TEST_PORT),
  249. ?assert(is_port(ListenSocket)),
  250. {ok, ServerSocket} = accept(ListenSocket),
  251. controlling_process(ServerSocket, Self),
  252. Self ! ListenSocket
  253. end),
  254. {ok, ClientSocket} = connect(tcp, "localhost", ?TEST_PORT),
  255. receive ListenSocket when is_port(ListenSocket) -> ok end,
  256. ?assert(is_port(ClientSocket)),
  257. close(ListenSocket)
  258. end
  259. },
  260. {"listen and connect via ssl",
  261. fun() ->
  262. Self = self(),
  263. application:start(crypto),
  264. application:start(public_key),
  265. application:start(ssl),
  266. spawn(fun() ->
  267. {ok, ListenSocket} = listen(ssl, ?TEST_PORT),
  268. ?assertMatch([sslsocket|_], tuple_to_list(ListenSocket)),
  269. {ok, ServerSocket} = accept(ListenSocket),
  270. controlling_process(ServerSocket, Self),
  271. Self ! ListenSocket
  272. end),
  273. {ok, ClientSocket} = connect(ssl, "localhost", ?TEST_PORT, []),
  274. receive {sslsocket,_,_} = ListenSocket -> ok end,
  275. ?assertMatch([sslsocket|_], tuple_to_list(ClientSocket)),
  276. close(ListenSocket)
  277. end
  278. }
  279. ].
  280. evented_connections_test_() ->
  281. [
  282. {"current process receives connection to TCP listen sockets",
  283. fun() ->
  284. {ok, ListenSocket} = listen(tcp, ?TEST_PORT),
  285. begin_inet_async(ListenSocket),
  286. spawn(fun()-> connect(tcp, "localhost", ?TEST_PORT) end),
  287. receive
  288. {inet_async, ListenSocket, _, {ok,ServerSocket}} -> ok
  289. end,
  290. {ok, NewServerSocket} = handle_inet_async(ListenSocket, ServerSocket),
  291. ?assert(is_port(ServerSocket)),
  292. ?assertEqual(ServerSocket, NewServerSocket), %% only true for TCP
  293. ?assert(is_port(ListenSocket)),
  294. % Stop the async
  295. spawn(fun()-> connect(tcp, "localhost", ?TEST_PORT) end),
  296. receive _Ignored -> ok end,
  297. close(NewServerSocket),
  298. close(ListenSocket)
  299. end
  300. },
  301. {"current process receives connection to SSL listen sockets",
  302. fun() ->
  303. application:start(crypto),
  304. application:start(public_key),
  305. application:start(ssl),
  306. {ok, ListenSocket} = listen(ssl, ?TEST_PORT),
  307. begin_inet_async(ListenSocket),
  308. spawn(fun()-> connect(ssl, "localhost", ?TEST_PORT) end),
  309. receive
  310. {inet_async, ListenPort, _, {ok,ServerSocket}} -> ok
  311. end,
  312. {ok, NewServerSocket} = handle_inet_async(ListenSocket, ServerSocket),
  313. ?assert(is_port(ServerSocket)),
  314. ?assertMatch([sslsocket|_], tuple_to_list(NewServerSocket)),
  315. ?assertMatch([sslsocket|_], tuple_to_list(ListenSocket)),
  316. % Stop the async
  317. spawn(fun()-> connect(ssl, "localhost", ?TEST_PORT) end),
  318. receive _Ignored -> ok end,
  319. close(ListenSocket),
  320. close(NewServerSocket)
  321. end
  322. },
  323. %% TODO: figure out if the following passes because
  324. %% of an incomplete test case or if this really is
  325. %% a magical feature where a single listener
  326. %% can respond to either ssl or tcp connections.
  327. {"current TCP listener receives SSL connection",
  328. fun() ->
  329. application:start(crypto),
  330. application:start(public_key),
  331. application:start(ssl),
  332. {ok, ListenSocket} = listen(tcp, ?TEST_PORT),
  333. begin_inet_async(ListenSocket),
  334. spawn(fun()-> connect(ssl, "localhost", ?TEST_PORT) end),
  335. receive
  336. {inet_async, ListenPort, _, {ok,ServerSocket}} -> ok
  337. end,
  338. {ok, ServerSocket} = handle_inet_async(ListenSocket, ServerSocket),
  339. ?assert(is_port(ListenSocket)),
  340. ?assert(is_port(ServerSocket)),
  341. {ok, NewServerSocket} = to_ssl_server(ServerSocket),
  342. ?assertMatch([sslsocket|_], tuple_to_list(NewServerSocket)),
  343. % Stop the async
  344. spawn(fun()-> connect(ssl, "localhost", ?TEST_PORT) end),
  345. receive _Ignored -> ok end,
  346. close(ListenSocket),
  347. close(NewServerSocket)
  348. end
  349. }
  350. ].
  351. accept_test_() ->
  352. [
  353. {"Accept via tcp",
  354. fun() ->
  355. {ok, ListenSocket} = listen(tcp, ?TEST_PORT, tcp_listen_options([])),
  356. ?assert(is_port(ListenSocket)),
  357. spawn(fun()-> connect(ssl, "localhost", ?TEST_PORT, tcp_connect_options([])) end),
  358. {ok, ServerSocket} = accept(ListenSocket),
  359. ?assert(is_port(ListenSocket)),
  360. close(ServerSocket),
  361. close(ListenSocket)
  362. end
  363. },
  364. {"Accept via ssl",
  365. fun() ->
  366. application:start(crypto),
  367. application:start(public_key),
  368. application:start(ssl),
  369. {ok, ListenSocket} = listen(ssl, ?TEST_PORT),
  370. ?assertMatch([sslsocket|_], tuple_to_list(ListenSocket)),
  371. spawn(fun()->connect(ssl, "localhost", ?TEST_PORT) end),
  372. accept(ListenSocket),
  373. close(ListenSocket)
  374. end
  375. }
  376. ].
  377. type_test_() ->
  378. [
  379. {"a tcp socket returns 'tcp'",
  380. fun() ->
  381. {ok, ListenSocket} = listen(tcp, ?TEST_PORT),
  382. ?assertMatch(tcp, type(ListenSocket)),
  383. close(ListenSocket)
  384. end
  385. },
  386. {"an ssl socket returns 'ssl'",
  387. fun() ->
  388. application:start(crypto),
  389. application:start(public_key),
  390. application:start(ssl),
  391. {ok, ListenSocket} = listen(ssl, ?TEST_PORT),
  392. ?assertMatch(ssl, type(ListenSocket)),
  393. close(ListenSocket)
  394. end
  395. }
  396. ].
  397. active_once_test_() ->
  398. [
  399. {"socket is set to active:once on tcp",
  400. fun() ->
  401. {ok, ListenSocket} = listen(tcp, ?TEST_PORT, tcp_listen_options([])),
  402. ?assertEqual({ok, [{active,false}]}, inet:getopts(ListenSocket, [active])),
  403. active_once(ListenSocket),
  404. ?assertEqual({ok, [{active,once}]}, inet:getopts(ListenSocket, [active])),
  405. close(ListenSocket)
  406. end
  407. },
  408. {"socket is set to active:once on ssl",
  409. fun() ->
  410. {ok, ListenSocket} = listen(ssl, ?TEST_PORT, ssl_listen_options([])),
  411. ?assertEqual({ok, [{active,false}]}, ssl:getopts(ListenSocket, [active])),
  412. active_once(ListenSocket),
  413. ?assertEqual({ok, [{active,once}]}, ssl:getopts(ListenSocket, [active])),
  414. close(ListenSocket)
  415. end
  416. }
  417. ].
  418. option_test_() ->
  419. [
  420. {"options removes bogus values",
  421. fun() ->
  422. ?assertEqual([list|?TCP_LISTEN_OPTIONS], tcp_listen_options([{notvalid,whatever}]))
  423. end
  424. },
  425. {"tcp_listen_options has defaults",
  426. fun() ->
  427. ?assertEqual([list|?TCP_LISTEN_OPTIONS], tcp_listen_options([]))
  428. end
  429. },
  430. {"tcp_connect_options has defaults",
  431. fun() ->
  432. ?assertEqual([list|?TCP_CONNECT_OPTIONS], tcp_connect_options([]))
  433. end
  434. },
  435. {"ssl_listen_options has defaults",
  436. fun() ->
  437. ?assertEqual([list|?SSL_LISTEN_OPTIONS], ssl_listen_options([]))
  438. end
  439. },
  440. {"ssl_connect_options has defaults",
  441. fun() ->
  442. ?assertEqual([list|?SSL_CONNECT_OPTIONS], ssl_connect_options([]))
  443. end
  444. },
  445. {"tcp_listen_options defaults to list type",
  446. fun() ->
  447. ?assertEqual([list|?TCP_LISTEN_OPTIONS], tcp_listen_options([{active,false}])),
  448. ?assertEqual([binary|?TCP_LISTEN_OPTIONS], tcp_listen_options([binary,{active,false}]))
  449. end
  450. },
  451. {"tcp_connect_options defaults to list type",
  452. fun() ->
  453. ?assertEqual([list|?TCP_CONNECT_OPTIONS], tcp_connect_options([{active,false}])),
  454. ?assertEqual([binary|?TCP_CONNECT_OPTIONS], tcp_connect_options([binary,{active,false}]))
  455. end
  456. },
  457. {"ssl_listen_options defaults to list type",
  458. fun() ->
  459. ?assertEqual([list|?SSL_LISTEN_OPTIONS], ssl_listen_options([{active,false}])),
  460. ?assertEqual([binary|?SSL_LISTEN_OPTIONS], ssl_listen_options([binary,{active,false}]))
  461. end
  462. },
  463. {"ssl_connect_options defaults to list type",
  464. fun() ->
  465. ?assertEqual([list|?SSL_CONNECT_OPTIONS], ssl_connect_options([{active,false}])),
  466. ?assertEqual([binary|?SSL_CONNECT_OPTIONS], ssl_connect_options([binary,{active,false}]))
  467. end
  468. },
  469. {"tcp_listen_options merges provided proplist",
  470. fun() ->
  471. ?assertMatch([list,{active, true},
  472. {backlog, 30},
  473. {ip,{0,0,0,0}},
  474. {keepalive, true},
  475. {packet, 2},
  476. {reuseaddr, true}],
  477. tcp_listen_options([{active, true},{packet,2}]))
  478. end
  479. },
  480. {"tcp_connect_options merges provided proplist",
  481. fun() ->
  482. ?assertMatch([list,{active, true},
  483. {packet, 2}],
  484. tcp_connect_options([{active, true},{packet,2}]))
  485. end
  486. },
  487. {"ssl_listen_options merges provided proplist",
  488. fun() ->
  489. ?assertMatch([list,{active, true},
  490. {backlog, 30},
  491. {certfile, "server.crt"},
  492. {depth, 0},
  493. {keepalive, true},
  494. {keyfile, "server.key"},
  495. {packet, 2},
  496. {reuse_sessions, false},
  497. {reuseaddr, true},
  498. {ssl_imp, new}],
  499. ssl_listen_options([{active, true},{packet,2}]))
  500. end
  501. },
  502. {"ssl_connect_options merges provided proplist",
  503. fun() ->
  504. ?assertMatch([list,{active, true},
  505. {depth, 0},
  506. {packet, 2},
  507. {ssl_imp, new}],
  508. ssl_connect_options([{active, true},{packet,2}]))
  509. end
  510. }
  511. ].
  512. ssl_upgrade_test_() ->
  513. [
  514. {"TCP connection can be upgraded to ssl",
  515. fun() ->
  516. Self = self(),
  517. application:start(crypto),
  518. application:start(public_key),
  519. application:start(ssl),
  520. spawn(fun() ->
  521. {ok, ListenSocket} = listen(tcp, ?TEST_PORT),
  522. {ok, ServerSocket} = accept(ListenSocket),
  523. {ok, NewServerSocket} = socket:to_ssl_server(ServerSocket),
  524. Self ! NewServerSocket
  525. end),
  526. {ok, ClientSocket} = connect(tcp, "localhost", ?TEST_PORT),
  527. ?assert(is_port(ClientSocket)),
  528. {ok, NewClientSocket} = to_ssl_client(ClientSocket),
  529. ?assertMatch([sslsocket|_], tuple_to_list(NewClientSocket)),
  530. receive NewServerSocket -> ok end,
  531. ?assertMatch({sslsocket, _, _}, NewServerSocket),
  532. close(NewClientSocket),
  533. close(NewServerSocket)
  534. end
  535. },
  536. {"SSL server connection can't be upgraded again",
  537. fun() ->
  538. Self = self(),
  539. application:start(crypto),
  540. application:start(public_key),
  541. application:start(ssl),
  542. spawn(fun() ->
  543. {ok, ListenSocket} = listen(ssl, ?TEST_PORT),
  544. {ok, ServerSocket} = accept(ListenSocket),
  545. ?assertException(error, ssl_connected, to_ssl_server(ServerSocket)),
  546. close(ServerSocket)
  547. end),
  548. {ok, ClientSocket} = connect(tcp, "localhost", ?TEST_PORT),
  549. close(ClientSocket)
  550. end
  551. },
  552. {"SSL client connection can't be upgraded again",
  553. fun() ->
  554. Self = self(),
  555. application:start(crypto),
  556. application:start(public_key),
  557. application:start(ssl),
  558. spawn(fun() ->
  559. {ok, ListenSocket} = listen(ssl, ?TEST_PORT),
  560. {ok, ServerSocket} = accept(ListenSocket),
  561. Self ! ServerSocket
  562. end),
  563. {ok, ClientSocket} = connect(ssl, "localhost", ?TEST_PORT),
  564. receive ServerSocket -> ok end,
  565. ?assertException(error, ssl_connected, to_ssl_client(ClientSocket)),
  566. close(ClientSocket),
  567. close(ServerSocket)
  568. end
  569. }
  570. ].
  571. -endif.