From 60ab72f5c4770e3f66611c88797c9608b8e516f2 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 17 Sep 2014 14:34:36 +0200 Subject: eldap: Enable all tcp options in eldap:open Options: OTP-12171 Correct error msgs for Options: OTP-12182 --- lib/eldap/doc/src/eldap.xml | 4 ++- lib/eldap/src/eldap.erl | 65 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 8009a8d6a3..dbd478fb17 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -75,7 +75,9 @@ filter() See present/1, substrings/2,

Setup a connection to an LDAP server, the HOST's are tried in order.

The log function takes three arguments, fun(Level, FormatString, [FormatArg]) end.

Timeout set the maximum time in milliseconds that each server request may take.

-

Currently, the only TCP socket option accepted is inet6. Default is inet.

+

All TCP socket options are accepted except + active, binary, deliver, list, mode and packet +

diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index 1cd328cde3..416334e365 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -12,6 +12,7 @@ -vc('$Id$ '). -export([open/1,open/2,simple_bind/3,controlling_process/2, start_tls/2, start_tls/3, + getopts/2, baseObject/0,singleLevel/0,wholeSubtree/0,close/1, equalityMatch/2,greaterOrEqual/2,lessOrEqual/2, approxMatch/2,search/2,substrings/2,present/1, @@ -91,6 +92,15 @@ start_tls(Handle, TlsOptions, Timeout) -> send(Handle, {start_tls,TlsOptions,Timeout}), recv(Handle). +%%% -------------------------------------------------------------------- +%%% Ask for option values on the socket. +%%% Warning: This is an undocumented function for testing purposes only. +%%% Use at own risk... +%%% -------------------------------------------------------------------- +getopts(Handle, OptNames) when is_pid(Handle), is_list(OptNames) -> + send(Handle, {getopts, OptNames}), + recv(Handle). + %%% -------------------------------------------------------------------- %%% Shutdown connection (and process) asynchronous. %%% -------------------------------------------------------------------- @@ -374,24 +384,35 @@ parse_args([{sslopts, Opts}|T], Cpid, Data) when is_list(Opts) -> parse_args([{sslopts, _}|T], Cpid, Data) -> parse_args(T, Cpid, Data); parse_args([{tcpopts, Opts}|T], Cpid, Data) when is_list(Opts) -> - parse_args(T, Cpid, Data#eldap{tcp_opts = inet6_opt(Opts) ++ Data#eldap.tcp_opts}); + parse_args(T, Cpid, Data#eldap{tcp_opts = tcp_opts(Opts,Cpid,Data#eldap.tcp_opts)}); parse_args([{log, F}|T], Cpid, Data) when is_function(F) -> parse_args(T, Cpid, Data#eldap{log = F}); parse_args([{log, _}|T], Cpid, Data) -> parse_args(T, Cpid, Data); parse_args([H|_], Cpid, _) -> send(Cpid, {error,{wrong_option,H}}), + unlink(Cpid), exit(wrong_option); parse_args([], _, Data) -> Data. -inet6_opt(Opts) -> - case proplists:get_value(inet6, Opts) of +tcp_opts([Opt|Opts], Cpid, Acc) -> + Key = if is_atom(Opt) -> Opt; + is_tuple(Opt) -> element(1,Opt) + end, + case lists:member(Key,[active,binary,deliver,list,mode,packet]) of + false -> + tcp_opts(Opts, Cpid, [Opt|Acc]); true -> - [inet6]; - _ -> - [] - end. + tcp_opts_error(Opt, Cpid) + end; +tcp_opts([], _Cpid, Acc) -> Acc. + +tcp_opts_error(Opt, Cpid) -> + send(Cpid, {error, {{forbidden_tcp_option,Opt}, + "This option affects the eldap functionality and can't be set by user"}}), + unlink(Cpid), + exit(forbidden_tcp_option). %%% Try to connect to the hosts in the listed order, %%% and stop with the first one to which a successful @@ -466,6 +487,36 @@ loop(Cpid, Data) -> unlink(Cpid), exit(closed); + {From, {getopts, OptNames}} -> + Result = + try + [case OptName of + port -> {port, Data#eldap.port}; + log -> {log, Data#eldap.log}; + timeout -> {timeout, Data#eldap.timeout}; + ssl -> {ssl, Data#eldap.ldaps}; + {sslopts, SslOptNames} when Data#eldap.using_tls==true -> + case ssl:getopts(Data#eldap.fd, SslOptNames) of + {ok,SslOptVals} -> {sslopts, SslOptVals}; + {error,Reason} -> throw({error,Reason}) + end; + {sslopts, _} -> + throw({error,no_tls}); + {tcpopts, TcpOptNames} -> + case inet:getopts(Data#eldap.fd, TcpOptNames) of + {ok,TcpOptVals} -> {tcpopts, TcpOptVals}; + {error,Posix} -> throw({error,Posix}) + end + end || OptName <- OptNames] + of + OptsList -> {ok,OptsList} + catch + throw:Error -> Error; + Class:Error -> {error,{Class,Error}} + end, + send(From, Result), + ?MODULE:loop(Cpid, Data); + {Cpid, 'EXIT', Reason} -> ?PRINT("Got EXIT from Cpid, reason=~p~n",[Reason]), exit(Reason); -- cgit v1.2.3 From d0f265224c8c202a1a3787e9f21b100ed68da8a8 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 17 Sep 2014 14:35:21 +0200 Subject: eldap: New very basic test suite. --- lib/eldap/test/Makefile | 1 + lib/eldap/test/eldap_connections_SUITE.erl | 126 +++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 lib/eldap/test/eldap_connections_SUITE.erl diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile index 3c5810eece..24e71cebaa 100644 --- a/lib/eldap/test/Makefile +++ b/lib/eldap/test/Makefile @@ -28,6 +28,7 @@ INCLUDES= -I. -I ../include # ---------------------------------------------------- MODULES= \ + eldap_connections_SUITE \ eldap_basic_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/eldap/test/eldap_connections_SUITE.erl b/lib/eldap/test/eldap_connections_SUITE.erl new file mode 100644 index 0000000000..4c8aa9c2cf --- /dev/null +++ b/lib/eldap/test/eldap_connections_SUITE.erl @@ -0,0 +1,126 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012-2014. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(eldap_connections_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +%-include_lib("eldap/include/eldap.hrl"). + + +all() -> + [ + tcp_connection, + tcp_inet6_connection, + tcp_connection_option, + tcp_inet6_connection_option + ]. + + +init_per_suite(Config) -> Config. + +end_per_suite(_Config) -> ok. + + +init_per_testcase(_TestCase, Config) -> + {ok,Sl} = gen_tcp:listen(0,[]), + {ok,Sl6} = gen_tcp:listen(0,[inet6]), + [{listen_socket,Sl}, {listen_socket6,Sl6} | Config]. + +end_per_testcase(_TestCase, Config) -> + catch gen_tcp:close( proplists:get_value(listen_socket, Config) ), + catch gen_tcp:close( proplists:get_value(listen_socket6, Config) ), + ok. + +%%%================================================================ +%%% +%%% Test cases +%%% +%%%---------------------------------------------------------------- +tcp_connection(Config) -> + do_tcp_connection(Config, listen_socket, "localhost", []). + +tcp_inet6_connection(Config) -> + do_tcp_connection(Config, listen_socket6, "::", [{tcpopts,[inet6]}]). + + +do_tcp_connection(Config, SockKey, Host, Opts) -> + Sl = proplists:get_value(SockKey, Config), + {ok,{_,Port}} = inet:sockname(Sl), + case eldap:open([Host], [{port,Port}|Opts]) of + {ok,_H} -> + case gen_tcp:accept(Sl,1000) of + {ok,_S} -> ok; + {error,timeout} -> ct:fail("server side accept timeout",[]) + end; + Other -> ct:fail("eldap:open failed: ~p",[Other]) + end. + +%%%---------------------------------------------------------------- +tcp_connection_option(Config) -> + do_tcp_connection_option(Config, listen_socket, "localhost", []). + +tcp_inet6_connection_option(Config) -> + do_tcp_connection_option(Config, listen_socket6, "::", [{tcpopts,[inet6]}]). + + +do_tcp_connection_option(Config, SockKey, Host, Opts) -> + Sl = proplists:get_value(SockKey, Config), + {ok,{_,Port}} = inet:sockname(Sl), + + %% Make an option value to test. The option must be implemented on all + %% platforms that we test on. Must check what the default value is + %% so we don't happen to choose that particular value. + {ok,[{linger,DefaultLinger}]} = inet:getopts(Sl, [linger]), + TestLinger = case DefaultLinger of + {false,_} -> {true,5}; + {true,_} -> {false,0} + end, + + case catch eldap:open([Host], + [{port,Port},{tcpopts,[{linger,TestLinger}]}|Opts]) of + {ok,H} -> + case gen_tcp:accept(Sl,1000) of + {ok,_} -> + case eldap:getopts(H, [{tcpopts,[linger]}]) of + {ok,[{tcpopts,[{linger,ActualLinger}]}]} -> + case ActualLinger of + TestLinger -> + ok; + DefaultLinger -> + ct:fail("eldap:getopts: 'linger' didn't change," + " got ~p (=default) expected ~p", + [ActualLinger,TestLinger]); + _ -> + ct:fail("eldap:getopts: bad 'linger', got ~p expected ~p", + [ActualLinger,TestLinger]) + end; + Other -> + ct:fail("eldap:getopts: bad result ~p",[Other]) + end; + {error,timeout} -> + ct:fail("server side accept timeout",[]) + end; + + Other -> + ct:fail("eldap:open failed: ~p",[Other]) + end. + +%%%---------------------------------------------------------------- -- cgit v1.2.3 From 1e5844012ab8c3963e2d3b0f05adc2a7b2b0afb7 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 17 Sep 2014 15:05:53 +0200 Subject: eldap: update version --- lib/eldap/vsn.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk index efdc30b476..5e32f92fa8 100644 --- a/lib/eldap/vsn.mk +++ b/lib/eldap/vsn.mk @@ -1,2 +1 @@ -ELDAP_VSN = 1.0.3 - +ELDAP_VSN = 1.0.4 \ No newline at end of file -- cgit v1.2.3