From 12c84d2ec315c8d26afc2adb8aa50cfe6183fc8a Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 1 Sep 2011 13:07:38 +0200 Subject: Fix two minor disk_log bugs disk_log:reopen/2,3 and disk_log:breopen/3 could return the error reason from file:rename/2 rather than the reason {file_error, Filename, Reason}. The message {disk_log, Node, {error, disk_log_stopped}} which according the documentation is sent upon failure to truncate or reopen a disk log was sometimes turned into a reply. --- lib/kernel/src/disk_log.erl | 22 ++++++++++++++++------ lib/kernel/test/disk_log_SUITE.erl | 15 ++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index 9b8d2db437..d6bc23be6d 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -1240,20 +1240,29 @@ is_owner(Pid, L) -> %% ok | throw(Error) rename_file(File, NewFile, halt) -> - file:rename(File, NewFile); + case file:rename(File, NewFile) of + ok -> + ok; + Else -> + file_error(NewFile, Else) + end; rename_file(File, NewFile, wrap) -> rename_file(wrap_file_extensions(File), File, NewFile, ok). -rename_file([Ext|Exts], File, NewFile, Res) -> - NRes = case file:rename(add_ext(File, Ext), add_ext(NewFile, Ext)) of +rename_file([Ext|Exts], File, NewFile0, Res) -> + NewFile = add_ext(NewFile0, Ext), + NRes = case file:rename(add_ext(File, Ext), NewFile) of ok -> Res; Else -> - Else + file_error(NewFile, Else) end, - rename_file(Exts, File, NewFile, NRes); + rename_file(Exts, File, NewFile0, NRes); rename_file([], _File, _NewFiles, Res) -> Res. +file_error(FileName, {error, Error}) -> + {error, {file_error, FileName, Error}}. + %% "Old" error messages have been kept, arg_mismatch has been added. %%-spec compare_arg(dlog_options(), #arg{}, compare_arg([], _A, none, _OrigHead) -> @@ -1947,7 +1956,8 @@ monitor_request(Pid, Req) -> receive {'DOWN', Ref, process, Pid, _Info} -> {error, no_such_log}; - {disk_log, Pid, Reply} -> + {disk_log, Pid, Reply} when not is_tuple(Reply) orelse + element(2, Reply) =/= disk_log_stopped -> erlang:demonitor(Ref), receive {'DOWN', Ref, process, Pid, _Reason} -> diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl index 4ae47b4762..ad987fe7a7 100644 --- a/lib/kernel/test/disk_log_SUITE.erl +++ b/lib/kernel/test/disk_log_SUITE.erl @@ -1831,11 +1831,16 @@ block_queue2(Conf) when is_list(Conf) -> %% Asynchronous stuff is ignored. ?line ok = disk_log:balog_terms(n, [<<"foo">>,<<"bar">>]), ?line ok = disk_log:balog_terms(n, [<<"more">>,<<"terms">>]), + Parent = self(), ?line Fun = - fun() -> {error,disk_log_stopped} = disk_log:sync(n) + fun() -> + {error,no_such_log} = disk_log:sync(n), + receive {disk_log, _, {error, disk_log_stopped}} -> ok end, + Parent ! disk_log_stopped_ok end, ?line spawn(Fun), ?line ok = sync_do(Pid, close), + ?line receive disk_log_stopped_ok -> ok end, ?line sync_do(Pid, terminate), ?line {ok,<<>>} = file:read_file(File ++ ".1"), ?line del(File, No), @@ -2708,7 +2713,7 @@ error_log(Conf) when is_list(Conf) -> % reopen (rename) fails, the log is terminated, ./File.2/ exists ?line {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, {format, external},{size, 100000}]), - ?line {error, eisdir} = disk_log:reopen(n, LDir), + ?line {error, {file_error, _, eisdir}} = disk_log:reopen(n, LDir), ?line true = (P0 == pps()), ?line file:delete(File), @@ -2719,7 +2724,7 @@ error_log(Conf) when is_list(Conf) -> ?line {ok, n} = disk_log:open([{name, n}, {file, File2}, {type, wrap}, {format, external},{size, {100, No}}]), ?line ok = disk_log:blog_terms(n, [B,B,B]), - ?line {error, eisdir} = disk_log:reopen(n, File), + ?line {error, {file_error, _, eisdir}} = disk_log:reopen(n, File), ?line {error, no_such_log} = disk_log:close(n), ?line del(File2, No), ?line del(File, No), @@ -4917,7 +4922,7 @@ mark(FileName, What) -> ok = file:close(Fd). crash(File, Where) -> - {ok, Fd} = file:open(File, read_write), + {ok, Fd} = file:open(File, [read,write]), file:position(Fd, Where), ok = file:write(Fd, [10]), ok = file:close(Fd). @@ -4933,7 +4938,7 @@ writable(Fname) -> file:write_file_info(Fname, Info#file_info{mode = Mode}). truncate(File, Where) -> - {ok, Fd} = file:open(File, read_write), + {ok, Fd} = file:open(File, [read,write]), file:position(Fd, Where), ok = file:truncate(Fd), ok = file:close(Fd). -- cgit v1.2.3 From 4c747daecf8bfd22dafaf0e0d649ad02ec813f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 26 Aug 2011 14:43:27 +0200 Subject: test_server: Show line number for caller of test_server:fail() Showing the line number of fail/{1,2} in the test_server module is not especially useful. --- lib/test_server/src/test_server.erl | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 04f92c5738..2cb33a9a69 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -1716,7 +1716,16 @@ adjusted_sleep(MSecs) -> %% to read when using this function, rather than exit directly. fail(Reason) -> comment(cast_to_list(Reason)), - exit({suite_failed,Reason}). + try + exit({suite_failed,Reason}) + catch + Class:R -> + case erlang:get_stacktrace() of + [{?MODULE,fail,1,_}|Stk] -> ok; + Stk -> ok + end, + erlang:raise(Class, R, Stk) + end. cast_to_list(X) when is_list(X) -> X; cast_to_list(X) when is_atom(X) -> atom_to_list(X); @@ -1730,7 +1739,16 @@ cast_to_list(X) -> lists:flatten(io_lib:format("~p", [X])). %% Immediately calls exit. Included because test suites are easier %% to read when using this function, rather than exit directly. fail() -> - exit(suite_failed). + try + exit(suite_failed) + catch + Class:R -> + case erlang:get_stacktrace() of + [{?MODULE,fail,0,_}|Stk] -> ok; + Stk -> ok + end, + erlang:raise(Class, R, Stk) + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% break(Comment) -> ok -- cgit v1.2.3 From c5eb04243f480d860626e955c1d6b82b938cdf02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 13 Sep 2011 09:49:49 +0200 Subject: beam_lib_SUITE: Don't assume that "Abst" is the last chunk "Line" is now the last chunk in a BEAM file, causing beam_lib_SUITE:error/1 to fail. To avoid being bitten by this problem again, don't simply change "Abst" to "Line", but use beam_lib:info/1 to find out the name of the last chunk. --- lib/stdlib/test/beam_lib_SUITE.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl index b7fb1f618f..1788dcc85e 100644 --- a/lib/stdlib/test/beam_lib_SUITE.erl +++ b/lib/stdlib/test/beam_lib_SUITE.erl @@ -181,7 +181,8 @@ error(Conf) when is_list(Conf) -> ?line verify(not_a_beam_file, beam_lib:info(<<"short">>)), ?line {Binary1, _} = split_binary(Binary, byte_size(Binary)-10), - ?line verify(chunk_too_big, beam_lib:chunks(Binary1, ["Abst"])), + LastChunk = last_chunk(Binary), + ?line verify(chunk_too_big, beam_lib:chunks(Binary1, [LastChunk])), ?line Chunks = chunk_info(Binary), ?line {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks), ?line {Binary2, _} = split_binary(Binary, AbstractStart), @@ -205,6 +206,12 @@ error(Conf) when is_list(Conf) -> ?line file:delete(ACopy), ok. +last_chunk(Bin) -> + L = beam_lib:info(Bin), + {chunks,Chunks} = lists:keyfind(chunks, 1, L), + {Last,_,_} = lists:last(Chunks), + Last. + do_error(BeamFile, ACopy) -> % evil tests ?line Chunks = chunk_info(BeamFile), -- cgit v1.2.3 From 64a3651b3ece1a1e3195f20e37247f929d179f61 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 14 Sep 2011 10:57:17 +0200 Subject: Remove old ssl implementation and deprecated function ssl:peercert/1 --- erts/configure.in | 2 +- lib/ssl/Makefile | 4 +- lib/ssl/c_src/Makefile | 26 - lib/ssl/c_src/Makefile.dist | 33 - lib/ssl/c_src/Makefile.in | 211 --- lib/ssl/c_src/Makefile.win32 | 147 --- lib/ssl/c_src/Makefile.win32.dist | 45 - lib/ssl/c_src/debuglog.c | 251 ---- lib/ssl/c_src/debuglog.h | 50 - lib/ssl/c_src/esock.c | 1904 --------------------------- lib/ssl/c_src/esock.h | 273 ---- lib/ssl/c_src/esock_openssl.c | 1213 ----------------- lib/ssl/c_src/esock_osio.c | 328 ----- lib/ssl/c_src/esock_osio.h | 34 - lib/ssl/c_src/esock_poll.c | 222 ---- lib/ssl/c_src/esock_poll.h | 60 - lib/ssl/c_src/esock_posix_str.c | 642 --------- lib/ssl/c_src/esock_posix_str.h | 28 - lib/ssl/c_src/esock_ssl.h | 110 -- lib/ssl/c_src/esock_utils.c | 150 --- lib/ssl/c_src/esock_utils.h | 32 - lib/ssl/c_src/esock_winsock.h | 36 - lib/ssl/doc/src/Makefile | 4 +- lib/ssl/doc/src/old_ssl.xml | 709 ---------- lib/ssl/doc/src/refman.xml | 5 +- lib/ssl/doc/src/ssl.xml | 8 +- lib/ssl/src/Makefile | 7 +- lib/ssl/src/inet_ssl_dist.erl | 453 ------- lib/ssl/src/ssl.app.src | 7 +- lib/ssl/src/ssl.erl | 366 +---- lib/ssl/src/ssl_broker.erl | 1188 ----------------- lib/ssl/src/ssl_broker_int.hrl | 38 - lib/ssl/src/ssl_broker_sup.erl | 46 - lib/ssl/src/ssl_connection.erl | 1 - lib/ssl/src/ssl_int.hrl | 99 -- lib/ssl/src/ssl_internal.hrl | 3 + lib/ssl/src/ssl_prim.erl | 173 --- lib/ssl/src/ssl_server.erl | 1378 ------------------- lib/ssl/src/ssl_sup.erl | 7 +- lib/ssl/test/Makefile | 13 +- lib/ssl/test/old_ssl_active_SUITE.erl | 395 ------ lib/ssl/test/old_ssl_active_once_SUITE.erl | 417 ------ lib/ssl/test/old_ssl_dist_SUITE.erl | 617 --------- lib/ssl/test/old_ssl_misc_SUITE.erl | 117 -- lib/ssl/test/old_ssl_passive_SUITE.erl | 382 ------ lib/ssl/test/old_ssl_peer_cert_SUITE.erl | 191 --- lib/ssl/test/old_ssl_protocol_SUITE.erl | 185 --- lib/ssl/test/old_ssl_verify_SUITE.erl | 153 --- lib/ssl/test/old_transport_accept_SUITE.erl | 258 ---- lib/ssl/test/ssl.cover | 19 +- lib/ssl/test/ssl_basic_SUITE.erl | 48 +- lib/ssl/test/ssl_test_MACHINE.erl | 940 ------------- lib/ssl/test/ssl_test_MACHINE.hrl | 39 - 53 files changed, 80 insertions(+), 13987 deletions(-) delete mode 100644 lib/ssl/c_src/Makefile delete mode 100644 lib/ssl/c_src/Makefile.dist delete mode 100644 lib/ssl/c_src/Makefile.in delete mode 100644 lib/ssl/c_src/Makefile.win32 delete mode 100644 lib/ssl/c_src/Makefile.win32.dist delete mode 100644 lib/ssl/c_src/debuglog.c delete mode 100644 lib/ssl/c_src/debuglog.h delete mode 100644 lib/ssl/c_src/esock.c delete mode 100644 lib/ssl/c_src/esock.h delete mode 100644 lib/ssl/c_src/esock_openssl.c delete mode 100644 lib/ssl/c_src/esock_osio.c delete mode 100644 lib/ssl/c_src/esock_osio.h delete mode 100644 lib/ssl/c_src/esock_poll.c delete mode 100644 lib/ssl/c_src/esock_poll.h delete mode 100644 lib/ssl/c_src/esock_posix_str.c delete mode 100644 lib/ssl/c_src/esock_posix_str.h delete mode 100644 lib/ssl/c_src/esock_ssl.h delete mode 100644 lib/ssl/c_src/esock_utils.c delete mode 100644 lib/ssl/c_src/esock_utils.h delete mode 100644 lib/ssl/c_src/esock_winsock.h delete mode 100644 lib/ssl/doc/src/old_ssl.xml delete mode 100644 lib/ssl/src/inet_ssl_dist.erl delete mode 100644 lib/ssl/src/ssl_broker.erl delete mode 100644 lib/ssl/src/ssl_broker_int.hrl delete mode 100644 lib/ssl/src/ssl_broker_sup.erl delete mode 100644 lib/ssl/src/ssl_int.hrl delete mode 100644 lib/ssl/src/ssl_prim.erl delete mode 100644 lib/ssl/src/ssl_server.erl delete mode 100644 lib/ssl/test/old_ssl_active_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_active_once_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_dist_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_misc_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_passive_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_peer_cert_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_protocol_SUITE.erl delete mode 100644 lib/ssl/test/old_ssl_verify_SUITE.erl delete mode 100644 lib/ssl/test/old_transport_accept_SUITE.erl delete mode 100644 lib/ssl/test/ssl_test_MACHINE.erl delete mode 100644 lib/ssl/test/ssl_test_MACHINE.hrl diff --git a/erts/configure.in b/erts/configure.in index 88337e79fd..80e35cb8c5 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -4325,7 +4325,7 @@ dnl The ones below should be moved to their respective lib dnl ../lib/ic/c_src/$host/Makefile:../lib/ic/c_src/Makefile.in ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in - ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in +dnl ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in ../lib/crypto/c_src/$host/Makefile:../lib/crypto/c_src/Makefile.in ../lib/orber/c_src/$host/Makefile:../lib/orber/c_src/Makefile.in ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile index daad7dc3e6..a7a95004a6 100644 --- a/lib/ssl/Makefile +++ b/lib/ssl/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2010. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. 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 @@ -25,7 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # -SUB_DIRECTORIES = src c_src doc/src examples/certs examples/src +SUB_DIRECTORIES = src doc/src examples/certs examples/src include vsn.mk VSN = $(SSL_VSN) diff --git a/lib/ssl/c_src/Makefile b/lib/ssl/c_src/Makefile deleted file mode 100644 index 52d9140153..0000000000 --- a/lib/ssl/c_src/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2009. 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% -# - -# - -# -# Invoke with GNU make or clearmake -C gnu. -# - -include $(ERL_TOP)/make/run_make.mk diff --git a/lib/ssl/c_src/Makefile.dist b/lib/ssl/c_src/Makefile.dist deleted file mode 100644 index 2468468921..0000000000 --- a/lib/ssl/c_src/Makefile.dist +++ /dev/null @@ -1,33 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2009. 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% -# - -# Makefile for SSL on Unix -# -# Placed in obj directory. -# -CC = gcc - -BINDIR = %BINDIR% -LIBS = %LIBS% -SSL_LIBDIR = %SSL_LIBDIR% -OBJS = %OBJS% - -$(BINDIR)/ssl_esock: $(OBJS) - $(CC) -L$(SSL_LIBDIR) -Wl,-R$(SSL_LIBDIR) -o $@ $^ \ - $(LIBS) -lssl -lcrypto diff --git a/lib/ssl/c_src/Makefile.in b/lib/ssl/c_src/Makefile.in deleted file mode 100644 index a894e6dcd7..0000000000 --- a/lib/ssl/c_src/Makefile.in +++ /dev/null @@ -1,211 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2011. 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% -# - -# -# Makefile only for Unix and Win32/Cygwin. -# - -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk -# ---------------------------------------------------- -# SSL locations and include options from configure -# ---------------------------------------------------- -SSL_LIBDIR = @SSL_LIBDIR@ -SSL_INCLUDE = @SSL_INCLUDE@ -SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@ -SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@ - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(SSL_VSN) - -# ---------------------------------------------------- -# Commands -# ---------------------------------------------------- -CC = @CC@ -LD = @LD@ -SHELL = /bin/sh -LIBS = @LIBS@ -PLAIN_CFLAGS = @CFLAGS@ - -# ---------------------------------------------------- -# Includes and libs -# ---------------------------------------------------- - -ALL_CFLAGS = @WFLAGS@ @CFLAGS@ @DEFS@ $(TYPE_FLAGS) -TARGET = @host@ - -ifeq ($(TYPE),debug) -TYPEMARKER = .debug -TYPE_FLAGS = -g -DDEBUG @DEBUG_FLAGS@ -else -TYPEMARKER = -TYPE_FLAGS = -O2 -endif - -PRIVDIR = ../priv -BINDIR = $(PRIVDIR)/bin/$(TARGET) -OBJDIR = $(PRIVDIR)/obj/$(TARGET) - -# ---------------------------------------------------- -# File suffixes -# ---------------------------------------------------- -exe = @EXEEXT@ -obj = .@OBJEXT@ - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) - -# ---------------------------------------------------- -# Common Macros -# ---------------------------------------------------- -OBJS = $(OBJDIR)/esock$(obj) \ - $(OBJDIR)/debuglog$(obj) \ - $(OBJDIR)/esock_poll$(obj) \ - $(OBJDIR)/esock_osio$(obj) \ - $(OBJDIR)/esock_utils$(obj) \ - $(OBJDIR)/esock_posix_str$(obj) \ - $(OBJDIR)/esock_openssl$(obj) - -PORT_PROGRAM = $(BINDIR)/ssl_esock$(exe) - -SKIP_BUILDING_BINARIES := false - -# Try to be BC for R10 -ifeq ($(findstring @SSL_,@SSL_DYNAMIC_ONLY@),@SSL_) -DYNAMIC_CRYPTO_LIB=yes -else -DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@ -endif - - -ifeq ($(DYNAMIC_CRYPTO_LIB),yes) - -ifneq ($(findstring win32,$(TARGET)),win32) -SSL_MAKEFILE = $(OBJDIR)/Makefile -else -SSL_MAKEFILE = -endif - -CC_R_FLAG=@CFLAG_RUNTIME_LIBRARY_PATH@ - -ifeq ($(findstring @,$(CC_R_FLAG)),@) -# Old erts configure used which hasn't replaced @CFLAG_RUNTIME_LIBRARY_PATH@; -# we try our best here instead... - -ifeq ($(findstring darwin,$(TARGET)),darwin) # darwin: no flag -CC_R_FLAG = -else -ifeq ($(findstring osf,$(TARGET)),osf) # osf1: -Wl,-rpath, -CC_R_FLAG = -Wl,-rpath, -else # Default: -Wl,-R -CC_R_FLAG = -Wl,-R -endif -endif -endif - -ifeq ($(strip $(CC_R_FLAG)),) -CC_R_OPT = -else -CC_R_OPT = $(CC_R_FLAG)$(SSL_LIBDIR) -endif - -SSL_CC_RUNTIME_LIBRARY_PATH=@SSL_CC_RUNTIME_LIBRARY_PATH@ -# Sigh... -ifeq ($(findstring @,$(SSL_CC_RUNTIME_LIBRARY_PATH)),@) -SSL_CC_RUNTIME_LIBRARY_PATH = $(CC_R_OPT) -endif - -SSL_LINK_LIB=-L$(SSL_LIBDIR) -l$(SSL_SSL_LIBNAME) -l$(SSL_CRYPTO_LIBNAME) -else -# not dynamic crypto lib (default from R11B-5) -NEED_KERBEROS=@SSL_LINK_WITH_KERBEROS@ -NEED_ZLIB=@SSL_LINK_WITH_ZLIB@ -SSL_MAKEFILE = -CC_R_OPT = -SSL_CC_RUNTIME_LIBRARY_PATH= -SSL_LINK_LIB = $(SSL_LIBDIR)/lib$(SSL_SSL_LIBNAME).a $(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a -ifeq ($(NEED_KERBEROS),yes) -SSL_LINK_LIB += @STATIC_KERBEROS_LIBS@ -endif -ifeq ($(NEED_ZLIB),yes) -SSL_LINK_LIB += @STATIC_ZLIB_LIBS@ -endif -endif - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -_create_dirs := $(shell mkdir -p $(OBJDIR) $(BINDIR)) - -debug opt: $(OBJS) $(PORT_PROGRAM) $(SSL_MAKEFILE) - -$(OBJDIR)/esock_openssl$(obj): esock_openssl.c - $(CC) -c -o $@ $(ALL_CFLAGS) $(SSL_INCLUDE) $< - -$(OBJDIR)/%$(obj): %.c - $(CC) -c -o $@ $(ALL_CFLAGS) $< - -# Unix -$(BINDIR)/ssl_esock: $(OBJS) - $(CC) $(PLAIN_CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SSL_CC_RUNTIME_LIBRARY_PATH) $(SSL_LINK_LIB) - -# Win32/Cygwin -$(BINDIR)/ssl_esock.exe: $(OBJS) - $(LD) $(SSL_CC_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -o $@ $^ -lwsock32 -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) - -# Unix only, and only when linking statically -$(SSL_MAKEFILE): - sed -e "s;%BINDIR%;../../bin/$(TARGET);" \ - -e "s;%SSL_LIBDIR%;$(SSL_LIBDIR);" \ - -e "s;%OBJS;$(OBJS);" \ - -e "s;%LIBS%;$(LIBS);" ./Makefile.dist \ - > $(OBJDIR)/Makefile - - -clean: - rm -f $(PORT_PROGRAM) $(OBJS) core *~ $(SSL_MAKEFILE) - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/priv/bin - $(INSTALL_PROGRAM) $(PORT_PROGRAM) $(RELSYSDIR)/priv/bin -ifneq ($(SSL_MAKEFILE),) - $(INSTALL_DIR) $(RELSYSDIR)/priv/obj - $(INSTALL_DATA) $(OBJS) $(RELSYSDIR)/priv/obj - sed -e "s;%BINDIR%;../bin;" \ - -e "s;%SSL_LIBDIR%;$(SSL_LIBDIR);" \ - -e "s;%OBJS;$(OBJS);" \ - -e "s;%LIBS%;$(LIBS);" ./Makefile.dist \ - > $(RELSYSDIR)/priv/obj/Makefile -endif - -release_docs_spec: - diff --git a/lib/ssl/c_src/Makefile.win32 b/lib/ssl/c_src/Makefile.win32 deleted file mode 100644 index 668cd2a28d..0000000000 --- a/lib/ssl/c_src/Makefile.win32 +++ /dev/null @@ -1,147 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2009. 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% -# - -# -# SSL - Makefile for Windows NT -# -# It is assumed that the following environment variables have been set: -# -# INCLUDE X:\MSDEV\INCLUDE -# LIB X:\MSDEV\LIB -# -# so that standard include files, and the socket library can be found. -# -# When ssl_esock.exe is run, the PATH environment variable must contain -# the name of a directory that contains ssleay32.dll and libeay32.dll, -# and windows socket dll. -# - -# Roots -!ifndef OPENSSL_ROOT -! error "Makefile.win32: ssl: OPENSSL_ROOT not set" -!endif - -TARGET = win32 - -BINDIR = ..\priv\bin\$(TARGET) -OBJDIR = ..\priv\obj\$(TARGET) - -!if !exist($(BINDIR)) -! if [mkdir $(BINDIR)] -! error "SSL: cannot create BINDIR" -! endif -!endif - -!if !exist($(OBJDIR)) -! if [mkdir $(OBJDIR)] -! error "SSL: cannot create OBJDIR" -! endif -!endif - -# Includes -# -OPENSSL_INCLUDE = $(OPENSSL_ROOT)\inc32 - -INCLUDES = /I. /I$(OPENSSL_INCLUDE) - -# Libraries -# -OPENSSL_LIBDIR = $(OPENSSL_ROOT)\out32dll -OPENSSL_LIBS = \ - $(OPENSSL_LIBDIR)\ssleay32.lib \ - $(OPENSSL_LIBDIR)\libeay32.lib - -!ifdef ESOCK_WINSOCK2 -WINSOCK_LIB = ws2_32.lib -DEFS = -DESOCK_WINSOCK2 -!else -WINSOCK_LIB = wsock32.lib -!endif - -# Compiler options -# -# NOTE: Size of fd_set is set in esock_winsock.h but can be overridden -# with a -D option here. -# -OPTS = /MDd /G5 /Ox /O2 /Ob2 /Z7 -DEFS = -D__WIN32__ -DWIN32 $(DEFS) -CFLAGS = $(INCLUDES) /nologo $(OPTS) $(DEFS) - -# Object files -# -SSL_BASE_OBJS = \ - $(OBJDIR)\esock.obj \ - $(OBJDIR)\debuglog.obj \ - $(OBJDIR)\esock_poll$(obj) \ - $(OBJDIR)\esock_osio.obj \ - $(OBJDIR)\esock_utils.obj \ - $(OBJDIR)\esock_posix_str.obj - -OPENSSL_OBJS = \ - $(OBJDIR)\esock_openssl.obj - -# -# Targets -# - -all: $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(BINDIR)\ssl_esock.exe - -clean: - del $(BINDIR)\*.exe - del $(OBJDIR)\*.obj - -# Inference rule .c.obj: -# -{.}.c{$(OBJDIR)}.obj: - $(CC) $(CFLAGS) /c /Fo$@ $(*B).c - -# Binary -# -$(BINDIR)\ssl_esock.exe: $(SSL_BASE_OBJS) $(OPENSSL_OBJS) - $(CC) /nologo $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(OPENSSL_LIBS) \ - $(WINSOCK_LIB) /Fe$(BINDIR)\ssl_esock.exe - - - -# Dependencies -# -$(OBJDIR)\esock.o: esock.h debuglog.h esock_ssl.h esock_osio.h \ - esock_utils.h esock_winsock.h -$(OBJDIR)\debuglog.o: debuglog.h esock_ssl.h esock_utils.h -$(OBJDIR)\esock_osio.o: esock_osio.h esock.h debuglog.h esock_utils.h \ - esock_winsock.h -$(OBJDIR)\esock_utils.o: esock_utils.h -$(OBJDIR)\esock_posix_str.o: esock_posix_str.h esock_winsock.h - -$(OBJDIR)\esock_openssl.o: esock.h esock_ssl.h debuglog.h esock_utils.h \ - $(OPENSSL_INCLUDE)\crypto.h \ - $(OPENSSL_INCLUDE)\ssl.h \ - $(OPENSSL_INCLUDE)\err.h - - - - - - - - - - - - diff --git a/lib/ssl/c_src/Makefile.win32.dist b/lib/ssl/c_src/Makefile.win32.dist deleted file mode 100644 index 8510c44e08..0000000000 --- a/lib/ssl/c_src/Makefile.win32.dist +++ /dev/null @@ -1,45 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2009. 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% -# - -# Makefile.win32.dist for SSL -# -# To be placed in obj directory. -# - -CC = cl - -BINDIR = %BINDIR% - -OPENSSL_LIBS = \ - $(BINDIR)\ssleay32.lib \ - $(BINDIR)\libeay32.lib - -WINSOCK_LIB = ws2_32.lib - -SSL_BASE_OBJS = esock.obj debuglog.obj esock_osio.obj esock_utils.obj \ - esock_posix_str.obj - -OPENSSL_OBJS = esock_openssl.obj - -$(BINDIR)\ssl_esock.exe: $(SSL_BASE_OBJS) $(OPENSSL_OBJS) - $(CC) /nologo $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(OPENSSL_LIBS) \ - $(WINSOCK_LIB) /Fe$(BINDIR)\ssl_esock.exe - - - diff --git a/lib/ssl/c_src/debuglog.c b/lib/ssl/c_src/debuglog.c deleted file mode 100644 index e2e55df4b2..0000000000 --- a/lib/ssl/c_src/debuglog.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 1999-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Various routines for debug printouts and logs. - */ - -#include -#include -#include -#include -#include -#include -#include "debuglog.h" -#include "esock_utils.h" - -#ifndef __WIN32__ -static char tr_format_buf[256]; -static char *tr_format(const char *format); -static int vfprintclistf(FILE *fp, const char *format, va_list args); -#endif - -int debug = 0; -int debugmsg = 0; -FILE *ssllogfp = NULL; -FILE *__locallogfp = NULL; - -void open_ssllog(char *path) -{ - ssllogfp = openlog(path); -} - -void close_ssllog(void) -{ - if (ssllogfp) - closelog(ssllogfp); -} - -FILE *openlog(char *s) -{ - FILE *fp; - time_t t = time(NULL); - - if ((fp = fopen(s, "a"))) { - setbuf(fp, NULL); - fprintf(fp, "===== Opened [%s] %s", s, ctime(&t)); - } - return fp; -} - -void closelog(FILE *fp) -{ - time_t t = time(NULL); - - if (fp) { - fprintf(fp, "Closed %s", ctime(&t)); - fclose(fp); - } -} - -int __debugprintf(const char *format, ...) -{ - va_list args; - int ret; -#ifndef __WIN32__ - char *newformat; - - va_start(args, format); - newformat = tr_format(format); - ret = vfprintf(stderr, newformat, args); - if (newformat != format && newformat != tr_format_buf) - esock_free(newformat); -#else - va_start(args, format); - ret = vfprintf(stderr, format, args); -#endif - va_end(args); - if (ssllogfp) { - va_start(args, format); - vfprintf(ssllogfp, format, args); - va_end(args); - } - return ret; -} - -int __debugprintclistf(const char *format, ...) -{ - va_list args; - int ret; -#ifndef __WIN32__ - char *newformat; - - va_start(args, format); - newformat = tr_format(format); - ret = vfprintclistf(stderr, newformat, args); - if (newformat != format && newformat != tr_format_buf) - esock_free(newformat); -#else - va_start(args, format); - ret = vfprintclistf(stderr, format, args); -#endif - if (ssllogfp) - vfprintclistf(ssllogfp, format, args); - va_end(args); - return ret; -} - -int __debuglogf(const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - ret = vfprintf(__locallogfp, format, args); - va_end(args); - return ret; -} - -#ifndef __WIN32__ - -/* Insert `\r' before each `\n' i format */ -static char *tr_format(const char *format) -{ - char *newformat, *s, *t; - int len; - - len = strlen(format); - if ((newformat = (len > 127) ? esock_malloc(len) : tr_format_buf)) { - for (s = (char *)format, t = newformat; *s; *t++ = *s++) - if (*s == '\n') - *t++ = '\r'; - *t = '\0'; - } else - newformat = (char *)format; - return newformat; -} - -#endif - -/* This function is for printing arrays of characters with formats - * %FPa or %FPb, where F and P are the ordinary specifiers for - * field width and precision, respectively. - * - * The conversion specifier `a' implies hex-string output, while - * the `b' specifier provides character output (for non-printable - * characters a `.' is written. - * - * The F specifier contains the width for each character. The - * P specifier tells how many characters to print. - * - * Example: Suppose we have a function myprintf(char *format, ...) - * that calls our vfprintclistf(), and that - * - * char buf[] = "h\r\n"; - * len = 3; - * - * Then - * - * myprintf("%.2b", buf) prints "h." - * myprintf("%2.3b", buf) prints "h . . " - * myprintf("%3.*a", len, buf) prints "68 0d 0a" - * - */ - -static int vfprintclistf(FILE *fp, const char *format, va_list args) -{ - - int i, len, width, prec, written = 0; - char *s, *prevs, *fstart; - unsigned char *buf; - - if (!format || !*format) - return 0; - - /* %{[0-9]*|\*}{.{[0-9]*|\*}{a|b} */ - - prevs = (char *)format; /* format is const */ - s = strchr(format, '%'); - while (s && *s) { - if (s - prevs > 0) - written += fprintf(fp, "%.*s", s - prevs, prevs); - width = prec = 0; - fstart = s; - s++; - if (*s != '%') { /* otherwise it is not a format */ - if (*s == '*') { /* width in arg */ - s++; - width = va_arg(args, int); - } else if ((len = strspn(s, "0123456789"))) { /* const width */ - width = atoi(s); - s += len; - } else - width = 0; - if (*s == '.') { /* precision specified */ - s++; - if (*s == '*') { /* precision in arg */ - s++; - prec = va_arg(args, int); - } else if ((len = strspn(s, "0123456789"))) { /* const prec */ - prec = atoi(s); - s += len; - } else /* no precision value, defaults to zero */ - prec = 0; - } else - prec = 0; /* no precision defaults to zero */ - if (*s == 'a' || *s == 'b') { /* only valid specifiers */ - buf = va_arg(args, unsigned char *); - if (*s == 'a') { - for (i = 0; i < prec; i++) - written += fprintf(fp, "%*.2x", width, buf[i]); - }else if (*s == 'b') { - for (i = 0; i < prec; i++) { - if (isprint(buf[i])) - written += fprintf(fp, "%*c", width, buf[i]); - else - written += fprintf(fp, "%*c", width, '.'); - } - } - } else { - fprintf(stderr, "fprintclistf: format \"%s\" invalid.\n", - format); - va_end(args); - return written; - } - } - s++; - /* Now s points to the next character after the format */ - prevs = s; - s = strchr(s, '%'); - } - if (format + strlen(format) + 1 - prevs > 0) - written += fprintf(fp, "%s", prevs); - return written; -} - diff --git a/lib/ssl/c_src/debuglog.h b/lib/ssl/c_src/debuglog.h deleted file mode 100644 index 5699e6b495..0000000000 --- a/lib/ssl/c_src/debuglog.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 1998-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Debug functions and macros. - * - */ - -#ifndef __DEBUGLOG_H_ -#define __DEBUGLOG_H_ - -#include -#include "esock_ssl.h" - -#define DEBUGF(x) if (debug) __debugprintf x; -#define DEBUGMSGF(x) if (debugmsg) __debugprintclistf x; -#define LOGF(fp, x) if (fp) { __locallogfp = fp; __debuglogf x; } -#define SSLDEBUGF() if (debug) { esock_ssl_print_errors_fp(stderr); \ - if (ssllogfp) esock_ssl_print_errors_fp(ssllogfp); } - -int debug; -int debugmsg; -FILE *ssllogfp; -FILE *__locallogfp; - -void open_ssllog(char *path); -void close_ssllog(void); -FILE *openlog(char *); -void closelog(FILE *); -int __debugprintf(const char *, ...); -int __debugprintclistf(const char *, ...); -int __debuglogf(const char *, ...); - -#endif diff --git a/lib/ssl/c_src/esock.c b/lib/ssl/c_src/esock.c deleted file mode 100644 index 78d08f7c29..0000000000 --- a/lib/ssl/c_src/esock.c +++ /dev/null @@ -1,1904 +0,0 @@ -/* - * 1999-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ - -/* - * Purpose: Implementation of Secure Socket Layer (SSL). - * - * This is an "SSL proxy" for Erlang in the form of a port - * program. - * - * The implementation has borrowed somewhat from the original - * implementation of `socket' by Claes Wikström, and the former - * implementation of `ssl_socket' by Helen Ariyan. - * - * All I/O is now non-blocking. - * - * When a connection (cp) is in the state JOINED we have the following - * picture: - * - * proxy->fd fd - * | | - * proxy->eof | --------> wq -----------> | bp - * | | - * Erlang | | SSL - * | | - * proxy->bp | <------ proxy->wq --------- | eof - * | | - * - * We read from Erlang (proxy->fd) and write to SSL (fd); and read from - * SSL (fd) and write to Erlang (proxy->fd). - * - * The variables bp (broken pipe) and eof (end of file) take the - * values 0 and 1. - * - * What has been read and cannot be immediately written is put in a - * write queue (wq). A wq is emptied before reads are continued, which - * means that at most one chunk that is read can be in a wq. - * - * The proxy-to-ssl part of a cp is valid iff - * - * !bp && (wq.len > 0 || !proxy->eof). - * - * The ssl-to-proxy part of a cp is valid iff - * - * !proxy->bp && (proxy->wq.len > 0 || !eof). - * - * The connection is valid if any of the above parts are valid, i.e. - * invalid if both parts are invalid. - * - * Every SELECT_TIMEOUT second we try to write to those file - * descriptors that have non-empty wq's (the only way to detect that a - * far end has gone away is to write to it). - * - * STATE TRANSITIONS - * - * Below (*) means that the corresponding file descriptor is published - * (i.e. kwown outside this port program) when the state is entered, - * and thus cannot be closed without synchronization with the - * ssl_server. - * - * Listen: - * - * STATE_NONE ---> (*) PASSIVE_LISTENING <---> ACTIVE_LISTENING - * - * Accept: - * - * STATE_NONE ---> SSL_ACCEPT ---> (*) CONNECTED ---> JOINED ---> - * ---> SSL_SHUTDOWN ---> DEFUNCT - * - * Connect: - * - * STATE_NONE ---> (*) WAIT_CONNECT ---> SSL_CONNECT ---> CONNECTED ---> - * ---> JOINED ---> SSL_SHUTDOWN ---> DEFUNCT - * - * In states where file descriptors has been published, and where - * something goes wrong, the state of the connection is set to - * DEFUNCT. A connection in such a state can only be closed by a CLOSE - * message from Erlang (a reception of such a message is registered in - * cp->closed). The possible states are: WAIT_CONNECT, SSL_CONNECT, - * CONNECTED, JOINED, and SSL_SHUTDOWN. - * - * A connection in state SSL_ACCEPT can be closed and removed without - * synchronization. - * - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef __WIN32__ -#include "esock_winsock.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __WIN32__ -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff /* Should be in . */ -#endif - -#include "esock.h" -#include "debuglog.h" -#include "esock_utils.h" -#include "esock_ssl.h" -#include "esock_osio.h" -#include "esock_posix_str.h" -#include "esock_poll.h" - -#define MAJOR_VERSION 2 -#define MINOR_VERSION 0 -#define MAXREPLYBUF 256 -#define RWBUFLEN (32*1024) -#define IS_CLIENT 0 -#define IS_SERVER 1 -#define SELECT_TIMEOUT 2 /* seconds */ - -#define psx_errstr() esock_posix_str(sock_errno()) -#define ssl_errstr() esock_ssl_errstr - -#define PROXY_TO_SSL_VALID(cp) (!(cp)->bp && \ - ((cp)->wq.len > 0 || !(cp)->proxy->eof)) - -#define SSL_TO_PROXY_VALID(cp) (!(cp)->proxy->bp && \ - ((cp)->proxy->wq.len > 0 || !(cp)->eof)) - -#define JOINED_STATE_INVALID(cp) (!(PROXY_TO_SSL_VALID(cp)) && \ - !(SSL_TO_PROXY_VALID(cp))) -static int loop(void); -static int set_poll_conns(Connection *cp, EsockPoll *ep, int verbose); -static Connection *next_polled_conn(Connection *cp, Connection **cpnext, - EsockPoll *ep, int set_wq_fds); - -static void leave_joined_state(Connection *cp); -static void do_shutdown(Connection *cp); -static void close_and_remove_connection(Connection *cp); -static int reply(int cmd, char *fmt, ...); -static int input(char *fmt, ...); -static int put_pars(unsigned char *buf, char *fmt, va_list args); -static int get_pars(unsigned char *buf, char *fmt, va_list args); -static FD do_connect(char *lipstring, int lport, char *fipstring, int fport); -static FD do_listen(char *ipstring, int lport, int backlog, int *aport); -static FD do_accept(FD listensock, struct sockaddr *saddr, int *len); -static void print_connections(void); -static void dump_connections(void); -static int check_num_sock_fds(FD fd); -static void safe_close(FD fd); -static Connection *new_connection(int state, FD fd); -static Connection *get_connection(FD fd); -static void remove_connection(Connection *conn); -static Proxy *get_proxy_by_peerport(int port); -static Proxy *new_proxy(FD fd); -static void remove_proxy(Proxy *proxy); -static void ensure_write_queue(WriteQueue *wq, int size); -static void clean_up(void); - -static Connection *connections = NULL; -static int num_sock_fds; /* On UNIX all file descriptors */ -static Proxy *proxies = NULL; -static int proxy_listensock = INVALID_FD; -static int proxy_listenport = 0; -static int proxy_backlog = 128; -static int proxysock_last_err = 0; -static int proxysock_err_cnt = 0; -static char rwbuf[RWBUFLEN]; -static unsigned char *ebuf = NULL; /* Set by read_ctrl() */ - -static char *connstr[] = { - "STATE_NONE", - "ACTIVE_LISTENING", - "PASSIVE_LISTENING", - "CONNECTED", - "WAIT_CONNECT", - "SSL_CONNECT", - "SSL_ACCEPT", - "TRANSPORT_ACCEPT", - "JOINED", - "SSL_SHUTDOWN", - "DEFUNCT" -}; - -static char *originstr[] = { - "listen", - "accept", - "connect" -}; - -int main(int argc, char **argv) -{ - char *logfile = NULL; - int i; - esock_version *vsn; - char *ciphers; -#ifdef __WIN32__ - int pid; - WORD version; - WSADATA wsa_data; - - set_binary_mode(); - setvbuf(stderr, NULL, _IONBF, 0); - /* Two sockets for the stdin socket pipe (local thread). */ - num_sock_fds = 2; -#else - pid_t pid; - num_sock_fds = 3; /* 0, 1, 2 */ -#endif - - pid = getpid(); - i = 1; - while (i < argc) { - if (strcmp(argv[i], "-d") == 0) { - debug = 1; - i++; - } else if (strcmp(argv[i], "-dm") == 0) { - debugmsg = 1; - i++; - } else if (strcmp(argv[i], "-pp") == 0) { - i++; - proxy_listenport = atoi(argv[i]); - i++; - } else if (strcmp(argv[i], "-pb") == 0) { - i++; - proxy_backlog = atoi(argv[i]); - i++; - } else if (strcmp(argv[i], "-pv") == 0) { - i++; - protocol_version = atoi(argv[i]); - i++; - } else if (strcmp(argv[i], "-dd") == 0) { - i++; - logfile = esock_malloc(strlen(argv[i]) + 64); - sprintf(logfile, "%s/ssl_esock.%d.log", argv[i], (int)pid); - i++; - } else if (strcmp(argv[i], "-ersa") == 0) { - ephemeral_rsa = 1; - i++; - } else if (strcmp(argv[i], "-edh") == 0) { - ephemeral_dh = 1; - i++; - } - } - if (debug || debugmsg) { - DEBUGF(("Starting ssl_esock\n")); - if (logfile) { - open_ssllog(logfile); -#ifndef __WIN32__ - num_sock_fds++; -#endif - } - atexit(close_ssllog); - DEBUGF(("pid = %d\n", getpid())); - } - if (esock_ssl_init() < 0) { - fprintf(stderr, "esock: Could not do esock_ssl_init\n"); - exit(EXIT_FAILURE); - } - - atexit(esock_ssl_finish); - -#ifdef __WIN32__ - /* Start Windows' sockets */ - version = MAKEWORD(MAJOR_VERSION, MINOR_VERSION); - if (WSAStartup(version, &wsa_data) != 0) { - fprintf(stderr, "esock: Could not start up Windows' sockets\n"); - exit(EXIT_FAILURE); - } - atexit((void (*)(void))WSACleanup); - if (LOBYTE(wsa_data.wVersion) < MAJOR_VERSION || - (LOBYTE(wsa_data.wVersion) == MAJOR_VERSION && - HIBYTE(wsa_data.wVersion) < MINOR_VERSION)) { - fprintf(stderr, "esock: Windows socket version error. " - "Requested version:" - "%d.%d, version found: %d.%d\n", MAJOR_VERSION, - MINOR_VERSION, LOBYTE(wsa_data.wVersion), - HIBYTE(wsa_data.wVersion)); - exit(EXIT_FAILURE); - } - DEBUGF(("Using Windows socket version: %d.%d\n", - LOBYTE(wsa_data.wVersion), HIBYTE(wsa_data.wVersion))); - DEBUGF(("Maximum number of sockets available: %d\n", - wsa_data.iMaxSockets)); - - if (esock_osio_init() < 0) { - fprintf(stderr, "esock: Could not init osio\n"); - exit(EXIT_FAILURE); - } - atexit(esock_osio_finish); -#endif - - /* Create the local proxy listen socket and set it to non-blocking */ - proxy_listensock = do_listen("127.0.0.1", proxy_listenport, - proxy_backlog, &proxy_listenport); - if (proxy_listensock == INVALID_FD) { - fprintf(stderr, "esock: Cannot create local listen socket\n"); - exit(EXIT_FAILURE); - } - SET_NONBLOCKING(proxy_listensock); - DEBUGF(("Local proxy listen socket: fd = %d, port = %d\n", - proxy_listensock, proxy_listenport)); - - vsn = esock_ssl_version(); - ciphers = esock_ssl_ciphers(); - - /* Report: port number of the local proxy listen socket, the native - * os pid, the compile and lib versions of the ssl library, and - * the list of available ciphers. */ - reply(ESOCK_PROXY_PORT_REP, "24sss", proxy_listenport, (int)pid, - vsn->compile_version, vsn->lib_version, ciphers); - - atexit(clean_up); - - loop(); - - if (logfile) - esock_free(logfile); - exit(EXIT_SUCCESS); -} - - -/* - * Local functions - * - */ - -static int loop(void) -{ - EsockPoll pollfd; - FD fd, msgsock, listensock, connectsock, proxysock; - int cc, wc, fport, lport, pport, length, backlog, intref, op; - int value; - char *lipstring, *fipstring; - char *flags; - char *protocol_vsn, *cipher; - unsigned char *cert, *bin; - int certlen, binlen; - struct sockaddr_in iserv_addr; - int sret = 1; - Connection *cp, *cpnext, *newcp; - Proxy *pp; - time_t last_time = 0, now = 0; - int set_wq_fds; - - esock_poll_init(&pollfd); - - while(1) { - esock_poll_zero(&pollfd); - esock_poll_fd_set_read(&pollfd, proxy_listensock); - esock_poll_fd_set_read(&pollfd, local_read_fd); - - set_wq_fds = 0; - - if (sret) /* sret == 1 the first time. */ - DEBUGF(("==========LOOP=============\n")); - - cc = set_poll_conns(connections, &pollfd, sret) + 1; - - if (sret) { - print_connections(); - DEBUGF(("Before poll/select: %d descriptor%s (total %d)\n", - cc, (cc == 1) ? "" : "s", num_sock_fds)); - } - - sret = esock_poll(&pollfd, SELECT_TIMEOUT); - if (sret < 0) { - DEBUGF(("select/poll error: %s\n", psx_errstr())); - continue; - } - - time(&now); - if (now >= last_time + SELECT_TIMEOUT) { - set_wq_fds = 1; - last_time = now; - } - /* - * First accept as many connections as possible on the - * proxy listen socket. We record the peer port, which - * is later used as a reference for joining a proxy - * connection with a network connection. - */ - - if (esock_poll_fd_isset_read(&pollfd, proxy_listensock)) { - while (1) { - length = sizeof(iserv_addr); - proxysock = do_accept(proxy_listensock, - (struct sockaddr *)&iserv_addr, - (int*)&length); - if(proxysock == INVALID_FD) { - if (sock_errno() != ERRNO_BLOCK) { - /* We can here for example get the error - * EMFILE, i.e. no more file descriptors - * available, but we do not have any specific - * connection to report the error to. We - * increment the error counter and saves the - * last err. - */ - proxysock_err_cnt++; - proxysock_last_err = sock_errno(); - DEBUGF(("accept error (proxy_listensock): %s\n", - psx_errstr())); - } - break; - } else { - /* Get peer port number */ -/* length = sizeof(iserv_addr); */ -/* if (getpeername(proxysock, (struct sockaddr *)&iserv_addr, */ -/* &length) < 0) { */ -/* DEBUGF(("Can't get peername of proxy socket")); */ -/* safe_close(proxysock); */ -/* } else { */ - /* Add to pending proxy connections */ - SET_NONBLOCKING(proxysock); - pp = new_proxy(proxysock); - pp->peer_port = ntohs(iserv_addr.sin_port); - DEBUGF(("-----------------------------------\n")); - DEBUGF(("[PROXY_LISTEN_SOCK] conn accepted: " - "proxyfd = %d, " - "peer port = %d\n", proxysock, pp->peer_port)); -/* } */ - } - } - } - - /* - * Read control messages from Erlang - */ - if (esock_poll_fd_isset_read(&pollfd, local_read_fd)) { - cc = read_ctrl(&ebuf); - if ( cc < 0 ) { - DEBUGF(("Read loop -1 or 0\n")); - return -1; - } else if (cc == 0) { /* not eof */ - DEBUGF(("GOT empty string \n")); - - } else { - - switch((int)*ebuf) { - - case ESOCK_SET_SEED_CMD: - /* - * ebuf = {cmd(1), binary(N) } - */ - input("b", &binlen, &bin); - DEBUGF(("[SET_SEED_CMD]\n")); - esock_ssl_seed(bin, binlen); - /* no reply */ - break; - - case ESOCK_GETPEERNAME_CMD: - /* - * ebuf = {cmd(1), fd(4)} - */ - input("4", &fd); - DEBUGF(("[GETPEERNAME_CMD] fd = %d\n", fd)); - cp = get_connection(fd); - length = sizeof(iserv_addr); - if (!cp) { - sock_set_errno(ERRNO_NOTSOCK); - reply(ESOCK_GETPEERNAME_ERR, "4s", fd, psx_errstr()); - } else if (getpeername(fd, - (struct sockaddr *) &iserv_addr, - &length) < 0) { - reply(ESOCK_GETPEERNAME_ERR, "4s", fd, psx_errstr()); - } else { - /* - * reply = {cmd(1), fd(4), port(2), - * ipstring(N), 0(1)} - */ - reply(ESOCK_GETPEERNAME_REP, "42s", fd, - ntohs(iserv_addr.sin_port), - inet_ntoa(iserv_addr.sin_addr)); - } - break; - - case ESOCK_GETSOCKNAME_CMD: - /* - * ebuf = {cmd(1), fd(4)} - */ - input("4", &fd); - DEBUGF(("[GETSOCKNAME_CMD] fd = %d\n", fd)); - cp = get_connection(fd); - length = sizeof(iserv_addr); - if (!cp) { - sock_set_errno(ERRNO_NOTSOCK); - reply(ESOCK_GETSOCKNAME_ERR, "4s", fd, psx_errstr()); - } else if (getsockname(fd, - (struct sockaddr *)&iserv_addr, - &length) < 0) { - reply(ESOCK_GETSOCKNAME_ERR, "4s", fd, psx_errstr()); - } else { - /* - * reply = {cmd(1), fd(4), port(2), - * ipstring(N), 0(1)} - */ - reply(ESOCK_GETSOCKNAME_REP, "42s", fd, - ntohs(iserv_addr.sin_port), - inet_ntoa(iserv_addr.sin_addr)); - } - break; - - case ESOCK_GETCONNINFO_CMD: - /* - * ebuf = {cmd(1), fd(4)} - */ - input("4", &fd); - DEBUGF(("[GETCONNINFO_CMD] fd = %d\n", fd)); - cp = get_connection(fd); - if (!cp) { - sock_set_errno(ERRNO_NOTSOCK); - reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr()); - } else { - if (esock_ssl_getprotocol_version(cp, - &protocol_vsn) < 0) - reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr()); - else if (esock_ssl_getcipher(cp, &cipher) < 0) - reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr()); - else - /* - * reply = {cmd(1), fd(4), protocol(N), 0(1), - * cipher(N), 0(1)} - */ - reply(ESOCK_GETCONNINFO_REP, "4ss", fd, - protocol_vsn, cipher); - } - break; - - case ESOCK_GETPEERCERT_CMD: - /* - * ebuf = {cmd(1), fd(4)} - */ - input("4", &fd); - DEBUGF(("[GETPEERCERT_CMD] fd = %d\n", fd)); - cp = get_connection(fd); - if (!cp) { - sock_set_errno(ERRNO_NOTSOCK); - reply(ESOCK_GETPEERCERT_ERR, "4s", fd, psx_errstr()); - } else { - if ((certlen = esock_ssl_getpeercert(cp, &cert)) < 0) - reply(ESOCK_GETPEERCERT_ERR, "4s", fd, psx_errstr()); - else { - /* - * reply = {cmd(1), fd(4), certlen(4), cert(N)} - */ - reply(ESOCK_GETPEERCERT_REP, "4b", fd, - certlen, cert); - esock_free(cert); - } - } - break; - - case ESOCK_CONNECT_CMD: - /* - * ebuf = {cmd(1), intref(4), - * lport(2), lipstring(N), 0(1), -- local - * fport(2), fipstring(N), 0(1), -- foreign - * flags(N), 0(1)} - */ - input("42s2ss", &intref, &lport, &lipstring, - &fport, &fipstring, &flags); - DEBUGF(("[CONNECT_CMD] intref = %d, " - "lipstring = %s lport = %d, " - "fipstring = %s fport = %d, " - "flags = %s\n", intref, lipstring, lport, - fipstring, fport, flags)); - connectsock = do_connect(lipstring, lport, - fipstring, fport); - if(connectsock == INVALID_FD) { - reply(ESOCK_CONNECT_SYNC_ERR, "4s", intref, psx_errstr()); - break; - } - DEBUGF((" fd = %d\n", connectsock)); - cp = new_connection(ESOCK_WAIT_CONNECT, connectsock); - cp->origin = ORIG_CONNECT; - length = strlen(flags); - cp->flags = esock_malloc(length + 1); - strcpy(cp->flags, flags); - DEBUGF(("-> WAIT_CONNECT fd = %d\n", connectsock)); - /* Publish connectsock */ - reply(ESOCK_CONNECT_WAIT_REP, "44", intref, connectsock); - break; - - case ESOCK_TERMINATE_CMD: - /* - * ebuf = {cmd(1)} - */ - exit(EXIT_SUCCESS); - break; - - case ESOCK_CLOSE_CMD: - /* - * ebuf = {cmd(1), fd(4)} - */ - input("4", &fd); - if ((cp = get_connection(fd))) { - DEBUGF(("%s[CLOSE_CMD]: fd = %d\n", - connstr[cp->state], fd)); - if (cp->proxy) - cp->proxy->bp = 1; - switch (cp->state) { - case ESOCK_JOINED: - cp->close = 1; - if (JOINED_STATE_INVALID(cp)) - leave_joined_state(cp); - break; - case ESOCK_SSL_SHUTDOWN: - cp->close = 1; - DEBUGF((" close flag set\n")); - break; - default: - DEBUGF(("-> (removal)\n")); - close_and_remove_connection(cp); - } - } else - DEBUGF(("[CLOSE_CMD]: ERROR: fd = %d not found\n", fd)); - break; - - case ESOCK_SET_SOCKOPT_CMD: - /* - * ebuf = {cmd(1), fd(4), op(1), on(1)} - */ - input("411", &fd, &op, &value); - switch(op) { - case ESOCK_SET_TCP_NODELAY: - if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - (void *)&value, sizeof(value)) < 0) { - DEBUGF(("Error: setsockopt TCP_NODELAY\n")); - reply(ESOCK_IOCTL_ERR, "4s", fd, psx_errstr()); - } else { - reply(ESOCK_IOCTL_OK, "4", fd); - } - break; - default: - DEBUGF(("Error: set_sock_opt - Not implemented\n")); - sock_set_errno(ERRNO_OPNOTSUPP); - reply(ESOCK_IOCTL_ERR, "4", fd, psx_errstr()); - break; - } - break; - - case ESOCK_LISTEN_CMD: - /* - * ebuf = {cmd(1), intref(4), lport(2), ipstring(N), 0(1), - * backlog(2), flags(N), 0(1)} - */ - input("42s2s", &intref, &lport, &lipstring, &backlog, - &flags); - DEBUGF(("[LISTEN_CMD] intref = %d, port = %d, " - "ipstring = %s, backlog = %d, flags = %s\n", - intref, lport, lipstring, backlog, flags)); - - listensock = do_listen(lipstring, lport, backlog, &lport); - if(listensock == INVALID_FD) { - reply(ESOCK_LISTEN_SYNC_ERR, "4s", intref, psx_errstr()); - break; - } - cp = new_connection(ESOCK_PASSIVE_LISTENING, listensock); - /* Flags may be an empty string */ - length = strlen(flags); - cp->flags = esock_malloc(length + 1); - strcpy(cp->flags, flags); - - cp->origin = ORIG_LISTEN; - if (esock_ssl_listen_init(cp) < 0) { - DEBUGF(("esock_ssl_listen_init() failed.\n")); - reply(ESOCK_LISTEN_SYNC_ERR, "4s", intref, - ssl_errstr()); - close_and_remove_connection(cp); - break; - } - DEBUGF(("-> PASSIVE_LISTENING (fd = %d)\n", listensock)); - /* Publish listensock */ - reply(ESOCK_LISTEN_REP, "442", intref, listensock, - ntohs(iserv_addr.sin_port)); - break; - - case ESOCK_TRANSPORT_ACCEPT_CMD: - /* - * ebuf = { op(1), fd(4), flags(N), 0(1)} - */ - input("4s", &fd, &flags); - DEBUGF(("[TRANSPORT_ACCEPT_CMD] listenfd = %d, flags = %s\n", fd, - flags)); - cp = get_connection(fd); - if (cp) { - /* We store the flags in the listen socket's - * connection, and overwrite previous flags. - */ - if ((length = strlen(flags)) > 0) { - if (cp->flags) - cp->flags = esock_realloc(cp->flags, - length + 1); - else - cp->flags = esock_malloc(length + 1); - strcpy(cp->flags, flags); - } - if (cp->flags && cp->flags[0] != '\0') { - cp->acceptors++; - cp->state = ESOCK_ACTIVE_LISTENING; - DEBUGF(("-> ACTIVE_LISTENING\n")); - break; - } - DEBUGF(("ERROR: flags empty\n")); - } - reply(ESOCK_TRANSPORT_ACCEPT_ERR, "4s", fd, "ebadf"); - break; - - case ESOCK_SSL_ACCEPT_CMD: - input("4s", &fd, &flags); - DEBUGF(("[SSL_ACCEPT_CMD] fd = %d, flags = %s\n", fd, flags)); - cp = get_connection(fd); - if (cp) - cp->state = ESOCK_SSL_ACCEPT; - //reply(ESOCK_SSL_ACCEPT_REP, "4", fd); - break; - - case ESOCK_NOACCEPT_CMD: - /* - * ebuf = {cmd(1), fd(4)} - */ - input("4", &fd); - DEBUGF(("[NOACCEPT_CMD] listenfd = %d\n", fd)); - cp = get_connection(fd); - if (cp && (--cp->acceptors <= 0)) { - cp->acceptors = 0; - cp->state = ESOCK_PASSIVE_LISTENING; - esock_poll_clear_event(&pollfd, fd); - DEBUGF(("-> PASSIVE_LISTENING\n")); - } - break; - - case ESOCK_PROXY_JOIN_CMD: - /* - * ebuf = {cmd(1), fd(4), portnum(2)} - * - * fd - file descriptor of a connection in state - * CONNECTED - * portnum - port number of the Erlang proxy peer - */ - input("42", &fd, &pport); - cp = get_connection(fd); - pp = get_proxy_by_peerport(pport); - if (cp && cp->state == ESOCK_CONNECTED && pp) { - DEBUGF(("CONNECTED[PROXY_JOIN_CMD] fd = %d " - "portnum = %d\n", fd, pport)); - cp->proxy = pp; - pp->conn = cp; - reply(ESOCK_PROXY_JOIN_REP, "4", fd); - cp->state = ESOCK_JOINED; - DEBUGF(("-> JOINED\n")); - break; - } - if (!cp) { - DEBUGF(("[PROXY_JOIN_CMD] ERROR: No connection " - "having fd = %d\n", fd)); - reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, "ebadsocket"); - } else if (cp->state != ESOCK_CONNECTED) { - DEBUGF(("%s[PROXY_JOIN_CMD] ERROR: Bad state: " - "fd = %d\n", connstr[cp->state], cp->fd)); - reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, "ebadstate"); - } else { - DEBUGF(("ERROR: No proxy: fd = %d, pport = %d\n", - fd, pport)); - if (proxysock_err_cnt > 0) { - proxysock_err_cnt--; - reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, - esock_posix_str(proxysock_last_err)); - } else { - reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, - "enoproxysocket"); - } - cp->state = ESOCK_DEFUNCT; - } - break; - - case ESOCK_DUMP_STATE_CMD: - dump_connections(); - break; - - case ESOCK_SET_DEBUG_CMD: - /* - * ebuf = {cmd(1), debug(1)} - */ - input("1", &debug); - break; - - case ESOCK_SET_DEBUGMSG_CMD: - /* - * ebuf = {cmd(1), debugmsg(1)} - */ - input("1", &debugmsg); - break; - - default: - fprintf(stderr, "esock: default value in loop %c\n", - *ebuf); - exit(EXIT_FAILURE); - break; - } - } - } - - /* Go through all connections that have their file descriptors - set. */ - - /* Note: We may remove the current connection (cp). Thus we - * must be careful not to read cp->next after cp has been - * removed. */ - for (cp = next_polled_conn(connections, &cpnext, &pollfd, set_wq_fds); - cp != NULL; - cp = next_polled_conn(cpnext, &cpnext, &pollfd, set_wq_fds) - ) { - - switch(cp->state) { - - case ESOCK_PASSIVE_LISTENING: - DEBUGF(("-----------------------------------\n")); - fprintf(stderr, "esock: Got connect request while PASSIVE\n"); - exit(EXIT_FAILURE); - break; - - case ESOCK_ACTIVE_LISTENING: - /* new connect from network */ - DEBUGF(("-----------------------------------\n")); - DEBUGF(("ACTIVE_LISTENING - trying to accept on %d\n", - cp->fd)); - length = sizeof(iserv_addr); - msgsock = do_accept(cp->fd, (struct sockaddr*)&iserv_addr, - (int*)&length); - if(msgsock == INVALID_FD) { - DEBUGF(("accept error: %s\n", psx_errstr())); - reply(ESOCK_TRANSPORT_ACCEPT_ERR, "4s", cp->fd, psx_errstr()); - break; - } - SET_NONBLOCKING(msgsock); - if (--cp->acceptors <= 0) { - cp->acceptors = 0; - cp->state = ESOCK_PASSIVE_LISTENING; - DEBUGF(("-> PASSIVE_LISTENING\n")); - } - DEBUGF(("server accepted connection on fd %d\n", msgsock)); - newcp = new_connection(ESOCK_TRANSPORT_ACCEPT, msgsock); - newcp->origin = ORIG_ACCEPT; - reply(ESOCK_TRANSPORT_ACCEPT_REP, "44", cp->fd, msgsock); - newcp->listen_fd = cp->fd; /* Needed for ESOCK_ACCEPT_ERR */ - length = strlen(cp->flags); - /* XXX new flags are not needed */ - newcp->flags = esock_malloc(length + 1); - strcpy(newcp->flags, cp->flags); /* XXX Why? */ - if (esock_ssl_accept_init(newcp, cp->opaque) < 0) { - cp->errstr = ssl_errstr(); - break; - } - newcp->ssl_want = ESOCK_SSL_WANT_READ; - break; - - case ESOCK_SSL_ACCEPT: - /* SSL accept handshake. msgsock is *not* published yet. */ - msgsock = cp->fd; - DEBUGF(("-----------------------------------\n")); - DEBUGF(("SSL_ACCEPT fd = %d\n", msgsock)); - if (cp->errstr != NULL) { /* this means we got an error in ssl_accept_init */ - /* N.B.: The *listen fd* is reported. */ - reply(ESOCK_SSL_ACCEPT_ERR, "4s", msgsock, cp->errstr); - close_and_remove_connection(cp); - break; - } - if (esock_ssl_accept(cp) < 0) { - if (sock_errno() != ERRNO_BLOCK) { - /* Handshake failed. */ - reply(ESOCK_SSL_ACCEPT_ERR, "4s", msgsock, - ssl_errstr()); - DEBUGF(("ERROR: handshake: %s\n", ssl_errstr())); - close_and_remove_connection(cp); - } - } else { - /* SSL handshake successful: publish */ - reply(ESOCK_SSL_ACCEPT_REP, "4", msgsock); - DEBUGF(("-> CONNECTED\n")); - DEBUGF((" Session was %sreused.\n", - (esock_ssl_session_reused(cp)) ? "" : "NOT ")); - cp->state = ESOCK_CONNECTED; - } - break; - - case ESOCK_CONNECTED: - /* Should not happen. We do not read or write until - the connection is in state JOINED. */ - DEBUGF(("-----------------------------------\n")); - DEBUGF(("CONNECTED: Error: should not happen. fd = %d\n", - cp->fd)); - break; - - case ESOCK_JOINED: - /* - * Reading from Proxy, writing to SSL - */ - if (esock_poll_fd_isset_write(&pollfd, cp->fd)) { - /* If there is a write queue, write to ssl only */ - if (cp->wq.len > 0) { - /* The write retry semantics of SSL_write in - * the OpenSSL package is strange. Partial - * writes never occur, only complete writes or - * failures. A failure, however, still - * consumes all data written, although not all - * encrypted data could be written to the - * underlying socket. To retry a write we have - * to provide the same buf and length as in - * the original call, in our case rwbuf and - * the original buffer length. Hence the - * strange memcpy(). Note that wq.offset will - * always be zero when we use OpenSSL. - */ - DEBUGF(("-----------------------------------\n")); - DEBUGF(("JOINED: writing to ssl " - "fd = %d, from write queue only, wc = %d\n", - cp->fd, cp->wq.len - cp->wq.offset)); - memcpy(rwbuf, cp->wq.buf, cp->wq.len - cp->wq.offset); - - /* esock_ssl_write sets cp->eof, cp->bp when return - * value is zero */ - wc = esock_ssl_write(cp, rwbuf, - cp->wq.len - cp->wq.offset); - if (wc < 0) { - if (sock_errno() != ERRNO_BLOCK) { - /* Assume broken SSL pipe */ - DEBUGF(("broken SSL pipe\n")); - cp->bp = 1; - shutdown(cp->proxy->fd, SHUTDOWN_READ); - cp->proxy->eof = 1; - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } - } else if (wc == 0) { - /* SSL broken pipe */ - DEBUGF(("broken SSL pipe\n")); - cp->bp = 1; - shutdown(cp->proxy->fd, SHUTDOWN_READ); - cp->proxy->eof = 1; - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } else { - cp->wq.offset += wc; - if (cp->wq.offset == cp->wq.len) - cp->wq.len = 0; - } - } - } else if (esock_poll_fd_isset_read(&pollfd, cp->proxy->fd)) { - /* Read from proxy and write to SSL */ - DEBUGF(("-----------------------------------\n")); - DEBUGF(("JOINED: reading from proxy, " - "proxyfd = %d\n", cp->proxy->fd)); - cc = sock_read(cp->proxy->fd, rwbuf, RWBUFLEN); - DEBUGF(("read from proxyfd = %d, cc = %d\n", - cp->proxy->fd, cc)); - if (cc > 0) { - /* esock_ssl_write sets cp->eof, cp->bp when return - * value is zero */ - wc = esock_ssl_write(cp, rwbuf, cc); - if (wc < 0) { - if (sock_errno() != ERRNO_BLOCK) { - /* Assume broken pipe */ - DEBUGF(("broken SSL pipe\n")); - cp->bp = 1; - shutdown(cp->proxy->fd, SHUTDOWN_READ); - cp->proxy->eof = 1; - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } else { - /* add to write queue */ - DEBUGF(("adding all to write queue " - "%d bytes\n", cc)); - ensure_write_queue(&cp->wq, cc); - memcpy(cp->wq.buf, rwbuf, cc); - cp->wq.len = cc; - cp->wq.offset = 0; - } - } else if (wc == 0) { - /* Broken SSL pipe */ - DEBUGF(("broken SSL pipe\n")); - cp->bp = 1; - shutdown(cp->proxy->fd, SHUTDOWN_READ); - cp->proxy->eof = 1; - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } else if (wc < cc) { - /* add remainder to write queue */ - DEBUGF(("adding remainder to write queue " - "%d bytes\n", cc - wc)); - ensure_write_queue(&cp->wq, cc - wc); - memcpy(cp->wq.buf, rwbuf + wc, cc - wc); - cp->wq.len = cc - wc; - cp->wq.offset = 0; - } - } else { - /* EOF proxy or error */ - DEBUGF(("proxy eof or error %d\n", errno)); - cp->proxy->eof = 1; - if (cp->wq.len == 0) { - esock_ssl_shutdown(cp); - cp->bp = 1; - } - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } - } - /* - * Reading from SSL, writing to proxy - */ - if (esock_poll_fd_isset_write(&pollfd, cp->proxy->fd)) { - /* If there is a write queue, write to proxy only */ - if (cp->proxy->wq.len > 0) { - DEBUGF(("-----------------------------------\n")); - DEBUGF(("JOINED: writing to proxyfd = %d, " - "from write queue only, wc = %d\n", - cp->proxy->fd, cp->proxy->wq.len - - cp->proxy->wq.offset)); - wc = sock_write(cp->proxy->fd, cp->proxy->wq.buf + - cp->proxy->wq.offset, - cp->proxy->wq.len - - cp->proxy->wq.offset); - if (wc < 0) { - if (sock_errno() != ERRNO_BLOCK) { - /* Assume broken pipe */ - DEBUGF(("broken proxy pipe\n")); - cp->proxy->bp = 1; - /* There is no SSL shutdown for read */ - cp->eof = 1; - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } - } else { - cp->proxy->wq.offset += wc; - if (cp->proxy->wq.offset == cp->proxy->wq.len) - cp->proxy->wq.len = 0; - } - } - } else if (esock_poll_fd_isset_read(&pollfd, cp->fd)) { - /* Read from SSL and write to proxy */ - DEBUGF(("-----------------------------------\n")); - DEBUGF(("JOINED: read from ssl fd = %d\n", - cp->fd)); - cc = esock_ssl_read(cp, rwbuf, RWBUFLEN); - DEBUGF(("read from fd = %d, cc = %d\n", cp->fd, cc)); - if (cc > 0) { - wc = sock_write(cp->proxy->fd, rwbuf, cc); - if (wc < 0) { - if (sock_errno() != ERRNO_BLOCK) { - DEBUGF(("broken proxy pipe\n")); - /* Assume broken pipe */ - cp->proxy->bp = 1; - /* There is no SSL shutdown for read */ - cp->eof = 1; - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } else { - /* add all to write queue */ - DEBUGF(("adding to write queue %d bytes\n", - cc)); - ensure_write_queue(&cp->proxy->wq, cc); - memcpy(cp->proxy->wq.buf, rwbuf, cc); - cp->proxy->wq.len = cc; - cp->proxy->wq.offset = 0; - } - } else if (wc < cc) { - /* add to write queue */ - DEBUGF(("adding to write queue %d bytes\n", - cc - wc)); - ensure_write_queue(&cp->proxy->wq, cc - wc); - memcpy(cp->proxy->wq.buf, rwbuf + wc, cc - wc); - cp->proxy->wq.len = cc - wc; - cp->proxy->wq.offset = 0; - } - } else if (cc == 0) { - /* SSL eof */ - DEBUGF(("SSL eof\n")); - cp->eof = 1; - if (cp->proxy->wq.len == 0) { - shutdown(cp->proxy->fd, SHUTDOWN_WRITE); - cp->proxy->bp = 1; - } - if (JOINED_STATE_INVALID(cp)) { - leave_joined_state(cp); - break; - } - } else { - /* This may very well happen when reading from SSL. */ - DEBUGF(("NOTE: readmask set, cc < 0, fd = %d, " - "is ok\n", cp->fd)); - } - } - break; - - case ESOCK_SSL_SHUTDOWN: - DEBUGF(("-----------------------------------\n")); - DEBUGF(("SSL_SHUTDOWN: fd = %d\n", cp->fd)); - do_shutdown(cp); - break; - - case ESOCK_DEFUNCT: - DEBUGF(("-----------------------------------\n")); - DEBUGF(("DEFUNCT: ERROR: should not happen. fd = %d\n", - cp->fd)); - break; - - case ESOCK_WAIT_CONNECT: - /* New connection shows up */ - connectsock = cp->fd;/* Is published */ - DEBUGF(("-----------------------------------\n")); - DEBUGF(("WAIT_CONNECT fd = %d\n", connectsock)); - - /* If the connection did succeed it's possible to - * fetch the peer name (UNIX); or failure shows in - * exceptmask (WIN32). Sorry for the mess below, but - * we have to have balanced paren's in #ifdefs in - * order not to confuse Emacs' indentation. */ - length = sizeof(iserv_addr); - if ( -#ifdef __WIN32__ - esock_poll_fd_isset_exception(&pollfd, connectsock) -#else - getpeername(connectsock, (struct sockaddr *)&iserv_addr, - &length) < 0 -#endif - ) { - sock_set_errno(ERRNO_CONNREFUSED); - DEBUGF(("connect error: %s\n", psx_errstr())); - reply(ESOCK_CONNECT_ERR, "4s", connectsock, psx_errstr()); - cp->state = ESOCK_DEFUNCT; - break; - } - if (esock_ssl_connect_init(cp) < 0) { - DEBUGF(("esock_ssl_connect_init() failed\n")); - reply(ESOCK_CONNECT_ERR, "4s", connectsock, ssl_errstr()); - cp->state = ESOCK_DEFUNCT; - break; - } - DEBUGF(("-> SSL_CONNECT\n")); - cp->state = ESOCK_SSL_CONNECT; - cp->ssl_want = ESOCK_SSL_WANT_WRITE; - break; - - case ESOCK_SSL_CONNECT: - /* SSL connect handshake. connectsock is published. */ - connectsock = cp->fd; - DEBUGF(("-----------------------------------\n")); - DEBUGF(("SSL_CONNECT fd = %d\n", connectsock)); - if (esock_ssl_connect(cp) < 0) { - if (sock_errno() != ERRNO_BLOCK) { - /* Handshake failed */ - DEBUGF(("ERROR: handshake: %s\n", ssl_errstr())); - reply(ESOCK_CONNECT_ERR, "4s", connectsock, - ssl_errstr()); - cp->state = ESOCK_DEFUNCT; - } - } else { - /* SSL connect handshake successful */ - DEBUGF(("-> CONNECTED\n")); - reply(ESOCK_CONNECT_REP, "4", connectsock); - cp->state = ESOCK_CONNECTED; - } - break; - - default: - DEBUGF(("ERROR: Connection in unknown state.\n")); - } - } - } -} - -static int set_poll_conns(Connection *cp, EsockPoll *ep, int verbose) -{ - int i = 0; - - if (verbose) - DEBUGF(("MASKS SET FOR FD: ")); - while (cp) { - switch (cp->state) { - case ESOCK_ACTIVE_LISTENING: - if (verbose) - DEBUGF(("%d (read) ", cp->fd)); - esock_poll_fd_set_read(ep, cp->fd); - break; - case ESOCK_WAIT_CONNECT: - if (verbose) - DEBUGF(("%d (write) ", cp->fd)); - esock_poll_fd_set_write(ep, cp->fd); -#ifdef __WIN32__ - esock_poll_fd_set_exception(ep, cp->fd); /* Failure shows in exceptions */ -#endif - break; - case ESOCK_SSL_CONNECT: - case ESOCK_SSL_ACCEPT: - if (cp->ssl_want == ESOCK_SSL_WANT_READ) { - if (verbose) - DEBUGF(("%d (read) ", cp->fd)); - esock_poll_fd_set_read(ep, cp->fd); - } else if (cp->ssl_want == ESOCK_SSL_WANT_WRITE) { - if (verbose) - DEBUGF(("%d (write) ", cp->fd)); - esock_poll_fd_set_write(ep, cp->fd); - } - break; - case ESOCK_JOINED: - if (!cp->bp) { - if (cp->wq.len) { - if (verbose) - DEBUGF(("%d (write) ", cp->fd)); - esock_poll_fd_set_write(ep, cp->fd); - } else if (!cp->proxy->eof) { - if (verbose) - DEBUGF(("%d (read) ", cp->proxy->fd)); - esock_poll_fd_set_read(ep, cp->proxy->fd); - } - } - if (!cp->proxy->bp) { - if (cp->proxy->wq.len) { - if (verbose) - DEBUGF(("%d (write) ", cp->proxy->fd)); - esock_poll_fd_set_write(ep, cp->proxy->fd); - } else if (!cp->eof) { - if (verbose) - DEBUGF(("%d (read) ", cp->fd)); - esock_poll_fd_set_read(ep, cp->fd); - } - } - break; - case ESOCK_SSL_SHUTDOWN: - if (cp->ssl_want == ESOCK_SSL_WANT_READ) { - if (verbose) - DEBUGF(("%d (read) ", cp->fd)); - esock_poll_fd_set_read(ep, cp->fd); - } else if (cp->ssl_want == ESOCK_SSL_WANT_WRITE) { - if (verbose) - DEBUGF(("%d (write) ", cp->fd)); - esock_poll_fd_set_write(ep, cp->fd); - } - break; - default: - break; - } - i++; - cp = cp->next; - } - if (verbose) - DEBUGF(("\n")); - return i; -} - - -static Connection *next_polled_conn(Connection *cp, Connection **cpnext, - EsockPoll *ep, int set_wq_fds) -{ - while(cp) { - if (esock_poll_fd_isset_read(ep, cp->fd) || - (cp->proxy && esock_poll_fd_isset_read(ep, cp->proxy->fd)) || - (esock_poll_fd_isset_write(ep, cp->fd)) || - (cp->proxy && esock_poll_fd_isset_write(ep, cp->proxy->fd)) -#ifdef __WIN32__ - || esock_poll_fd_isset_exception(ep, cp->fd) /* Connect failure in WIN32 */ -#endif - || (set_wq_fds && (cp->wq.len || - (cp->proxy && cp->proxy->wq.len))) - || cp->errstr != NULL) { - *cpnext = cp->next; - return cp; - } - cp = cp->next; - } - *cpnext = NULL; - return NULL; -} - -static void leave_joined_state(Connection *cp) -{ - shutdown(cp->proxy->fd, SHUTDOWN_ALL); - if (((cp->bp || cp->eof) && cp->clean) || - (!cp->bp && !cp->eof)) { - DEBUGF(("-> SSL_SHUTDOWN\n")); - cp->state = ESOCK_SSL_SHUTDOWN; - cp->ssl_want = ESOCK_SSL_WANT_WRITE; - do_shutdown(cp); - } else if (cp->close) { - DEBUGF(("-> (removal)\n")); - close_and_remove_connection(cp); - } else { - DEBUGF(("-> DEFUNCT\n")); - cp->state = ESOCK_DEFUNCT; - } -} - -/* We are always in state SHUTDOWN here */ -static void do_shutdown(Connection *cp) -{ - int ret; - - ret = esock_ssl_shutdown(cp); - if (ret < 0) { - if (sock_errno() == ERRNO_BLOCK) { - return; - } else { - /* Something is wrong -- close and remove or move to DEFUNCT */ - DEBUGF(("Error in SSL shutdown\n")); - if (cp->close) { - DEBUGF(("-> (removal)\n")); - close_and_remove_connection(cp); - } else { - DEBUGF(("-> DEFUNCT\n")); - cp->state = ESOCK_DEFUNCT; - } - } - } else if (ret == 0) { - /* `close_notify' has been sent. Wait for reception of - same. */ - return; - } else if (ret == 1) { - /* `close_notify' has been sent, and received. */ - if (cp->close) { - DEBUGF(("-> (removal)\n")); - close_and_remove_connection(cp); - } else { - DEBUGF(("-> DEFUNCT\n")); - cp->state = ESOCK_DEFUNCT; - } - } -} - -static void close_and_remove_connection(Connection *cp) -{ - safe_close(cp->fd); - remove_connection(cp); -} - -static int reply(int cmd, char *fmt, ...) -{ - static unsigned char replybuf[MAXREPLYBUF]; - unsigned char *buf = replybuf; - va_list args; - int len; - - va_start(args, fmt); - len = put_pars(NULL, fmt, args); - va_end(args); - len++; - if (len > sizeof(replybuf)) - buf = esock_malloc(len); - - PUT_INT8(cmd, buf); - va_start(args, fmt); - (void) put_pars(buf + 1, fmt, args); - va_end(args); - write_ctrl(buf, len); - if (buf != replybuf) - esock_free(buf); - return len; -} - -static int input(char *fmt, ...) -{ - va_list args; - int len; - - va_start(args, fmt); - len = get_pars(ebuf + 1, fmt, args); - va_end(args); - return len + 1; -} - -static int put_pars(unsigned char *buf, char *fmt, va_list args) -{ - char *s, *str, *bin; - int val, len, pos = 0; - - s = fmt; - while (*s) { - switch (*s) { - case '1': - val = va_arg(args, int); - if (buf) - PUT_INT8(val, buf + pos); - pos++; - break; - case '2': - val = va_arg(args, int); - if (buf) - PUT_INT16(val, buf + pos); - pos += 2; - break; - case '4': - val = va_arg(args, int); - if (buf) - PUT_INT32(val, buf + pos); - pos += 4; - break; - case 's': /* string */ - str = va_arg(args, char *); - if (buf) - strcpy((char *)(buf + pos), str); - pos += strlen(str) + 1; - break; - case 'b': /* binary */ - len = va_arg(args, int); - if (buf) - PUT_INT32(len, buf + pos); - pos += 4; - bin = va_arg(args, char *); - if (buf) - memcpy(buf + pos, bin, len); - pos += len; - break; - default: - fprintf(stderr, "esock: Invalid format character: %c\n", *s); - exit(EXIT_FAILURE); - break; - } - s++; - } - return pos; -} - - -static int get_pars(unsigned char *buf, char *fmt, va_list args) -{ - int *ip; - char *s, **strp, **bin; - int pos = 0; - - s = fmt; - while (*s) { - switch (*s) { - case '1': - ip = va_arg(args, int *); - *ip = GET_INT8(buf + pos); - pos++; - break; - case '2': - ip = va_arg(args, int *); - *ip = GET_INT16(buf + pos); - pos += 2; - break; - case '4': - ip = va_arg(args, int *); - *ip = GET_INT32(buf + pos); - pos += 4; - break; - case 's': - strp = va_arg(args, char **); - *strp = (char *)(buf + pos); - pos += strlen(*strp) + 1; - break; - case 'b': - ip = va_arg(args, int *); - *ip = GET_INT32(buf + pos); - pos += 4; - bin = va_arg(args, char **); - *bin = (char *)(buf + pos); - pos += *ip; - break; - default: - fprintf(stderr, "esock: Invalid format character: %c\n", *s); - exit(EXIT_FAILURE); - break; - } - s++; - } - return pos; -} - -static FD do_connect(char *lipstring, int lport, char *fipstring, int fport) -{ - struct sockaddr_in sock_addr; - long inaddr; - FD fd; - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) { - DEBUGF(("Error calling socket()\n")); - return fd; - } - if (check_num_sock_fds(fd) < 0) - return INVALID_FD; - DEBUGF((" fd = %d\n", fd)); - - /* local */ - if ((inaddr = inet_addr(lipstring)) == INADDR_NONE) { - DEBUGF(("Error in inet_addr(): lipstring = %s\n", lipstring)); - safe_close(fd); - sock_set_errno(ERRNO_ADDRNOTAVAIL); - return INVALID_FD; - } - memset(&sock_addr, 0, sizeof(sock_addr)); - sock_addr.sin_family = AF_INET; - sock_addr.sin_addr.s_addr = inaddr; - sock_addr.sin_port = htons(lport); - if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) { - DEBUGF(("Error in bind()\n")); - safe_close(fd); - /* XXX Set error code for bind error */ - return INVALID_FD; - } - - /* foreign */ - if ((inaddr = inet_addr(fipstring)) == INADDR_NONE) { - DEBUGF(("Error in inet_addr(): fipstring = %s\n", fipstring)); - safe_close(fd); - sock_set_errno(ERRNO_ADDRNOTAVAIL); - return INVALID_FD; - } - memset(&sock_addr, 0, sizeof(sock_addr)); - sock_addr.sin_family = AF_INET; - sock_addr.sin_addr.s_addr = inaddr; - sock_addr.sin_port = htons(fport); - - SET_NONBLOCKING(fd); - - if(connect(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) { - if (sock_errno() != ERRNO_PROGRESS && /* UNIX */ - sock_errno() != ERRNO_BLOCK) { /* WIN32 */ - DEBUGF(("Error in connect()\n")); - safe_close(fd); - return INVALID_FD; - } - } - return fd; -} - -static FD do_listen(char *ipstring, int lport, int backlog, int *aport) -{ - static int one = 1; /* Type must be int, not long */ - struct sockaddr_in sock_addr; - long inaddr; - int length; - FD fd; - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) { - DEBUGF(("Error calling socket()\n")); - return fd; - } - if (check_num_sock_fds(fd) < 0) - return INVALID_FD; - DEBUGF((" fd = %d\n", fd)); - if ((inaddr = inet_addr(ipstring)) == INADDR_NONE) { - DEBUGF(("Error in inet_addr(): ipstring = %s\n", ipstring)); - safe_close(fd); - sock_set_errno(ERRNO_ADDRNOTAVAIL); - return INVALID_FD; - } - memset(&sock_addr, 0, sizeof(sock_addr)); - sock_addr.sin_family = AF_INET; - sock_addr.sin_addr.s_addr = inaddr; - sock_addr.sin_port = htons(lport); - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); - - if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) { - DEBUGF(("Error in bind()\n")); - safe_close(fd); - return INVALID_FD; - } - if (listen(fd, backlog) < 0) { - DEBUGF(("Error in listen()\n")); - safe_close(fd); - return INVALID_FD; - } - /* find out assigned local port number */ - length = sizeof(sock_addr); - if (getsockname(fd, (struct sockaddr *)&sock_addr, &length) < 0) { - DEBUGF(("Error in getsockname()\n")); - safe_close(fd); - return INVALID_FD; - } - if (aport) - *aport = ntohs(sock_addr.sin_port); - return fd; -} - -static FD do_accept(FD listensock, struct sockaddr *saddr, int *len) -{ - FD fd; - - if ((fd = accept(listensock, saddr, len)) == INVALID_FD) { - DEBUGF(("Error calling accept()\n")); - return fd; - } - if (check_num_sock_fds(fd) < 0) - return INVALID_FD; - return fd; -} - -static Connection *new_connection(int state, FD fd) -{ - Connection *cp; - - if (!(cp = esock_malloc(sizeof(Connection)))) - return NULL; - cp->state = state; - cp->acceptors = 0; - cp->fd = fd; - cp->listen_fd = INVALID_FD; - cp->proxy = NULL; - cp->opaque = NULL; - cp->ssl_want = 0; - cp->eof = 0; - cp->bp = 0; - cp->clean = 0; /* XXX Used? */ - cp->close = 0; - cp->origin = -1; - cp->flags = NULL; - cp->logfp = NULL; - cp->wq.size = 0; - cp->wq.buf = NULL; - cp->wq.len = 0; - cp->wq.offset = 0; - cp->next = connections; - cp->errstr = NULL; - connections = cp; - return cp; -} - - -static void print_connections(void) -{ - if (debug) { - Connection *cp = connections; - DEBUGF(("CONNECTIONS:\n")); - while (cp) { - if (cp->state == ESOCK_JOINED) { - DEBUGF((" - %s [%8p] (origin = %s)\n" - " (fd = %d, eof = %d, wq = %d, bp = %d)\n" - " (proxyfd = %d, eof = %d, wq = %d, bp = %d)\n", - connstr[cp->state], cp, originstr[cp->origin], - cp->fd, cp->eof, cp->wq.len, cp->bp, - cp->proxy->fd, cp->proxy->eof, cp->proxy->wq.len, - cp->proxy->bp)); - } else if (cp->state == ESOCK_ACTIVE_LISTENING) { - DEBUGF((" - %s [%8p] (fd = %d, acceptors = %d)\n", - connstr[cp->state], cp, cp->fd, cp->acceptors)); - } else { - DEBUGF((" - %s [%8p] (fd = %d)\n", connstr[cp->state], cp, - cp->fd)); - } - cp= cp->next; - } - } -} - -static void dump_connections(void) -{ - Connection *cp = connections; - Proxy *pp = proxies; - time_t t = time(NULL); - int length = 0; - struct sockaddr_in iserv_addr; - - __debugprintf("CONNECTIONS %s", ctime(&t)); - while (cp) { - if (cp->state == ESOCK_JOINED) { - __debugprintf(" - %s [%8p] (origin = %s)\n" - " (fd = %d, eof = %d, wq = %d, bp = %d), close = %d\n" - " (proxyfd = %d, eof = %d, wq = %d, bp = %d)\n", - connstr[cp->state], cp, originstr[cp->origin], - cp->fd, cp->eof, cp->wq.len, cp->bp, cp->close, - cp->proxy->fd, cp->proxy->eof, cp->proxy->wq.len, - cp->proxy->bp); - } else if (cp->state == ESOCK_ACTIVE_LISTENING) { - __debugprintf(" - %s [%8p] (fd = %d, acceptors = %d)\n", - connstr[cp->state], cp, cp->fd, cp->acceptors); - } else { - __debugprintf(" - %s [%8p] (fd = %d)\n", connstr[cp->state], cp, - cp->fd); - } - length = sizeof(iserv_addr); - if ((cp->state == ESOCK_ACTIVE_LISTENING) || - (cp->state == ESOCK_PASSIVE_LISTENING)) { - getsockname(cp->fd, (struct sockaddr *) &iserv_addr, &length); - __debugprintf(" (ip = %s, port = %d)\n", - inet_ntoa(iserv_addr.sin_addr), - ntohs(iserv_addr.sin_port)); - } - else { - getsockname(cp->fd, (struct sockaddr *) &iserv_addr, &length); - __debugprintf(" (local_ip = %s, local_port = %d)\n", - inet_ntoa(iserv_addr.sin_addr), - ntohs(iserv_addr.sin_port)); - length = sizeof(iserv_addr); - getpeername(cp->fd, (struct sockaddr *) &iserv_addr, &length); - __debugprintf(" (remote_ip = %s, remote_port = %d)\n", - inet_ntoa(iserv_addr.sin_addr), - ntohs(iserv_addr.sin_port)); - } - cp=cp->next; - } - - __debugprintf("PROXIES\n"); - while (pp) { - __debugprintf(" - fd = %d [%8p] (external_fd = %d, peer_port = %d," - " eof = %d)\n", pp->fd, pp, pp->conn->fd, pp->peer_port, - pp->eof); - - pp= pp->next; - } -} - -static Connection *get_connection(FD fd) -{ - Connection *cp = connections; - - while(cp) { - if(cp->fd == fd) - return cp; - cp = cp->next; - } - return NULL; -} - -/* - * Remove a connection from the list of connection, close the proxy - * socket and free all resources. The main socket (fd) is *not* - * closed here, because the closing of that socket has to be synchronized - * with the Erlang process controlling this port program. - */ -static void remove_connection(Connection *conn) -{ - Connection **prev = &connections; - Connection *cp = connections; - - while (cp) { - if(cp == conn) { - DEBUGF(("remove_connection: fd = %d\n", cp->fd)); - esock_ssl_free(cp); /* frees cp->opaque only */ - esock_free(cp->flags); - closelog(cp->logfp); /* XXX num_sock_fds */ - esock_free(cp->wq.buf); - if (cp->proxy) { - safe_close(cp->proxy->fd); - remove_proxy(cp->proxy); - } - *prev = cp->next; - esock_free(cp); - return; - } - prev = &cp->next; - cp = cp->next; - } -} - -static Proxy *get_proxy_by_peerport(int port) -{ - Proxy *p = proxies; - - while(p) { - if (p->peer_port == port) - return p; - p = p->next; - } - return NULL; -} - -static Proxy *new_proxy(FD fd) -{ - Proxy *p; - - if (!(p = esock_malloc(sizeof(Proxy)))) - return NULL; - - p->fd = fd; - p->peer_port = -1; - p->eof = 0; - p->bp = 0; - p->conn = NULL; - p->wq.size = 0; - p->wq.buf = NULL; - p->wq.len = 0; - p->wq.offset = 0; - p->next = proxies; - proxies = p; - return p; -} - -static void remove_proxy(Proxy *proxy) -{ - Proxy *p = proxies, **pp = &proxies; - - while(p) { - if (p == proxy) { - DEBUGF(("remove_proxyfd = %d\n", p->fd)); - esock_free(p->wq.buf); - *pp = p->next; - esock_free(p); - return; - } - pp = &p->next; - p = p->next; - } -} - -static int check_num_sock_fds(FD fd) -{ - num_sock_fds++; /* fd is valid */ -#ifdef USE_SELECT - if (num_sock_fds > FD_SETSIZE) { - num_sock_fds--; - sock_set_errno(ERRNO_MFILE); - safe_close(fd); - return -1; - } -#endif - return 0; -} - -static void safe_close(FD fd) -{ - int err; - - err = sock_errno(); - DEBUGF(("safe_close fd = %d\n", fd)); - if (sock_close(fd) < 0) { - DEBUGF(("safe_close failed\n")); - } else { - num_sock_fds--; - } - sock_set_errno(err); -} - -static void clean_up(void) -{ - Connection *cp, *cpnext; - Proxy *pp, *ppnext; - - cp = connections; - while (cp) { - safe_close(cp->fd); - cpnext = cp->next; - remove_connection(cp); - cp = cpnext; - } - - pp = proxies; - while (pp) { - safe_close(pp->fd); - ppnext = pp->next; - remove_proxy(pp); - pp = ppnext; - } -} - -static void ensure_write_queue(WriteQueue *wq, int size) -{ - if (wq->size < size) { - wq->buf = esock_realloc(wq->buf, size); - wq->size = size; - } -} - - - - - - - diff --git a/lib/ssl/c_src/esock.h b/lib/ssl/c_src/esock.h deleted file mode 100644 index 16c9faa530..0000000000 --- a/lib/ssl/c_src/esock.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 1999-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Implementation of Secure Socket Layer (SSL). - * - */ - -#ifndef ESOCK_H -#define ESOCK_H - -#ifdef __WIN32__ -#include "esock_winsock.h" -#endif -#include - -#ifdef __WIN32__ -#define INVALID_FD INVALID_SOCKET - -#define sock_read(fd, buf, len) recv((fd), (buf), (len), 0) -#define sock_write(fd, buf, len) send((fd), (buf), (len), 0) -#define sock_close(fd) closesocket(fd) -#define sock_errno() WSAGetLastError() -#define sock_set_errno(err) WSASetLastError(err) - -#define ERRNO_NONE 0 -#define ERRNO_BLOCK WSAEWOULDBLOCK -#define ERRNO_CONNREFUSED WSAECONNREFUSED -#define ERRNO_PROGRESS WSAEINPROGRESS -#define ERRNO_PROTONOSUPPORT WSAEPROTONOSUPPORT -#define ERRNO_INVAL WSAEINVAL -#define ERRNO_ADDRNOTAVAIL WSAEADDRNOTAVAIL -#define ERRNO_NOTSOCK WSAENOTSOCK -#define ERRNO_OPNOTSUPP WSAEOPNOTSUPP -#define ERRNO_MFILE WSAEMFILE -#define SET_BLOCKING(fd) do { \ - unsigned long zeroval = 0; \ - ioctlsocket((fd), FIONBIO, &zeroval); \ - } while (0) -#define SET_NONBLOCKING(fd) do { \ - unsigned long oneval = 1; \ - ioctlsocket((fd), FIONBIO, &oneval); \ - } while (0) -#else -#define INVALID_FD (-1) - -#define sock_read(fd, buf, len) read((fd), (buf), (len)) -#define sock_write(fd, buf, len) write((fd), (buf), (len)) -#define sock_close(fd) close(fd) -#define sock_errno() errno -#define sock_set_errno(err) do {errno = (err);} while(0) - -#define ERRNO_NONE 0 -#define ERRNO_BLOCK EAGAIN -#define ERRNO_CONNREFUSED ECONNREFUSED -#define ERRNO_PROGRESS EINPROGRESS -#define ERRNO_PROTONOSUPPORT EPROTONOSUPPORT -#define ERRNO_INVAL EINVAL -#define ERRNO_ADDRNOTAVAIL EADDRNOTAVAIL -#define ERRNO_NOTSOCK ENOTSOCK -#define ERRNO_OPNOTSUPP EOPNOTSUPP -#define ERRNO_MFILE EMFILE -#define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \ - fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK) -#define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \ - fcntl((fd), F_GETFL, 0) | O_NONBLOCK) -#endif - -#define GET_INT8(s) ((s)[0]) -#define GET_INT16(s) (((s)[0] << 8) | (s)[1]) -#define GET_INT32(s) (((s)[0] << 24) | ((s)[1] << 16) | \ - ((s)[2] << 8) | (s)[3]) - -#define PUT_INT8(x, s) do { (s)[0] = x; } while(0) -#define PUT_INT16(x, s) do { (s)[0] = ((x) >> 8) & 0xff; \ - (s)[1] = ((x) & 0xff); } while(0) -#define PUT_INT32(x, s) do { (s)[0] = ((x) >> 24) & 0xff; \ - (s)[1] = ((x) >> 16) & 0xff; \ - (s)[2] = ((x) >> 8) & 0xff; \ - (s)[3] = (x) & 0xff; } while(0) - -/* type for Connections */ -#define ESOCK_STATE_NONE 0 -#define ESOCK_ACTIVE_LISTENING 1 -#define ESOCK_PASSIVE_LISTENING 2 -#define ESOCK_CONNECTED 3 -#define ESOCK_WAIT_CONNECT 4 -#define ESOCK_SSL_CONNECT 5 -#define ESOCK_SSL_ACCEPT 6 -#define ESOCK_TRANSPORT_ACCEPT 7 -#define ESOCK_JOINED 8 -#define ESOCK_SSL_SHUTDOWN 9 -#define ESOCK_DEFUNCT 10 - -#ifdef __WIN32__ - typedef SOCKET FD; -#else - typedef int FD; -#endif - -/* For the shutdown(fd, how) call */ -#ifdef __WIN32__ -#define SHUTDOWN_READ SD_RECEIVE -#define SHUTDOWN_WRITE SD_SEND -#define SHUTDOWN_ALL SD_BOTH -#else -#define SHUTDOWN_READ 0 -#define SHUTDOWN_WRITE 1 -#define SHUTDOWN_ALL 2 -#endif - -#define ORIG_LISTEN 0 -#define ORIG_ACCEPT 1 -#define ORIG_CONNECT 2 - -typedef struct { - int size; /* Total size of buf */ - unsigned char *buf; - int len; /* Current number of bytes in buf */ - int offset; /* Bytes already written */ -} WriteQueue; - -typedef struct _proxy Proxy; - -typedef struct Connection { - FD fd; - FD listen_fd; /* Needed for async listen error */ - unsigned char state; - int acceptors; /* Count acceptors for listen socket */ - Proxy *proxy; - void *opaque; /* Any suitable ssl structure */ - int ssl_want; /* read/write flags */ - int eof; /* end of file (read) */ - int bp; /* broken pipe (write) */ - int clean; /* Clean SSL shutdown initiated */ - int close; /* Close if set */ - int origin; /* listen, accept or connect */ - int encrypted; /* 1 = SSL encrypted, 0 = normal, unencrypted tcp */ - char *flags; /* ssl parameters */ - FILE *logfp; /* connection log file (not used) */ - WriteQueue wq; - struct Connection* next; - const char* errstr; /* only used to report errors from ssl_accept_init in SSL_ACCEPT */ -} Connection; - -struct _proxy { - FD fd; - int peer_port; - int eof; /* end of file (read) */ - int bp; /* broken pipe (write) */ - Connection *conn; - WriteQueue wq; - Proxy *next; -}; - -/* Commands, replies, and error responses */ - -#define ESOCK_CONNECT_CMD 1 -#define ESOCK_CONNECT_WAIT_REP 2 -#define ESOCK_CONNECT_REP 3 -#define ESOCK_CONNECT_ERR 4 - -#define ESOCK_TERMINATE_CMD 5 -#define ESOCK_CLOSE_CMD 6 - -#define ESOCK_LISTEN_CMD 7 -#define ESOCK_LISTEN_REP 8 -#define ESOCK_LISTEN_ERR 9 - -#define ESOCK_TRANSPORT_ACCEPT_CMD 10 -#define ESOCK_NOACCEPT_CMD 11 -#define ESOCK_TRANSPORT_ACCEPT_REP 12 -#define ESOCK_TRANSPORT_ACCEPT_ERR 13 - -#define ESOCK_FROMNET_CLOSE_REP 14 - -#define ESOCK_CONNECT_SYNC_ERR 15 -#define ESOCK_LISTEN_SYNC_ERR 16 - -#define ESOCK_PROXY_PORT_REP 23 -#define ESOCK_PROXY_JOIN_CMD 24 -#define ESOCK_PROXY_JOIN_REP 25 -#define ESOCK_PROXY_JOIN_ERR 26 - -#define ESOCK_SET_SOCKOPT_CMD 27 -#define ESOCK_IOCTL_OK 28 -#define ESOCK_IOCTL_ERR 29 - -#define ESOCK_GETPEERNAME_CMD 30 -#define ESOCK_GETPEERNAME_REP 31 -#define ESOCK_GETPEERNAME_ERR 32 - -#define ESOCK_GETSOCKNAME_CMD 33 -#define ESOCK_GETSOCKNAME_REP 34 -#define ESOCK_GETSOCKNAME_ERR 35 - -#define ESOCK_GETPEERCERT_CMD 36 -#define ESOCK_GETPEERCERT_REP 37 -#define ESOCK_GETPEERCERT_ERR 38 - -#define ESOCK_GETVERSION_CMD 39 -#define ESOCK_GETVERSION_REP 40 - -#define ESOCK_SET_SEED_CMD 41 - -#define ESOCK_GETCONNINFO_CMD 42 -#define ESOCK_GETCONNINFO_REP 43 -#define ESOCK_GETCONNINFO_ERR 44 - -#define ESOCK_SSL_ACCEPT_CMD 45 -#define ESOCK_SSL_ACCEPT_REP 46 -#define ESOCK_SSL_ACCEPT_ERR 47 - -#define ESOCK_DUMP_STATE_CMD 48 -#define ESOCK_SET_DEBUG_CMD 49 -#define ESOCK_SET_DEBUGMSG_CMD 50 - - -/* Option codes for ESOCK_SET_SOCKOPT_CMD */ -#define ESOCK_SET_TCP_NODELAY 1 - -/* SSL want to read or write */ -#define ESOCK_SSL_WANT_READ 1 -#define ESOCK_SSL_WANT_WRITE 2 - -/* Protocol version according to ssl_server */ -#define ESOCK_SSLv2 1 -#define ESOCK_SSLv3 2 -#define ESOCK_TLSv1 4 - - -#endif - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/ssl/c_src/esock_openssl.c b/lib/ssl/c_src/esock_openssl.c deleted file mode 100644 index 0bc42958f0..0000000000 --- a/lib/ssl/c_src/esock_openssl.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* - * 1999-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Adaptions for the OpenSSL package. - * - * This file implements the functions defined in esock_ssl.h for - * the OpenSSL package. - * - * The following holds true for non-blockling I/O: - * - * Function Return values - * -------- ------------- - * SSL_accept() success: 1, failure: =<0 - * SSL_connect() success: 1, failure: =<0 - * SSL_read() success: >0, eof: 0, failure: <0 - * SSL_write() success: > 0, failure: =<0 - * SSL_shutdown() success: 1, not finished: 0 - * - * If the return value of any of the above functions is `ret' and the - * ssl connection is `ssl', the call - * - * ssl_error = SSL_get_error(ssl, ret); - * - * returns one of the following eight values: - * - * SSL_ERROR_NONE ret > 0 - * SSL_ERROR_ZERO_RETURN ret = 0 - * SSL_ERROR_WANT_READ ret < 0 and ssl wants to read - * SSL_ERROR_WANT_WRITE ret < 0 and ssl wants to write - * SSL_ERROR_SYSCALL ret < 0 or ret = 0 - * SSL_ERROR_SSL if there was an ssl internal error - * SSL_ERROR_WANT_X509_LOOKUP ret < 0 and ssl wants x509 lookup - * SSL_ERROR_WANT_CONNECT ret < 0 and ssl wants connect - * - * It is the case that SSL_read() sometimes returns -1, even when the - * underlying file descriptor is ready for reading. - * - * Also, sometimes we may have SSL_ERROR_SSL in SSL_accept() and SSL_connect() - * when a retry should be done. - * - */ - -#include -#include -#include -#include -#ifndef __WIN32__ -# include -# include -#endif - -#include "esock.h" -#include "esock_ssl.h" -#include "debuglog.h" -#include "esock_utils.h" -#include "esock_posix_str.h" - -#include -#include -#include -#include - -int ephemeral_rsa = 0; -int ephemeral_dh = 0; /* XXX Not used yet */ -int protocol_version = 0; - -char *esock_ssl_errstr = ""; - -#define FLAGSBUFSIZE 512 -#define X509BUFSIZE 256 -#define DEFAULT_VERIFY_DEPTH 1 - -#define SET_WANT(cp, ssl_error) \ - switch((ssl_error)) { \ - case SSL_ERROR_WANT_READ: \ - (cp)->ssl_want = ESOCK_SSL_WANT_READ; \ - break; \ - case SSL_ERROR_WANT_WRITE: \ - (cp)->ssl_want = ESOCK_SSL_WANT_WRITE; \ - break; \ - default: \ - (cp)->ssl_want = 0; \ - break; \ - } - -#define RESET_ERRSTR() \ - esock_ssl_errstr = ""; - -#define MAYBE_SET_ERRSTR(s) \ - if (!esock_ssl_errstr[0]) \ - esock_ssl_errstr = (s); - -typedef struct { - int code; - char *text; -} err_entry; - -typedef struct { - SSL_CTX *ctx; - char *passwd; - int verify_depth; -} callback_data; - -static char *ssl_error_str(int error); -static void end_ssl_call(int ret, Connection *cp, int ssl_error); -static void check_shutdown(Connection *cp); -static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx); -static int verify_callback(int ok, X509_STORE_CTX *ctx); -static int passwd_callback(char *buf, int num, int rwflag, void *userdata); -static void info_callback(const SSL *ssl, int where, int ret); -static void callback_data_free(void *parent, void *ptr, - CRYPTO_EX_DATA *ad, - int idx, long arg1, void *argp); -static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylen); -static void restrict_protocols(SSL_CTX *ctx); - -static err_entry errs[] = { - {SSL_ERROR_NONE, "SSL_ERROR_NONE"}, - {SSL_ERROR_ZERO_RETURN, "SSL_ERROR_ZERO_RETURN"}, - {SSL_ERROR_WANT_READ, "SSL_ERROR_WANT_READ"}, - {SSL_ERROR_WANT_WRITE, "SSL_ERROR_WANT_WRITE"}, - {SSL_ERROR_SYSCALL, "SSL_ERROR_SYSCALL"}, - {SSL_ERROR_SSL, "SSL_ERROR_SSL"}, - {SSL_ERROR_WANT_X509_LOOKUP, "SSL_ERROR_WANT_X509_LOOKUP"}, - {SSL_ERROR_WANT_CONNECT, "SSL_ERROR_WANT_CONNECT"} -}; - -static SSL_METHOD *method; /* for listen and connect init */ -static char x509_buf[X509BUFSIZE]; /* for verify_callback */ -static int callback_data_index = -1; /* for ctx ex_data */ -static unsigned char randvec[1024]; /* XXX */ - -#if defined(__WIN32__) || OPEN_MAX > 256 -# define FOPEN_WORKAROUND(var, expr) var = (expr) -# define VOID_FOPEN_WORKAROUND(expr) expr -#else -/* - * This is an ugly workaround. On Solaris, fopen() will return NULL if - * it gets a file descriptor > 255. To avoid that, we'll make sure that - * there is always one low-numbered file descriptor available when - * fopen() is called. - */ -static int reserved_fd; /* Reserve a low-numbered file descriptor */ -# define USE_FOPEN_WORKAROUND 1 - -# define FOPEN_WORKAROUND(var, expr) \ -do { \ - close(reserved_fd); \ - var = (expr); \ - reserved_fd = open("/dev/null", O_RDONLY); \ -} while (0) - -# define VOID_FOPEN_WORKAROUND(expr) \ -do { \ - close(reserved_fd); \ - expr; \ - reserved_fd = open("/dev/null", O_RDONLY); \ -} while (0) -#endif - -esock_version *esock_ssl_version(void) -{ - static esock_version vsn; - - vsn.compile_version = OPENSSL_VERSION_TEXT; - vsn.lib_version = SSLeay_version(SSLEAY_VERSION); - return &vsn; -} - -char *esock_ssl_ciphers(void) -{ - SSL_CTX *ctx; - SSL *ssl; - char *ciphers; - const char *cp; - int i = 0, used = 0, len, incr = 1024; - - if (!(ctx = SSL_CTX_new(method))) - return NULL; - restrict_protocols(ctx); - if (!(ssl = SSL_new(ctx))) { - SSL_CTX_free(ctx); - return NULL; - } - - ciphers = esock_malloc(incr); - len = incr; - *ciphers = '\0'; - - while (1) { - if (!(cp = SSL_get_cipher_list(ssl, i))) - break; - if (i > 0) { - if (used == len) { - len += incr; - ciphers = esock_realloc(ciphers, len); - } - strcat(ciphers, ":"); - used++; - } - if (strlen(cp) + used >= len) { - len += incr; - ciphers = esock_realloc(ciphers, len); - } - strcat(ciphers, cp); - used += strlen(cp); - i++; - } - SSL_free(ssl); - SSL_CTX_free(ctx); - return ciphers; -} - -void esock_ssl_seed(void *buf, int len) -{ - RAND_seed(buf, len); - - /* XXX Maybe we should call RAND_status() and check if we have got - * enough randomness. - */ -} - -int esock_ssl_init(void) -{ - method = SSLv23_method(); /* SSLv2, SSLv3 and TLSv1, may be restricted - in listen and connect */ - SSL_load_error_strings(); - SSL_library_init(); - esock_ssl_seed(randvec, sizeof(randvec)); - callback_data_index = SSL_CTX_get_ex_new_index(0, "callback_data", - NULL, NULL, - callback_data_free); -#ifdef USE_FOPEN_WORKAROUND - reserved_fd = open("/dev/null", O_RDONLY); - DEBUGF(("init: reserved_fd=%d\r\n", reserved_fd)); -#endif - return 0; -} - - -void esock_ssl_finish(void) -{ - /* Nothing */ -} - - -void esock_ssl_free(Connection *cp) -{ - SSL *ssl = cp->opaque; - SSL_CTX *ctx; - - if (ssl) { - ctx = SSL_get_SSL_CTX(ssl); - SSL_free(ssl); - if (cp->origin != ORIG_ACCEPT) - SSL_CTX_free(ctx); - cp->opaque = NULL; - } -} - - -/* - * Print SSL specific errors. - */ -void esock_ssl_print_errors_fp(FILE *fp) -{ - ERR_print_errors_fp(fp); -} - - -int esock_ssl_accept_init(Connection *cp, void *listenssl) -{ - SSL_CTX *listenctx; - SSL *ssl; - - RESET_ERRSTR(); - MAYBE_SET_ERRSTR("esslacceptinit"); - - if(!listenssl) { - DEBUGF(("esock_ssl_accept_init: listenssl null\n")); - return -1; - } - if (!(listenctx = SSL_get_SSL_CTX(listenssl))) { - DEBUGF(("esock_ssl_accept_init: SSL_get_SSL_CTX\n")); - return -1; - } - if (!(ssl = cp->opaque = SSL_new(listenctx))) { - DEBUGF(("esock_ssl_accept_init: SSL_new(listenctx)\n")); - return -1; - } - SSL_set_fd(ssl, cp->fd); - return 0; - -} - - -int esock_ssl_connect_init(Connection *cp) -{ - SSL_CTX *ctx; - SSL *ssl; - - RESET_ERRSTR(); - MAYBE_SET_ERRSTR("esslconnectinit"); - - if (!(ctx = SSL_CTX_new(method))) - return -1; - if (set_ssl_parameters(cp, ctx) < 0) { - SSL_CTX_free(ctx); - return -1; - } - restrict_protocols(ctx); - if (!(ssl = cp->opaque = SSL_new(ctx))) { - SSL_CTX_free(ctx); - return -1; - } - SSL_set_fd(ssl, cp->fd); - return 0; -} - - -int esock_ssl_listen_init(Connection *cp) -{ - SSL_CTX *ctx; - SSL *ssl; - - RESET_ERRSTR(); - MAYBE_SET_ERRSTR("essllisteninit"); - - if (!(ctx = SSL_CTX_new(method))) - return -1; - if (set_ssl_parameters(cp, ctx) < 0) { - SSL_CTX_free(ctx); - return -1; - } - restrict_protocols(ctx); - - /* The allocation of ctx is for setting ssl parameters, so that - * accepts can inherit them. We allocate ssl to be able to - * refer to it via cp->opaque, but will not be used otherwise. - */ - if (!(ssl = cp->opaque = SSL_new(ctx))) { - SSL_CTX_free(ctx); - return -1; - } - /* Set callback for temporary ephemeral RSA key generation. - * Note: for servers only. */ - SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_callback); - return 0; -} - -/* - * esock_ssl_accept(Connection *cp) - * - */ -int esock_ssl_accept(Connection *cp) -{ - int ret, ssl_error; - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - - DEBUGF(("esock_ssl_accept: calling SSL_accept fd = %d\n" - " state before: %s\n", cp->fd, SSL_state_string(ssl))); - ret = SSL_accept(ssl); - DEBUGF((" sock_errno %d errno %d \n", sock_errno(), errno)); - ssl_error = SSL_get_error(ssl, ret); - DEBUGF((" SSL_accept = %d\n" - " ssl_error: %s\n" - " state after: %s\n", - ret, ssl_error_str(ssl_error), SSL_state_string(ssl))); - DEBUGF((" ret %d os error %s\n", ret, strerror(errno))); - if (ret > 0) - return ret; - else if (ret == 0) { - const char* f; int l; unsigned int e; - while ((e = ERR_get_error_line(&f, &l))) { - DEBUGF((" error %s:%d %s\n", f, l, ssl_error_str(e))); - } - /* permanent accept error */ - sock_set_errno(ERRNO_NONE); - MAYBE_SET_ERRSTR("esslaccept"); - return -1; - } - end_ssl_call(ret, cp, ssl_error); - return ret; -} - -/* - * esock_ssl_connect(Connection *cp) - * - */ -int esock_ssl_connect(Connection *cp) -{ - int ret, ssl_error; - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - - DEBUGF(("esock_ssl_connect: calling SSL_connect fd = %d\n" - " state before: %s\n", cp->fd, SSL_state_string(ssl))); - ret = SSL_connect(ssl); - ssl_error = SSL_get_error(ssl, ret); - DEBUGF((" SSL_connect() = %d\n" - " ssl_error: %s\n" - " state after: %s\n", - ret, ssl_error_str(ssl_error), SSL_state_string(ssl))); - if (ret > 0) - return ret; - else if (ret == 0) { - /* permanent connect error */ - sock_set_errno(ERRNO_NONE); - MAYBE_SET_ERRSTR("esslconnect"); - return -1; - } - end_ssl_call(ret, cp, ssl_error); - return ret; -} - - -int esock_ssl_session_reused(Connection *cp) -{ - SSL *ssl = cp->opaque; - - return SSL_session_reused(ssl); -} - - -/* esock_ssl_read(Connection *cp, char *buf, int len) - * - * Read at most `len' chars into `buf'. Returns number of chars - * read ( > 0), or 0 at EOF, or -1 on error. Sets cp->eof, cp->bp if - * appropriate. - */ - -int esock_ssl_read(Connection *cp, char *buf, int len) -{ - int ret, ssl_error; - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - DEBUGF(("esock_ssl_read: calling SSL_read fd = %d\n" - " state before: %s\n", cp->fd, SSL_state_string(ssl))); - - ret = SSL_read(ssl, buf, len); - ssl_error = SSL_get_error(ssl, ret); - - DEBUGF((" SSL_read = %d\n" - " ssl_error: %s\n" - " state after: %s\n", - ret, ssl_error_str(ssl_error), SSL_state_string(ssl))); - - if (ssl_error == SSL_ERROR_NONE) { - DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf)); - DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf)); - } - if (ret > 0) - return ret; - if (ret == 0) { - check_shutdown(cp); - return ret; - } - end_ssl_call(ret, cp, ssl_error); - return ret; -} - -/* - * esock_ssl_write(Connection *cp, char *buf, int len) - * - * Writes at most `len' chars from `buf'. Returns number of chars - * written, or -1 on error. - */ -int esock_ssl_write(Connection *cp, char *buf, int len) -{ - int ret, ssl_error; - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - DEBUGF(("esock_ssl_write: calling SSL_write fd = %d\n" - " state before: %s\n", cp->fd, SSL_state_string(ssl))); - ret = SSL_write(ssl, buf, len); - ssl_error = SSL_get_error(ssl, ret); - DEBUGF((" SSL_write = %d\n" - " ssl_error: %s\n" - " state after: %s\n", - ret, ssl_error_str(ssl_error), SSL_state_string(ssl))); - if (ssl_error == SSL_ERROR_NONE) { - DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf)); - DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf)); - } - if (ret > 0) - return ret; - if (ret == 0) { - check_shutdown(cp); - return ret; - } - end_ssl_call(ret, cp, ssl_error); - return ret; -} - - -int esock_ssl_shutdown(Connection *cp) -{ - int ret, ssl_error; - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - DEBUGF(("esock_ssl_shutdown: calling SSL_shutdown fd = %d\n" - " state before: %s\n", cp->fd, SSL_state_string(ssl))); - ret = SSL_shutdown(ssl); - ssl_error = SSL_get_error(ssl, ret); - DEBUGF((" SSL_shutdown = %d\n" - " ssl_error: %s\n" - " state after: %s\n", - ret, ssl_error_str(ssl_error), SSL_state_string(ssl))); - if (ret >= 0) { - check_shutdown(cp); - return ret; - } - end_ssl_call(ret, cp, ssl_error); - return ret; -} - - -/* Returns total number of bytes in DER encoded cert pointed to by - * *buf, which is allocated by this function, unless return < 0. - * XXX X509_free ?? - */ -int esock_ssl_getpeercert(Connection *cp, unsigned char **buf) -{ - int len; - SSL *ssl = cp->opaque; - X509 *x509; - unsigned char *tmp; - - RESET_ERRSTR(); - if((x509 = SSL_get_peer_certificate(ssl)) == NULL) { - MAYBE_SET_ERRSTR("enopeercert"); /* XXX doc */ - return -1; - } - - if ((len = i2d_X509(x509, NULL)) <= 0) { - MAYBE_SET_ERRSTR("epeercert"); - return -1; - } - - tmp = *buf = esock_malloc(len); - - /* We must use a temporary value here, since i2d_X509(X509 *x, - * unsigned char **out) increments *out. - */ - if (i2d_X509(x509, &tmp) < 0) { - esock_free(tmp); - MAYBE_SET_ERRSTR("epeercert"); - return -1; - } - return len; -} - -/* Returns total number of bytes in chain of certs. Each cert begins - * with a 4-bytes length. The last cert is ended with 4-bytes of - * zeros. The result is returned in *buf, which is allocated unless - * the return value is < 0. - * XXX X509_free ? sk_X509_free ? - * XXX X509_free is reference counting. - */ -int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf) -{ - SSL *ssl = cp->opaque; - STACK_OF(X509) *x509_stack; - X509 *x509; - int num, i, totlen, pos, *der_len; - unsigned char *vbuf; - - RESET_ERRSTR(); - if((x509_stack = SSL_get_peer_cert_chain(ssl)) == NULL) { - MAYBE_SET_ERRSTR("enopeercertchain"); /* XXX doc */ - return -1; - } - - num = sk_X509_num(x509_stack); - der_len = esock_malloc(num * sizeof(int)); - totlen = 0; - - for (i = 0; i < num; i++) { - x509 = sk_X509_value(x509_stack, i); - totlen += 4; - if ((der_len[i] = i2d_X509(x509, NULL)) < 0) { - MAYBE_SET_ERRSTR("epeercertchain"); - esock_free(der_len); - return -1; - } - totlen += der_len[i]; - } - totlen += 4; - - vbuf = *buf = esock_malloc(totlen); - pos = 0; - - for (i = 0; i < num; i++) { - x509 = sk_X509_value(x509_stack, i); - PUT_INT32(der_len[i], vbuf); - vbuf += 4; - /* Note: i2d_X509 increments vbuf */ - if (i2d_X509(x509, &vbuf) < 0) { - MAYBE_SET_ERRSTR("epeercertchain"); - esock_free(*buf); - esock_free(der_len); - return -1; - } - } - esock_free(der_len); - return totlen; -} - - -int esock_ssl_getprotocol_version(Connection *cp, char **buf) -{ - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - if (!ssl) { - MAYBE_SET_ERRSTR("enoent"); - return -1; - } - *buf = (char *) SSL_get_version(ssl); - - return 0; -} - - -int esock_ssl_getcipher(Connection *cp, char **buf) -{ - SSL *ssl = cp->opaque; - - RESET_ERRSTR(); - if (!ssl) { - MAYBE_SET_ERRSTR("enoent"); - return -1; - } - *buf = (char *) SSL_get_cipher(ssl); - - return 0; -} - -/* Local functions */ - -static char *ssl_error_str(int ssl_error) -{ - int i; - static char buf[128]; - - for (i = 0; i < sizeof(errs)/sizeof(err_entry); i ++) { - if (ssl_error == errs[i].code) - return errs[i].text; - } - sprintf(buf, "esock_openssl: SSL_error unknown: %d", ssl_error); - return buf; -} - -void end_ssl_call(int ret, Connection *cp, int ssl_error) -{ - SET_WANT(cp, ssl_error); - switch (ssl_error) { - case SSL_ERROR_SYSCALL: - /* Typically sock_errno() is equal to ERRNO_BLOCK */ - MAYBE_SET_ERRSTR(esock_posix_str(sock_errno())); - break; - case SSL_ERROR_SSL: - sock_set_errno(ERRNO_NONE); - MAYBE_SET_ERRSTR("esslerrssl"); - break; - case SSL_ERROR_WANT_X509_LOOKUP: - SSLDEBUGF(); - sock_set_errno(ERRNO_NONE); - MAYBE_SET_ERRSTR("ex509lookup"); - break; - case SSL_ERROR_WANT_CONNECT: - SSLDEBUGF(); - sock_set_errno(ERRNO_NONE); - MAYBE_SET_ERRSTR("ewantconnect"); - break; - default: - break; - } -} - -void check_shutdown(Connection *cp) -{ - int sd_mode; - SSL *ssl = cp->opaque; - - sd_mode = SSL_get_shutdown(ssl); - if (sd_mode & SSL_RECEIVED_SHUTDOWN) - cp->eof = 1; - if (sd_mode & SSL_SENT_SHUTDOWN) { - DEBUGF(("check_shutdown SSL_SENT_SHUTDOWN\n")); - cp->bp = 1; - } -} - -/* - * set_ssl_parameters - * - * Set ssl parameters from connection structure. Only called for - * listen and connect. - * - * Note: The -cacertdir option is not documented. - */ -static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx) -{ - char *cacertfile = NULL, *cacertdir = NULL, *certfile = NULL; - char *keyfile = NULL, *ciphers = NULL, *password = NULL; - int verify = 0, verify_depth = DEFAULT_VERIFY_DEPTH, verify_mode; - int i, argc; - char **argv; - callback_data *cb_data; - - RESET_ERRSTR(); - - argc = esock_build_argv(cp->flags, &argv); - - DEBUGF(("Argv:\n")); - for (i = 0; i < argc; i++) { - DEBUGF(("%d: %s\n", i, argv[i])); - } - - for (i = 0; i < argc; i++) { - if (strcmp(argv[i], "-verify") == 0) { - verify = atoi(argv[++i]); - } else if (strcmp(argv[i], "-depth") == 0) { - verify_depth = atoi(argv[++i]); - } else if (strcmp(argv[i], "-log") == 0) { - /* XXX ignored: logging per connection not supported */ - i++; - } else if (strcmp(argv[i], "-certfile") == 0) { - certfile = argv[++i]; - } else if (strcmp(argv[i], "-keyfile") == 0) { - keyfile = argv[++i]; - } else if (strcmp(argv[i], "-password") == 0) { - password = argv[++i]; - } else if (strcmp(argv[i], "-cacertfile") == 0) { - cacertfile = argv[++i]; - } else if (strcmp(argv[i], "-cacertdir") == 0) { - cacertdir = argv[++i]; - } else if (strcmp(argv[i], "-d") == 0) { - /* XXX ignored: debug per connection not supported */ - i++; - } else if (strcmp(argv[i], "-ciphers") == 0) { - ciphers = argv[++i]; - } else { - /* XXX Error: now ignored */ - } - } - DEBUGF(("set_ssl_parameters: all arguments read\n")); - - if (cp->origin == ORIG_LISTEN && !certfile) { - DEBUGF(("ERROR: Server must have certificate\n")); - MAYBE_SET_ERRSTR("enoservercert"); - goto err_end; - } - - /* Define callback data */ - /* XXX Check for NULL */ - cb_data = esock_malloc(sizeof(callback_data)); - cb_data->ctx = ctx; - if (password) { - cb_data->passwd = esock_malloc(strlen(password) + 1); - strcpy(cb_data->passwd, password); - } else - cb_data->passwd = NULL; - cb_data->verify_depth = verify_depth; - SSL_CTX_set_ex_data(ctx, callback_data_index, cb_data); - - /* password callback */ - SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); - SSL_CTX_set_default_passwd_cb_userdata(ctx, cb_data); - - /* Set location for "trusted" certificates */ - if (cacertfile || cacertdir) { - int res; - DEBUGF(("set_ssl_parameters: SSL_CTX_load_verify_locations\n")); - FOPEN_WORKAROUND(res, SSL_CTX_load_verify_locations(ctx, cacertfile, - cacertdir)); - if (!res) { - DEBUGF(("ERROR: Cannot load verify locations\n")); - MAYBE_SET_ERRSTR("ecacertfile"); - goto err_end; - } - } else { - int res; - DEBUGF(("set_ssl_parameters: SSL_CTX_set_default_verify_paths\n")); - FOPEN_WORKAROUND(res, SSL_CTX_set_default_verify_paths(ctx)); - if (!res) { - DEBUGF(("ERROR: Cannot set default verify paths\n")); - MAYBE_SET_ERRSTR("ecacertfile"); - goto err_end; - } - } - - /* For a server the following sets the list of CA distinguished - * names that it sends to its client when it requests the - * certificate from the client. - * XXX The names of certs in cacertdir ignored. - */ - if (cp->origin == ORIG_LISTEN && cacertfile) { - DEBUGF(("set_ssl_parameters: SSL_CTX_set_client_CA_list\n")); - VOID_FOPEN_WORKAROUND(SSL_CTX_set_client_CA_list(ctx, - SSL_load_client_CA_file(cacertfile))); - if (!SSL_CTX_get_client_CA_list(ctx)) { - DEBUGF(("ERROR: Cannot set client CA list\n")); - MAYBE_SET_ERRSTR("ecacertfile"); - goto err_end; - } - } - - /* Use certificate file if key file has not been set. */ - if (!keyfile) - keyfile = certfile; - - if (certfile) { - int res; - DEBUGF(("set_ssl_parameters: SSL_CTX_use_certificate_file\n")); - FOPEN_WORKAROUND(res, SSL_CTX_use_certificate_file(ctx, certfile, - SSL_FILETYPE_PEM)); - if (res <= 0) { - DEBUGF(("ERROR: Cannot set certificate file\n")); - MAYBE_SET_ERRSTR("ecertfile"); - goto err_end; - } - } - if (keyfile) { - int res; - DEBUGF(("set_ssl_parameters: SSL_CTX_use_PrivateKey_file\n")); - FOPEN_WORKAROUND(res, SSL_CTX_use_PrivateKey_file(ctx, keyfile, - SSL_FILETYPE_PEM)); - if (res <= 0) { - DEBUGF(("ERROR: Cannot set private key file\n")); - MAYBE_SET_ERRSTR("ekeyfile"); - goto err_end; - } - } - if(certfile && keyfile) { - DEBUGF(("set_ssl_parameters: SSL_CTX_check_private_key\n")); - if (!SSL_CTX_check_private_key(ctx)) { - DEBUGF(("ERROR: Private key does not match the certificate\n")); - MAYBE_SET_ERRSTR("ekeymismatch"); - goto err_end; - } - } - - /* Ciphers */ - if (ciphers) { - DEBUGF(("set_ssl_parameters: SSL_CTX_set_cipher_list\n")); - if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { - DEBUGF(("ERROR: Cannot set cipher list\n")); - MAYBE_SET_ERRSTR("ecipher"); - goto err_end; - } - } - - /* Verify depth */ - DEBUGF(("set_ssl_parameters: SSL_CTX_set_verify_depth (depth = %d)\n", - verify_depth)); - SSL_CTX_set_verify_depth(ctx, verify_depth); - - /* Verify mode and callback */ - /* XXX Why precisely these modes? */ - switch (verify) { - case 0: - verify_mode = SSL_VERIFY_NONE; - break; - case 1: - verify_mode = SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; - break; - case 2: - verify_mode = SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE| - SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - break; - default: - verify_mode = SSL_VERIFY_NONE; - } - DEBUGF(("set_ssl_parameters: SSL_CTX_set_verify (verify = %d)\n", - verify)); - SSL_CTX_set_verify(ctx, verify_mode, verify_callback); - - /* Session id context. Should be an option really. */ - if (cp->origin == ORIG_LISTEN) { - unsigned char *sid = "Erlang/OTP/ssl"; - SSL_CTX_set_session_id_context(ctx, sid, strlen(sid)); - } - - /* info callback */ - if (debug) - SSL_CTX_set_info_callback(ctx, info_callback); - - DEBUGF(("set_ssl_parameters: done\n")); - /* Free arg list */ - for (i = 0; argv[i]; i++) - esock_free(argv[i]); - esock_free(argv); - return 0; - - err_end: - DEBUGF(("set_ssl_parameters: error\n")); - /* Free arg list */ - for (i = 0; argv[i]; i++) - esock_free(argv[i]); - esock_free(argv); - return -1; -} - -/* Call back functions */ - -static int verify_callback(int ok, X509_STORE_CTX *x509_ctx) -{ - X509 *cert; - int cert_err, depth; - SSL *ssl; - SSL_CTX *ctx; - callback_data *cb_data; - - cert = X509_STORE_CTX_get_current_cert(x509_ctx); - cert_err = X509_STORE_CTX_get_error(x509_ctx); - depth = X509_STORE_CTX_get_error_depth(x509_ctx); - - ssl = X509_STORE_CTX_get_ex_data(x509_ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - ctx = SSL_get_SSL_CTX(ssl); - cb_data = SSL_CTX_get_ex_data(ctx, callback_data_index); - - X509_NAME_oneline(X509_get_subject_name(cert), x509_buf, sizeof(x509_buf)); - DEBUGF((" +vfy: depth = %d\n", depth)); - DEBUGF((" subject = %s\n", x509_buf)); - X509_NAME_oneline(X509_get_issuer_name(cert), x509_buf, sizeof(x509_buf)); - DEBUGF((" issuer = %s\n", x509_buf)); - - if (!ok) { - DEBUGF((" +vfy: error = %d [%s]\n", cert_err, - X509_verify_cert_error_string(cert_err))); - if (depth >= cb_data->verify_depth) - ok = 1; - } - - switch (cert_err) { - case X509_V_OK: - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - ok = 1; - break; - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - MAYBE_SET_ERRSTR("enoissuercert"); - break; - case X509_V_ERR_CERT_HAS_EXPIRED: - MAYBE_SET_ERRSTR("epeercertexpired"); - break; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - MAYBE_SET_ERRSTR("epeercertinvalid"); - break; - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - MAYBE_SET_ERRSTR("eselfsignedcert"); - break; - case X509_V_ERR_CERT_CHAIN_TOO_LONG: - MAYBE_SET_ERRSTR("echaintoolong"); - break; - default: - MAYBE_SET_ERRSTR("epeercert"); - break; - } - DEBUGF((" +vfy: return = %d\n",ok)); - return ok; -} - -static int passwd_callback(char *buf, int num, int rwflag, void *userdata) -{ - callback_data *cb_data = userdata; - int len; - - if (cb_data && cb_data->passwd) { - DEBUGF((" +passwd: %s\n", cb_data->passwd)); - strncpy(buf, cb_data->passwd, num); - len = strlen(cb_data->passwd); - return len; - } - DEBUGF((" +passwd: ERROR: No password set.\n")); - return 0; -} - -static void info_callback(const SSL *ssl, int where, int ret) -{ - char *str; - - if (where & SSL_CB_LOOP) { - DEBUGF((" info: %s\n",SSL_state_string_long(ssl))); - } else if (where & SSL_CB_ALERT) { - str = (where & SSL_CB_READ) ? "read" : "write"; - DEBUGF((" info: SSL3 alert %s:%s:%s\n", str, - SSL_alert_type_string_long(ret), - SSL_alert_desc_string_long(ret))); - } else if (where & SSL_CB_EXIT) { - if (ret == 0) { - DEBUGF((" info: failed in %s\n", SSL_state_string_long(ssl))); - } else if (ret < 0) { - DEBUGF((" info: error in %s\n", SSL_state_string_long(ssl))); - } - } -} - -/* This function is called whenever an SSL_CTX *ctx structure is - * freed. -*/ -static void callback_data_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, - int idx, long arg1, void *argp) -{ - callback_data *cb_data = ptr; - - if (cb_data) { - if (cb_data->passwd) - esock_free(cb_data->passwd); - esock_free(cb_data); - } -} - -static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylen) -{ - static RSA *rsa512 = NULL; - static RSA *rsa1024 = NULL; - - switch (keylen) { - case 512: - if (!rsa512) - rsa512 = RSA_generate_key(keylen, RSA_F4, NULL, NULL); - return rsa512; - break; - case 1024: - if (!rsa1024) - rsa1024 = RSA_generate_key(keylen, RSA_F4, NULL, NULL); - return rsa1024; - break; - default: - if (rsa1024) - return rsa1024; - if (rsa512) - return rsa512; - rsa512 = RSA_generate_key(keylen, RSA_F4, NULL, NULL); - return rsa512; - } -} - -/* Restrict protocols (SSLv2, SSLv3, TLSv1) */ -static void restrict_protocols(SSL_CTX *ctx) -{ - long options = 0; - - if (protocol_version) { - if ((protocol_version & ESOCK_SSLv2) == 0) - options |= SSL_OP_NO_SSLv2; - if ((protocol_version & ESOCK_SSLv3) == 0) - options |= SSL_OP_NO_SSLv3; - if ((protocol_version & ESOCK_TLSv1) == 0) - options |= SSL_OP_NO_TLSv1; - SSL_CTX_set_options(ctx, options); - } -} - - -static unsigned char randvec [] = { - 181, 177, 237, 240, 107, 24, 43, 148, - 105, 4, 248, 13, 199, 255, 23, 58, - 71, 181, 57, 151, 156, 25, 165, 7, - 73, 80, 80, 231, 70, 110, 96, 162, - 24, 205, 178, 178, 67, 122, 210, 180, - 92, 6, 156, 182, 84, 159, 85, 6, - 175, 66, 165, 167, 137, 34, 179, 237, - 77, 90, 87, 185, 21, 106, 92, 115, - 137, 65, 233, 42, 164, 153, 208, 133, - 160, 172, 129, 202, 46, 220, 98, 66, - 115, 66, 46, 28, 226, 200, 140, 145, - 207, 194, 58, 71, 56, 203, 113, 34, - 221, 116, 63, 114, 188, 210, 45, 238, - 200, 123, 35, 150, 2, 78, 160, 22, - 226, 167, 162, 10, 182, 75, 109, 97, - 86, 252, 93, 125, 117, 214, 220, 37, - 105, 160, 56, 158, 97, 57, 22, 14, - 73, 169, 111, 190, 222, 176, 14, 82, - 111, 42, 87, 90, 136, 236, 22, 209, - 156, 207, 40, 251, 88, 141, 51, 211, - 31, 158, 153, 91, 119, 83, 255, 60, - 55, 94, 5, 115, 119, 210, 224, 185, - 163, 163, 5, 3, 197, 106, 110, 206, - 109, 132, 50, 190, 177, 133, 175, 129, - 225, 161, 156, 244, 77, 150, 99, 38, - 17, 111, 46, 230, 152, 64, 50, 164, - 19, 78, 3, 164, 169, 175, 104, 97, - 103, 158, 91, 168, 186, 191, 73, 88, - 118, 112, 41, 188, 219, 0, 198, 209, - 206, 7, 5, 169, 127, 180, 80, 74, - 124, 4, 4, 108, 197, 67, 204, 29, - 101, 95, 174, 147, 64, 163, 89, 160, - 10, 5, 56, 134, 209, 69, 209, 55, - 214, 136, 45, 212, 113, 85, 159, 133, - 141, 249, 75, 40, 175, 91, 142, 13, - 179, 179, 51, 0, 136, 63, 148, 175, - 103, 162, 8, 214, 4, 24, 59, 71, - 9, 185, 48, 127, 159, 165, 8, 8, - 135, 151, 92, 214, 132, 151, 204, 169, - 24, 112, 229, 59, 236, 81, 238, 64, - 150, 196, 97, 213, 140, 159, 20, 24, - 79, 210, 191, 53, 130, 33, 157, 87, - 16, 180, 175, 217, 56, 123, 115, 196, - 130, 6, 155, 37, 220, 80, 232, 129, - 240, 57, 199, 249, 196, 152, 28, 111, - 124, 192, 59, 46, 29, 21, 178, 51, - 156, 17, 248, 61, 254, 80, 201, 131, - 203, 59, 227, 191, 71, 121, 134, 181, - 55, 79, 130, 225, 246, 36, 179, 224, - 189, 243, 200, 75, 73, 41, 251, 41, - 71, 251, 78, 146, 99, 101, 104, 69, - 18, 122, 65, 24, 232, 84, 246, 242, - 209, 18, 241, 114, 3, 65, 177, 99, - 49, 99, 215, 59, 9, 175, 195, 11, - 25, 46, 43, 120, 109, 179, 159, 250, - 239, 246, 135, 78, 2, 238, 214, 237, - 64, 170, 50, 44, 68, 67, 111, 232, - 225, 230, 224, 124, 76, 32, 52, 158, - 151, 54, 184, 135, 122, 66, 211, 215, - 121, 90, 124, 158, 55, 73, 116, 137, - 240, 15, 38, 31, 183, 86, 93, 49, - 148, 184, 125, 250, 155, 216, 84, 246, - 27, 172, 141, 54, 80, 158, 227, 254, - 189, 164, 238, 229, 68, 26, 231, 11, - 198, 222, 15, 141, 98, 8, 124, 219, - 60, 125, 170, 213, 114, 24, 189, 65, - 80, 186, 71, 126, 223, 153, 20, 141, - 110, 73, 173, 218, 214, 63, 205, 177, - 132, 115, 184, 28, 122, 232, 210, 72, - 237, 41, 93, 17, 152, 95, 242, 138, - 79, 98, 47, 197, 36, 17, 137, 230, - 15, 73, 193, 1, 181, 123, 0, 186, - 185, 135, 142, 200, 139, 78, 57, 145, - 191, 32, 98, 250, 113, 188, 71, 32, - 205, 81, 219, 99, 60, 87, 42, 95, - 249, 252, 121, 125, 246, 230, 74, 162, - 73, 59, 179, 142, 178, 47, 163, 161, - 236, 14, 123, 219, 18, 6, 102, 140, - 215, 210, 76, 9, 119, 147, 252, 63, - 13, 51, 161, 172, 180, 116, 212, 129, - 116, 237, 38, 64, 213, 222, 35, 14, - 183, 237, 78, 204, 250, 250, 5, 41, - 142, 5, 207, 154, 65, 183, 108, 82, - 1, 43, 149, 233, 89, 195, 25, 233, - 4, 34, 19, 122, 16, 58, 121, 5, - 118, 168, 22, 213, 49, 226, 163, 169, - 21, 78, 179, 232, 125, 216, 198, 147, - 245, 196, 199, 138, 185, 167, 179, 82, - 175, 53, 6, 162, 5, 141, 180, 212, - 95, 201, 234, 169, 111, 175, 138, 197, - 177, 246, 154, 41, 185, 201, 134, 187, - 88, 99, 231, 23, 190, 36, 72, 174, - 244, 185, 205, 50, 230, 226, 210, 119, - 175, 107, 109, 244, 12, 122, 84, 51, - 146, 95, 68, 74, 76, 212, 221, 103, - 244, 71, 63, 133, 149, 233, 48, 3, - 176, 168, 6, 98, 88, 226, 120, 190, - 205, 249, 38, 157, 205, 148, 250, 203, - 147, 62, 195, 229, 219, 109, 177, 119, - 120, 43, 165, 99, 253, 210, 180, 32, - 227, 180, 174, 64, 156, 139, 251, 53, - 205, 132, 210, 208, 3, 199, 115, 64, - 59, 27, 249, 164, 224, 191, 124, 241, - 142, 10, 19, 120, 227, 46, 174, 231, - 48, 65, 41, 56, 51, 38, 185, 95, - 250, 182, 100, 40, 196, 124, 173, 119, - 162, 148, 170, 34, 51, 68, 175, 60, - 242, 201, 225, 34, 146, 157, 159, 0, - 144, 148, 82, 72, 149, 53, 201, 10, - 248, 206, 154, 126, 33, 153, 56, 48, - 5, 90, 194, 22, 251, 173, 211, 202, - 203, 253, 112, 147, 188, 200, 142, 206, - 206, 175, 233, 76, 93, 104, 125, 41, - 64, 145, 202, 53, 130, 251, 23, 90, - 28, 199, 13, 128, 185, 154, 53, 194, - 195, 55, 80, 56, 151, 216, 195, 138, - 7, 170, 143, 236, 74, 141, 229, 174, - 32, 165, 131, 68, 174, 104, 35, 143, - 183, 41, 80, 191, 120, 79, 166, 240, - 123, 55, 60, 2, 128, 56, 4, 199, - 122, 85, 90, 76, 246, 29, 13, 6, - 126, 229, 14, 203, 244, 73, 121, 42, - 169, 35, 44, 202, 18, 69, 153, 120, - 141, 77, 124, 191, 215, 18, 115, 187, - 108, 246, 135, 151, 225, 192, 50, 89, - 128, 45, 39, 253, 149, 234, 203, 84, - 51, 174, 15, 237, 17, 57, 76, 81, - 39, 107, 40, 36, 22, 52, 92, 39}; diff --git a/lib/ssl/c_src/esock_osio.c b/lib/ssl/c_src/esock_osio.c deleted file mode 100644 index 41c5271c16..0000000000 --- a/lib/ssl/c_src/esock_osio.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 1999-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Std filedescriptors, break handler - * - */ - -#include -#include -#ifdef __WIN32__ -#include "esock_winsock.h" -#include -#include -#include -#else -#include -#include -#endif - -#include "esock.h" -#include "debuglog.h" -#include "esock_utils.h" -#include "esock_osio.h" - -#ifdef __WIN32__ -#define write _write -#define read _read -#define LOCALHOSTADDR "127.0.0.1" -#define LOCBUFSIZE 1024 -#endif - -#define PACKET_SIZE 4 -#define EBUFSIZE 256 - -FD local_read_fd = 0; - -static int inc_rbuf(int size); -static void free_rbuf(void); -static int read_fill(unsigned char *buf, int len); -#ifdef __WIN32__ -static int create_local_thread(void); -static DWORD WINAPI local_thread(LPVOID lpvParam); -static BOOL WINAPI signal_handler(DWORD ctrl); -#endif - -static unsigned char *rbuf = NULL; -static int rbuf_malloced = 0; -#ifdef __WIN32__ -static unsigned long one = 1, zero = 0; -static int local_portno; -static char *local_buf; -#endif - -int set_break_handler(void) -{ -#ifndef __WIN32__ - struct sigaction act; - - /* Ignore SIGPIPE signal */ - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &act, NULL); - return 0; -#else - SetConsoleCtrlHandler(signal_handler, TRUE); - return 0; -#endif -} - - -#ifdef __WIN32__ - -int set_binary_mode(void) -{ - _setmode(0, _O_BINARY); - _setmode(1, _O_BINARY); - return 0; -} - -int esock_osio_init(void) -{ - return create_local_thread(); -} - -void esock_osio_finish(void) -{ - sock_close(local_read_fd); -} - -#endif - -int read_ctrl(unsigned char **ebufp) -{ - int tbh, cc; - unsigned char *mbuf; - - if (inc_rbuf(EBUFSIZE) < 0) { - fprintf(stderr, "read_ctrl: cannot alloc rbuf\n"); - return -1; - } - cc = read_fill(rbuf, PACKET_SIZE); - if (cc < 0) { - free_rbuf(); - return -1; - } - if (cc == 0) { - free_rbuf(); - return -1; /* XXX 0 ?? */ - } - tbh = GET_INT32(rbuf); - - if (tbh > rbuf_malloced - 4) { - if (inc_rbuf(tbh + 4) < 0) - return -1; - } - - mbuf = rbuf + PACKET_SIZE; - cc = read_fill(mbuf, tbh); - DEBUGF(("-----------------------------------\n")); - DEBUGF(("read_ctrl: cc = %d\n", cc)); - if(cc > 0) { - DEBUGMSGF(("message (hex) : [%3.*a]\n", cc, mbuf)); - DEBUGMSGF(("message (char): [%3.*b]\n", cc, mbuf)); - } - *ebufp = mbuf; - return cc; -} - -int write_ctrl(unsigned char *buf, int len) -{ - unsigned char lb[4]; - - PUT_INT32(len, lb); - DEBUGF(("write_ctrl: len = %d\n", len)); - DEBUGMSGF(("message (hex) : [%3.*a] [%3.*a]\n", PACKET_SIZE, lb, - len, buf)); - DEBUGMSGF(("message (char): [%3.*b] [%3.*b]\n", PACKET_SIZE, lb, - len, buf)); - - if (write(1, lb, PACKET_SIZE) != PACKET_SIZE) { /* XXX */ - fprintf(stderr, "write_ctrl: Bad write \n"); - return -1; - } - if (write(1, buf, len) != len) { /* XXX */ - fprintf(stderr, "write_ctrl: Bad write \n"); - return -1; - } - return len; -} - - -/* - * Local functions - * - */ - -static int inc_rbuf(int size) -{ - unsigned char *nbuf; - - if (rbuf_malloced >= size) - return 0; - if (rbuf != NULL) - nbuf = esock_realloc(rbuf, size); - else - nbuf = esock_malloc(size); - if(nbuf != NULL) { - rbuf = nbuf; - rbuf_malloced = size; - return 0; - } - return -1; -} - -static void free_rbuf(void) -{ - if (rbuf != NULL) { - esock_free(rbuf); - rbuf = NULL; - rbuf_malloced = 0; - } -} - -/* Fill buffer, return buffer length, 0 for EOF, < 0 for error. */ - -static int read_fill(unsigned char *buf, int len) -{ - int i, got = 0; - - do { - if ((i = sock_read(local_read_fd, buf+got, len-got)) <= 0) - return i; - got += i; - } while (got < len); - return len; -} - - -#ifdef __WIN32__ - -/* - * This routine creates a local thread, which reads from standard input - * and writes to a socket. - */ - -static int create_local_thread(void) -{ - struct sockaddr_in iserv_addr; - SOCKET tmpsock; - int length; - unsigned threadaddr; - - local_buf = esock_malloc(LOCBUFSIZE); - if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - fprintf(stderr, "create_local_thread could not create socket.\n"); - return -1; - } - memset(&iserv_addr, 0, sizeof(iserv_addr)); - iserv_addr.sin_family = AF_INET; - iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR); - iserv_addr.sin_port = htons(0); /* Have any port */ - - if (bind(tmpsock, (struct sockaddr *) &iserv_addr, - sizeof(iserv_addr)) < 0) { - fprintf(stderr, "create_local_thread could not bind.\n"); - closesocket(tmpsock); - return -1; - } - listen(tmpsock, 1); - length = sizeof(iserv_addr); - if (getsockname(tmpsock, (struct sockaddr *) &iserv_addr, &length) < 0) { - fprintf(stderr, "create_local_thread could not getsockname.\n"); - closesocket(tmpsock); - return -1; - } - local_portno = ntohs(iserv_addr.sin_port); - - if (_beginthreadex(NULL, 0, local_thread, NULL, 0, &threadaddr) == 0) { - fprintf(stderr, "create_local_thread could not _beginthreadex().\n"); - closesocket(tmpsock); - return -1; - } - local_read_fd = accept(tmpsock, (struct sockaddr *) NULL, (int *) NULL); - if (local_read_fd == INVALID_FD) { - fprintf(stderr, "create_local_thread could not accept.\n"); - closesocket(tmpsock); - return -1; - } - closesocket(tmpsock); - return 0; -} - -static DWORD WINAPI local_thread(LPVOID lpvParam) -{ - SOCKET sock; - struct hostent *host; - char hostname[64]; - struct sockaddr_in iserv_addr; - unsigned long addr; - int len; - HANDLE thread; - - sock = socket(AF_INET, SOCK_STREAM, 0); - memset(&iserv_addr, 0, sizeof(struct sockaddr_in)); - iserv_addr.sin_family = AF_INET; - iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR); - iserv_addr.sin_port = htons(local_portno); - if(connect(sock, (struct sockaddr*)&iserv_addr, sizeof iserv_addr) == - SOCKET_ERROR) { - fprintf(stderr, "local_thread thread could not connect\n"); - closesocket(sock); - return 0; - } - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); - - /* read from 0 and write to sock */ - while (1) { - if ((len = read(0, local_buf, LOCBUFSIZE)) <= 0) { - closesocket(sock); - close(0); - return 0; - } - if (send(sock, local_buf, len, 0) != len ) { - closesocket(sock); - close(0); - return 0; - } - } - return 0; -} - -/* Signal handler */ - -static BOOL WINAPI signal_handler(DWORD ctrl) -{ - switch (ctrl) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - break; - case CTRL_LOGOFF_EVENT: - if (!getenv("ERLSRV_SERVICE_NAME")) - return FALSE; - break; - default: - exit(1); - } - return TRUE; -} - -#endif diff --git a/lib/ssl/c_src/esock_osio.h b/lib/ssl/c_src/esock_osio.h deleted file mode 100644 index 8742c3b05b..0000000000 --- a/lib/ssl/c_src/esock_osio.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. 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% - */ - -#ifndef ESOCK_OSIO_H -#define ESOCK_OSIO_H - -extern FD local_read_fd; - -#ifdef __WIN32__ -int set_binary_mode(void); -int esock_osio_init(void); -void esock_osio_finish(void); -#endif -int set_break_handler(void); -int read_ctrl(unsigned char **ebufp); -int write_ctrl(unsigned char *buf, int len); - -#endif diff --git a/lib/ssl/c_src/esock_poll.c b/lib/ssl/c_src/esock_poll.c deleted file mode 100644 index e982eba881..0000000000 --- a/lib/ssl/c_src/esock_poll.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 2005-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ - -/* - * Purpose: Hide poll() and select() behind an API so that we - * can use either one. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef __WIN32__ -#include "esock_winsock.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __WIN32__ -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include "esock.h" -#include "esock_ssl.h" -#include "esock_utils.h" -#include "esock_poll.h" -#include "debuglog.h" - -#if !defined(USE_SELECT) - -/* At least on FreeBSD, we need POLLRDNORM for normal files, not POLLIN. */ -/* Whether this is a bug in FreeBSD, I don't know. */ -#ifdef POLLRDNORM -#define POLL_INPUT (POLLIN | POLLRDNORM) -#else -#define POLL_INPUT POLLIN -#endif - -static void poll_fd_set(EsockPoll *ep, FD fd, short events) -{ - int i, j; - int prev_num_fds = ep->num_fds; - - if (ep->num_fds <= fd) { - ep->num_fds = fd + 64; - ep->fd_to_poll = (int *) esock_realloc(ep->fd_to_poll, - ep->num_fds*sizeof(int)); - for (j = prev_num_fds; j < ep->num_fds; j++) - ep->fd_to_poll[j] = -1; - } - i = ep->fd_to_poll[fd]; - if (i > 0 && i < ep->active && ep->fds[i].fd == fd) { - /* Already present in poll array */ - ep->fds[i].events |= events; - } else { - /* Append to poll array */ - if (ep->active >= ep->allocated) { - ep->allocated *= 2; - ep->fds = (struct pollfd *) - esock_realloc(ep->fds, ep->allocated*sizeof(struct pollfd)); - } - ep->fd_to_poll[fd] = ep->active; - ep->fds[ep->active].fd = fd; - ep->fds[ep->active].events = events; - ep->fds[ep->active].revents = 0; - ep->active++; - } -} - -static int poll_is_set(EsockPoll *ep, FD fd, short mask) -{ - if (fd >= ep->num_fds) { - return 0; - } else { - int i = ep->fd_to_poll[fd]; - return 0 <= i && i < ep->active && ep->fds[i].fd == fd && - (ep->fds[i].revents & mask) != 0; - } -} - -#endif - -void esock_poll_init(EsockPoll *ep) -{ -#ifdef USE_SELECT - /* Nothing to do here */ -#else - ep->allocated = 2; - ep->fds = (struct pollfd *) esock_malloc(ep->allocated*sizeof(struct pollfd)); - ep->num_fds = 1; - ep->fd_to_poll = esock_malloc(ep->num_fds*sizeof(int)); -#endif -} - -void esock_poll_zero(EsockPoll *ep) -{ -#ifdef USE_SELECT - FD_ZERO(&ep->readmask); - FD_ZERO(&ep->writemask); - FD_ZERO(&ep->exceptmask); -#else - int i; - - for (i = 0; i < ep->num_fds; i++) - ep->fd_to_poll[i] = -1; - ep->active = 0; -#endif -} - -void esock_poll_fd_set_read(EsockPoll *ep, FD fd) -{ -#ifdef USE_SELECT - FD_SET(fd, &ep->readmask); -#else - poll_fd_set(ep, fd, POLL_INPUT); -#endif -} - -void esock_poll_fd_set_write(EsockPoll *ep, FD fd) -{ -#ifdef USE_SELECT - FD_SET(fd, &ep->writemask); -#else - poll_fd_set(ep, fd, POLLOUT); -#endif -} - -int esock_poll_fd_isset_read(EsockPoll *ep, FD fd) -{ -#ifdef USE_SELECT - return FD_ISSET(fd, &ep->readmask); -#else - return poll_is_set(ep, fd, (POLL_INPUT|POLLHUP|POLLERR|POLLNVAL)); -#endif -} - -int esock_poll_fd_isset_write(EsockPoll *ep, FD fd) -{ -#ifdef USE_SELECT - return FD_ISSET(fd, &ep->writemask); -#else - return poll_is_set(ep, fd, (POLLOUT|POLLHUP|POLLERR|POLLNVAL)); -#endif -} - -#ifdef __WIN32__ -void esock_poll_fd_set_exception(EsockPoll *ep, FD fd) -{ - FD_SET(fd, &ep->exceptmask); -} - -int esock_poll_fd_isset_exception(EsockPoll *ep, FD fd) -{ - return FD_ISSET(fd, &ep->exceptmask); -} -#endif - -int esock_poll(EsockPoll *ep, int seconds) -{ - int sret; - -#ifdef USE_SELECT - struct timeval tv; - - tv.tv_sec = seconds; - tv.tv_usec = 0; - sret = select(FD_SETSIZE, &ep->readmask, &ep->writemask, &ep->exceptmask, &tv); - if (sret == 0) { - FD_ZERO(&ep->readmask); - FD_ZERO(&ep->writemask); - FD_ZERO(&ep->exceptmask); - } -#else - sret = poll(ep->fds, ep->active, 1000*seconds); -#endif - return sret; -} - -void esock_poll_clear_event(EsockPoll* ep, FD fd) -{ -#ifdef USE_SELECT - FD_CLR(fd, &ep->readmask); - FD_CLR(fd, &ep->writemask); - FD_CLR(fd, &ep->exceptmask); -#else - int i = ep->fd_to_poll[fd]; - if (i > 0 && ep->fds[i].fd == fd) - ep->fds[i].revents = 0; -#endif -} diff --git a/lib/ssl/c_src/esock_poll.h b/lib/ssl/c_src/esock_poll.h deleted file mode 100644 index 639976dfa9..0000000000 --- a/lib/ssl/c_src/esock_poll.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 2005-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -#ifndef ESOCK_POLL_SELECT_H -#define ESOCK_POLL_SELECT_H - -#if !defined(USE_SELECT) -#include -#endif - -typedef struct esock_poll { -#ifdef USE_SELECT - fd_set readmask; - fd_set writemask; - fd_set exceptmask; -#else - int* fd_to_poll; /* Map from fd to index into poll - * descriptor array. - */ - int num_fds; /* Number of entries in fd_to_poll. */ - struct pollfd* fds; /* Array of poll descriptors. */ - int allocated; /* Allocated number of fds. */ - int active; /* Active number of fds */ -#endif -} EsockPoll; - -void esock_poll_init(EsockPoll *ep); -void esock_poll_zero(EsockPoll *ep); - -void esock_poll_fd_set_read(EsockPoll *ep, FD fd); -void esock_poll_fd_set_write(EsockPoll *ep, FD fd); - -void esock_poll_clear_event(EsockPoll *ep, FD fd); - -int esock_poll_fd_isset_read(EsockPoll *ep, FD fd); -int esock_poll_fd_isset_write(EsockPoll *ep, FD fd); - -#ifdef __WIN32__ -void esock_poll_fd_set_exception(EsockPoll *ep, FD fd); -int esock_poll_fd_isset_exception(EsockPoll *ep, FD fd); -#endif - -int esock_poll(EsockPoll *ep, int seconds); -#endif diff --git a/lib/ssl/c_src/esock_posix_str.c b/lib/ssl/c_src/esock_posix_str.c deleted file mode 100644 index 31062baaaf..0000000000 --- a/lib/ssl/c_src/esock_posix_str.c +++ /dev/null @@ -1,642 +0,0 @@ -/* - * %ExternalCopyright% - */ - -/* - * Original: tclPosixStr.c -- - * - * This file contains procedures that generate strings - * corresponding to various POSIX-related codes, such - * as errno and signals. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * SCCS: @(#) tclPosixStr.c 1.32 96/10/10 10:09:42 - */ - -/* Copy of erl_posix_str.c */ - -#ifdef __WIN32__ -#include "esock_winsock.h" -#endif - -#include -#include -#include "esock_posix_str.h" - -/* - *---------------------------------------------------------------------- - * - * esock_posix_str -- - * - * Return a textual identifier for the given errno value. - * - * Results: - * This procedure returns a machine-readable textual identifier - * that corresponds to the current errno value (e.g. "eperm"). - * The identifier is the same as the #define name in errno.h, - * except that it is in lowercase. - * - *---------------------------------------------------------------------- - */ - -static char errstrbuf[32]; - -char *esock_posix_str(int error) -{ - switch (error) { -#ifdef E2BIG - case E2BIG: return "e2big"; -#endif -#ifdef EACCES - case EACCES: return "eacces"; -#endif -#ifdef EADDRINUSE - case EADDRINUSE: return "eaddrinuse"; -#endif -#ifdef EADDRNOTAVAIL - case EADDRNOTAVAIL: return "eaddrnotavail"; -#endif -#ifdef EADV - case EADV: return "eadv"; -#endif -#ifdef EAFNOSUPPORT - case EAFNOSUPPORT: return "eafnosupport"; -#endif -#ifdef EAGAIN - case EAGAIN: return "eagain"; -#endif -#ifdef EALIGN - case EALIGN: return "ealign"; -#endif -#if defined(EALREADY) && (!defined(EBUSY) || (EALREADY != EBUSY )) - case EALREADY: return "ealready"; -#endif -#ifdef EBADE - case EBADE: return "ebade"; -#endif -#ifdef EBADF - case EBADF: return "ebadf"; -#endif -#ifdef EBADFD - case EBADFD: return "ebadfd"; -#endif -#ifdef EBADMSG - case EBADMSG: return "ebadmsg"; -#endif -#ifdef EBADR - case EBADR: return "ebadr"; -#endif -#ifdef EBADRPC - case EBADRPC: return "ebadrpc"; -#endif -#ifdef EBADRQC - case EBADRQC: return "ebadrqc"; -#endif -#ifdef EBADSLT - case EBADSLT: return "ebadslt"; -#endif -#ifdef EBFONT - case EBFONT: return "ebfont"; -#endif -#ifdef EBUSY - case EBUSY: return "ebusy"; -#endif -#ifdef ECHILD - case ECHILD: return "echild"; -#endif -#ifdef ECHRNG - case ECHRNG: return "echrng"; -#endif -#ifdef ECOMM - case ECOMM: return "ecomm"; -#endif -#ifdef ECONNABORTED - case ECONNABORTED: return "econnaborted"; -#endif -#ifdef ECONNREFUSED - case ECONNREFUSED: return "econnrefused"; -#endif -#ifdef ECONNRESET - case ECONNRESET: return "econnreset"; -#endif -#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) - case EDEADLK: return "edeadlk"; -#endif -#if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK)) - case EDEADLOCK: return "edeadlock"; -#endif -#ifdef EDESTADDRREQ - case EDESTADDRREQ: return "edestaddrreq"; -#endif -#ifdef EDIRTY - case EDIRTY: return "edirty"; -#endif -#ifdef EDOM - case EDOM: return "edom"; -#endif -#ifdef EDOTDOT - case EDOTDOT: return "edotdot"; -#endif -#ifdef EDQUOT - case EDQUOT: return "edquot"; -#endif -#ifdef EDUPPKG - case EDUPPKG: return "eduppkg"; -#endif -#ifdef EEXIST - case EEXIST: return "eexist"; -#endif -#ifdef EFAULT - case EFAULT: return "efault"; -#endif -#ifdef EFBIG - case EFBIG: return "efbig"; -#endif -#ifdef EHOSTDOWN - case EHOSTDOWN: return "ehostdown"; -#endif -#ifdef EHOSTUNREACH - case EHOSTUNREACH: return "ehostunreach"; -#endif -#if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS)) - case EIDRM: return "eidrm"; -#endif -#ifdef EINIT - case EINIT: return "einit"; -#endif -#ifdef EINPROGRESS - case EINPROGRESS: return "einprogress"; -#endif -#ifdef EINTR - case EINTR: return "eintr"; -#endif -#ifdef EINVAL - case EINVAL: return "einval"; -#endif -#ifdef EIO - case EIO: return "eio"; -#endif -#ifdef EISCONN - case EISCONN: return "eisconn"; -#endif -#ifdef EISDIR - case EISDIR: return "eisdir"; -#endif -#ifdef EISNAME - case EISNAM: return "eisnam"; -#endif -#ifdef ELBIN - case ELBIN: return "elbin"; -#endif -#ifdef EL2HLT - case EL2HLT: return "el2hlt"; -#endif -#ifdef EL2NSYNC - case EL2NSYNC: return "el2nsync"; -#endif -#ifdef EL3HLT - case EL3HLT: return "el3hlt"; -#endif -#ifdef EL3RST - case EL3RST: return "el3rst"; -#endif -#ifdef ELIBACC - case ELIBACC: return "elibacc"; -#endif -#ifdef ELIBBAD - case ELIBBAD: return "elibbad"; -#endif -#ifdef ELIBEXEC - case ELIBEXEC: return "elibexec"; -#endif -#ifdef ELIBMAX - case ELIBMAX: return "elibmax"; -#endif -#ifdef ELIBSCN - case ELIBSCN: return "elibscn"; -#endif -#ifdef ELNRNG - case ELNRNG: return "elnrng"; -#endif -#if defined(ELOOP) && (!defined(ENOENT) || (ELOOP != ENOENT)) - case ELOOP: return "eloop"; -#endif -#ifdef EMFILE - case EMFILE: return "emfile"; -#endif -#ifdef EMLINK - case EMLINK: return "emlink"; -#endif -#ifdef EMSGSIZE - case EMSGSIZE: return "emsgsize"; -#endif -#ifdef EMULTIHOP - case EMULTIHOP: return "emultihop"; -#endif -#ifdef ENAMETOOLONG - case ENAMETOOLONG: return "enametoolong"; -#endif -#ifdef ENAVAIL - case ENAVAIL: return "enavail"; -#endif -#ifdef ENET - case ENET: return "enet"; -#endif -#ifdef ENETDOWN - case ENETDOWN: return "enetdown"; -#endif -#ifdef ENETRESET - case ENETRESET: return "enetreset"; -#endif -#ifdef ENETUNREACH - case ENETUNREACH: return "enetunreach"; -#endif -#ifdef ENFILE - case ENFILE: return "enfile"; -#endif -#ifdef ENOANO - case ENOANO: return "enoano"; -#endif -#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) - case ENOBUFS: return "enobufs"; -#endif -#ifdef ENOCSI - case ENOCSI: return "enocsi"; -#endif -#if defined(ENODATA) && (!defined(ECONNREFUSED) || (ENODATA != ECONNREFUSED)) - case ENODATA: return "enodata"; -#endif -#ifdef ENODEV - case ENODEV: return "enodev"; -#endif -#ifdef ENOENT - case ENOENT: return "enoent"; -#endif -#ifdef ENOEXEC - case ENOEXEC: return "enoexec"; -#endif -#ifdef ENOLCK - case ENOLCK: return "enolck"; -#endif -#ifdef ENOLINK - case ENOLINK: return "enolink"; -#endif -#ifdef ENOMEM - case ENOMEM: return "enomem"; -#endif -#ifdef ENOMSG - case ENOMSG: return "enomsg"; -#endif -#ifdef ENONET - case ENONET: return "enonet"; -#endif -#ifdef ENOPKG - case ENOPKG: return "enopkg"; -#endif -#ifdef ENOPROTOOPT - case ENOPROTOOPT: return "enoprotoopt"; -#endif -#ifdef ENOSPC - case ENOSPC: return "enospc"; -#endif -#if defined(ENOSR) && (!defined(ENAMETOOLONG) || (ENAMETOOLONG != ENOSR)) - case ENOSR: return "enosr"; -#endif -#if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR)) - case ENOSTR: return "enostr"; -#endif -#ifdef ENOSYM - case ENOSYM: return "enosym"; -#endif -#ifdef ENOSYS - case ENOSYS: return "enosys"; -#endif -#ifdef ENOTBLK - case ENOTBLK: return "enotblk"; -#endif -#ifdef ENOTCONN - case ENOTCONN: return "enotconn"; -#endif -#ifdef ENOTDIR - case ENOTDIR: return "enotdir"; -#endif -#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST)) - case ENOTEMPTY: return "enotempty"; -#endif -#ifdef ENOTNAM - case ENOTNAM: return "enotnam"; -#endif -#ifdef ENOTSOCK - case ENOTSOCK: return "enotsock"; -#endif -#ifdef ENOTSUP - case ENOTSUP: return "enotsup"; -#endif -#ifdef ENOTTY - case ENOTTY: return "enotty"; -#endif -#ifdef ENOTUNIQ - case ENOTUNIQ: return "enotuniq"; -#endif -#ifdef ENXIO - case ENXIO: return "enxio"; -#endif -#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP) - case EOPNOTSUPP: return "eopnotsupp"; -#endif -#ifdef EPERM - case EPERM: return "eperm"; -#endif -#if defined(EPFNOSUPPORT) && (!defined(ENOLCK) || (ENOLCK != EPFNOSUPPORT)) - case EPFNOSUPPORT: return "epfnosupport"; -#endif -#ifdef EPIPE - case EPIPE: return "epipe"; -#endif -#ifdef EPROCLIM - case EPROCLIM: return "eproclim"; -#endif -#ifdef EPROCUNAVAIL - case EPROCUNAVAIL: return "eprocunavail"; -#endif -#ifdef EPROGMISMATCH - case EPROGMISMATCH: return "eprogmismatch"; -#endif -#ifdef EPROGUNAVAIL - case EPROGUNAVAIL: return "eprogunavail"; -#endif -#ifdef EPROTO - case EPROTO: return "eproto"; -#endif -#ifdef EPROTONOSUPPORT - case EPROTONOSUPPORT: return "eprotonosupport"; -#endif -#ifdef EPROTOTYPE - case EPROTOTYPE: return "eprototype"; -#endif -#ifdef ERANGE - case ERANGE: return "erange"; -#endif -#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) - case EREFUSED: return "erefused"; -#endif -#ifdef EREMCHG - case EREMCHG: return "eremchg"; -#endif -#ifdef EREMDEV - case EREMDEV: return "eremdev"; -#endif -#ifdef EREMOTE - case EREMOTE: return "eremote"; -#endif -#ifdef EREMOTEIO - case EREMOTEIO: return "eremoteio"; -#endif -#ifdef EREMOTERELEASE - case EREMOTERELEASE: return "eremoterelease"; -#endif -#ifdef EROFS - case EROFS: return "erofs"; -#endif -#ifdef ERPCMISMATCH - case ERPCMISMATCH: return "erpcmismatch"; -#endif -#ifdef ERREMOTE - case ERREMOTE: return "erremote"; -#endif -#ifdef ESHUTDOWN - case ESHUTDOWN: return "eshutdown"; -#endif -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: return "esocktnosupport"; -#endif -#ifdef ESPIPE - case ESPIPE: return "espipe"; -#endif -#ifdef ESRCH - case ESRCH: return "esrch"; -#endif -#ifdef ESRMNT - case ESRMNT: return "esrmnt"; -#endif -#ifdef ESTALE - case ESTALE: return "estale"; -#endif -#ifdef ESUCCESS - case ESUCCESS: return "esuccess"; -#endif -#if defined(ETIME) && (!defined(ELOOP) || (ETIME != ELOOP)) - case ETIME: return "etime"; -#endif -#if defined(ETIMEDOUT) && (!defined(ENOSTR) || (ETIMEDOUT != ENOSTR)) - case ETIMEDOUT: return "etimedout"; -#endif -#ifdef ETOOMANYREFS - case ETOOMANYREFS: return "etoomanyrefs"; -#endif -#ifdef ETXTBSY - case ETXTBSY: return "etxtbsy"; -#endif -#ifdef EUCLEAN - case EUCLEAN: return "euclean"; -#endif -#ifdef EUNATCH - case EUNATCH: return "eunatch"; -#endif -#ifdef EUSERS - case EUSERS: return "eusers"; -#endif -#ifdef EVERSION - case EVERSION: return "eversion"; -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) - case EWOULDBLOCK: return "ewouldblock"; -#endif -#ifdef EXDEV - case EXDEV: return "exdev"; -#endif -#ifdef EXFULL - case EXFULL: return "exfull"; -#endif -#ifdef WSAEINTR - case WSAEINTR: return "eintr"; -#endif -#ifdef WSAEBADF - case WSAEBADF: return "ebadf"; -#endif -#ifdef WSAEACCES - case WSAEACCES: return "eacces"; -#endif -#ifdef WSAEFAULT - case WSAEFAULT: return "efault"; -#endif -#ifdef WSAEINVAL - case WSAEINVAL: return "einval"; -#endif -#ifdef WSAEMFILE - case WSAEMFILE: return "emfile"; -#endif -#ifdef WSAEWOULDBLOCK - case WSAEWOULDBLOCK: return "ewouldblock"; -#endif -#ifdef WSAEINPROGRESS - case WSAEINPROGRESS: return "einprogress"; -#endif -#ifdef WSAEALREADY - case WSAEALREADY: return "ealready"; -#endif -#ifdef WSAENOTSOCK - case WSAENOTSOCK: return "enotsock"; -#endif -#ifdef WSAEDESTADDRREQ - case WSAEDESTADDRREQ: return "edestaddrreq"; -#endif -#ifdef WSAEMSGSIZE - case WSAEMSGSIZE: return "emsgsize"; -#endif -#ifdef WSAEPROTOTYPE - case WSAEPROTOTYPE: return "eprototype"; -#endif -#ifdef WSAENOPROTOOPT - case WSAENOPROTOOPT: return "enoprotoopt"; -#endif -#ifdef WSAEPROTONOSUPPORT - case WSAEPROTONOSUPPORT: return "eprotonosupport"; -#endif -#ifdef WSAESOCKTNOSUPPORT - case WSAESOCKTNOSUPPORT: return "esocktnosupport"; -#endif -#ifdef WSAEOPNOTSUPP - case WSAEOPNOTSUPP: return "eopnotsupp"; -#endif -#ifdef WSAEPFNOSUPPORT - case WSAEPFNOSUPPORT: return "epfnosupport"; -#endif -#ifdef WSAEAFNOSUPPORT - case WSAEAFNOSUPPORT: return "eafnosupport"; -#endif -#ifdef WSAEADDRINUSE - case WSAEADDRINUSE: return "eaddrinuse"; -#endif -#ifdef WSAEADDRNOTAVAIL - case WSAEADDRNOTAVAIL: return "eaddrnotavail"; -#endif -#ifdef WSAENETDOWN - case WSAENETDOWN: return "enetdown"; -#endif -#ifdef WSAENETUNREACH - case WSAENETUNREACH: return "enetunreach"; -#endif -#ifdef WSAENETRESET - case WSAENETRESET: return "enetreset"; -#endif -#ifdef WSAECONNABORTED - case WSAECONNABORTED: return "econnaborted"; -#endif -#ifdef WSAECONNRESET - case WSAECONNRESET: return "econnreset"; -#endif -#ifdef WSAENOBUFS - case WSAENOBUFS: return "enobufs"; -#endif -#ifdef WSAEISCONN - case WSAEISCONN: return "eisconn"; -#endif -#ifdef WSAENOTCONN - case WSAENOTCONN: return "enotconn"; -#endif -#ifdef WSAESHUTDOWN - case WSAESHUTDOWN: return "eshutdown"; -#endif -#ifdef WSAETOOMANYREFS - case WSAETOOMANYREFS: return "etoomanyrefs"; -#endif -#ifdef WSAETIMEDOUT - case WSAETIMEDOUT: return "etimedout"; -#endif -#ifdef WSAECONNREFUSED - case WSAECONNREFUSED: return "econnrefused"; -#endif -#ifdef WSAELOOP - case WSAELOOP: return "eloop"; -#endif -#ifdef WSAENAMETOOLONG - case WSAENAMETOOLONG: return "enametoolong"; -#endif -#ifdef WSAEHOSTDOWN - case WSAEHOSTDOWN: return "ehostdown"; -#endif -#ifdef WSAEHOSTUNREACH - case WSAEHOSTUNREACH: return "ehostunreach"; -#endif -#ifdef WSAENOTEMPTY - case WSAENOTEMPTY: return "enotempty"; -#endif -#ifdef WSAEPROCLIM - case WSAEPROCLIM: return "eproclim"; -#endif -#ifdef WSAEUSERS - case WSAEUSERS: return "eusers"; -#endif -#ifdef WSAEDQUOT - case WSAEDQUOT: return "edquot"; -#endif -#ifdef WSAESTALE - case WSAESTALE: return "estale"; -#endif -#ifdef WSAEREMOTE - case WSAEREMOTE: return "eremote"; -#endif -#ifdef WSASYSNOTREADY - case WSASYSNOTREADY: return "sysnotready"; -#endif -#ifdef WSAVERNOTSUPPORTED - case WSAVERNOTSUPPORTED: return "vernotsupported"; -#endif -#ifdef WSANOTINITIALISED - case WSANOTINITIALISED: return "notinitialised"; -#endif -#ifdef WSAEDISCON - case WSAEDISCON: return "ediscon"; -#endif -#ifdef WSAENOMORE - case WSAENOMORE: return "enomore"; -#endif -#ifdef WSAECANCELLED - case WSAECANCELLED: return "ecancelled"; -#endif -#ifdef WSAEINVALIDPROCTABLE - case WSAEINVALIDPROCTABLE: return "einvalidproctable"; -#endif -#ifdef WSAEINVALIDPROVIDER - case WSAEINVALIDPROVIDER: return "einvalidprovider"; -#endif -#ifdef WSAEPROVIDERFAILEDINIT - case WSAEPROVIDERFAILEDINIT: return "eproviderfailedinit"; -#endif -#ifdef WSASYSCALLFAILURE - case WSASYSCALLFAILURE: return "syscallfailure"; -#endif -#ifdef WSASERVICE_NOT_FOUND - case WSASERVICE_NOT_FOUND: return "service_not_found"; -#endif -#ifdef WSATYPE_NOT_FOUND - case WSATYPE_NOT_FOUND: return "type_not_found"; -#endif -#ifdef WSA_E_NO_MORE - case WSA_E_NO_MORE: return "e_no_more"; -#endif -#ifdef WSA_E_CANCELLED - case WSA_E_CANCELLED: return "e_cancelled"; -#endif - default: - sprintf(errstrbuf, "unknown:%d", error); - return errstrbuf; - } -} - diff --git a/lib/ssl/c_src/esock_posix_str.h b/lib/ssl/c_src/esock_posix_str.h deleted file mode 100644 index 53916c888a..0000000000 --- a/lib/ssl/c_src/esock_posix_str.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. 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% - */ - -/* esock_posix_str.h */ - -#ifndef ESOCK_POSIX_STR_H -#define ESOCK_POSIX_STR_H - -char *esock_posix_str(int error); - -#endif - diff --git a/lib/ssl/c_src/esock_ssl.h b/lib/ssl/c_src/esock_ssl.h deleted file mode 100644 index 535e9a6491..0000000000 --- a/lib/ssl/c_src/esock_ssl.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 1999-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Header file for adaptions to various SSL packages. - */ - -#ifndef ESOCK_SSL_H -#define ESOCK_SSL_H - -#include -#include -#include "esock.h" - -typedef struct { - const char *compile_version;/* version of OpenSSL when compiling esock */ - const char *lib_version; /* version of OpenSSL in library */ -} esock_version; - -/* Variables to be set by certain functions (see below) */ -char *esock_ssl_errstr; - -/* Ephemeral RSA and DH */ -int ephemeral_rsa, ephemeral_dh; - -/* Protocol version (sslv2, sslv3, tlsv1) */ -int protocol_version; - -/* version info */ -esock_version *esock_ssl_version(void); - -/* ciphers info */ -char *esock_ssl_ciphers(void); - -/* seeding */ -void esock_ssl_seed(void *buf, int len); - -/* Initialization and finalization of SSL */ - -int esock_ssl_init(void); -void esock_ssl_finish(void); - -/* Freeing of SSL resources for a connection */ - -void esock_ssl_free(Connection *cp); - -/* Print error diagnostics to a file pointer */ - -void esock_ssl_print_errors_fp(FILE *fp); - -/* All functions below have to return >= 0 on success, and < 0 on - * failure. - * - * If the return indicates a failure (return value < 0) and the failure - * is temporary the error context (sock_errno()/sock_set_errno()) must - * be set to ERRNO_BLOCK. - * - * If the failure is permanent, the error context must be set to something - * else than ERRNO_BLOCK, and `esock_ssl_errstr' must be set to point to - * short diagnostic string describing the error. - */ - -int esock_ssl_accept_init(Connection *cp, void *listenssl); -int esock_ssl_connect_init(Connection *cp); -int esock_ssl_listen_init(Connection *cp); - -/* All functions below may involve non-blocking I/O with a temporary - * failure. Hence they have to have the error context set to - * ERRNO_BLOCK, or else have esock_ssl_errstr set to point to a - * diagnostic string, in case the return value is < 0. If the return - * value is 0, cp->eof and cp->bp are set, if appropritate. - */ - -int esock_ssl_accept(Connection *cp); -int esock_ssl_connect(Connection *cp); - -int esock_ssl_read(Connection *cp, char *buf, int len); -int esock_ssl_write(Connection *cp, char *buf, int len); - -int esock_ssl_shutdown(Connection *cp); - -/* Peer certificate */ - -int esock_ssl_getpeercert(Connection *cp, unsigned char **buf); -int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf); - -/* Sessions */ -int esock_ssl_session_reused(Connection *cp); - -/* Protocol version and cipher of established connection */ -int esock_ssl_getprotocol_version(Connection *cp, char **buf); -int esock_ssl_getcipher(Connection *cp, char **buf); - -#endif diff --git a/lib/ssl/c_src/esock_utils.c b/lib/ssl/c_src/esock_utils.c deleted file mode 100644 index 0098a4f5f6..0000000000 --- a/lib/ssl/c_src/esock_utils.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. 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% - */ - -/* - * Purpose: Safe memory allocation and other utilities. - * - */ -#include -#include -#include -#include "esock_utils.h" - -static char *strtok_quote(char *s1, const char *s2); - - -void *esock_malloc(size_t size) -{ - void *p; - - p = malloc(size); - if (!p) { - fprintf(stderr, "esock_malloc: cannot alloc %d bytes\n", size); - exit(EXIT_FAILURE); - } - return p; -} - -void *esock_realloc(void *p, size_t size) -{ - void *np; - - np = realloc(p, size); - if (!np) { - fprintf(stderr, "esock_realloc: cannot realloc %d bytes\n", size); - exit(EXIT_FAILURE); - } - return np; -} - -void esock_free(void *p) -{ - free(p); -} - -/* Builds an argv array from cmd. Spaces and tabs within double quotes - * are not considered delimiters. Double quotes are removed. - * - * The return value is argc, and the pointer to char ** is set. argc - * is non-negative, argv[0], ..., argv[argc - 1] are pointers to - * strings, and argv[argc] == NULL. All argv[0], ..., argv[argc - 1] - * must be freed by the user, and also the argv pointer itself. - * - * Example: cmd = abc"/program files/"olle nisse, results in - * argv[0] = abc/program files/olle, argv[1] = nisse, argc = 2. - * - */ -int esock_build_argv(char *cmd, char ***argvp) -{ - int argvsize = 10, argc = 0; - char *args, *tokp, *argp; - char **argv; - - argv = esock_malloc(argvsize * sizeof(char *)); - args = esock_malloc(strlen(cmd) + 1); - strcpy(args, cmd); - tokp = strtok_quote(args, " \t"); - while (tokp != NULL) { - if (argc + 1 >= argvsize) { - argvsize += 10; - argv = esock_realloc(argv, argvsize * sizeof(char *)); - } - argp = esock_malloc(strlen(tokp) + 1); - strcpy(argp, tokp); - argv[argc++] = argp; - tokp = strtok_quote(NULL, " \t"); - } - esock_free(args); - argv[argc] = NULL; - *argvp = argv; - return argc; -} - -/* strtok_quote - * Works as strtok, but characters within pairs of double quotes are not - * considered as delimiters. Quotes are removed. - */ -static char *strtok_quote(char *s1, const char *s2) -{ - static char *last; - char *s, *t, *u; - - s = (s1) ? s1 : last; - if (!s) - return last = NULL; - - while (*s != '"' && *s != '\0' && strchr(s2, *s)) - s++; - t = s; - - while (1) { - if (*t == '"') { - t++; - while (*t != '"' && *t != '\0') - t++; - if (*t == '\0') { - last = NULL; - goto end; - } - t++; - } - while(*t != '"' && *t != '\0' && !strchr(s2, *t)) - t++; - if (*t == '\0') { - last = NULL; - goto end; - } else if (*t != '"') { - *t = '\0'; - last = t + 1; - goto end; - } - } -end: - /* Remove quotes */ - u = t = s; - while (*u) { - if (*u == '"') - u++; - else - *t++ = *u++; - } - *t = '\0'; - return s; -} - diff --git a/lib/ssl/c_src/esock_utils.h b/lib/ssl/c_src/esock_utils.h deleted file mode 100644 index 99ed6c23e3..0000000000 --- a/lib/ssl/c_src/esock_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. 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% - */ - -#ifndef ESOCK_UTILS_H -#define ESOCK_UTILS_H - -#include - -void *esock_malloc(size_t size); -void *esock_realloc(void *p, size_t size); -void esock_free(void *p); -int esock_build_argv(char *cmd, char ***argvp); - -#endif - - diff --git a/lib/ssl/c_src/esock_winsock.h b/lib/ssl/c_src/esock_winsock.h deleted file mode 100644 index 069782a18d..0000000000 --- a/lib/ssl/c_src/esock_winsock.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 2003-2008 - * Ericsson AB, 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. - * - * The Initial Developer of the Original Code is Ericsson AB. - * - */ -/* - * Purpose: Control winsock version and setting of FD_SETSIZE. - * - */ - -/* Maybe set FD_SETSIZE */ - -#ifdef ESOCK_WINSOCK2 -#include -#else -#include -/* These are defined in winsock2.h but not in winsock.h */ -#define SD_RECEIVE 0x00 -#define SD_SEND 0x01 -#define SD_BOTH 0x02 -#endif - diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile index 3119d37af0..5d808d6727 100644 --- a/lib/ssl/doc/src/Makefile +++ b/lib/ssl/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2010. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. 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 @@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- XML_APPLICATION_FILES = refman.xml -XML_REF3_FILES = ssl.xml old_ssl.xml ssl_session_cache_api.xml +XML_REF3_FILES = ssl.xml ssl_session_cache_api.xml XML_REF6_FILES = ssl_app.xml XML_PART_FILES = release_notes.xml usersguide.xml diff --git a/lib/ssl/doc/src/old_ssl.xml b/lib/ssl/doc/src/old_ssl.xml deleted file mode 100644 index 0d2e1afdbd..0000000000 --- a/lib/ssl/doc/src/old_ssl.xml +++ /dev/null @@ -1,709 +0,0 @@ - - - - -
- - 19992010 - Ericsson AB. 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. - - - - ssl - Peter Högfeldt - Peter Högfeldt - - Peter Högfeldt - - 2003-03-25 - D - old_ssl.xml -
- old_ssl - Interface Functions for Secure Socket Layer - -

This module contains interface functions to the Secure Socket Layer.

-
- -
- General - -

This manual page describes functions that are defined - in the ssl module and represents the old ssl implementation - that coexists with the new one until it has been - totally phased out.

- -

The old implementation can be - accessed by providing the option {ssl_imp, old} to the - ssl:connect and ssl:listen functions.

- -

The reader is advised to also read the ssl(6) manual page - describing the SSL application. -

- -

It is strongly advised to seed the random generator after - the ssl application has been started (see seed/1 - below), and before any connections are established. Although - the port program interfacing to the ssl libraries does a - "random" seeding of its own in order to make everything work - properly, that seeding is by no means random for the world - since it has a constant value which is known to everyone - reading the source code of the port program.

-
-
- -
- Common data types -

The following datatypes are used in the functions below: -

- - -

options() = [option()]

-
- -

option() = socketoption() | ssloption()

-
- -

socketoption() = {mode, list} | {mode, binary} | binary | {packet, packettype()} | {header, integer()} | {nodelay, boolean()} | {active, activetype()} | {backlog, integer()} | {ip, ipaddress()} | {port, integer()}

-
- -

ssloption() = {verify, code()} | {depth, depth()} | {certfile, path()} | {keyfile, path()} | {password, string()} | {cacertfile, path()} | {ciphers, string()}

-
- -

packettype() (see inet(3))

-
- -

activetype() (see inet(3))

-
- -

reason() = atom() | {atom(), string()}

-
- -

bytes() = [byte()]

-
- -

string() = [byte()]

-
- -

byte() = 0 | 1 | 2 | ... | 255

-
- -

code() = 0 | 1 | 2

-
- -

depth() = byte()

-
- -

address() = hostname() | ipstring() | ipaddress()

-
- -

ipaddress() = ipstring() | iptuple()

-
- -

hostname() = string()

-
- -

ipstring() = string()

-
- -

iptuple() = {byte(), byte(), byte(), byte()}

-
- -

sslsocket()

-
- -

protocol() = sslv2 | sslv3 | tlsv1

-
- -

-
-
-

The socket option {backlog, integer()} is for - listen/2 only, and the option {port, integer()} - is for connect/3/4 only. -

-

The following socket options are set by default: {mode, list}, {packet, 0}, {header, 0}, {nodelay, false}, {active, true}, {backlog, 5}, - {ip, {0,0,0,0}}, and {port, 0}. -

-

Note that the options {mode, binary} and binary - are equivalent. Similarly {mode, list} and the absence of - option binary are equivalent. -

-

The ssl options are for setting specific SSL parameters as follows: -

- - -

{verify, code()} Specifies type of verification: - 0 = do not verify peer; 1 = verify peer, 2 = verify peer, - fail if no peer certificate. The default value is 0. -

-
- -

{depth, depth()} Specifies the maximum - verification depth, i.e. how far in a chain of certificates - the verification process can proceed before the verification - is considered to fail. -

-

Peer certificate = 0, CA certificate = 1, higher level CA - certificate = 2, etc. The value 2 thus means that a chain - can at most contain peer cert, CA cert, next CA cert, and an - additional CA cert. -

-

The default value is 1. -

-
- -

{certfile, path()} Path to a file containing the - user's certificate. - chain of PEM encoded certificates.

-
- -

{keyfile, path()} Path to file containing user's - private PEM encoded key.

-
- -

{password, string()} String containing the user's - password. Only used if the private keyfile is password protected.

-
- -

{cacertfile, path()} Path to file containing PEM encoded - CA certificates (trusted certificates used for verifying a peer - certificate).

-
- -

{ciphers, string()} String of ciphers as a colon - separated list of ciphers. The function ciphers/0 can - be used to find all available ciphers.

-
-
-

The type sslsocket() is opaque to the user. -

-

The owner of a socket is the one that created it by a call to - transport_accept/[1,2], connect/[3,4], - or listen/2. -

-

When a socket is in active mode (the default), data from the - socket is delivered to the owner of the socket in the form of - messages: -

- - -

{ssl, Socket, Data}

-
- -

{ssl_closed, Socket}

-
- -

{ssl_error, Socket, Reason}

-
-
-

A Timeout argument specifies a timeout in milliseconds. The - default value for a Timeout argument is infinity. -

-

Functions listed below may return the value {error, closed}, which only indicates that the SSL socket is - considered closed for the operation in question. It is for - instance possible to have {error, closed} returned from - an call to send/2, and a subsequent call to recv/3 - returning {ok, Data}. -

-

Hence a return value of {error, closed} must not be - interpreted as if the socket was completely closed. On the - contrary, in order to free all resources occupied by an SSL - socket, close/1 must be called, or else the process owning - the socket has to terminate. -

-

For each SSL socket there is an Erlang process representing the - socket. When a socket is opened, that process links to the - calling client process. Implementations that want to detect - abnormal exits from the socket process by receiving {'EXIT', Pid, Reason} messages, should use the function pid/1 - to retrieve the process identifier from the socket, in order to - be able to match exit messages properly.

-
- - - ciphers() -> {ok, string()} | {error, enotstarted} - Get supported ciphers. - -

Returns a string consisting of colon separated cipher - designations that are supported by the current SSL library - implementation. -

-

The SSL application has to be started to return the string - of ciphers.

-
-
- - close(Socket) -> ok | {error, Reason} - Close a socket returned by transport_accept/[1,2], connect/3/4, or listen/2. - - Socket = sslsocket() - - -

Closes a socket returned by transport_accept/[1,2], - connect/[3,4], or listen/2

-
-
- - connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} - connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason} - Connect to Portat Address. - - Address = address() - Port = integer() - Options = [connect_option()] - connect_option() = {mode, list} | {mode, binary} | binary | {packet, packettype()} | {header, integer()} | {nodelay, boolean()} | {active, activetype()} | {ip, ipaddress()} | {port, integer()} | {verify, code()} | {depth, depth()} | {certfile, path()} | {keyfile, path()} | {password, string()} | {cacertfile, path()} | {ciphers, string()} - Timeout = integer() - Socket = sslsocket() - - -

Connects to Port at Address. If the optional - Timeout argument is specified, and a connection could not - be established within the given time, {error, timeout} is - returned. The default value for Timeout is infinity. -

-

The ip and port options are for binding to a - particular local address and port, respectively.

-
-
- - connection_info(Socket) -> {ok, {Protocol, Cipher}} | {error, Reason} - Get current protocol version and cipher. - - Socket = sslsocket() - Protocol = protocol() - Cipher = string() - - -

Gets the chosen protocol version and cipher for an established - connection (accepted och connected).

-
-
- - controlling_process(Socket, NewOwner) -> ok | {error, Reason} - Assign a new controlling process to the socket. - - Socket = sslsocket() - NewOwner = pid() - - -

Assigns a new controlling process to Socket. A controlling - process is the owner of a socket, and receives all messages from - the socket.

-
-
- - format_error(ErrorCode) -> string() - Return an error string. - - ErrorCode = term() - - -

Returns a diagnostic string describing an error.

-
-
- - getopts(Socket, OptionsTags) -> {ok, Options} | {error, Reason} - Get options set for socket - - Socket = sslsocket() - OptionTags = [optiontag()]() - - -

Returns the options the tags of which are OptionTags for - for the socket Socket.

-
-
- - listen(Port, Options) -> {ok, ListenSocket} | {error, Reason} - Set up a socket to listen on a port on the local host. - - Port = integer() - Options = [listen_option()] - listen_option() = {mode, list} | {mode, binary} | binary | {packet, packettype()} | {header, integer()} | {active, activetype()} | {backlog, integer()} | {ip, ipaddress()} | {verify, code()} | {depth, depth()} | {certfile, path()} | {keyfile, path()} | {password, string()} | {cacertfile, path()} | {ciphers, string()} - ListenSocket = sslsocket() - - -

Sets up a socket to listen on port Port at the local host. - If Port is zero, listen/2 picks an available port - number (use port/1 to retrieve it). -

-

The listen queue size defaults to 5. If a different value is - wanted, the option {backlog, Size} should be added to the - list of options. -

-

An empty Options list is considered an error, and - {error, enooptions} is returned. -

-

The returned ListenSocket can only be used in calls to - transport_accept/[1,2].

-
-
- - peercert(Socket) -> {ok, Cert} | {error, Reason} - Return the peer certificate. - - Socket = sslsocket() - Cert = binary()() - Subject = term()() - - -

Returns the DER encoded peer certificate, the certificate can be decoded with - public_key:pkix_decode_cert/2. -

-
-
- - peername(Socket) -> {ok, {Address, Port}} | {error, Reason} - Return peer address and port. - - Socket = sslsocket() - Address = ipaddress() - Port = integer() - - -

Returns the address and port number of the peer.

-
-
- - pid(Socket) -> pid() - Return the pid of the socket process. - - Socket = sslsocket() - - -

Returns the pid of the socket process. The returned pid should - only be used for receiving exit messages.

-
-
- - recv(Socket, Length) -> {ok, Data} | {error, Reason} - recv(Socket, Length, Timeout) -> {ok, Data} | {error, Reason} - Receive data on socket. - - Socket = sslsocket() - Length = integer() >= 0 - Timeout = integer() - Data = bytes() | binary() - - -

Receives data on socket Socket when the socket is in - passive mode, i.e. when the option {active, false} - has been specified. -

-

A notable return value is {error, closed} which - indicates that the socket is closed. -

-

A positive value of the Length argument is only - valid when the socket is in raw mode (option {packet, 0} is set, and the option binary is not - set); otherwise it should be set to 0, whence all available - bytes are returned. -

-

If the optional Timeout parameter is specified, and - no data was available within the given time, {error, timeout} is returned. The default value for - Timeout is infinity.

-
-
- - seed(Data) -> ok | {error, Reason} - Seed the ssl random generator. - - Data = iolist() | binary() - - -

Seeds the ssl random generator. -

-

It is strongly advised to seed the random generator after - the ssl application has been started, and before any - connections are established. Although the port program - interfacing to the OpenSSL libraries does a "random" seeding - of its own in order to make everything work properly, that - seeding is by no means random for the world since it has a - constant value which is known to everyone reading the source - code of the seeding. -

-

A notable return value is {error, edata}} indicating that - Data was not a binary nor an iolist.

-
-
- - send(Socket, Data) -> ok | {error, Reason} - Write data to a socket. - - Socket = sslsocket() - Data = iolist() | binary() - - -

Writes Data to Socket.

-

A notable return value is {error, closed} indicating that - the socket is closed.

-
-
- - setopts(Socket, Options) -> ok | {error, Reason} - Set socket options. - - Socket = sslsocket() - Options = [socketoption]() - - -

Sets options according to Options for the socket - Socket.

-
-
- - ssl_accept(Socket) -> ok | {error, Reason} - ssl_accept(Socket, Timeout) -> ok | {error, Reason} - Perform server-side SSL handshake and key exchange - - Socket = sslsocket() - Timeout = integer() - Reason = atom() - - -

The ssl_accept function establish the SSL connection - on the server side. It should be called directly after - transport_accept, in the spawned server-loop.

-

Note that the ssl connection is not complete until ssl_accept - has returned true, and if an error is returned, the socket - is unavailable and for instance close/1 will crash.

-
-
- - sockname(Socket) -> {ok, {Address, Port}} | {error, Reason} - Return the local address and port. - - Socket = sslsocket() - Address = ipaddress() - Port = integer() - - -

Returns the local address and port number of the socket - Socket.

-
-
- - transport_accept(Socket) -> {ok, NewSocket} | {error, Reason} - transport_accept(Socket, Timeout) -> {ok, NewSocket} | {error, Reason} - Accept an incoming connection and prepare for ssl_accept - - Socket = NewSocket = sslsocket() - Timeout = integer() - Reason = atom() - - -

Accepts an incoming connection request on a listen socket. - ListenSocket must be a socket returned from listen/2. - The socket returned should be passed to ssl_accept to - complete ssl handshaking and establishing the connection.

- -

The socket returned can only be used with ssl_accept, - no traffic can be sent or received before that call.

-
-

The accepted socket inherits the options set for ListenSocket - in listen/2.

-

The default value for Timeout is infinity. If - Timeout is specified, and no connection is accepted within - the given time, {error, timeout} is returned.

-
-
- - version() -> {ok, {SSLVsn, CompVsn, LibVsn}} - Return the version of SSL. - - SSLVsn = CompVsn = LibVsn = string()() - - -

Returns the SSL application version (SSLVsn), the library - version used when compiling the SSL application port program - (CompVsn), and the actual library version used when - dynamically linking in runtime (LibVsn). -

-

If the SSL application has not been started, CompVsn and - LibVsn are empty strings. -

-
-
-
- -
- ERRORS -

The possible error reasons and the corresponding diagnostic strings - returned by format_error/1 are either the same as those defined - in the inet(3) reference manual, or as follows: -

- - closed - -

Connection closed for the operation in question. -

-
- ebadsocket - -

Connection not found (internal error). -

-
- ebadstate - -

Connection not in connect state (internal error). -

-
- ebrokertype - -

Wrong broker type (internal error). -

-
- ecacertfile - -

Own CA certificate file is invalid. -

-
- ecertfile - -

Own certificate file is invalid. -

-
- echaintoolong - -

The chain of certificates provided by peer is too long. -

-
- ecipher - -

Own list of specified ciphers is invalid. -

-
- ekeyfile - -

Own private key file is invalid. -

-
- ekeymismatch - -

Own private key does not match own certificate. -

-
- enoissuercert - -

Cannot find certificate of issuer of certificate provided - by peer. -

-
- enoservercert - -

Attempt to do accept without having set own certificate. -

-
- enotlistener - -

Attempt to accept on a non-listening socket. -

-
- enoproxysocket - -

No proxy socket found (internal error). -

-
- enooptions - -

The list of options is empty. -

-
- enotstarted - -

The SSL application has not been started. -

-
- eoptions - -

Invalid list of options. -

-
- epeercert - -

Certificate provided by peer is in error. -

-
- epeercertexpired - -

Certificate provided by peer has expired. -

-
- epeercertinvalid - -

Certificate provided by peer is invalid. -

-
- eselfsignedcert - -

Certificate provided by peer is self signed. -

-
- esslaccept - -

Server SSL handshake procedure between client and server failed. -

-
- esslconnect - -

Client SSL handshake procedure between client and server failed. -

-
- esslerrssl - -

SSL protocol failure. Typically because of a fatal alert - from peer. -

-
- ewantconnect - -

Protocol wants to connect, which is not supported in - this version of the SSL application. -

-
- ex509lookup - -

Protocol wants X.509 lookup, which is not supported in - this version of the SSL application. -

-
- {badcall, Call} - -

Call not recognized for current mode (active or passive) and - state of socket. -

-
- {badcast, Cast} - -

Call not recognized for current mode (active or passive) and - state of socket. -

-
- {badinfo, Info} - -

Call not recognized for current mode (active or passive) and - state of socket. -

-
-
-
- -
- SEE ALSO -

gen_tcp(3), inet(3) public_key(3)

-
- -
- - diff --git a/lib/ssl/doc/src/refman.xml b/lib/ssl/doc/src/refman.xml index 68f84660f3..011819e82b 100644 --- a/lib/ssl/doc/src/refman.xml +++ b/lib/ssl/doc/src/refman.xml @@ -1,10 +1,10 @@ - +
- 19992010 + 19992011 Ericsson AB. All Rights Reserved. @@ -45,7 +45,6 @@ - diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 0c4c8796be..66d2644b76 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -121,8 +121,6 @@

hash() = md5 | sha

-

ssl_imp() = new | old - default is new.

-
@@ -177,9 +175,9 @@ by the peer also. - {ssl_imp, ssl_imp()} - Specify which ssl implementation you want to use. Defaults to - new. + {ssl_imp, new | old} + No longer has any meaning as the old implementation has + been removed, it will be ignored. {secure_renegotiate, boolean()} diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index 9c40d4ea53..dc69b53b28 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -41,13 +41,8 @@ MODULES= \ ssl \ ssl_alert \ ssl_app \ - ssl_broker \ - ssl_broker_sup \ ssl_dist_sup\ - ssl_server \ ssl_sup \ - ssl_prim \ - inet_ssl_dist \ inet_tls_dist \ ssl_certificate\ ssl_certificate_db\ @@ -67,7 +62,7 @@ MODULES= \ ssl_tls_dist_proxy INTERNAL_HRL_FILES = \ - ssl_int.hrl ssl_broker_int.hrl ssl_debug.hrl \ + ssl_debug.hrl \ ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \ ssl_record.hrl diff --git a/lib/ssl/src/inet_ssl_dist.erl b/lib/ssl/src/inet_ssl_dist.erl deleted file mode 100644 index 42a03a4879..0000000000 --- a/lib/ssl/src/inet_ssl_dist.erl +++ /dev/null @@ -1,453 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2011. 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(inet_ssl_dist). - -%% Handles the connection setup phase with other Erlang nodes. - --export([childspecs/0, listen/1, accept/1, accept_connection/5, - setup/5, close/1, select/1, is_node_name/1]). - -%% internal exports - --export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]). - --import(error_logger,[error_msg/2]). - --include_lib("kernel/include/net_address.hrl"). - --define(to_port(Socket, Data, Opts), - case ssl_prim:send(Socket, Data, Opts) of - {error, closed} -> - self() ! {ssl_closed, Socket}, - {error, closed}; - R -> - R - end). - --include_lib("kernel/include/dist.hrl"). --include_lib("kernel/include/dist_util.hrl"). - -%% ------------------------------------------------------------- -%% This function should return a valid childspec, so that -%% the primitive ssl_server gets supervised -%% ------------------------------------------------------------- -childspecs() -> - {ok, [{ssl_server_prim,{ssl_server, start_link_prim, []}, - permanent, 2000, worker, [ssl_server]}]}. - - -%% ------------------------------------------------------------ -%% Select this protocol based on node name -%% select(Node) => Bool -%% ------------------------------------------------------------ - -select(Node) -> - case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> true; - _ -> false - end. - -%% ------------------------------------------------------------ -%% Create the listen socket, i.e. the port that this erlang -%% node is accessible through. -%% ------------------------------------------------------------ - -listen(Name) -> - case ssl_prim:listen(0, [{active, false}, {packet,4}] ++ - get_ssl_options(server)) of - {ok, Socket} -> - TcpAddress = get_tcp_address(Socket), - {_,Port} = TcpAddress#net_address.address, - {ok, Creation} = erl_epmd:register_node(Name, Port), - {ok, {Socket, TcpAddress, Creation}}; - Error -> - Error - end. - -%% ------------------------------------------------------------ -%% Accepts new connection attempts from other Erlang nodes. -%% ------------------------------------------------------------ - -accept(Listen) -> - spawn_link(?MODULE, accept_loop, [self(), Listen]). - -accept_loop(Kernel, Listen) -> - process_flag(priority, max), - case ssl_prim:accept(Listen) of - {ok, Socket} -> - Kernel ! {accept,self(),Socket,inet,ssl}, - controller(Kernel, Socket), - accept_loop(Kernel, Listen); - Error -> - exit(Error) - end. - -controller(Kernel, Socket) -> - receive - {Kernel, controller, Pid} -> - flush_controller(Pid, Socket), - ssl_prim:controlling_process(Socket, Pid), - flush_controller(Pid, Socket), - Pid ! {self(), controller}; - {Kernel, unsupported_protocol} -> - exit(unsupported_protocol) - end. - -flush_controller(Pid, Socket) -> - receive - {ssl, Socket, Data} -> - Pid ! {ssl, Socket, Data}, - flush_controller(Pid, Socket); - {ssl_closed, Socket} -> - Pid ! {ssl_closed, Socket}, - flush_controller(Pid, Socket) - after 0 -> - ok - end. - -%% ------------------------------------------------------------ -%% Accepts a new connection attempt from another Erlang node. -%% Performs the handshake with the other side. -%% ------------------------------------------------------------ - -accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - spawn_link(?MODULE, do_accept, - [self(), AcceptPid, Socket, MyNode, - Allowed, SetupTime]). - -%% Suppress dialyzer warning, we do not really care about old ssl code -%% as we intend to remove it. --spec(do_accept(_,_,_,_,_,_) -> no_return()). -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - process_flag(priority, max), - receive - {AcceptPid, controller} -> - Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of - true -> - HSData = #hs_data{ - kernel_pid = Kernel, - this_node = MyNode, - socket = Socket, - timer = Timer, - this_flags = 0, - allowed = Allowed, - f_send = fun(S,D) -> ssl_prim:send(S,D) end, - f_recv = fun(S,N,T) -> ssl_prim:recv(S,N,T) - end, - f_setopts_pre_nodeup = - fun(S) -> - ssl_prim:setopts(S, - [{active, false}]) - end, - f_setopts_post_nodeup = - fun(S) -> - ssl_prim:setopts(S, - [{deliver, port}, - {active, true}]) - end, - f_getll = fun(S) -> - ssl_prim:getll(S) - end, - f_address = fun get_remote_id/2, - mf_tick = fun ?MODULE:tick/1, - mf_getstat = fun ?MODULE:getstat/1 - }, - dist_util:handshake_other_started(HSData); - {false,IP} -> - error_msg("** Connection attempt from " - "disallowed IP ~w ** ~n", [IP]), - ?shutdown(no_node) - end - end. - -%% ------------------------------------------------------------ -%% Get remote information about a Socket. -%% ------------------------------------------------------------ - -get_remote_id(Socket, Node) -> - {ok, Address} = ssl_prim:peername(Socket), - [_, Host] = split_node(atom_to_list(Node), $@, []), - #net_address { - address = Address, - host = Host, - protocol = ssl, - family = inet }. - -%% ------------------------------------------------------------ -%% Setup a new connection to another Erlang node. -%% Performs the handshake with the other side. -%% ------------------------------------------------------------ - -setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> - spawn_link(?MODULE, do_setup, [self(), - Node, - Type, - MyNode, - LongOrShortNames, - SetupTime]). - -%% Suppress dialyzer warning, we do not really care about old ssl code -%% as we intend to remove it. --spec(do_setup(_,_,_,_,_,_) -> no_return()). -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> - process_flag(priority, max), - ?trace("~p~n",[{inet_ssl_dist,self(),setup,Node}]), - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet) of - {ok, Ip} -> - Timer = dist_util:start_timer(SetupTime), - case erl_epmd:port_please(Name, Ip) of - {port, TcpPort, Version} -> - ?trace("port_please(~p) -> version ~p~n", - [Node,Version]), - dist_util:reset_timer(Timer), - case ssl_prim:connect(Ip, TcpPort, - [{active, false}, - {packet,4}] ++ - get_ssl_options(client)) of - {ok, Socket} -> - HSData = #hs_data{ - kernel_pid = Kernel, - other_node = Node, - this_node = MyNode, - socket = Socket, - timer = Timer, - this_flags = 0, - other_version = Version, - f_send = fun(S,D) -> - ssl_prim:send(S,D) - end, - f_recv = fun(S,N,T) -> - ssl_prim:recv(S,N,T) - end, - f_setopts_pre_nodeup = - fun(S) -> - ssl_prim:setopts - (S, - [{active, false}]) - end, - f_setopts_post_nodeup = - fun(S) -> - ssl_prim:setopts - (S, - [{deliver, port},{active, true}]) - end, - f_getll = fun(S) -> - ssl_prim:getll(S) - end, - f_address = - fun(_,_) -> - #net_address { - address = {Ip,TcpPort}, - host = Address, - protocol = ssl, - family = inet} - end, - mf_tick = fun ?MODULE:tick/1, - mf_getstat = fun ?MODULE:getstat/1, - request_type = Type - }, - dist_util:handshake_we_started(HSData); - _ -> - %% Other Node may have closed since - %% port_please ! - ?trace("other node (~p) " - "closed since port_please.~n", - [Node]), - ?shutdown(Node) - end; - _ -> - ?trace("port_please (~p) " - "failed.~n", [Node]), - ?shutdown(Node) - end; - _Other -> - ?trace("inet_getaddr(~p) " - "failed (~p).~n", [Node,Other]), - ?shutdown(Node) - end. - -%% -%% Close a socket. -%% -close(Socket) -> - ssl_prim:close(Socket). - - -%% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> - case split_node(atom_to_list(Node), $@, []) of - [Name|Tail] when Tail =/= [] -> - Host = lists:append(Tail), - case split_node(Host, $., []) of - [_] when LongOrShortNames == longnames -> - error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); - [_, _ | _] when LongOrShortNames == shortnames -> - error_msg("** System NOT running to use fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); - _ -> - [Name, Host] - end; - [_] -> - error_msg("** Nodename ~p illegal, no '@' character **~n", - [Node]), - ?shutdown(Node); - _ -> - error_msg("** Nodename ~p illegal **~n", [Node]), - ?shutdown(Node) - end. - -split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])]; -split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]); -split_node([], _, Ack) -> [lists:reverse(Ack)]. - -%% ------------------------------------------------------------ -%% Fetch local information about a Socket. -%% ------------------------------------------------------------ -get_tcp_address(Socket) -> - {ok, Address} = ssl_prim:sockname(Socket), - {ok, Host} = inet:gethostname(), - #net_address { - address = Address, - host = Host, - protocol = ssl, - family = inet - }. - -%% ------------------------------------------------------------ -%% Do only accept new connection attempts from nodes at our -%% own LAN, if the check_ip environment parameter is true. -%% ------------------------------------------------------------ -check_ip(Socket) -> - case application:get_env(check_ip) of - {ok, true} -> - case get_ifs(Socket) of - {ok, IFs, IP} -> - check_ip(IFs, IP); - _ -> - ?shutdown(no_node) - end; - _ -> - true - end. - -get_ifs(Socket) -> - case ssl_prim:peername(Socket) of - {ok, {IP, _}} -> - case ssl_prim:getif(Socket) of - {ok, IFs} -> {ok, IFs, IP}; - Error -> Error - end; - Error -> - Error - end. - -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of - {M, M} -> true; - _ -> check_ip(IFs, PeerIP) - end; -check_ip([], PeerIP) -> - {false, PeerIP}. - -mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4}. - -is_node_name(Node) when is_atom(Node) -> - case split_node(atom_to_list(Node), $@, []) of - [_, _Host] -> true; - _ -> false - end; -is_node_name(_Node) -> - false. -tick(Sock) -> - ?to_port(Sock,[],[force]). -getstat(Socket) -> - case ssl_prim:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of - {ok, Stat} -> - split_stat(Stat,0,0,0); - Error -> - Error - end. - -split_stat([{recv_cnt, R}|Stat], _, W, P) -> - split_stat(Stat, R, W, P); -split_stat([{send_cnt, W}|Stat], R, _, P) -> - split_stat(Stat, R, W, P); -split_stat([{send_pend, P}|Stat], R, W, _) -> - split_stat(Stat, R, W, P); -split_stat([], R, W, P) -> - {ok, R, W, P}. - - -get_ssl_options(Type) -> - case init:get_argument(ssl_dist_opt) of - {ok, Args} -> - ssl_options(Type, Args); - _ -> - [] - end. - -ssl_options(_,[]) -> - []; -ssl_options(server, [["server_certfile", Value]|T]) -> - [{certfile, Value} | ssl_options(server,T)]; -ssl_options(client, [["client_certfile", Value]|T]) -> - [{certfile, Value} | ssl_options(client,T)]; -ssl_options(server, [["server_cacertfile", Value]|T]) -> - [{cacertfile, Value} | ssl_options(server,T)]; -ssl_options(server, [["server_keyfile", Value]|T]) -> - [{keyfile, Value} | ssl_options(server,T)]; -ssl_options(Type, [["client_certfile", _Value]|T]) -> - ssl_options(Type,T); -ssl_options(Type, [["server_certfile", _Value]|T]) -> - ssl_options(Type,T); -ssl_options(Type, [[Item, Value]|T]) -> - [{atomize(Item),fixup(Value)} | ssl_options(Type,T)]; -ssl_options(Type, [[Item,Value |T1]|T2]) -> - ssl_options(atomize(Type),[[Item,Value],T1|T2]); -ssl_options(_,_) -> - exit(malformed_ssl_dist_opt). - -fixup(Value) -> - case catch list_to_integer(Value) of - {'EXIT',_} -> - Value; - Int -> - Int - end. - -atomize(List) when is_list(List) -> - list_to_atom(List); -atomize(Atom) when is_atom(Atom) -> - Atom. diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index afe19da900..13d5eaf4d7 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -4,14 +4,9 @@ {modules, [ssl, ssl_app, ssl_sup, - ssl_server, - ssl_broker, - ssl_broker_sup, - ssl_prim, inet_tls_dist, ssl_tls_dist_proxy, ssl_dist_sup, - inet_ssl_dist, ssl_tls1, ssl_ssl3, ssl_ssl2, @@ -29,7 +24,7 @@ ssl_certificate, ssl_alert ]}, - {registered, [ssl_sup, ssl_server, ssl_broker_sup]}, + {registered, [ssl_sup, ssl_manager]}, {applications, [crypto, public_key, kernel, stdlib]}, {env, []}, {mod, {ssl_app, []}}]}. diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 55510e41e9..f812231c71 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -25,18 +25,18 @@ -export([start/0, start/1, stop/0, transport_accept/1, transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3, - ciphers/0, cipher_suites/0, cipher_suites/1, close/1, shutdown/2, + cipher_suites/0, cipher_suites/1, close/1, shutdown/2, connect/3, connect/2, connect/4, connection_info/1, - controlling_process/2, listen/2, pid/1, peername/1, recv/2, recv/3, - send/2, getopts/2, setopts/2, seed/1, sockname/1, peercert/1, - peercert/2, version/0, versions/0, session_info/1, format_error/1, + controlling_process/2, listen/2, pid/1, peername/1, recv/2, + recv/3, send/2, getopts/2, setopts/2, sockname/1, + versions/0, session_info/1, format_error/1, renegotiate/1]). %% Should be deprecated as soon as old ssl is removed -%%-deprecated({pid, 1, next_major_release}). --deprecated({peercert, 2, next_major_release}). +-deprecated({pid, 1, next_major_release}). +%-deprecated({peercert, 2, next_major_release}). --include("ssl_int.hrl"). +%%-include("ssl_int.hrl"). -include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). @@ -134,20 +134,13 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket) -> connect(Host, Port, Options) -> connect(Host, Port, Options, infinity). -connect(Host, Port, Options0, Timeout) -> - case proplists:get_value(ssl_imp, Options0, new) of - new -> - new_connect(Host, Port, Options0, Timeout); - old -> - %% Allow the option reuseaddr to be present - %% so that new and old ssl can be run by the same - %% code, however the option will be ignored by old ssl - %% that hardcodes reuseaddr to true in its portprogram. - Options1 = proplists:delete(reuseaddr, Options0), - Options = proplists:delete(ssl_imp, Options1), - old_connect(Host, Port, Options, Timeout); - Value -> - {error, {eoptions, {ssl_imp, Value}}} +connect(Host, Port, Options, Timeout) -> + try handle_options(Options, client) of + {ok, Config} -> + do_connect(Host,Port,Config,Timeout) + catch + throw:Error -> + Error end. %%-------------------------------------------------------------------- @@ -159,21 +152,19 @@ connect(Host, Port, Options0, Timeout) -> listen(_Port, []) -> {error, enooptions}; listen(Port, Options0) -> - case proplists:get_value(ssl_imp, Options0, new) of - new -> - new_listen(Port, Options0); - old -> - %% Allow the option reuseaddr to be present - %% so that new and old ssl can be run by the same - %% code, however the option will be ignored by old ssl - %% that hardcodes reuseaddr to true in its portprogram. - Options1 = proplists:delete(reuseaddr, Options0), - Options = proplists:delete(ssl_imp, Options1), - old_listen(Port, Options); - Value -> - {error, {eoptions, {ssl_imp, Value}}} + try + {ok, Config} = handle_options(Options0, server), + #config{cb={CbModule, _, _, _},inet_user=Options} = Config, + case CbModule:listen(Port, Options) of + {ok, ListenSocket} -> + {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}}; + Err = {error, _} -> + Err + end + catch + Error = {error, _} -> + Error end. - %%-------------------------------------------------------------------- -spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} | {error, reason()}. @@ -185,8 +176,7 @@ listen(Port, Options0) -> transport_accept(ListenSocket) -> transport_accept(ListenSocket, infinity). -transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts}}, - fd = new_ssl}, Timeout) -> +transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts}}}, Timeout) -> %% The setopt could have been invoked on the listen socket %% and options should be inherited. @@ -208,12 +198,7 @@ transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts} end; {error, Reason} -> {error, Reason} - end; - -transport_accept(#sslsocket{} = ListenSocket, Timeout) -> - ensure_old_ssl_started(), - {ok, Pid} = ssl_broker:start_broker(acceptor), - ssl_broker:transport_accept(Pid, ListenSocket, Timeout). + end. %%-------------------------------------------------------------------- -spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}. @@ -227,16 +212,11 @@ transport_accept(#sslsocket{} = ListenSocket, Timeout) -> ssl_accept(ListenSocket) -> ssl_accept(ListenSocket, infinity). -ssl_accept(#sslsocket{fd = new_ssl} = Socket, Timeout) -> +ssl_accept(#sslsocket{} = Socket, Timeout) -> ssl_connection:handshake(Socket, Timeout); ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) -> - ssl_accept(ListenSocket, SslOptions, infinity); - -%% Old ssl -ssl_accept(#sslsocket{} = Socket, Timeout) -> - ensure_old_ssl_started(), - ssl_broker:ssl_accept(Socket, Timeout). + ssl_accept(ListenSocket, SslOptions, infinity). ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> EmulatedOptions = emulated_options(), @@ -257,25 +237,18 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> %% %% Description: Close an ssl connection %%-------------------------------------------------------------------- -close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}) -> +close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}) -> CbMod:close(ListenSocket); -close(#sslsocket{pid = Pid, fd = new_ssl}) -> - ssl_connection:close(Pid); -close(Socket = #sslsocket{}) -> - ensure_old_ssl_started(), - ssl_broker:close(Socket). +close(#sslsocket{pid = Pid}) -> + ssl_connection:close(Pid). %%-------------------------------------------------------------------- -spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}. %% %% Description: Sends data over the ssl connection %%-------------------------------------------------------------------- -send(#sslsocket{pid = Pid, fd = new_ssl}, Data) -> - ssl_connection:send(Pid, Data); - -send(#sslsocket{} = Socket, Data) -> - ensure_old_ssl_started(), - ssl_broker:send(Socket, Data). +send(#sslsocket{pid = Pid}, Data) -> + ssl_connection:send(Pid, Data). %%-------------------------------------------------------------------- -spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}. @@ -286,11 +259,7 @@ send(#sslsocket{} = Socket, Data) -> recv(Socket, Length) -> recv(Socket, Length, infinity). recv(#sslsocket{pid = Pid, fd = new_ssl}, Length, Timeout) -> - ssl_connection:recv(Pid, Length, Timeout); - -recv(Socket = #sslsocket{}, Length, Timeout) -> - ensure_old_ssl_started(), - ssl_broker:recv(Socket, Length, Timeout). + ssl_connection:recv(Pid, Length, Timeout). %%-------------------------------------------------------------------- -spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}. @@ -298,13 +267,8 @@ recv(Socket = #sslsocket{}, Length, Timeout) -> %% Description: Changes process that receives the messages when active = true %% or once. %%-------------------------------------------------------------------- -controlling_process(#sslsocket{pid = Pid, fd = new_ssl}, NewOwner) - when is_pid(Pid) -> - ssl_connection:new_user(Pid, NewOwner); - -controlling_process(Socket, NewOwner) when is_pid(NewOwner) -> - ensure_old_ssl_started(), - ssl_broker:controlling_process(Socket, NewOwner). +controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid) -> + ssl_connection:new_user(Pid, NewOwner). %%-------------------------------------------------------------------- -spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} | @@ -312,80 +276,16 @@ controlling_process(Socket, NewOwner) when is_pid(NewOwner) -> %% %% Description: Returns ssl protocol and cipher used for the connection %%-------------------------------------------------------------------- -connection_info(#sslsocket{pid = Pid, fd = new_ssl}) -> - ssl_connection:info(Pid); - -connection_info(#sslsocket{} = Socket) -> - ensure_old_ssl_started(), - ssl_broker:connection_info(Socket). - -%%-------------------------------------------------------------------- --spec peercert(#sslsocket{}) ->{ok, der_cert()} | {error, reason()}. -%% -%% Description: Returns the peercert. -%%-------------------------------------------------------------------- -peercert(Socket) -> - peercert(Socket, []). - -peercert(#sslsocket{pid = Pid, fd = new_ssl}, Opts) -> - case ssl_connection:peer_certificate(Pid) of - {ok, undefined} -> - {error, no_peercert}; - {ok, BinCert} -> - decode_peercert(BinCert, Opts); - {error, Reason} -> - {error, Reason} - end; - -peercert(#sslsocket{} = Socket, Opts) -> - ensure_old_ssl_started(), - case ssl_broker:peercert(Socket) of - {ok, Bin} -> - decode_peercert(Bin, Opts); - {error, Reason} -> - {error, Reason} - end. - - -decode_peercert(BinCert, Opts) -> - PKOpts = [case Opt of ssl -> otp; pkix -> plain end || - Opt <- Opts, Opt =:= ssl orelse Opt =:= pkix], - case PKOpts of - [Opt] -> - select_part(Opt, public_key:pkix_decode_cert(BinCert, Opt), Opts); - [] -> - {ok, BinCert} - end. - -select_part(otp, Cert, Opts) -> - case lists:member(subject, Opts) of - true -> - TBS = Cert#'OTPCertificate'.tbsCertificate, - {ok, TBS#'OTPTBSCertificate'.subject}; - false -> - {ok, Cert} - end; - -select_part(plain, Cert, Opts) -> - case lists:member(subject, Opts) of - true -> - TBS = Cert#'Certificate'.tbsCertificate, - {ok, TBS#'TBSCertificate'.subject}; - false -> - {ok, Cert} - end. +connection_info(#sslsocket{pid = Pid}) -> + ssl_connection:info(Pid). %%-------------------------------------------------------------------- -spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}. %% %% Description: same as inet:peername/1. %%-------------------------------------------------------------------- -peername(#sslsocket{fd = new_ssl, pid = Pid}) -> - ssl_connection:peername(Pid); - -peername(#sslsocket{} = Socket) -> - ensure_old_ssl_started(), - ssl_broker:peername(Socket). +peername(#sslsocket{pid = Pid}) -> + ssl_connection:peername(Pid). %%-------------------------------------------------------------------- -spec cipher_suites() -> [erl_cipher_suite()]. @@ -410,9 +310,9 @@ cipher_suites(openssl) -> %% %% Description: Gets options %%-------------------------------------------------------------------- -getopts(#sslsocket{fd = new_ssl, pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) -> +getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) -> ssl_connection:get_opts(Pid, OptionTags); -getopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptionTags) when is_list(OptionTags) -> +getopts(#sslsocket{pid = {ListenSocket, _}}, OptionTags) when is_list(OptionTags) -> try inet:getopts(ListenSocket, OptionTags) of {ok, _} = Result -> Result; @@ -422,18 +322,15 @@ getopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptionTags) when is_l _:_ -> {error, {eoptions, {inet_options, OptionTags}}} end; -getopts(#sslsocket{fd = new_ssl}, OptionTags) -> - {error, {eoptions, {inet_options, OptionTags}}}; -getopts(#sslsocket{} = Socket, OptionTags) -> - ensure_old_ssl_started(), - ssl_broker:getopts(Socket, OptionTags). +getopts(#sslsocket{}, OptionTags) -> + {error, {eoptions, {inet_options, OptionTags}}}. %%-------------------------------------------------------------------- -spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}. %% %% Description: Sets options %%-------------------------------------------------------------------- -setopts(#sslsocket{fd = new_ssl, pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) -> +setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) -> try proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Options0) of Options -> @@ -443,7 +340,7 @@ setopts(#sslsocket{fd = new_ssl, pid = Pid}, Options0) when is_pid(Pid), is_list {error, {eoptions, {not_a_proplist, Options0}}} end; -setopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, Options) when is_list(Options) -> +setopts(#sslsocket{pid = {ListenSocket, _}}, Options) when is_list(Options) -> try inet:setopts(ListenSocket, Options) of ok -> ok; @@ -453,20 +350,17 @@ setopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, Options) when is_list _:Error -> {error, {eoptions, {inet_options, Options, Error}}} end; -setopts(#sslsocket{fd = new_ssl}, Options) -> - {error, {eoptions,{not_a_proplist, Options}}}; -setopts(#sslsocket{} = Socket, Options) -> - ensure_old_ssl_started(), - ssl_broker:setopts(Socket, Options). +setopts(#sslsocket{}, Options) -> + {error, {eoptions,{not_a_proplist, Options}}}. %%--------------------------------------------------------------- -spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}. %% %% Description: Same as gen_tcp:shutdown/2 %%-------------------------------------------------------------------- -shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}, How) -> +shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}, How) -> CbMod:shutdown(ListenSocket, How); -shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) -> +shutdown(#sslsocket{pid = Pid}, How) -> ssl_connection:shutdown(Pid, How). %%-------------------------------------------------------------------- @@ -474,25 +368,11 @@ shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) -> %% %% Description: Same as inet:sockname/1 %%-------------------------------------------------------------------- -sockname(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}) -> +sockname(#sslsocket{pid = {ListenSocket, _}}) -> inet:sockname(ListenSocket); -sockname(#sslsocket{fd = new_ssl, pid = Pid}) -> - ssl_connection:sockname(Pid); - -sockname(#sslsocket{} = Socket) -> - ensure_old_ssl_started(), - ssl_broker:sockname(Socket). - -%%--------------------------------------------------------------- --spec seed(term()) ->term(). -%% -%% Description: Only used by old ssl. -%%-------------------------------------------------------------------- -%% TODO: crypto:seed ? -seed(Data) -> - ensure_old_ssl_started(), - ssl_server:seed(Data). +sockname(#sslsocket{pid = Pid}) -> + ssl_connection:sockname(Pid). %%--------------------------------------------------------------- -spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}. @@ -548,63 +428,6 @@ format_error(esslconnect) -> format_error({eoptions, Options}) -> lists:flatten(io_lib:format("Error in options list: ~p~n", [Options])); -%%%%%%%%%%%% START OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -format_error(ebadsocket) -> - "Connection not found (internal error)."; -format_error(ebadstate) -> - "Connection not in connect state (internal error)."; -format_error(ebrokertype) -> - "Wrong broker type (internal error)."; -format_error(echaintoolong) -> - "The chain of certificates provided by peer is too long."; -format_error(ecipher) -> - "Own list of specified ciphers is invalid."; -format_error(ekeymismatch) -> - "Own private key does not match own certificate."; -format_error(enoissuercert) -> - "Cannot find certificate of issuer of certificate provided by peer."; -format_error(enoservercert) -> - "Attempt to do accept without having set own certificate."; -format_error(enotlistener) -> - "Attempt to accept on a non-listening socket."; -format_error(enoproxysocket) -> - "No proxy socket found (internal error or max number of file " - "descriptors exceeded)."; -format_error(enooptions) -> - "List of options is empty."; -format_error(enotstarted) -> - "The SSL application has not been started."; -format_error(eoptions) -> - "Invalid list of options."; -format_error(epeercert) -> - "Certificate provided by peer is in error."; -format_error(epeercertexpired) -> - "Certificate provided by peer has expired."; -format_error(epeercertinvalid) -> - "Certificate provided by peer is invalid."; -format_error(eselfsignedcert) -> - "Certificate provided by peer is self signed."; -format_error(esslerrssl) -> - "SSL protocol failure. Typically because of a fatal alert from peer."; -format_error(ewantconnect) -> - "Protocol wants to connect, which is not supported in this " - "version of the SSL application."; -format_error(ex509lookup) -> - "Protocol wants X.509 lookup, which is not supported in this " - "version of the SSL application."; -format_error({badcall, _Call}) -> - "Call not recognized for current mode (active or passive) and state " - "of socket."; -format_error({badcast, _Cast}) -> - "Call not recognized for current mode (active or passive) and state " - "of socket."; - -format_error({badinfo, _Info}) -> - "Call not recognized for current mode (active or passive) and state " - "of socket."; - -%%%%%%%%%%%%%%%%%% END OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - format_error(Error) -> case (catch inet:format_error(Error)) of "unkknown POSIX" ++ _ -> @@ -618,16 +441,7 @@ format_error(Error) -> %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- -new_connect(Address, Port, Options, Timeout) when is_list(Options) -> - try handle_options(Options, client) of - {ok, Config} -> - do_new_connect(Address,Port,Config,Timeout) - catch - throw:Error -> - Error - end. - -do_new_connect(Address, Port, +do_connect(Address, Port, #config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts, emulated=EmOpts,inet_ssl=SocketOpts}, Timeout) -> @@ -647,35 +461,9 @@ do_new_connect(Address, Port, {error, {eoptions, {inet_options, UserOpts}}} end. -old_connect(Address, Port, Options, Timeout) -> - ensure_old_ssl_started(), - {ok, Pid} = ssl_broker:start_broker(connector), - ssl_broker:connect(Pid, Address, Port, Options, Timeout). - -new_listen(Port, Options0) -> - try - {ok, Config} = handle_options(Options0, server), - #config{cb={CbModule, _, _, _},inet_user=Options} = Config, - case CbModule:listen(Port, Options) of - {ok, ListenSocket} -> - {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}}; - Err = {error, _} -> - Err - end - catch - Error = {error, _} -> - Error - end. - -old_listen(Port, Options) -> - ensure_old_ssl_started(), - {ok, Pid} = ssl_broker:start_broker(listener), - ssl_broker:listen(Pid, Port, Options). - handle_options(Opts0, _Role) -> Opts = proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Opts0), - ReuseSessionFun = fun(_, _, _, _) -> true end, DefaultVerifyNoneFun = @@ -769,8 +557,6 @@ handle_option(OptionName, Opts, Default) -> validate_option(versions, Versions) -> validate_versions(Versions, Versions); -validate_option(ssl_imp, Value) when Value == new; Value == old -> - Value; validate_option(verify, Value) when Value == verify_none; Value == verify_peer -> Value; @@ -913,7 +699,6 @@ emulated_options() -> internal_inet_values() -> [{packet_size,0},{packet, 0},{header, 0},{active, false},{mode,binary}]. - %%[{packet, ssl},{header, 0},{active, false},{mode,binary}]. socket_options(InetValues) -> #socket_options{ @@ -974,47 +759,14 @@ cipher_suites(Version, Ciphers0) -> no_format(Error) -> lists:flatten(io_lib:format("No format string for error: \"~p\" available.", [Error])). - -%% Start old ssl port program if needed. -ensure_old_ssl_started() -> - case whereis(ssl_server) of - undefined -> - (catch supervisor:start_child(ssl_sup, - {ssl_server, {ssl_server, start_link, []}, - permanent, 2000, worker, [ssl_server]})); - _ -> - ok - end. - -%%%%%%%%%%%%%%%% Deprecated %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -ciphers() -> - ensure_old_ssl_started(), - case (catch ssl_server:ciphers()) of - {'EXIT', _} -> - {error, enotstarted}; - Res = {ok, _} -> - Res - end. - -version() -> - ensure_old_ssl_started(), - SSLVsn = ?VSN, - {CompVsn, LibVsn} = case (catch ssl_server:version()) of - {'EXIT', _} -> - {"", ""}; - {ok, Vsns} -> - Vsns - end, - {ok, {SSLVsn, CompVsn, LibVsn}}. - %% Only used to remove exit messages from old ssl %% First is a nonsense clause to provide some %% backward compability for orber that uses this %% function in a none recommended way, but will %% work correctly if a valid pid is returned. +%% Deprcated to be removed in r16 pid(#sslsocket{fd = new_ssl}) -> - whereis(ssl_connection_sup); + whereis(ssl_connection_sup); pid(#sslsocket{pid = Pid}) -> - Pid. + Pid. diff --git a/lib/ssl/src/ssl_broker.erl b/lib/ssl/src/ssl_broker.erl deleted file mode 100644 index 7ef88baf2b..0000000000 --- a/lib/ssl/src/ssl_broker.erl +++ /dev/null @@ -1,1188 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2010. 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% -%% - -%% - -%%% Purpose : SSL broker - --module(ssl_broker). --behaviour(gen_server). - -%% This module implements brokers for ssl. A broker is either a connector, -%% an acceptor, or a listener. All brokers are children to ssl_broker_sup, -%% to which they are linked. Each broker is also linked to ssl_server, and -%% to its client. -%% -%% The purpose of the broker is to set up SSL connections through calls to -%% ssl_server and gen_tcp. All control information goes to the server, -%% while all data is exchanged directly between gen_tcp and the port program -%% of the ssl_server. -%% -%% A broker is created by a call to start_broker/3 (do *not* use start_link/4 -%% - it is for ssl_broker_sup to call that one), and then call listen/3, -%% accept/4, or connect/5. -%% -%% The following table shows all functions dependency on status, active -%% mode etc. -%% -%% Permitted status transitions: -%% -%% nil -> open -%% open -> closing | closed (termination) -%% closing -> closed (termination) -%% -%% We are rather sloppy about nil, and consider open/closing == !closed, -%% open/closing/closed === any etc. -%% -%% -%% function/ valid mode new -%% message status state -%% -%% calls -%% ----- -%% recv open passive ditto -%% send open any ditto -%% transport_accept nil any open -%% ssl_accept nil any open -%% connect nil any open -%% listen nil any open -%% peername open/closing any ditto -%% setopts open/closing any ditto -%% getopts open/closing any ditto -%% sockname open/closing any ditto -%% peercert open/closing any ditto -%% inhibit any any ditto -%% release any any ditto -%% close any any closed (1) -%% -%% info -%% ---- -%% tcp open active ditto -%% tcp_closed open | closing active closing -%% tcp_error open | closing active closing -%% -%% (1) We just terminate. -%% -%% TODO -%% -%% XXX Timeouts are not checked (integer or infinity). -%% -%% XXX The collector thing is not gen_server compliant. -%% -%% NOTE: There are three different "modes": (a) passive or active mode, -%% specified as {active, bool()}, and (b) list or binary mode, specified -%% as {mode, list | binary}, and (c) encrypted or clear mode -%% - --include("ssl_int.hrl"). - -%% External exports - --export([start_broker/1, start_broker/2, start_link/3, - transport_accept/3, ssl_accept/2, - close/1, connect/5, connection_info/1, controlling_process/2, - listen/3, recv/3, send/2, getopts/2, getopts/3, setopts/2, - sockname/1, peername/1, peercert/1]). - --export([listen_prim/5, connect_prim/8, - transport_accept_prim/5, ssl_accept_prim/6]). - -%% Internal exports - --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - code_change/3, terminate/2, collector_init/1]). - --include("ssl_broker_int.hrl"). - -%% start_broker(Type) -> {ok, Pid} | {error, Reason} -%% start_broker(Type, GenOpts) -> {ok, Pid} | {error, Reason} -%% Type = accept | connect | listen -%% GenOpts = /standard gen_server options/ -%% -%% This is the function to be called from the interface module ssl.erl. -%% Links to the caller. -%% -start_broker(Type) -> - start_broker(Type, []). - -start_broker(Type, GenOpts) -> - case lists:member(Type, [listener, acceptor, connector]) of - true -> - case supervisor:start_child(ssl_broker_sup, - [self(), Type, GenOpts]) of - {ok, Pid} -> - link(Pid), - {ok, Pid}; - {error, Reason} -> - {error, Reason} - end; - false -> - {error, ebrokertype} - end. - -%% start_link(Client, Type, GenOpts) -> {ok, Pid} | {error, Reason} -%% -%% Type = accept | connect | listen -%% GenOpts = /standard gen_server options/ -%% -%% This function is called by ssl_broker_sup and must *not* be called -%% from an interface module (ssl.erl). - -start_link(Client, Type, GenOpts) -> - gen_server:start_link(?MODULE, [Client, Type], GenOpts). - - -%% accept(Pid, ListenSocket, Timeout) -> {ok, Socket} | {error, Reason} -%% -%% Types: Pid = pid() of acceptor -%% ListenSocket = Socket = sslsocket() -%% Timeout = timeout() -%% -%% accept(Pid, ListenSocket, Timeout) -%% when is_pid(Pid), is_record(ListenSocket, sslsocket) -> -%% Req = {accept, self(), ListenSocket, Timeout}, -%% gen_server:call(Pid, Req, infinity). - -%% transport_accept(Pid, ListenSocket, Timeout) -> {ok, Socket} | -%% {error, Reason} -%% -%% Types: Pid = pid() of acceptor -%% ListenSocket = Socket = sslsocket() -%% Timeout = timeout() -%% -transport_accept(Pid, #sslsocket{} = ListenSocket, Timeout) when is_pid(Pid) -> - Req = {transport_accept, self(), ListenSocket, Timeout}, - gen_server:call(Pid, Req, infinity). - -%% ssl_accept(Pid, Socket, Timeout) -> {ok, Socket} | {error, Reason} -%% -%% Types: Pid = pid() of acceptor -%% ListenSocket = Socket = sslsocket() -%% Timeout = timeout() -%% -ssl_accept(#sslsocket{pid = Pid} = Socket, Timeout) -> - Req = {ssl_accept, self(), Socket, Timeout}, - gen_server:call(Pid, Req, infinity). - -%% close(Socket) -> ok | {error, Reason} -%% -%% Types: Socket = sslsocket() | pid() -%% -close(#sslsocket{pid = Pid}) -> - close(Pid); -close(Pid) when is_pid(Pid) -> - gen_server:call(Pid, {close, self()}, infinity). - -%% connect(Pid, Address, Port, Opts, Timeout) -> {ok, Socket} | {error, Reason} -%% -%% Types: Pid = pid() of connector -%% Address = string() | {byte(), byte(), byte(), byte()} -%% Port = int() -%% Opts = options() -%% Timeout = timeout() -%% Socket = sslsocket() -%% -connect(Pid, Address, Port, Opts, Timeout) when is_pid(Pid), is_list(Opts) -> - case are_connect_opts(Opts) of - true -> - Req = {connect, self(), Address, Port, Opts, Timeout}, - gen_server:call(Pid, Req, infinity); - false -> - {error, eoptions} - end. - -%% -%% connection_info(Socket) -> {ok, {Protocol, Cipher} | {error, Reason} -%% -connection_info(#sslsocket{pid = Pid}) -> - Req = {connection_info, self()}, - gen_server:call(Pid, Req, infinity). - -%% controlling_process(Socket, NewOwner) -> ok | {error, Reason} - -controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(NewOwner) -> - case gen_server:call(Pid, {inhibit_msgs, self()}, infinity) of - ok -> - transfer_messages(Pid, NewOwner), - gen_server:call(Pid, {release_msgs, self(), NewOwner}, infinity); - Error -> - Error - end. - -%% listen(Pid, Port, Opts) -> {ok, ListenSocket} | {error, Reason} -%% -%% Types: Pid = pid() of listener -%% Port = int() -%% Opts = options() -%% ListenSocket = sslsocket() -%% -listen(Pid, Port, Opts) when is_pid(Pid) -> - case are_listen_opts(Opts) of - true -> - Req = {listen, self(), Port, Opts}, - gen_server:call(Pid, Req, infinity); - false -> - {error, eoptions} - end. - - -%% -%% peername(Socket) -> {ok, {Address, Port}} | {error, Reason} -%% -peername(#sslsocket{pid = Pid}) -> - Req = {peername, self()}, - gen_server:call(Pid, Req, infinity). - - -%% recv(Socket, Length, Timeout) -> {ok, Data} | {error, Reason} -%% -%% Types: Socket = sslsocket() -%% Length = Timeout = integer() -%% Data = bytes() | binary() -%% -recv(#sslsocket{pid = Pid}, Length, Timeout) -> - Req = {recv, self(), Length, Timeout}, - gen_server:call(Pid, Req, infinity). - - -%% send(Socket, Data) -> ok | {error, Reason} -%% -%% Types: Socket = sslsocket() -%% -send(#sslsocket{pid = Pid}, Data) -> - gen_server:call(Pid, {send, self(), Data}, infinity). - - -%% getopts(Socket, OptTags) -> {ok, Opts} | {error, einval} -%% -%% Types: Pid = pid() of broker -%% Timeout = timeout() -%% OptTags = option_tags() -%% Opts = options() -%% -getopts(Socket, OptTags) -> - getopts(Socket, OptTags, infinity). - -getopts(#sslsocket{pid = Pid}, OptTags, Timeout) when is_list(OptTags) -> - Req = {getopts, self(), OptTags}, - gen_server:call(Pid, Req, Timeout). - - -%% -%% setopts(Socket, Opts) -> ok | {error, Reason} -%% -setopts(#sslsocket{pid = Pid}, Opts) -> - Req = {setopts, self(), Opts}, - gen_server:call(Pid, Req, infinity). - -%% -%% sockname(Socket) -> {ok, {Address, Port}} | {error, Reason} -%% -sockname(#sslsocket{pid = Pid}) -> - Req = {sockname, self()}, - gen_server:call(Pid, Req, infinity). - - -%% -%% peercert(Socket) -> {ok, Cert} | {error, Reason} -%% -peercert(#sslsocket{pid = Pid}) -> - Req = {peercert, self()}, - gen_server:call(Pid, Req, infinity). - -%% -%% INIT -%% - -%% init -%% -init([Client, Type]) -> - process_flag(trap_exit, true), - link(Client), - Debug = case application:get_env(ssl, edebug) of - {ok, true} -> - true; - _ -> - case application:get_env(ssl, debug) of - {ok, true} -> - true; - _ -> - os:getenv("ERL_SSL_DEBUG") =/= false - end - end, - Server = whereis(ssl_server), - if - is_pid(Server) -> - link(Server), - debug1(Debug, Type, "in start, client = ~w", [Client]), - {ok, #st{brokertype = Type, server = Server, client = Client, - collector = Client, debug = Debug}}; - true -> - {stop, no_ssl_server} - end. - - -%% -%% HANDLE CALL -%% - -%% recv - passive mode -%% -handle_call({recv, Client, Length, Timeout}, _From, - #st{active = false, proxysock = Proxysock, status = Status} = St) -> - debug(St, "recv: client = ~w~n", [Client]), - if - Status =/= open -> - {reply, {error, closed}, St}; - true -> - case gen_tcp:recv(Proxysock, Length, Timeout) of - {ok, Data} -> - {reply, {ok, Data}, St}; - {error, timeout} -> - {reply, {error, timeout}, St}; - {error, Reason} -> - {reply, {error, Reason}, St#st{status = closing}} - end - end; - -%% send -%% -handle_call({send, Client, Data}, _From, St) -> - debug(St, "send: client = ~w~n", [Client]), - if - St#st.status =/= open -> - {reply, {error, closed}, St}; - true -> - case gen_tcp:send(St#st.proxysock, Data) of - ok -> - {reply, ok, St}; - {error, _Reason} -> - {reply, {error, closed}, St#st{status = closing}} - end - end; - -%% transport_accept -%% -%% Client = pid of client -%% ListenSocket = sslsocket() -%% -handle_call({transport_accept, Client, ListenSocket, Timeout}, _From, St) -> - debug(St, "transport_accept: client = ~w, listensocket = ~w~n", - [Client, ListenSocket]), - case getopts(ListenSocket, tcp_listen_opt_tags(), ?DEF_TIMEOUT) of - {ok, LOpts} -> - case transport_accept_prim( - ssl_server, ListenSocket#sslsocket.fd, LOpts, Timeout, St) of - {ok, ThisSocket, NSt} -> - {reply, {ok, ThisSocket}, NSt}; - {error, Reason, St} -> - What = what(Reason), - {stop, normal, {error, What}, St} - end; - {error, Reason} -> - What = what(Reason), - {stop, normal, {error, What}, St} - end; - -%% ssl_accept -%% -%% Client = pid of client -%% ListenSocket = sslsocket() -%% -handle_call({ssl_accept, Client, Socket, Timeout}, _From, St) -> - debug(St, "ssl_accept: client = ~w, socket = ~w~n", [Client, Socket]), - case ssl_accept_prim(ssl_server, gen_tcp, Client, St#st.opts, Timeout, St#st{thissock=Socket}) of - {ok, Socket, NSt} -> - {reply, ok, NSt}; - {error, Reason, St} -> - What = what(Reason), - {stop, normal, {error, What}, St} - end; - -%% connect -%% -%% Client = client pid -%% Address = hostname | ipstring | IP -%% Port = integer() -%% Opts = options() -%% -handle_call({connect, Client, Address, Port, Opts, Timeout}, _From, St) -> - debug(St, "connect: client = ~w, address = ~p, port = ~w~n", - [Client, Address, Port]), - case connect_prim(ssl_server, gen_tcp, Client, Address, Port, Opts, - Timeout, St) of - {ok, Res, NSt} -> - {reply, {ok, Res}, NSt}; - {error, Reason, NSt} -> - What = what(Reason), - {stop, normal, {error, What}, NSt} - end; - -%% connection_info -%% -handle_call({connection_info, Client}, _From, St) -> - debug(St, "connection_info: client = ~w~n", [Client]), - Reply = ssl_server:connection_info(St#st.fd), - {reply, Reply, St}; - -%% close from client -%% -handle_call({close, Client}, _From, St) -> - debug(St, "close: client = ~w~n", [Client]), - %% Terminate - {stop, normal, ok, St#st{status = closed}}; - -%% listen -%% -%% Client = pid of client -%% Port = int() -%% Opts = options() -%% -handle_call({listen, Client, Port, Opts}, _From, St) -> - debug(St, "listen: client = ~w, port = ~w~n", - [Client, Port]), - case listen_prim(ssl_server, Client, Port, Opts, St) of - {ok, Res, NSt} -> - {reply, {ok, Res}, NSt}; - {error, Reason, NSt} -> - What = what(Reason), - {stop, normal, {error, What}, NSt} - end; - -%% peername -%% -handle_call({peername, Client}, _From, St) -> - debug(St, "peername: client = ~w~n", [Client]), - Reply = case ssl_server:peername(St#st.fd) of - {ok, {Address, Port}} -> - {ok, At} = inet_parse:ipv4_address(Address), - {ok, {At, Port}}; - Error -> - Error - end, - {reply, Reply, St}; - -%% setopts -%% -handle_call({setopts, Client, Opts0}, _From, St0) -> - debug(St0, "setopts: client = ~w~n", [Client]), - OptsOK = case St0#st.brokertype of - listener -> - are_opts(fun is_tcp_listen_opt/1, Opts0); - acceptor -> - are_opts(fun is_tcp_accept_opt/1, Opts0); - connector -> - are_opts(fun is_tcp_connect_opt/1, Opts0) - end, - if - OptsOK =:= false -> - {reply, {error, eoptions}, St0}; - true -> - Opts1 = lists:keydelete(nodelay, 1, Opts0), - case inet:setopts(St0#st.proxysock, Opts1) of - ok -> - Opts2 = replace_opts(Opts1, St0#st.opts), - Active = get_active(Opts2), - St2 = St0#st{opts = Opts2, - active = Active}, - case get_nodelay(Opts0) of - empty -> - {reply, ok, St2}; - Bool -> - case setnodelay(ssl_server, St0, Bool) of - ok -> - Opts3 = replace_opts([{nodelay, Bool}], - Opts2), - St3 = St0#st{opts = Opts3, - active = Active}, - {reply, ok, St3}; - {error, Reason} -> - {reply, {error, Reason}, St2} - end - end; - {error, Reason} -> - {reply, {error, Reason}, St0} - end - end; - -%% sockname -%% -handle_call({sockname, Client}, _From, St) -> - debug(St, "sockname: client = ~w~n", [Client]), - Reply = case ssl_server:sockname(St#st.fd) of - {ok, {Address, Port}} -> - {ok, At} = inet_parse:ipv4_address(Address), - {ok, {At, Port}}; - Error -> - Error - end, - {reply, Reply, St}; - -%% peercert -%% -handle_call({peercert, Client}, _From, St) -> - debug(St, "peercert: client = ~w~n", [Client]), - Reply = ssl_server:peercert(St#st.fd), - {reply, Reply, St}; - -%% inhibit msgs -%% -handle_call({inhibit_msgs, Client}, _From, #st{client = Client} = St) -> - debug(St, "inhibit_msgs: client = ~w~n", [Client]), - {ok, Collector} = start_collector(), - {reply, ok, St#st{collector = Collector}}; - -%% release msgs -%% -handle_call({release_msgs, Client, NewClient}, _From, - #st{client = Client, collector = Collector} = St) -> - debug(St, "release_msgs: client = ~w~n", [Client]), - unlink(Client), - link(NewClient), - release_collector(Collector, NewClient), - NSt = St#st{client = NewClient, collector = NewClient}, - {reply, ok, NSt}; - -%% getopts -%% -handle_call({getopts, Client, OptTags}, _From, St) -> - debug(St, "getopts: client = ~w~n", [Client]), - Reply = case are_opt_tags(St#st.brokertype, OptTags) of - true -> - {ok, extract_opts(OptTags, St#st.opts)}; - _ -> - {error, einval} - end, - {reply, Reply, St}; - -%% bad call -%% -handle_call(Request, _From, St) -> - debug(St, "++++ ssl_broker: bad call: ~w~n", [Request]), - {reply, {error, {badcall, Request}}, St}. - -%% -%% HANDLE CAST -%% - -handle_cast(Request, St) -> - debug(St, "++++ ssl_broker: bad cast: ~w~n", [Request]), - {stop, {error, {badcast, Request}}, St}. - -%% -%% HANDLE INFO -%% - -%% tcp - active mode -%% -%% The collector is different from client only during change of -%% controlling process. -%% -handle_info({tcp, Socket, Data}, - #st{active = Active, collector = Collector, status = open, - proxysock = Socket, thissock = Thissock} = St) - when Active =/= false -> - debug(St, "tcp: socket = ~w~n", [Socket]), - Msg = {ssl, Thissock, Data}, - Collector ! Msg, - if - Active =:= once -> - {noreply, St#st{active = false}}; - true -> - {noreply, St} - end; - -%% tcp_closed - from proxy socket, active mode -%% -%% -handle_info({tcp_closed, Socket}, - #st{active = Active, collector = Collector, - proxysock = Socket, thissock = Thissock} = St) - when Active =/= false -> - debug(St, "tcp_closed: socket = ~w~n", [Socket]), - Msg = {ssl_closed, Thissock}, - Collector ! Msg, - if - Active =:= once -> - {noreply, St#st{status = closing, active = false}}; - true -> - {noreply, St#st{status = closing}} - end; - -%% tcp_error - from proxy socket, active mode -%% -%% -handle_info({tcp_error, Socket, Reason}, - #st{active = Active, collector = Collector, - proxysock = Socket} = St) - when Active =/= false -> - debug(St, "tcp_error: socket = ~w, reason = ~w~n", [Socket, Reason]), - Msg = {ssl_error, Socket, Reason}, - Collector ! Msg, - if - Active =:= once -> - {noreply, St#st{status = closing, active = false}}; - true -> - {noreply, St#st{status = closing}} - end; - -%% EXIT - from client -%% -%% -handle_info({'EXIT', Client, Reason}, #st{client = Client} = St) -> - debug(St, "exit client: client = ~w, reason = ~w~n", [Client, Reason]), - {stop, normal, St#st{status = closed}}; % do not make noise - -%% EXIT - from server -%% -%% -handle_info({'EXIT', Server, Reason}, #st{server = Server} = St) -> - debug(St, "exit server: reason = ~w~n", [Reason]), - {stop, Reason, St}; - -%% handle info catch all -%% -handle_info(Info, St) -> - debug(St, " bad info: ~w~n", [Info]), - {stop, {error, {badinfo, Info}}, St}. - - -%% terminate -%% -%% -terminate(Reason, St) -> - debug(St, "in terminate reason: ~w, state: ~w~n", [Reason, St]), - ok. - -%% code_change -%% -%% -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -%% -%% Primitive interface -%% -listen_prim(ServerName, Client, Port, Opts, St) -> - LOpts = get_tcp_listen_opts(Opts), - SSLOpts = get_ssl_opts(Opts), - FlagStr =mk_ssl_optstr(SSLOpts), - BackLog = get_backlog(LOpts), - IP = get_ip(LOpts), - case ssl_server:listen_prim(ServerName, IP, Port, FlagStr, BackLog) of - {ok, ListenFd, _Port0} -> - ThisSocket = #sslsocket{fd = ListenFd, pid = self()}, - StOpts = add_default_tcp_listen_opts(LOpts) ++ - add_default_ssl_opts(SSLOpts), - NSt = St#st{fd = ListenFd, - active = get_active(LOpts), % irrelevant for listen - opts = StOpts, - thissock = ThisSocket, - status = open}, - debug(St, "listen: ok: client = ~w, listenfd = ~w~n", - [Client, ListenFd]), - {ok, ThisSocket, NSt}; - {error, Reason} -> - {error, Reason, St} - end. - -connect_prim(ServerName, TcpModule, Client, FAddress, FPort, Opts, - Timeout, St) -> - COpts = get_tcp_connect_opts(Opts), - SSLOpts = get_ssl_opts(Opts), - FlagStr = mk_ssl_optstr(SSLOpts), - case inet:getaddr(FAddress, inet) of - {ok, FIP} -> - %% Timeout is gen_server timeout - hence catch - LIP = get_ip(COpts), - LPort = get_port(COpts), - case (catch ssl_server:connect_prim(ServerName, - LIP, LPort, FIP, FPort, - FlagStr, Timeout)) of - {ok, Fd, ProxyPort} -> - case connect_proxy(ServerName, TcpModule, Fd, - ProxyPort, COpts, Timeout) of - {ok, Socket} -> - ThisSocket = #sslsocket{fd = Fd, pid = self()}, - StOpts = add_default_tcp_connect_opts(COpts) ++ - add_default_ssl_opts(SSLOpts), - NSt = St#st{fd = Fd, - active = get_active(COpts), - opts = StOpts, - thissock = ThisSocket, - proxysock = Socket, - status = open}, - case get_nodelay(COpts) of - true -> setnodelay(ServerName, NSt, true); - _ -> ok - end, - debug(St, "connect: ok: client = ~w, fd = ~w~n", - [Client, Fd]), - {ok, ThisSocket, NSt}; - {error, Reason} -> - {error, Reason, St} - end; - {'EXIT', Reason} -> - {error, Reason, St}; - {error, Reason} -> - {error, Reason, St} - end; - {error, Reason} -> - {error, Reason, St} - end. - -transport_accept_prim(ServerName, ListenFd, LOpts, Timeout, St) -> - AOpts = get_tcp_accept_opts(LOpts), - FlagStr = "", - %% Timeout is gen_server timeout - hence catch. - case (catch ssl_server:transport_accept_prim(ServerName, ListenFd, - FlagStr, Timeout)) of - {ok, Fd, ProxyPort} -> - ThisSocket = #sslsocket{fd = Fd, pid = self()}, - NSt = St#st{fd = Fd, - active = get_active(AOpts), - opts = AOpts, - thissock = ThisSocket, - proxyport = ProxyPort, - encrypted = false}, - debug(St, "transport_accept: ok: fd = ~w~n", [Fd]), - {ok, ThisSocket, NSt}; - {'EXIT', Reason} -> - debug(St, "transport_accept: EXIT: Reason = ~w~n", [Reason]), - {error, Reason, St}; - {error, Reason} -> - debug(St, "transport_accept: error: Reason = ~w~n", [Reason]), - {error, Reason, St} - end. - -ssl_accept_prim(ServerName, TcpModule, Client, LOpts, Timeout, St) -> - FlagStr = [], - SSLOpts = [], - AOpts = get_tcp_accept_opts(LOpts), - %% Timeout is gen_server timeout - hence catch. - debug(St, "ssl_accept_prim: self() ~w Client ~w~n", [self(), Client]), - Socket = St#st.thissock, - Fd = Socket#sslsocket.fd, - A = (catch ssl_server:ssl_accept_prim(ServerName, Fd, FlagStr, Timeout)), - debug(St, "ssl_accept_prim: ~w~n", [A]), - case A of - ok -> - B = connect_proxy(ServerName, TcpModule, Fd, - St#st.proxyport, AOpts, Timeout), - debug(St, "ssl_accept_prim: connect_proxy ~w~n", [B]), - case B of - {ok, Socket2} -> - StOpts = add_default_tcp_accept_opts(AOpts) ++ - add_default_ssl_opts(SSLOpts), - NSt = St#st{opts = StOpts, - proxysock = Socket2, - encrypted = true, - status = open}, - case get_nodelay(AOpts) of - true -> setnodelay(ServerName, NSt, true); - _ -> ok - end, - debug(St, "transport_accept: ok: client = ~w, fd = ~w~n", - [Client, Fd]), - {ok, St#st.thissock, NSt}; - {error, Reason} -> - {error, Reason, St} - end; - {'EXIT', Reason} -> - {error, Reason, St}; - {error, Reason} -> - {error, Reason, St} - end. - - -%% -%% LOCAL FUNCTIONS -%% - -%% -%% connect_proxy(Fd, ProxyPort, TOpts, Timeout) -> {ok, Socket} | -%% {error, Reason} -%% -connect_proxy(ServerName, TcpModule, Fd, ProxyPort, TOpts, Timeout) -> - case TcpModule:connect({127, 0, 0, 1}, ProxyPort, TOpts, Timeout) of - {ok, Socket} -> - {ok, Port} = inet:port(Socket), - A = ssl_server:proxy_join_prim(ServerName, Fd, Port), - case A of - ok -> - {ok, Socket}; - Error -> - Error - end; - Error -> - Error - end. - - -setnodelay(ServerName, St, Bool) -> - case ssl_server:setnodelay_prim(ServerName, St#st.fd, Bool) of - ok -> - case inet:setopts(St#st.proxysock, [{nodelay, Bool}]) of - ok -> - ok; - {error, Reason} -> - {error, Reason} - end; - {error, Reason} -> - {error, Reason} - end. - -%% -%% start_collector() -%% -%% A collector is a little process that keeps messages during change of -%% controlling process. -%% XXX This is not gen_server compliant :-(. -%% -start_collector() -> - Pid = spawn_link(?MODULE, collector_init, [self()]), - {ok, Pid}. - -%% -%% release_collector(Collector, NewOwner) -%% -release_collector(Collector, NewOwner) -> - Collector ! {release, self(), NewOwner}, - receive - %% Reap collector - {'EXIT', Collector, normal} -> - ok - end. - -%% -%% collector_init(Broker) -> void() -%% -collector_init(Broker) -> - receive - {release, Broker, NewOwner} -> - transfer_messages(Broker, NewOwner) - end. - -%% -%% transfer_messages(Pid, NewOwner) -> void() -%% -transfer_messages(Pid, NewOwner) -> - receive - {ssl, Sock, Data} -> - NewOwner ! {ssl, Sock, Data}, - transfer_messages(Pid, NewOwner); - {ssl_closed, Sock} -> - NewOwner ! {ssl_closed, Sock}, - transfer_messages(Pid, NewOwner); - {ssl_error, Sock, Reason} -> - NewOwner ! {ssl_error, Sock, Reason}, - transfer_messages(Pid, NewOwner) - after 0 -> - ok - end. - -%% -%% debug(St, Format, Args) -> void() - printouts -%% -debug(St, Format, Args) -> - debug1(St#st.debug, St#st.brokertype, Format, Args). - -debug1(true, Type, Format0, Args) -> - {_MS, S, MiS} = erlang:now(), - Secs = S rem 100, - MiSecs = MiS div 1000, - Format = "++++ ~3..0w:~3..0w ssl_broker (~w)[~w]: " ++ Format0, - io:format(Format, [Secs, MiSecs, self(), Type| Args]); -debug1(_, _, _, _) -> - ok. - -%% -%% what(Reason) -> What -%% -what(Reason) when is_atom(Reason) -> - Reason; -what({'EXIT', Reason}) -> - what(Reason); -what({What, _Where}) when is_atom(What) -> - What; -what(Reason) -> - Reason. - - -%% -%% OPTIONS -%% -%% Note that `accept' has no options when invoked, but get all its options -%% by inheritance from `listen'. -%% - -are_opt_tags(listener, OptTags) -> - is_subset(OptTags, listen_opt_tags()); -are_opt_tags(acceptor, OptTags) -> - is_subset(OptTags, accept_opt_tags()); -are_opt_tags(connector, OptTags) -> - is_subset(OptTags, connect_opt_tags()). - -listen_opt_tags() -> - tcp_listen_opt_tags() ++ ssl_opt_tags(). - -accept_opt_tags() -> - tcp_gen_opt_tags(). - -connect_opt_tags() -> - tcp_gen_opt_tags() ++ ssl_opt_tags(). - -tcp_listen_opt_tags() -> - tcp_gen_opt_tags() ++ tcp_listen_only_opt_tags(). - -tcp_gen_opt_tags() -> - %% All except `reuseaddr' and `deliver'. - [nodelay, active, packet, mode, header]. - -tcp_listen_only_opt_tags() -> - [ip, backlog]. - -ssl_opt_tags() -> - %% XXX Should remove cachetimeout. - [verify, depth, certfile, password, cacertfile, ciphers, cachetimeout]. - -%% Options - -%% -%% are_*_opts(Opts) -> boolean() -%% -are_connect_opts(Opts) -> - are_opts(fun is_connect_opt/1, Opts). - -are_listen_opts(Opts) -> - are_opts(fun is_listen_opt/1, Opts). - -are_opts(F, Opts) -> - lists:all(F, transform_opts(Opts)). - -%% -%% get_*_opts(Opts) -> Value -%% -get_tcp_accept_opts(Opts) -> - [O || O <- transform_opts(Opts), is_tcp_accept_opt(O)]. - -get_tcp_connect_opts(Opts) -> - [O || O <- transform_opts(Opts), is_tcp_connect_opt(O)]. - -get_tcp_listen_opts(Opts) -> - [O || O <- transform_opts(Opts), is_tcp_listen_opt(O)]. - -get_ssl_opts(Opts) -> - [O || O <- transform_opts(Opts), is_ssl_opt(O)]. - -get_active(Opts) -> - get_tagged_opt(active, Opts, true). - -get_backlog(Opts) -> - get_tagged_opt(backlog, Opts, ?DEF_BACKLOG). - -get_ip(Opts) -> - get_tagged_opt(ip, Opts, {0, 0, 0, 0}). - -get_port(Opts) -> - get_tagged_opt(port, Opts, 0). - -get_nodelay(Opts) -> - get_tagged_opt(nodelay, Opts, empty). - -%% -%% add_default_*_opts(Opts) -> NOpts -%% - -add_default_tcp_accept_opts(Opts) -> - add_default_opts(Opts, default_tcp_accept_opts()). - -add_default_tcp_connect_opts(Opts) -> - add_default_opts(Opts, default_tcp_connect_opts()). - -add_default_tcp_listen_opts(Opts) -> - add_default_opts(Opts, default_tcp_listen_opts()). - -add_default_ssl_opts(Opts) -> - add_default_opts(Opts, default_ssl_opts()). - -add_default_opts(Opts, DefOpts) -> - TOpts = transform_opts(Opts), - TOpts ++ [DP || {DTag, _DVal} = DP <- DefOpts, - not lists:keymember(DTag, 1, TOpts)]. - -default_tcp_accept_opts() -> - [O || O <- default_opts(), is_tcp_accept_opt(O)]. - -default_tcp_connect_opts() -> - [O || O <- default_opts(), is_tcp_connect_opt(O)]. - -default_tcp_listen_opts() -> - [O || O <- default_opts(), is_tcp_listen_opt(O)]. - -default_ssl_opts() -> - [O || O <- default_opts(), is_ssl_opt(O)]. - -default_opts() -> - [{mode, list}, {packet, 0}, {nodelay, false}, {active, true}, - {backlog, ?DEF_BACKLOG}, {ip, {0, 0, 0, 0}}, - {verify, 0}, {depth, 1}]. - - -%% Transform from old to new options, and also from old gen_tcp -%% options to new ones. All returned options are tagged options. -%% -transform_opts(Opts) -> - lists:flatmap(fun transform_opt/1, Opts). - -transform_opt(binary) -> [{mode, binary}]; -transform_opt(list) -> [{mode, list}]; -transform_opt({packet, raw}) -> [{packet, 0}]; -transform_opt(raw) -> []; -transform_opt(Opt) -> [Opt]. - -%% NOTE: The is_*_opt/1 functions must be applied on transformed options -%% only. - -is_connect_opt(Opt) -> - is_tcp_connect_opt(Opt) or is_ssl_opt(Opt). - -is_listen_opt(Opt) -> - is_tcp_listen_opt(Opt) or is_ssl_opt(Opt). - -is_tcp_accept_opt(Opt) -> - is_tcp_gen_opt(Opt). - -is_tcp_connect_opt(Opt) -> - is_tcp_gen_opt(Opt) or is_tcp_connect_only_opt(Opt). - -is_tcp_listen_opt(Opt) -> - is_tcp_gen_opt(Opt) or is_tcp_listen_only_opt(Opt). - -%% General options supported by gen_tcp: All except `reuseaddr' and -%% `deliver'. -is_tcp_gen_opt({mode, list}) -> true; -is_tcp_gen_opt({mode, binary}) -> true; -is_tcp_gen_opt({header, Sz}) when is_integer(Sz), 0 =< Sz -> true; -is_tcp_gen_opt({packet, Sz}) when is_integer(Sz), 0 =< Sz, Sz =< 4-> true; -is_tcp_gen_opt({packet, sunrm}) -> true; -is_tcp_gen_opt({packet, asn1}) -> true; -is_tcp_gen_opt({packet, cdr}) -> true; -is_tcp_gen_opt({packet, fcgi}) -> true; -is_tcp_gen_opt({packet, line}) -> true; -is_tcp_gen_opt({packet, tpkt}) -> true; -is_tcp_gen_opt({packet, http}) -> true; -is_tcp_gen_opt({packet, httph}) -> true; -is_tcp_gen_opt({nodelay, true}) -> true; -is_tcp_gen_opt({nodelay, false}) -> true; -is_tcp_gen_opt({active, true}) -> true; -is_tcp_gen_opt({active, false}) -> true; -is_tcp_gen_opt({active, once}) -> true; -is_tcp_gen_opt({keepalive, true}) -> true; -is_tcp_gen_opt({keepalive, false}) -> true; -is_tcp_gen_opt({ip, Addr}) -> is_ip_address(Addr); -is_tcp_gen_opt(_Opt) -> false. - -is_tcp_listen_only_opt({backlog, Size}) when is_integer(Size), 0 =< Size -> - true; -is_tcp_listen_only_opt({reuseaddr, Bool}) when is_boolean(Bool) -> - true; -is_tcp_listen_only_opt(_Opt) -> false. - -is_tcp_connect_only_opt({port, Port}) when is_integer(Port), 0 =< Port -> true; -is_tcp_connect_only_opt(_Opt) -> false. - -%% SSL options - -is_ssl_opt({verify, Code}) when 0 =< Code, Code =< 2 -> true; -is_ssl_opt({depth, Depth}) when 0 =< Depth -> true; -is_ssl_opt({certfile, String}) -> is_string(String); -is_ssl_opt({keyfile, String}) -> is_string(String); -is_ssl_opt({password, String}) -> is_string(String); -is_ssl_opt({cacertfile, String}) -> is_string(String); -is_ssl_opt({ciphers, String}) -> is_string(String); -is_ssl_opt({cachetimeout, Timeout}) when Timeout >= 0 -> true; -is_ssl_opt(_Opt) -> false. - -%% Various types -is_string(String) when is_list(String) -> - lists:all(fun (C) when is_integer(C), 0 =< C, C =< 255 -> true; - (_C) -> false end, - String); -is_string(_) -> - false. - -is_ip_address(Addr) when tuple_size(Addr) =:= 4 -> - is_string(tuple_to_list(Addr)); -is_ip_address(Addr) when is_list(Addr) -> - is_string(Addr); -is_ip_address(_) -> - false. - -get_tagged_opt(Tag, Opts, Default) -> - case lists:keysearch(Tag, 1, Opts) of - {value, {_, Value}} -> - Value; - _Other -> - Default - end. - -%% -%% mk_ssl_optstr(Opts) -> string() -%% -%% Makes a "command line" string of SSL options -%% -mk_ssl_optstr(Opts) -> - lists:flatten([mk_one_ssl_optstr(O) || O <- Opts]). - -mk_one_ssl_optstr({verify, Code}) -> - [" -verify ", integer_to_list(Code)]; -mk_one_ssl_optstr({depth, Depth}) -> - [" -depth ", integer_to_list(Depth)]; -mk_one_ssl_optstr({certfile, String}) -> - [" -certfile ", String]; -mk_one_ssl_optstr({keyfile, String}) -> - [" -keyfile ", String]; -mk_one_ssl_optstr({password, String}) -> - [" -password ", String]; -mk_one_ssl_optstr({cacertfile, String}) -> - [" -cacertfile ", String]; -mk_one_ssl_optstr({ciphers, String}) -> - [" -ciphers ", String]; -mk_one_ssl_optstr({cachetimeout, Timeout}) -> - [" -cachetimeout ", integer_to_list(Timeout)]; -mk_one_ssl_optstr(_) -> - "". - -extract_opts(OptTags, Opts) -> - [O || O = {Tag,_} <- Opts, lists:member(Tag, OptTags)]. - -replace_opts(NOpts, Opts) -> - lists:foldl(fun({Key, Val}, Acc) -> - lists:keyreplace(Key, 1, Acc, {Key, Val}); - %% XXX Check. Patch from Chandrashekhar Mullaparthi. - (binary, Acc) -> - lists:keyreplace(mode, 1, Acc, {mode, binary}) - end, - Opts, NOpts). - -%% Misc - -is_subset(A, B) -> - [] =:= A -- B. diff --git a/lib/ssl/src/ssl_broker_int.hrl b/lib/ssl/src/ssl_broker_int.hrl deleted file mode 100644 index b791485725..0000000000 --- a/lib/ssl/src/ssl_broker_int.hrl +++ /dev/null @@ -1,38 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. 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% -%% - -%% - -%% Purpose: record definitions shared between ssl_prim.erl and ssl_broker.erl - --record(st, {brokertype = nil, % connector | listener | acceptor - server = nil, % pid of ssl_server - client = nil, % client pid - collector = nil, % client pid, or collector during change of - % controlling process - fd = nil, % fd of "external" socket in port program - active = true, % true | false | once - opts = [], % options - thissock = nil, % this sslsocket - proxysock = nil, % local proxy socket within Erlang - proxyport = nil, % local port for proxy within Erlang - status = nil, % open | closing | closed - encrypted = false, % - debug = false % - }). diff --git a/lib/ssl/src/ssl_broker_sup.erl b/lib/ssl/src/ssl_broker_sup.erl deleted file mode 100644 index 6d56a5fcf6..0000000000 --- a/lib/ssl/src/ssl_broker_sup.erl +++ /dev/null @@ -1,46 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. 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% -%% - -%% - -%%% Purpose : Supervisor for brokers - --module(ssl_broker_sup). - --behaviour(supervisor). - --export([start_link/0]). - -%% supervisor callbacks --export([init/1]). - -start_link() -> - supervisor:start_link({local, ssl_broker_sup}, ssl_broker_sup, - []). - -init([]) -> - {ok, {{simple_one_for_one, 10, 3600}, - [{ssl_broker, - {ssl_broker, start_link, []}, - temporary, - 100, - worker, - [ssl_broker]} - ]}}. - diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 049354c19b..41afd2044c 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -34,7 +34,6 @@ -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). --include("ssl_int.hrl"). -include_lib("public_key/include/public_key.hrl"). %% Internal application API diff --git a/lib/ssl/src/ssl_int.hrl b/lib/ssl/src/ssl_int.hrl deleted file mode 100644 index 3686deffce..0000000000 --- a/lib/ssl/src/ssl_int.hrl +++ /dev/null @@ -1,99 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. 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% -%% - -%% - -%% op codes commands are in capital and reply codes in lower case - --define(CONNECT, 1). --define(CONNECT_WAIT, 2). --define(CONNECT_REP, 3). --define(CONNECT_ERR, 4). - --define(TERMINATE, 5). --define(CLOSE, 6). - --define(LISTEN, 7). --define(LISTEN_REP, 8). --define(LISTEN_ERR, 9). - --define(TRANSPORT_ACCEPT, 10). --define(NOACCEPT, 11). --define(TRANSPORT_ACCEPT_REP, 12). --define(TRANSPORT_ACCEPT_ERR, 13). - --define(FROMNET_CLOSE, 14). - --define(CONNECT_SYNC_ERR, 15). --define(LISTEN_SYNC_ERR, 16). - --define(PROXY_PORT, 23). --define(PROXY_JOIN, 24). --define(PROXY_JOIN_REP, 25). --define(PROXY_JOIN_ERR, 26). - --define(SET_SOCK_OPT, 27). --define(IOCTL_OK, 28). --define(IOCTL_ERR, 29). - --define(GETPEERNAME, 30). --define(GETPEERNAME_REP, 31). --define(GETPEERNAME_ERR, 32). - --define(GETSOCKNAME, 33). --define(GETSOCKNAME_REP, 34). --define(GETSOCKNAME_ERR, 35). - --define(GETPEERCERT, 36). --define(GETPEERCERT_REP, 37). --define(GETPEERCERT_ERR, 38). - --define(GETVERSION, 39). --define(GETVERSION_REP, 40). - --define(SET_SEED, 41). - --define(GETCONNINFO, 42). --define(GETCONNINFO_REP, 43). --define(GETCONNINFO_ERR, 44). - --define(SSL_ACCEPT, 45). --define(SSL_ACCEPT_REP, 46). --define(SSL_ACCEPT_ERR, 47). - --define(DUMP_CMD, 48). --define(DEBUG_CMD, 49). --define(DEBUGMSG_CMD, 50). - -%% -------------- - --define(SSLv2, 1). --define(SSLv3, 2). --define(TLSv1, 4). - - -%% Set socket options codes 'SET_SOCK_OPT' --define(SET_TCP_NODELAY, 1). - --define(DEF_BACKLOG, 128). - --define(DEF_TIMEOUT, 10000). - --record(sslsocket, { fd = nil, pid = nil}). - diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 483e06067c..18cfcdcd68 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -24,6 +24,9 @@ -include_lib("public_key/include/public_key.hrl"). +%% Looks like it does for backwards compatibility reasons +-record(sslsocket, {fd = nil, pid = nil}). + -type reason() :: term(). -type reply() :: term(). -type msg() :: term(). diff --git a/lib/ssl/src/ssl_prim.erl b/lib/ssl/src/ssl_prim.erl deleted file mode 100644 index e3140a89d1..0000000000 --- a/lib/ssl/src/ssl_prim.erl +++ /dev/null @@ -1,173 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. 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% -%% - -%% - -%% Purpose: Primitive interface to SSL, without broker process (used by -%% SSL distribution). - --module(ssl_prim). - --export([listen/2, connect/3, accept/1, close/1, send/2, send/3, recv/2, recv/3, - getll/1, getstat/2, setopts/2, controlling_process/2, peername/1, - sockname/1, getif/1]). - --include("ssl_int.hrl"). --include("ssl_broker_int.hrl"). - -%-define(filter(Call), filter((catch Call))). --define(filter(Call), filter(Call)). - -listen(Port, Opts) -> - St = newstate(listener), - ?filter(ssl_broker:listen_prim(ssl_server_prim, self(), Port, nonactive(Opts), St)). - -connect(Address, Port, Opts) -> - St = newstate(connector), - ?filter(ssl_broker:connect_prim(ssl_server_prim, inet_tcp, self(), Address, - Port, nonactive(Opts), infinity, St)). - -accept(#st{} = ListenSt0) -> - case transport_accept(ListenSt0) of - {ok, ListenSt1} -> - ssl_accept(ListenSt0, ListenSt1); - Error -> - Error - end. - -transport_accept(#st{opts = ListenOpts, thissock = ListenSocket}) -> - NewSt = newstate(acceptor), - ListenFd = ListenSocket#sslsocket.fd, - ?filter(ssl_broker:transport_accept_prim(ssl_server_prim, ListenFd, - ListenOpts, infinity, NewSt)). - -ssl_accept(#st{opts = LOpts}, ListenSt1) -> - ?filter(ssl_broker:ssl_accept_prim(ssl_server_prim, gen_tcp, self(), - LOpts, infinity, ListenSt1)). - -close(#st{fd = Fd}) when is_integer(Fd) -> - ssl_server:close_prim(ssl_server_prim, Fd), - ok; -close(_) -> - ok. - -send(St, Data) -> - send(St, Data, []). - -send(#st{proxysock = Proxysock, status = open}, Data, Opts) -> - case inet_tcp:send(Proxysock, Data, Opts) of - ok -> - ok; - {error, _} -> - {error, closed} - end; -send(#st{}, _Data, _Opts) -> - {error, closed}. - -recv(St, Length) -> - recv(St, Length, infinity). - -recv(#st{proxysock = Proxysock, status = open}, Length, Tmo) -> - inet_tcp:recv(Proxysock, Length, Tmo); -recv(#st{}, _Length, _Tmo) -> - {error, closed}. - -getll(#st{proxysock = Proxysock, status = open}) -> - inet:getll(Proxysock); -getll(#st{}) -> - {error, closed}. - -getstat(#st{proxysock = Proxysock, status = open}, Opts) -> - inet:getstat(Proxysock, Opts); -getstat(#st{}, _Opts) -> - {error, closed}. - -setopts(#st{proxysock = Proxysock, status = open}, Opts) -> - case remove_supported(Opts) of - [] -> - inet:setopts(Proxysock, Opts); - _ -> - {error, enotsup} - end; -setopts(#st{}, _Opts) -> - {error, closed}. - - -controlling_process(#st{proxysock = Proxysock, status = open}, Pid) - when is_pid(Pid) -> - inet_tcp:controlling_process(Proxysock, Pid); -controlling_process(#st{}, Pid) when is_pid(Pid) -> - {error, closed}. - -peername(#st{fd = Fd, status = open}) -> - case ssl_server:peername_prim(ssl_server_prim, Fd) of - {ok, {Address, Port}} -> - {ok, At} = inet_parse:ipv4_address(Address), - {ok, {At, Port}}; - Error -> - Error - end; -peername(#st{}) -> - {error, closed}. - -sockname(#st{fd = Fd, status = open}) -> - case ssl_server:sockname_prim(ssl_server_prim, Fd) of - {ok, {Address, Port}} -> - {ok, At} = inet_parse:ipv4_address(Address), - {ok, {At, Port}}; - Error -> - Error - end; -sockname(#st{}) -> - {error, closed}. - -getif(#st{proxysock = Proxysock, status = open}) -> - inet:getif(Proxysock); -getif(#st{}) -> - {error, closed}. - -remove_supported([{active, _}|T]) -> - remove_supported(T); -remove_supported([{packet,_}|T]) -> - remove_supported(T); -remove_supported([{deliver,_}|T]) -> - remove_supported(T); -remove_supported([H|T]) -> - [H | remove_supported(T)]; -remove_supported([]) -> - []. - -filter(Result) -> - case Result of - {ok, _Sock,St} -> - {ok, St}; - {error, Reason, _St} -> - {error,Reason} - end. - -nonactive([{active,_}|T]) -> - nonactive(T); -nonactive([H|T]) -> - [H | nonactive(T)]; -nonactive([]) -> - [{active, false}]. - -newstate(Type) -> - #st{brokertype = Type, server = whereis(ssl_server_prim), - client = undefined, collector = undefined, debug = false}. diff --git a/lib/ssl/src/ssl_server.erl b/lib/ssl/src/ssl_server.erl deleted file mode 100644 index b66e20a397..0000000000 --- a/lib/ssl/src/ssl_server.erl +++ /dev/null @@ -1,1378 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. 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% -%% - -%% - -%%% Purpose : SSL server - -%% -%% TODO -%% -%% XXX The ip option in listen is not general enough. It is assumed -%% to be a tuple, which is not always the case. - --module(ssl_server). --behaviour(gen_server). - -%% External exports --export([start_link/0]). - --export([transport_accept/2, transport_accept/3, ssl_accept/2, ssl_accept/3, - ciphers/0, connect/5, connect/6, - connection_info/1, close/1, listen/3, listen/4, peercert/1, - peername/1, proxy_join/2, seed/1, setnodelay/2, sockname/1, - version/0]). - --export([start_link_prim/0]). --export([ssl_accept_prim/4, transport_accept_prim/4, - connect_prim/7, close_prim/2, - listen_prim/5, proxy_join_prim/3, peername_prim/2, setnodelay_prim/3, - sockname_prim/2]). - --export([dump/0, dump/1]). --export([enable_debug/0, disable_debug/0, set_debug/1]). --export([enable_debugmsg/0, disable_debugmsg/0, set_debugmsg/1]). - -%% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - code_change/3, terminate/2]). - --include("ssl_int.hrl"). - --record(st, { - port = [], % port() of port program - progpid = [], % OS pid of port program - debug = false, % debug printout flag - cons = [], % All brokers except pending accepts - paccepts = [], % Pending accept brokers - proxylsport = [], % proxy listen socket port - intref = 0, % internal reference counter - compvsn = "", % ssl compile library version - libvsn = "", % ssl library version - ciphers = [] % available ciphers - }). - - -%% In all functions below IP is a four tuple, e.g. {192, 236, 52, 7}. -%% Port, Fd and ListenFd are integers; Flags is a string of characters. -%% -%% The prefixes F and L mean foreign and local, respectively. -%% Example: FIP (IP address for foreign end). - -%% -%% start_link() -> {ok, Pid} | {error, Reason} -%% -start_link() -> - gen_server:start_link({local, ssl_server}, ssl_server, [], []). - -start_link_prim() -> - gen_server:start_link({local, ssl_server_prim}, ssl_server, [], []). - -%% -%% transport_accept(ListenFd, Flags) -> {ok, Fd, ProxyLLPort} | -%% {error, Reason} -%% -transport_accept(ListenFd, Flags) -> - transport_accept(ListenFd, Flags, infinity). -transport_accept(ListenFd, Flags, Timeout) -> - transport_accept_prim(ssl_server,ListenFd, Flags, Timeout). - -transport_accept_prim(ServerName, ListenFd, Flags, Timeout) -> - Req = {transport_accept, self(), ListenFd, Flags}, - gen_server:call(ServerName, Req, Timeout). - -%% -%% ssl_accept(ListenFd, Flags) -> {ok, Fd, ProxyLLPort} | -%% {error, Reason} -%% -ssl_accept(ListenFd, Flags) -> - ssl_accept(ListenFd, Flags, infinity). -ssl_accept(ListenFd, Flags, Timeout) -> - ssl_accept_prim(ssl_server, ListenFd, Flags, Timeout). - -ssl_accept_prim(ServerName, Fd, Flags, Timeout) -> - Req = {ssl_accept, Fd, Flags}, - gen_server:call(ServerName, Req, Timeout). - -%% -%% ciphers() -> {ok, Ciphers} -%% -ciphers() -> - gen_server:call(ssl_server, ciphers, infinity). - -%% -%% close(Fd) -> ok -%% -close(Fd) -> - close_prim(ssl_server, Fd). -close_prim(ServerName, Fd) -> - gen_server:call(ServerName, {close, self(), Fd}, infinity), - ok. - -%% -%% connect(LIP, LPort, FIP, FPort, Flags) -> {ok, Fd, ProxyLFPort} | -%% {error, Reason} -%% -connect(LIP, LPort, FIP, FPort, Flags) -> - connect(LIP, LPort, FIP, FPort, Flags, infinity). -connect(LIP, LPort, FIP, FPort, Flags, Timeout) -> - connect_prim(ssl_server, LIP, LPort, FIP, FPort, Flags, Timeout). - -connect_prim(ServerName, LIP, LPort, FIP, FPort, Flags, Timeout) -> - Req = {connect, self(), LIP, LPort, FIP, FPort, Flags}, - gen_server:call(ServerName, Req, Timeout). - -%% -%% connection_info(Fd) -> {ok, {Protocol, Cipher}} | {error, Reason} -%% -connection_info(Fd) -> - Req = {connection_info, self(), Fd}, - gen_server:call(ssl_server, Req, infinity). - -%% -%% listen(IP, LPort, Flags), -%% listen(IP, LPort, Flags, BackLog) -> {ok, ListenFd, LPort0} | -%% {error, Reason} -%% -listen(IP, LPort, Flags) -> - listen(IP, LPort, Flags, ?DEF_BACKLOG). -listen(IP, LPort, Flags, BackLog) -> - listen_prim(ssl_server, IP, LPort, Flags, BackLog). -listen_prim(ServerName, IP, LPort, Flags, BackLog) -> - Req = {listen, self(), IP, LPort, Flags, BackLog}, - gen_server:call(ServerName, Req, infinity). - -%% -%% peercert(Fd) -> {ok, Cert} | {error, Reason} -%% -peercert(Fd) -> - Req = {peercert, self(), Fd}, - gen_server:call(ssl_server, Req, infinity). - -%% -%% peername(Fd) -> {ok, {Address, Port}} | {error, Reason} -%% -peername(Fd) -> - peername_prim(ssl_server, Fd). -peername_prim(ServerName, Fd) -> - Req = {peername, self(), Fd}, - gen_server:call(ServerName, Req, infinity). - -%% -%% proxy_join(Fd, LPort) -> ok | {error, Reason} -%% -proxy_join(Fd, LPort) -> - proxy_join_prim(ssl_server, Fd, LPort). -proxy_join_prim(ServerName, Fd, LPort) -> - Req = {proxy_join, self(), Fd, LPort}, - gen_server:call(ServerName, Req, infinity). - -%% -%% seed(Data) -%% -seed(Data) -> - Req = {seed, Data}, - gen_server:call(ssl_server, Req, infinity). - -%% -%% set_nodelay(Fd, Boolean) -%% -setnodelay(Fd, Boolean) -> - setnodelay_prim(ssl_server, Fd, Boolean). -setnodelay_prim(ServerName, Fd, Boolean) -> - Req = {setnodelay, self(), Fd, Boolean}, - gen_server:call(ServerName, Req, infinity). - -%% -%% sockname(Fd) -> {ok, {Address, Port}} | {error, Reason} -%% -sockname(Fd) -> - sockname_prim(ssl_server, Fd). -sockname_prim(ServerName, Fd) -> - Req = {sockname, self(), Fd}, - gen_server:call(ServerName, Req, infinity). - -%% -%% version() -> {ok, {CompVsn, LibVsn}} -%% -version() -> - gen_server:call(ssl_server, version, infinity). - - -enable_debug() -> - set_debug(true). - -disable_debug() -> - set_debug(false). - -set_debug(Bool) -> - set_debug(Bool, infinity). - -set_debug(Bool, Timeout) when is_boolean(Bool) -> - Req = {set_debug, Bool, self()}, - gen_server:call(ssl_server, Req, Timeout). - -enable_debugmsg() -> - set_debugmsg(true). - -disable_debugmsg() -> - set_debugmsg(false). - -set_debugmsg(Bool) -> - set_debugmsg(Bool, infinity). - -set_debugmsg(Bool, Timeout) when is_boolean(Bool) -> - Req = {set_debugmsg, Bool, self()}, - gen_server:call(ssl_server, Req, Timeout). - -dump() -> - dump(infinity). - -dump(Timeout) -> - Req = {dump, self()}, - gen_server:call(ssl_server, Req, Timeout). - -%% -%% init -%% -init([]) -> - Debug = case application:get_env(ssl, edebug) of - {ok, true} -> - true; - _ -> - case application:get_env(ssl, debug) of - {ok, true} -> - true; - _ -> - os:getenv("ERL_SSL_DEBUG") =/= false - end - end, - ProgDir = - case init:get_argument(ssl_portprogram_dir) of - {ok, [[D]]} -> - D; - _ -> - find_priv_bin() - end, - {Program, Flags} = mk_cmd_line("ssl_esock"), - Cmd = filename:join(ProgDir, Program) ++ " " ++ Flags, - debug1(Debug, " start, Cmd = ~s~n", [Cmd]), - case (catch open_port({spawn, Cmd}, [binary, {packet, 4}])) of - Port when is_port(Port) -> - process_flag(trap_exit, true), - receive - {Port, {data, Bin}} -> - {ProxyLLPort, ProgPid, CompVsn, LibVsn, Ciphers} = - decode_msg(Bin, [int16, int32, string, string, - string]), - debug1(Debug, "port program pid = ~w~n", - [ProgPid]), - {ok, #st{port = Port, - proxylsport = ProxyLLPort, - progpid = ProgPid, - debug = Debug, - compvsn = CompVsn, - libvsn = LibVsn, - ciphers = Ciphers}}; - {'EXIT', Port, Reason} -> - {stop, Reason} - end; - {'EXIT', Reason} -> - {stop, Reason} - end. - -%% -%% transport_accept -%% -handle_call({transport_accept, Broker, ListenFd, Flags}, From, St) -> - debug(St, "transport_accept: broker = ~w, listenfd = ~w~n", - [Broker, ListenFd]), - case get_by_fd(ListenFd, St#st.cons) of - {ok, {ListenFd, _, _}} -> - send_cmd(St#st.port, ?TRANSPORT_ACCEPT, [int32(ListenFd), Flags, 0]), - PAccepts = add({ListenFd, Broker, From}, St#st.paccepts), - %% - %% We reply when we get TRANSPORT_ACCEPT_REP or ASYNC_ACCEPT_ERR - %% - {noreply, St#st{paccepts = PAccepts}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% ssl_accept -%% -handle_call({ssl_accept, Fd, Flags}, From, St) -> - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} = _Rep -> - send_cmd(St#st.port, ?SSL_ACCEPT, [int32(Fd), Flags, 0]), - %% We reply when we get SSL_ACCEPT_REP or ASYNC_ACCEPT_ERR - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% version -%% -handle_call(ciphers, From, St) -> - debug(St, "ciphers: from = ~w~n", [From]), - {reply, {ok, St#st.ciphers}, St}; - -%% -%% connect -%% -handle_call({connect, Broker, LIP, LPort, FIP, FPort, Flags}, From, St) -> - debug(St, "connect: broker = ~w, ip = ~w, " - "sport = ~w~n", [Broker, FIP, FPort]), - Port = St#st.port, - LIPStr = ip_to_string(LIP), - FIPStr = ip_to_string(FIP), - IntRef = new_intref(St), - send_cmd(Port, ?CONNECT, [int32(IntRef), - int16(LPort), LIPStr, 0, - int16(FPort), FIPStr, 0, - Flags, 0]), - Cons = add({{intref, IntRef}, Broker, From}, St#st.cons), - %% We reply when we have got CONNECT_SYNC_ERR, or CONNECT_WAIT - %% and CONNECT_REP, or CONNECT_ERR. - {noreply, St#st{cons = Cons, intref = IntRef}}; - -%% -%% connection_info -%% -handle_call({connection_info, Broker, Fd}, From, St) -> - debug(St, "connection_info: broker = ~w, fd = ~w~n", - [Broker, Fd]), - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} -> - send_cmd(St#st.port, ?GETCONNINFO, [int32(Fd)]), - %% We reply when we get GETCONNINFO_REP or GETCONNINFO_ERR. - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% close -%% -handle_call({close, Broker, Fd}, _From, St) -> - debug(St, "close: broker = ~w, fd = ~w~n", - [Broker, Fd]), - #st{port = Port, cons = Cons0, paccepts = PAccepts0} = St, - case delete_by_fd(Fd, Cons0) of - %% Must match Broker pid; fd may be reused already. - {ok, {Fd, Broker, _}, Cons} -> - send_cmd(Port, ?CLOSE, int32(Fd)), - %% If Fd is a listen socket fd, there might be pending - %% accepts for that fd. - case delete_all_by_fd(Fd, PAccepts0) of - {ok, DelAccepts, RemAccepts} -> - %% Reply {error, closed} to all pending accepts - lists:foreach(fun({_, _, AccFrom}) -> - gen_server:reply(AccFrom, - {error, closed}) - end, DelAccepts), - {reply, ok, - St#st{cons = Cons, paccepts = RemAccepts}}; - _ -> - {reply, ok, St#st{cons = Cons}} - end; - _ -> - {reply, ok, St} - end; - -%% -%% listen -%% -handle_call({listen, Broker, IP, LPort, Flags, BackLog}, From, St) -> - debug(St, "listen: broker = ~w, IP = ~w, " - "sport = ~w~n", [Broker, IP, LPort]), - Port = St#st.port, - IPStr = ip_to_string(IP), - IntRef = new_intref(St), - send_cmd(Port, ?LISTEN, [int32(IntRef), int16(LPort), IPStr, 0, - int16(BackLog), Flags, 0]), - Cons = add({{intref, IntRef}, Broker, From}, St#st.cons), - %% We reply when we have got LISTEN_REP. - {noreply, St#st{cons = Cons, intref = IntRef}}; - -%% -%% peercert -%% -handle_call({peercert, Broker, Fd}, From, St) -> - debug(St, "peercert: broker = ~w, fd = ~w~n", - [Broker, Fd]), - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} -> - send_cmd(St#st.port, ?GETPEERCERT, [int32(Fd)]), - %% We reply when we get GETPEERCERT_REP or GETPEERCERT_ERR. - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - - -%% -%% peername -%% -handle_call({peername, Broker, Fd}, From, St) -> - debug(St, "peername: broker = ~w, fd = ~w~n", - [Broker, Fd]), - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} -> - send_cmd(St#st.port, ?GETPEERNAME, [int32(Fd)]), - %% We reply when we get GETPEERNAME_REP or GETPEERNAME_ERR. - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% proxy join -%% -handle_call({proxy_join, Broker, Fd, LPort}, From, St) -> - debug(St, "proxy_join: broker = ~w, fd = ~w, " - "sport = ~w~n", [Broker, Fd, LPort]), - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} -> - send_cmd(St#st.port, ?PROXY_JOIN, [int32(Fd), - int16(LPort)]), - %% We reply when we get PROXY_JOIN_REP, or PROXY_JOIN_ERR. - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% seed -%% -handle_call({seed, Data}, _From, St) when is_binary(Data) -> - send_cmd(St#st.port, ?SET_SEED, [int32(byte_size(Data)), Data]), - {reply, ok, St}; - -handle_call({seed, Data}, From, St) -> - case catch list_to_binary(Data) of - {'EXIT', _} -> - {reply, {error, edata}, St}; - Bin -> - handle_call({seed, Bin}, From, St) - end; - -%% -%% setnodelay -%% -handle_call({setnodelay, Broker, Fd, Boolean}, From, St) -> - debug(St, "setnodelay: broker = ~w, fd = ~w, " - "boolean = ~w~n", [Broker, Fd, Boolean]), - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} -> - Val = if Boolean == true -> 1; true -> 0 end, - send_cmd(St#st.port, ?SET_SOCK_OPT, - [int32(Fd), ?SET_TCP_NODELAY, Val]), - %% We reply when we get IOCTL_OK or IOCTL_ERR. - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% sockname -%% -handle_call({sockname, Broker, Fd}, From, St) -> - debug(St, "sockname: broker = ~w, fd = ~w~n", - [Broker, Fd]), - case replace_from_by_fd(Fd, St#st.cons, From) of - {ok, _, Cons} -> - send_cmd(St#st.port, ?GETSOCKNAME, [int32(Fd)]), - %% We reply when we get GETSOCKNAME_REP or GETSOCKNAME_ERR. - {noreply, St#st{cons = Cons}}; - _Other -> - {reply, {error, ebadf}, St} - end; - -%% -%% version -%% -handle_call(version, From, St) -> - debug(St, "version: from = ~w~n", [From]), - {reply, {ok, {St#st.compvsn, St#st.libvsn}}, St}; - -%% -%% dump -%% -handle_call({dump, Broker}, _From, St) -> - debug(St, "dump: broker = ~w", [Broker]), - Port = St#st.port, - send_cmd(Port, ?DUMP_CMD, []), - {reply, ok, St}; - -%% -%% set_debug -%% -handle_call({set_debug, Bool, Broker}, _From, St) -> - debug(St, "set_debug: broker = ~w", [Broker]), - Value = case Bool of - true -> - 1; - false -> - 0 - end, - Port = St#st.port, - send_cmd(Port, ?DEBUG_CMD, [Value]), - {reply, ok, St}; - -%% -%% set_debugmsg -%% -handle_call({set_debugmsg, Bool, Broker}, _From, St) -> - debug(St, "set_debugmsg: broker = ~w", [Broker]), - Value = case Bool of - true -> - 1; - false -> - 0 - end, - Port = St#st.port, - send_cmd(Port, ?DEBUGMSG_CMD, [Value]), - {reply, ok, St}; - -handle_call(Request, _From, St) -> - debug(St, "unexpected call: ~w~n", [Request]), - Reply = {error, {badcall, Request}}, - {reply, Reply, St}. - -%% -%% handle_cast(Msg, St) -%% - - -handle_cast(Msg, St) -> - debug(St, "unexpected cast: ~w~n", [Msg]), - {noreply, St}. - -%% -%% handle_info(Info, St) -%% - -%% Data from port -%% -handle_info({Port, {data, Bin}}, - #st{cons = StCons, paccepts = Paccepts, - port = Port, proxylsport = Proxylsport} = St) - when is_binary(Bin) -> - %% io:format("++++ ssl_server got from port: ~w~n", [Bin]), - <> = Bin, - case OpCode of - %% - %% transport_accept - %% - ?TRANSPORT_ACCEPT_ERR when byte_size(Bin) >= 5 -> - {ListenFd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "transport_accept_err: listenfd = ~w, " - "reason = ~w~n", [ListenFd, Reason]), - case delete_last_by_fd(ListenFd, Paccepts) of - {ok, {_, _, From}, PAccepts} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{paccepts = PAccepts}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?TRANSPORT_ACCEPT_REP when byte_size(Bin) >= 9 -> - {ListenFd, Fd} = decode_msg(Bin, [int32, int32]), - debug(St, "transport_accept_rep: listenfd = ~w, " - "fd = ~w~n", [ListenFd, Fd]), - case delete_last_by_fd(ListenFd, Paccepts) of - {ok, {_, Broker, From}, PAccepts} -> - Reply = {ok, Fd, Proxylsport}, - gen_server:reply(From, Reply), - debug(St, "transport_accept_rep: From = ~w\n", [From]), - Cons = add({Fd, Broker, From}, StCons), - {noreply, St#st{cons = Cons, paccepts = PAccepts}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% ssl_accept - %% - ?SSL_ACCEPT_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "ssl_accept_err: listenfd = ~w, " - "reason = ~w~n", [Fd, Reason]), - %% JC: remove this? - case delete_last_by_fd(Fd, StCons) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?SSL_ACCEPT_REP when byte_size(Bin) >= 5 -> - Fd = decode_msg(Bin, [int32]), - debug(St, "ssl_accept_rep: Fd = ~w\n", [Fd]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, ok), - {noreply, St#st{cons = Cons}}; - _ -> - {noreply, St} - end; - - %% - %% connect - %% - ?CONNECT_SYNC_ERR when byte_size(Bin) >= 5 -> - {IntRef, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "connect_sync_err: intref = ~w, " - "reason = ~w~n", [IntRef, Reason]), - case delete_by_intref(IntRef, StCons) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - {noreply, St} - end; - ?CONNECT_WAIT when byte_size(Bin) >= 9 -> - {IntRef, Fd} = decode_msg(Bin, [int32, int32]), - debug(St, "connect_wait: intref = ~w, " - "fd = ~w~n", [IntRef, Fd]), - case replace_fd_by_intref(IntRef, StCons, Fd) of - {ok, _, Cons} -> - %% We reply when we get CONNECT_REP or CONNECT_ERR - {noreply, St#st{cons = Cons}}; - _Other -> - %% We have a new Fd which must be closed - send_cmd(Port, ?CLOSE, int32(Fd)), - {noreply, St} - end; - ?CONNECT_REP when byte_size(Bin) >= 5 -> - %% after CONNECT_WAIT - Fd = decode_msg(Bin, [int32]), - debug(St, "connect_rep: fd = ~w~n", [Fd]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {ok, Fd, Proxylsport}), - {noreply, St#st{cons = Cons}}; - _Other -> - {noreply, St} - end; - ?CONNECT_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "connect_err: fd = ~w, " - "reason = ~w~n", [Fd, Reason]), - case delete_by_fd(Fd, StCons) of - {ok, {_, _, From}, Cons} -> - %% Fd not yet published - hence close ourselves - send_cmd(Port, ?CLOSE, int32(Fd)), - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% connection_info - %% - ?GETCONNINFO_REP when byte_size(Bin) >= 5 -> - {Fd, Protocol, Cipher} = decode_msg(Bin, [int32, string, string]), - debug(St, "connection_info_rep: fd = ~w, " - "protcol = ~p, ip = ~p~n", [Fd, Protocol, Cipher]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {ok, {protocol_name(Protocol), - Cipher}}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?GETCONNINFO_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "connection_info_err: fd = ~w, " - "reason = ~w~n", [Fd, Reason]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% listen - %% - ?LISTEN_SYNC_ERR when byte_size(Bin) >= 5 -> - {IntRef, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "listen_sync_err: intref = ~w, " - "reason = ~w~n", [IntRef, Reason]), - case delete_by_intref(IntRef, StCons) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - {noreply, St} - end; - ?LISTEN_REP when byte_size(Bin) >= 11 -> - {IntRef, ListenFd, LPort} = decode_msg(Bin, [int32, int32, int16]), - debug(St, "listen_rep: intref = ~w, " - "listenfd = ~w, sport = ~w~n", [IntRef, ListenFd, LPort]), - case replace_fd_from_by_intref(IntRef, StCons, ListenFd, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {ok, ListenFd, LPort}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% ListenFd has to be closed. - send_cmd(Port, ?CLOSE, int32(ListenFd)), - {noreply, St} - end; - - %% - %% proxy join - %% - ?PROXY_JOIN_REP when byte_size(Bin) >= 5 -> - Fd = decode_msg(Bin, [int32]), - debug(St, "proxy_join_rep: fd = ~w~n", - [Fd]), - case get_by_fd(Fd, StCons) of - {ok, {_, _, From}} -> - gen_server:reply(From, ok), - {noreply, St}; - _Other -> - %% Already closed - {noreply, St} - end; - ?PROXY_JOIN_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "proxy_join_rep: fd = ~w, " - "reason = ~w~n", [Fd, Reason]), - case delete_by_fd(Fd, StCons) of - {ok, {_, _, From}, Cons} -> - case Reason of - enoproxysocket -> - send_cmd(Port, ?CLOSE, int32(Fd)); - _ -> - ok - %% Must not close Fd since it is published - end, - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% peername - %% - ?GETPEERNAME_REP when byte_size(Bin) >= 5 -> - {Fd, LPort, IPString} = decode_msg(Bin, [int32, int16, string]), - debug(St, "getpeername_rep: fd = ~w, " - "sport = ~w, ip = ~p~n", [Fd, LPort, IPString]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {ok, {IPString, LPort}}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?GETPEERNAME_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "getpeername_err: fd = ~w, " - "reason = ~w~n", [Fd, Reason]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% ioctl - %% - ?IOCTL_OK when byte_size(Bin) >= 5 -> - Fd = decode_msg(Bin, [int32]), - debug(St, "ioctl_ok: fd = ~w~n", - [Fd]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, ok), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?IOCTL_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "ioctl_err: fd = ~w, " - "reason = ~w~n", [Fd, Reason]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% sockname - %% - ?GETSOCKNAME_REP when byte_size(Bin) >= 5 -> - {Fd, LPort, IPString} = decode_msg(Bin, [int32, int16, string]), - debug(St, "getsockname_rep: fd = ~w, " - "sport = ~w, ip = ~p~n", [Fd, LPort, IPString]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {ok, {IPString, LPort}}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?GETSOCKNAME_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "getsockname_err: fd = ~w, " - "reason = ~w~n", [Fd, Reason]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - - %% - %% peercert - %% - ?GETPEERCERT_REP when byte_size(Bin) >= 5 -> - {Fd, Cert} = decode_msg(Bin, [int32, bin]), - debug(St, "getpeercert_rep: fd = ~w~n", [Fd]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {ok, Cert}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end; - ?GETPEERCERT_ERR when byte_size(Bin) >= 5 -> - {Fd, Reason} = decode_msg(Bin, [int32, atom]), - debug(St, "getpeercert_err: fd = ~w, reason = ~w~n", - [Fd, Reason]), - case replace_from_by_fd(Fd, StCons, []) of - {ok, {_, _, From}, Cons} -> - gen_server:reply(From, {error, Reason}), - {noreply, St#st{cons = Cons}}; - _Other -> - %% Already closed - {noreply, St} - end - end; - -%% -%% EXIT -%% -handle_info({'EXIT', Pid, Reason}, St) when is_pid(Pid) -> - debug(St, "exit pid = ~w, " - "reason = ~w~n", [Pid, Reason]), - case delete_by_pid(Pid, St#st.cons) of - {ok, {{intref, _}, Pid, _}, Cons} -> - {noreply, St#st{cons = Cons}}; - {ok, {Fd, Pid, _}, Cons} -> - send_cmd(St#st.port, ?CLOSE, int32(Fd)), - %% If Fd is a listen socket fd, there might be pending - %% accepts for that fd. - case delete_all_by_fd(Fd, St#st.paccepts) of - {ok, DelAccepts, RemAccepts} -> - %% Reply {error, closed} to all pending accepts. - lists:foreach(fun({_, _, From}) -> - gen_server:reply(From, - {error, closed}) - end, DelAccepts), - {noreply, - St#st{cons = Cons, paccepts = RemAccepts}}; - _ -> - {noreply, St#st{cons = Cons}} - end; - _ -> - case delete_by_pid(Pid, St#st.paccepts) of - {ok, {ListenFd, _, _}, PAccepts} -> - %% decrement ref count in port program - send_cmd(St#st.port, ?NOACCEPT, int32(ListenFd)), - {noreply, St#st{paccepts = PAccepts}}; - _ -> - {noreply, St} - end - end; - -%% -%% 'badsig' means bad message to port. Port program is unaffected. -%% -handle_info({'EXIT', Port, badsig}, #st{port = Port} = St) -> - debug(St, "badsig!!!~n", []), - {noreply, St}; - -handle_info({'EXIT', Port, Reason}, #st{port = Port} = St) -> - {stop, Reason, St}; - -handle_info(Info, St) -> - debug(St, "unexpected info: ~w~n", [Info]), - {noreply, St}. - -%% -%% terminate(Reason, St) -> any -%% -terminate(_Reason, _St) -> - ok. - -%% -%% code_change(OldVsn, St, Extra) -> {ok, NSt} -%% -code_change(_OldVsn, St, _Extra) -> - {ok, St}. - -%%%---------------------------------------------------------------------- -%%% Internal functions -%%%---------------------------------------------------------------------- - -%% -%% Send binary command to sock -%% -send_cmd(Port, Cmd, Args) -> - Port ! {self(), {command, [Cmd| Args]}}. - -%% -%% add(Descr, Cons) -> NCons -%% -add(D, L) -> - [D| L]. - -%% -%% get_by_fd(Fd, Cons) -> {ok, Descr} | not_found -%% -get_by_fd(Fd, Cons) -> - get_by_pos(Fd, 1, Cons). - -%% -%% delete_by_fd(Fd, Cons) -> {ok, OldDesc, NewCons} | not_found. -%% -delete_by_fd(Fd, Cons) -> - delete_by_pos(Fd, 1, Cons). - -%% -%% delete_all_by_fd(Fd, Cons) -> {ok, DelCons, RemCons} | not_found. -%% -delete_all_by_fd(Fd, Cons) -> - delete_all_by_pos(Fd, 1, Cons). - -%% -%% delete_by_intref(IntRef, Cons) -> {ok, OldDesc, NewCons} | not_found. -%% -delete_by_intref(IntRef, Cons) -> - delete_by_pos({intref, IntRef}, 1, Cons). - -%% -%% delete_by_pid(Pid, Cons) -> {ok, OldDesc, NewCons} | not_found. -%% -delete_by_pid(Pid, Cons) -> - delete_by_pos(Pid, 2, Cons). - -%% -%% delete_last_by_fd(Fd, Cons) -> {ok, OldDesc, NCons} | not_found -%% -delete_last_by_fd(Fd, Cons) -> - case dlbf(Fd, Cons) of - {X, L} -> - {ok, X, L}; - _Other -> - not_found - end. - -dlbf(Fd, [H]) -> - last_elem(Fd, H, []); -dlbf(Fd, [H|T]) -> - case dlbf(Fd, T) of - {X, L} -> - {X, [H|L]}; - L -> - last_elem(Fd, H, L) - end; -dlbf(_Fd, []) -> - []. - -last_elem(Fd, H, L) when element(1, H) == Fd -> - {H, L}; -last_elem(_, H, L) -> - [H|L]. - - -%% -%% replace_from_by_fd(Fd, Cons, From) -> {ok, OldDesc, NewList} | not_found -%% -replace_from_by_fd(Fd, Cons, From) -> - replace_posn_by_pos(Fd, 1, Cons, [{From, 3}]). - -%% -%% replace_fd_by_intref(IntRef, Cons, Fd) -> {ok, OldDesc, NewList} | not_f. -%% -replace_fd_by_intref(IntRef, Cons, Fd) -> - replace_posn_by_pos({intref, IntRef}, 1, Cons, [{Fd, 1}]). - -%% -%% replace_fd_from_by_intref(IntRef, Cons, NFd, From) -> -%% {ok, OldDesc, NewList} | not_found -%% -replace_fd_from_by_intref(IntRef, Cons, NFd, From) -> - replace_posn_by_pos({intref, IntRef}, 1, Cons, [{NFd, 1}, {From, 3}]). - - -%% -%% All *_by_pos functions -%% - -get_by_pos(Key, Pos, [H|_]) when element(Pos, H) == Key -> - {ok, H}; -get_by_pos(Key, Pos, [_|T]) -> - get_by_pos(Key, Pos, T); -get_by_pos(_, _, []) -> - not_found. - -delete_by_pos(Key, Pos, Cons) -> - case delete_by_pos1(Key, Pos, {not_found, Cons}) of - {not_found, _} -> - not_found; - {ODesc, NCons} -> - {ok, ODesc, NCons} - end. -delete_by_pos1(Key, Pos, {_R, [H|T]}) when element(Pos, H) == Key -> - {H, T}; -delete_by_pos1(Key, Pos, {R, [H|T]}) -> - {R0, T0} = delete_by_pos1(Key, Pos, {R, T}), - {R0, [H| T0]}; -delete_by_pos1(_, _, {R, []}) -> - {R, []}. - -delete_all_by_pos(Key, Pos, Cons) -> - case lists:foldl(fun(H, {Ds, Rs}) when element(Pos, H) == Key -> - {[H|Ds], Rs}; - (H, {Ds, Rs}) -> - {Ds, [H|Rs]} - end, {[], []}, Cons) of - {[], _} -> - not_found; - {DelCons, RemCons} -> - {ok, DelCons, RemCons} - end. - -replace_posn_by_pos(Key, Pos, Cons, Repls) -> - replace_posn_by_pos1(Key, Pos, Cons, Repls, []). - -replace_posn_by_pos1(Key, Pos, [H0| T], Repls, Acc) - when element(Pos, H0) =:= Key -> - H = lists:foldl(fun({Val, VPos}, Tuple) -> - setelement(VPos, Tuple, Val) - end, H0, Repls), - {ok, H0, lists:reverse(Acc, [H| T])}; -replace_posn_by_pos1(Key, Pos, [H|T], Repls, Acc) -> - replace_posn_by_pos1(Key, Pos, T, Repls, [H| Acc]); -replace_posn_by_pos1(_, _, [], _, _) -> - not_found. - -%% -%% Binary/integer conversions -%% -int16(I) -> - %%[(I bsr 8) band 255, I band 255]. - <>. - -int32(I) -> - %% [(I bsr 24) band 255, - %% (I bsr 16) band 255, - %% (I bsr 8) band 255, - %% I band 255]. - <>. - -%% decode_msg(Bin, Format) -> Tuple | integer() | atom() | string() | -%% list of binaries() -%% -%% Decode message from binary -%% Format = [spec()] -%% spec() = int16 | int32 | string | atom | bin | bins -%% -%% Notice: The first byte (op code) of the binary message is removed. -%% Notice: bins returns a *list* of binaries. -%% -decode_msg(<<_, Bin/binary>>, Format) -> - Dec = dec(Format, Bin), - case Dec of - [Dec1] -> Dec1; - _ -> list_to_tuple(Dec) - end. - -dec([], _) -> - []; -dec([int16| F], <>) -> - [N| dec(F, Bin)]; -dec([int32| F], <>) -> - [N| dec(F, Bin)]; -dec([string| F], Bin0) -> - {Cs, Bin1} = dec_string(Bin0), - [Cs| dec(F, Bin1)]; -dec([atom|F], Bin0) -> - {Cs, Bin1} = dec_string(Bin0), - [list_to_atom(Cs)| dec(F, Bin1)]; - -dec([bin|F], Bin) -> - {Bin1, Bin2} = dec_bin(Bin), - [Bin1| dec(F, Bin2)]. - -%% NOTE: This clause is not actually used yet. -%% dec([bins|F], <>) -> -%% {Bins, Bin1} = dec_bins(N, Bin0), -%% [Bins| dec(F, Bin1)]. - -dec_string(Bin) -> - dec_string(Bin, []). - -dec_string(<<0, Bin/binary>>, RCs) -> - {lists:reverse(RCs), Bin}; -dec_string(<>, RCs) -> - dec_string(Bin, [C| RCs]). - -dec_bin(<>) -> - <> = Bin0, - {Bin1, Bin2}. - -%% dec_bins(N, Bin) -> -%% dec_bins(N, Bin, []). - -%% dec_bins(0, Bin, Acc) -> -%% {lists:reverse(Acc), Bin}; -%% dec_bins(N, Bin0, Acc) when N > 0 -> -%% {Bin1, Bin2} = dec_bin(Bin0), -%% dec_bins(N - 1, Bin2, [Bin1| Acc]). - -%% -%% new_intref -%% -new_intref(St) -> - (St#st.intref + 1) band 16#ffffffff. - -%% -%% {Program, Flags} = mk_cmd_line(DefaultProgram) -%% -mk_cmd_line(Default) -> - {port_program(Default), - lists:flatten([debug_flag(), " ", debug_port_flag(), " ", - debugdir_flag(), " ", - msgdebug_flag(), " ", proxylsport_flag(), " ", - proxybacklog_flag(), " ", ephemeral_rsa_flag(), " ", - ephemeral_dh_flag(), " ", - protocol_version_flag(), " "])}. - -port_program(Default) -> - case application:get_env(ssl, port_program) of - {ok, Program} when is_list(Program) -> - Program; - _Other -> - Default - end. - -%% -%% As this server may be started by the distribution, it is not safe to assume -%% a working code server, neither a working file server. -%% I try to utilize the most primitive interfaces available to determine -%% the directory of the port_program. -%% -find_priv_bin() -> - PrivDir = case (catch code:priv_dir(ssl)) of - {'EXIT', _} -> - %% Code server probably not startet yet - {ok, P} = erl_prim_loader:get_path(), - ModuleFile = atom_to_list(?MODULE) ++ extension(), - Pd = (catch lists:foldl - (fun(X,Acc) -> - M = filename:join([X, ModuleFile]), - %% The file server probably not started - %% either, has to use raw interface. - case file:raw_read_file_info(M) of - {ok,_} -> - %% Found our own module in the - %% path, lets bail out with - %% the priv_dir of this directory - Y = filename:split(X), - throw(filename:join - (lists:sublist - (Y,length(Y) - 1) - ++ ["priv"])); - _ -> - Acc - end - end, - false,P)), - case Pd of - false -> - exit(ssl_priv_dir_indeterminate); - _ -> - Pd - end; - Dir -> - Dir - end, - filename:join([PrivDir, "bin"]). - -extension() -> - %% erlang:info(machine) returns machine name as text in all uppercase - "." ++ string:to_lower(erlang:system_info(machine)). - -debug_flag() -> - case os:getenv("ERL_SSL_DEBUG") of - false -> - get_env(debug, "-d"); - _ -> - "-d" - end. - -debug_port_flag() -> - case os:getenv("ERL_SSL_DEBUGPORT") of - false -> - get_env(debug, "-d"); - _ -> - "-d" - end. - -msgdebug_flag() -> - case os:getenv("ERL_SSL_MSGDEBUG") of - false -> - get_env(msgdebug, "-dm"); - _ -> - "-dm" - end. - -proxylsport_flag() -> - case application:get_env(ssl, proxylsport) of - {ok, PortNum} -> - "-pp " ++ integer_to_list(PortNum); - _Other -> - "" - end. - -proxybacklog_flag() -> - case application:get_env(ssl, proxylsbacklog) of - {ok, Size} -> - "-pb " ++ integer_to_list(Size); - _Other -> - "" - end. - -debugdir_flag() -> - case os:getenv("ERL_SSL_DEBUG") of - false -> - case application:get_env(ssl, debugdir) of - {ok, Dir} when is_list(Dir) -> - "-dd " ++ Dir; - _Other -> - "" - end; - _ -> - "-dd ./" - end. - -ephemeral_rsa_flag() -> - case application:get_env(ssl, ephemeral_rsa) of - {ok, true} -> - "-ersa "; - _Other -> - "" - end. - -ephemeral_dh_flag() -> - case application:get_env(ssl, ephemeral_dh) of - {ok, true} -> - "-edh "; - _Other -> - "" - end. - -protocol_version_flag() -> - case application:get_env(ssl, protocol_version) of - {ok, []} -> - ""; - {ok, Vsns} when is_list(Vsns) -> - case transform_vsns(Vsns) of - N when (N > 0) -> - "-pv " ++ integer_to_list(N); - _ -> - "" - end; - _Other -> - "" - end. - -transform_vsns(Vsns) -> - transform_vsns(Vsns, 0). - -transform_vsns([sslv2| Vsns], I) -> - transform_vsns(Vsns, I bor ?SSLv2); -transform_vsns([sslv3| Vsns], I) -> - transform_vsns(Vsns, I bor ?SSLv3); -transform_vsns([tlsv1| Vsns], I) -> - transform_vsns(Vsns, I bor ?TLSv1); -transform_vsns([_ | Vsns], I) -> - transform_vsns(Vsns, I); -transform_vsns([], I) -> - I. - -protocol_name("SSLv2") -> sslv2; -protocol_name("SSLv3") -> sslv3; -protocol_name("TLSv1") -> tlsv1. - -get_env(Key, Val) -> - case application:get_env(ssl, Key) of - {ok, true} -> - Val; - _Other -> - "" - end. - -ip_to_string({A,B,C,D}) -> - [integer_to_list(A),$.,integer_to_list(B),$., - integer_to_list(C),$.,integer_to_list(D)]. - -debug(St, Format, Args) -> - debug1(St#st.debug, Format, Args). - -debug1(true, Format0, Args) -> - {_MS, S, MiS} = erlang:now(), - Secs = S rem 100, - MiSecs = MiS div 1000, - Format = "++++ ~3..0w:~3..0w ssl_server (~w): " ++ Format0, - io:format(Format, [Secs, MiSecs, self()| Args]); -debug1(_, _, _) -> - ok. diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl index a008682b89..cb10b1362a 100644 --- a/lib/ssl/src/ssl_sup.erl +++ b/lib/ssl/src/ssl_sup.erl @@ -51,16 +51,15 @@ init([]) -> %% Does not start any port programs so it does matter %% so much if it is not used! - Child2 = {ssl_broker_sup, {ssl_broker_sup, start_link, []}, - permanent, 2000, supervisor, [ssl_broker_sup]}, + %% Child2 = {ssl_broker_sup, {ssl_broker_sup, start_link, []}, + %% permanent, 2000, supervisor, [ssl_broker_sup]}, %% New ssl SessionCertManager = session_and_cert_manager_child_spec(), ConnetionManager = connection_manager_child_spec(), - {ok, {{one_for_all, 10, 3600}, [Child2, SessionCertManager, - ConnetionManager]}}. + {ok, {{one_for_all, 10, 3600}, [SessionCertManager, ConnetionManager]}}. manager_opts() -> diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 45a401aa68..232e307a03 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -42,26 +42,15 @@ MODULES = \ ssl_to_openssl_SUITE \ ssl_session_cache_SUITE \ ssl_dist_SUITE \ - ssl_test_MACHINE \ - old_ssl_active_SUITE \ - old_ssl_active_once_SUITE \ - old_ssl_passive_SUITE \ - old_ssl_verify_SUITE \ - old_ssl_peer_cert_SUITE \ - old_ssl_misc_SUITE \ - old_ssl_protocol_SUITE \ - old_transport_accept_SUITE \ - old_ssl_dist_SUITE \ make_certs\ erl_make_certs ERL_FILES = $(MODULES:%=%.erl) -HRL_FILES = ssl_test_MACHINE.hrl +HRL_FILES = HRL_FILES_SRC = \ - ssl_int.hrl \ ssl_internal.hrl\ ssl_alert.hrl \ ssl_handshake.hrl \ diff --git a/lib/ssl/test/old_ssl_active_SUITE.erl b/lib/ssl/test/old_ssl_active_SUITE.erl deleted file mode 100644 index 52ff0bcc5d..0000000000 --- a/lib/ssl/test/old_ssl_active_SUITE.erl +++ /dev/null @@ -1,395 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2011. 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(old_ssl_active_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - cinit_return_chkclose/1, - sinit_return_chkclose/1, - cinit_big_return_chkclose/1, - sinit_big_return_chkclose/1, - cinit_big_echo_chkclose/1, - cinit_huge_echo_chkclose/1, - sinit_big_echo_chkclose/1, - cinit_few_echo_chkclose/1, - cinit_many_echo_chkclose/1, - cinit_cnocert/1 - ]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). - --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - --define(MANYCONNS, ssl_test_MACHINE:many_conns()). - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [cinit_return_chkclose, sinit_return_chkclose, - cinit_big_return_chkclose, sinit_big_return_chkclose, - cinit_big_echo_chkclose, cinit_huge_echo_chkclose, - sinit_big_echo_chkclose, cinit_few_echo_chkclose, - cinit_many_echo_chkclose, cinit_cnocert]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains, and record the number of available " - "file descriptors"; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - case os:type() of - {unix, _} -> - ?line io:format("Max fd value: ~s", [os:cmd("ulimit -n")]); - _ -> - ok - end, - %% XXX Also record: Erlang/SSL version, version of OpenSSL, - %% operating system, version of OTP, Erts, kernel and stdlib. - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto!"} - end. - -end_per_suite(doc) -> - "This test case has no mission other than closing the conf case"; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -cinit_return_chkclose(doc) -> - "Client sends 1000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -cinit_return_chkclose(suite) -> - []; -cinit_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_return_chkclose(doc) -> - "Server sends 1000 bytes to client, that receives them, sends them " - "back, and closes. Server waits for close. Both have certs."; -sinit_return_chkclose(suite) -> - []; -sinit_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, [{ssl_imp, old}|SsslOpts]}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sslopts, [{ssl_imp, old}|CsslOpts]}, - {connect, {Host, LPort}}, - {recv, DataSize}, {send, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_big_return_chkclose(doc) -> - "Client sends 50000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -cinit_big_return_chkclose(suite) -> - []; -cinit_big_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_big_return_chkclose(doc) -> - "Server sends 50000 bytes to client, that receives them, sends them " - "back, and closes. Server waits for close. Both have certs."; -sinit_big_return_chkclose(suite) -> - []; -sinit_big_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {recv, DataSize}, {send, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_big_echo_chkclose(doc) -> - "Client sends 50000 bytes to server, that echoes them back " - "and closes. Client waits for close. Both have certs."; -cinit_big_echo_chkclose(suite) -> - []; -cinit_big_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_huge_echo_chkclose(doc) -> - "Client sends 500000 bytes to server, that echoes them back " - "and closes. Client waits for close. Both have certs."; -cinit_huge_echo_chkclose(suite) -> - []; -cinit_huge_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 500000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_big_echo_chkclose(doc) -> - "Server sends 50000 bytes to client, that echoes them back " - "and closes. Server waits for close. Both have certs."; -sinit_big_echo_chkclose(suite) -> - []; -sinit_big_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {echo, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - - -%% This case is repeated several times. - -cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7). - -cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS). - -cinit_many_echo_chkclose(doc, _NConns) -> - "N client sends 10000 bytes to server, that echoes them back " - "and closes. Clients wait for close. All have certs."; -cinit_many_echo_chkclose(suite, _NConns) -> - []; -cinit_many_echo_chkclose(Config, NConns) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 10000, LPort = 3456, - Timeout = 80000, - - io:format("~w connections", [NConns]), - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - - -cinit_cnocert(doc) -> - "Client sends 1000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Client has no cert, " - "but server has."; -cinit_cnocert(suite) -> - []; -cinit_cnocert(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3457, - Timeout = 40000, NConns = 1, - - ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - - diff --git a/lib/ssl/test/old_ssl_active_once_SUITE.erl b/lib/ssl/test/old_ssl_active_once_SUITE.erl deleted file mode 100644 index c7beadb301..0000000000 --- a/lib/ssl/test/old_ssl_active_once_SUITE.erl +++ /dev/null @@ -1,417 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2011. 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(old_ssl_active_once_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - server_accept_timeout/1, - cinit_return_chkclose/1, - sinit_return_chkclose/1, - cinit_big_return_chkclose/1, - sinit_big_return_chkclose/1, - cinit_big_echo_chkclose/1, - cinit_huge_echo_chkclose/1, - sinit_big_echo_chkclose/1, - cinit_few_echo_chkclose/1, - cinit_many_echo_chkclose/1, - cinit_cnocert/1 - ]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - --define(MANYCONNS, ssl_test_MACHINE:many_conns()). - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [server_accept_timeout, cinit_return_chkclose, - sinit_return_chkclose, cinit_big_return_chkclose, - sinit_big_return_chkclose, cinit_big_echo_chkclose, - cinit_huge_echo_chkclose, sinit_big_echo_chkclose, - cinit_few_echo_chkclose, cinit_many_echo_chkclose, - cinit_cnocert]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains."; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto"} - end. - -end_per_suite(doc) -> - "This test case has no mission other than closing the conf case"; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -server_accept_timeout(doc) -> - "Server has one pending accept with timeout. Checks that return " - "value is {error, timeout}."; -server_accept_timeout(suite) -> - []; -server_accept_timeout(Config) when list(Config) -> - process_flag(trap_exit, true), - LPort = 3456, - Timeout = 40000, NConns = 1, - AccTimeout = 3000, - - ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, AccTimeout}, - accept_timeout], - ?line test_server_only(NConns, LCmds, ACmds, Timeout, ?MODULE, - Config). - -cinit_return_chkclose(doc) -> - "Client sends 1000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -cinit_return_chkclose(suite) -> - []; -cinit_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_return_chkclose(doc) -> - "Server sends 1000 bytes to client, that receives them, sends them " - "back, and closes. Server waits for close. Both have certs."; -sinit_return_chkclose(suite) -> - []; -sinit_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {recv, DataSize}, {send, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_big_return_chkclose(doc) -> - "Client sends 50000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -cinit_big_return_chkclose(suite) -> - []; -cinit_big_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - %% Set {active, false} so that accept is passive to begin with. - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {sockopts, [{active, once}]}, % {active, once} here. - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_big_return_chkclose(doc) -> - "Server sends 50000 bytes to client, that receives them, sends them " - "back, and closes. Server waits for close. Both have certs."; -sinit_big_return_chkclose(suite) -> - []; -sinit_big_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {recv, DataSize}, {send, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_big_echo_chkclose(doc) -> - "Client sends 50000 bytes to server, that echoes them back " - "and closes. Client waits for close. Both have certs."; -cinit_big_echo_chkclose(suite) -> - []; -cinit_big_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_huge_echo_chkclose(doc) -> - "Client sends 500000 bytes to server, that echoes them back " - "and closes. Client waits for close. Both have certs."; -cinit_huge_echo_chkclose(suite) -> - []; -cinit_huge_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 500000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_big_echo_chkclose(doc) -> - "Server sends 50000 bytes to client, that echoes them back " - "and closes. Server waits for close. Both have certs."; -sinit_big_echo_chkclose(suite) -> - []; -sinit_big_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {echo, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7). - -cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS). - -cinit_many_echo_chkclose(doc, _NConns) -> - "client send 10000 bytes to server, that echoes them back " - "and closes. Clients wait for close. All have certs."; -cinit_many_echo_chkclose(suite, _NConns) -> - []; -cinit_many_echo_chkclose(Config, NConns) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 10000, LPort = 3456, - Timeout = 80000, - - io:format("~w connections", [NConns]), - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_cnocert(doc) -> - "Client sends 1000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Client has no cert, " - "but server has."; -cinit_cnocert(suite) -> - []; -cinit_cnocert(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3457, - Timeout = 40000, NConns = 1, - - ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, once}]}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - - diff --git a/lib/ssl/test/old_ssl_dist_SUITE.erl b/lib/ssl/test/old_ssl_dist_SUITE.erl deleted file mode 100644 index 4544fb616a..0000000000 --- a/lib/ssl/test/old_ssl_dist_SUITE.erl +++ /dev/null @@ -1,617 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2011. 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% -%% - -%% - - -%%%------------------------------------------------------------------- -%%% File : ssl_dist_SUITE.erl -%%% Author : Rickard Green -%%% Description : Test that the Erlang distribution works over ssl. -%%% -%%% Created : 15 Nov 2007 by Rickard Green -%%%------------------------------------------------------------------- --module(old_ssl_dist_SUITE). - --include_lib("test_server/include/test_server.hrl"). - --define(DEFAULT_TIMETRAP_SECS, 240). - --define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000). - --export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]). --export([init_per_suite/1, - end_per_suite/1, - init_per_testcase/2, - end_per_testcase/2]). --export([cnct2tstsrvr/1]). - --export([basic/1]). - --record(node_handle, {connection_handler, socket, name, nodename}). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [basic]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(Config) -> - try crypto:start() of - ok -> - add_ssl_opts_config(Config) - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(Config) -> - application:stop(crypto), - Config. - -init_per_testcase(Case, Config) when list(Config) -> - Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)), - [{watchdog, Dog},{testcase, Case}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - ?t:timetrap_cancel(Dog), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% Testcases %% -%% %% - -basic(doc) -> - ["Test that two nodes can connect via ssl distribution"]; -basic(suite) -> - []; -basic(Config) when is_list(Config) -> - ?line NH1 = start_ssl_node(Config), - ?line Node1 = NH1#node_handle.nodename, - ?line NH2 = start_ssl_node(Config), - ?line Node2 = NH2#node_handle.nodename, - - ?line pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), - - ?line [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end), - ?line [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end), - - %% The test_server node has the same cookie as the ssl nodes - %% but it should not be able to communicate with the ssl nodes - %% via the erlang distribution. - ?line pang = net_adm:ping(Node1), - ?line pang = net_adm:ping(Node2), - - - %% - %% Check that we are able to communicate over the erlang - %% distribution between the ssl nodes. - %% - ?line Ref = make_ref(), - ?line spawn(fun () -> - apply_on_ssl_node( - NH1, - fun () -> - tstsrvr_format("Hi from ~p!~n", - [node()]), - send_to_tstcntrl({Ref, self()}), - receive - {From, ping} -> - From ! {self(), pong} - end - end) - end), - ?line receive - {Ref, SslPid} -> - ?line ok = apply_on_ssl_node( - NH2, - fun () -> - tstsrvr_format("Hi from ~p!~n", - [node()]), - SslPid ! {self(), ping}, - receive - {SslPid, pong} -> - ok - end - end) - end, - - ?line stop_ssl_node(NH1), - ?line stop_ssl_node(NH2), - ?line success(Config). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% Internal functions %% -%% %% - -%% -%% ssl_node side api -%% - -tstsrvr_format(Fmt, ArgList) -> - send_to_tstsrvr({format, Fmt, ArgList}). - -send_to_tstcntrl(Message) -> - send_to_tstsrvr({message, Message}). - - -%% -%% test_server side api -%% - -apply_on_ssl_node(Node, M, F, A) when atom(M), atom(F), list(A) -> - Ref = make_ref(), - send_to_ssl_node(Node, {apply, self(), Ref, M, F, A}), - receive - {Ref, Result} -> - Result - end. - -apply_on_ssl_node(Node, Fun) when is_function(Fun, 0) -> - Ref = make_ref(), - send_to_ssl_node(Node, {apply, self(), Ref, Fun}), - receive - {Ref, Result} -> - Result - end. - -stop_ssl_node(#node_handle{connection_handler = Handler, - socket = Socket, - name = Name}) -> - ?t:format("Trying to stop ssl node ~s.~n", [Name]), - Mon = erlang:monitor(process, Handler), - unlink(Handler), - case gen_tcp:send(Socket, term_to_binary(stop)) of - ok -> - receive - {'DOWN', Mon, process, Handler, Reason} -> - case Reason of - normal -> ok; - _ -> exit(Reason) - end - end; - Error -> - erlang:demonitor(Mon, [flush]), - exit(Error) - end. - -start_ssl_node(Config) -> - start_ssl_node(Config, ""). - -start_ssl_node(Config, XArgs) -> - Name = mk_node_name(Config), - SSL = ?config(ssl_opts, Config), - SSLDistOpts = setup_dist_opts(Name, ?config(priv_dir, Config)), - start_ssl_node_raw(Name, SSL ++ " " ++ SSLDistOpts ++ XArgs). - -start_ssl_node_raw(Name, Args) -> - {ok, LSock} = gen_tcp:listen(0, - [binary, {packet, 4}, {active, false}]), - {ok, ListenPort} = inet:port(LSock), - CmdLine = mk_node_cmdline(ListenPort, Name, Args), - ?t:format("Attempting to start ssl node ~s: ~s~n", [Name, CmdLine]), - case open_port({spawn, CmdLine}, []) of - Port when port(Port) -> - unlink(Port), - erlang:port_close(Port), - case await_ssl_node_up(Name, LSock) of - #node_handle{} = NodeHandle -> - ?t:format("Ssl node ~s started.~n", [Name]), - NodeName = list_to_atom(Name ++ "@" ++ host_name()), - NodeHandle#node_handle{nodename = NodeName}; - Error -> - exit({failed_to_start_node, Name, Error}) - end; - Error -> - exit({failed_to_start_node, Name, Error}) - end. - -%% -%% command line creation -%% - -host_name() -> - [$@ | Host] = lists:dropwhile(fun ($@) -> false; (_) -> true end, - atom_to_list(node())), - Host. - -mk_node_name(Config) -> - {A, B, C} = erlang:now(), - Case = ?config(testcase, Config), - atom_to_list(?MODULE) - ++ "_" - ++ atom_to_list(Case) - ++ "_" - ++ integer_to_list(A) - ++ "-" - ++ integer_to_list(B) - ++ "-" - ++ integer_to_list(C). - -mk_node_cmdline(ListenPort, Name, Args) -> - Static = "-detached -noinput", - Pa = filename:dirname(code:which(?MODULE)), - Prog = case catch init:get_argument(progname) of - {ok,[[P]]} -> P; - _ -> exit(no_progname_argument_found) - end, - NameSw = case net_kernel:longnames() of - false -> "-sname "; - _ -> "-name " - end, - {ok, Pwd} = file:get_cwd(), - Prog ++ " " - ++ Static ++ " " - ++ NameSw ++ " " ++ Name ++ " " - ++ "-pa " ++ Pa ++ " " - ++ "-run application start crypto -run application start public_key " - ++ "-run " ++ atom_to_list(?MODULE) ++ " cnct2tstsrvr " - ++ host_name() ++ " " - ++ integer_to_list(ListenPort) ++ " " - ++ Args ++ " " - ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ Name ++ " " - ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()). - -%% -%% Connection handler test_server side -%% - -await_ssl_node_up(Name, LSock) -> - case gen_tcp:accept(LSock, ?AWAIT_SLL_NODE_UP_TIMEOUT) of - timeout -> - gen_tcp:close(LSock), - ?t:format("Timeout waiting for ssl node ~s to come up~n", - [Name]), - timeout; - {ok, Socket} -> - gen_tcp:close(LSock), - case gen_tcp:recv(Socket, 0) of - {ok, Bin} -> - check_ssl_node_up(Socket, Name, Bin); - {error, closed} -> - gen_tcp:close(Socket), - exit({lost_connection_with_ssl_node_before_up, Name}) - end; - {error, Error} -> - gen_tcp:close(LSock), - exit({accept_failed, Error}) - end. - -check_ssl_node_up(Socket, Name, Bin) -> - case catch binary_to_term(Bin) of - {'EXIT', _} -> - gen_tcp:close(Socket), - exit({bad_data_received_from_ssl_node, Name, Bin}); - {ssl_node_up, NodeName} -> - case list_to_atom(Name++"@"++host_name()) of - NodeName -> - Parent = self(), - Go = make_ref(), - %% Spawn connection handler on test server side - Pid = spawn_link( - fun () -> - receive Go -> ok end, - tstsrvr_con_loop(Name, Socket, Parent) - end), - ok = gen_tcp:controlling_process(Socket, Pid), - Pid ! Go, - #node_handle{connection_handler = Pid, - socket = Socket, - name = Name}; - _ -> - exit({unexpected_ssl_node_connected, NodeName}) - end; - Msg -> - exit({unexpected_msg_instead_of_ssl_node_up, Name, Msg}) - end. - -send_to_ssl_node(#node_handle{connection_handler = Hndlr}, Term) -> - Hndlr ! {relay_to_ssl_node, term_to_binary(Term)}, - ok. - -tstsrvr_con_loop(Name, Socket, Parent) -> - inet:setopts(Socket,[{active,once}]), - receive - {relay_to_ssl_node, Data} when is_binary(Data) -> - case gen_tcp:send(Socket, Data) of - ok -> - ok; - _Error -> - gen_tcp:close(Socket), - exit({failed_to_relay_data_to_ssl_node, Name, Data}) - end; - {tcp, Socket, Bin} -> - case catch binary_to_term(Bin) of - {'EXIT', _} -> - gen_tcp:close(Socket), - exit({bad_data_received_from_ssl_node, Name, Bin}); - {format, FmtStr, ArgList} -> - ?t:format(FmtStr, ArgList); - {message, Msg} -> - Parent ! Msg; - {apply_res, To, Ref, Res} -> - To ! {Ref, Res}; - bye -> - ?t:format("Ssl node ~s stopped.~n", [Name]), - gen_tcp:close(Socket), - exit(normal); - Unknown -> - exit({unexpected_message_from_ssl_node, Name, Unknown}) - end; - {tcp_closed, Socket} -> - gen_tcp:close(Socket), - exit({lost_connection_with_ssl_node, Name}) - end, - tstsrvr_con_loop(Name, Socket, Parent). - -%% -%% Connection handler ssl_node side -%% - -% cnct2tstsrvr() is called via command line arg -run ... -cnct2tstsrvr([Host, Port]) when list(Host), list(Port) -> - %% Spawn connection handler on ssl node side - ConnHandler - = spawn(fun () -> - case catch gen_tcp:connect(Host, - list_to_integer(Port), - [binary, - {packet, 4}, - {active, false}]) of - {ok, Socket} -> - notify_ssl_node_up(Socket), - ets:new(test_server_info, - [set, - public, - named_table, - {keypos, 1}]), - ets:insert(test_server_info, - {test_server_handler, self()}), - ssl_node_con_loop(Socket); - _Error -> - halt("Failed to connect to test server") - end - end), - spawn(fun () -> - Mon = erlang:monitor(process, ConnHandler), - receive - {'DOWN', Mon, process, ConnHandler, Reason} -> - receive after 1000 -> ok end, - halt("test server connection handler terminated: " - ++ - lists:flatten(io_lib:format("~p", [Reason]))) - end - end). - -notify_ssl_node_up(Socket) -> - case catch gen_tcp:send(Socket, - term_to_binary({ssl_node_up, node()})) of - ok -> ok; - _ -> halt("Failed to notify test server that I'm up") - end. - -send_to_tstsrvr(Term) -> - case catch ets:lookup_element(test_server_info, test_server_handler, 2) of - Hndlr when pid(Hndlr) -> - Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok; - _ -> - receive after 200 -> ok end, - send_to_tstsrvr(Term) - end. - -ssl_node_con_loop(Socket) -> - inet:setopts(Socket,[{active,once}]), - receive - {relay_to_test_server, Data} when is_binary(Data) -> - case gen_tcp:send(Socket, Data) of - ok -> - ok; - _Error -> - gen_tcp:close(Socket), - halt("Failed to relay data to test server") - end; - {tcp, Socket, Bin} -> - case catch binary_to_term(Bin) of - {'EXIT', _} -> - gen_tcp:close(Socket), - halt("test server sent me bad data"); - {apply, From, Ref, M, F, A} -> - spawn_link( - fun () -> - send_to_tstsrvr({apply_res, - From, - Ref, - (catch apply(M, F, A))}) - end); - {apply, From, Ref, Fun} -> - spawn_link(fun () -> - send_to_tstsrvr({apply_res, - From, - Ref, - (catch Fun())}) - end); - stop -> - gen_tcp:send(Socket, term_to_binary(bye)), - gen_tcp:close(Socket), - init:stop(), - receive after infinity -> ok end; - _Unknown -> - halt("test server sent me an unexpected message") - end; - {tcp_closed, Socket} -> - halt("Lost connection to test server") - end, - ssl_node_con_loop(Socket). - -%% -%% Setup ssl dist info -%% - -rand_bin(N) -> - rand_bin(N, []). - -rand_bin(0, Acc) -> - Acc; -rand_bin(N, Acc) -> - rand_bin(N-1, [random:uniform(256)-1|Acc]). - -make_randfile(Dir) -> - {ok, IoDev} = file:open(filename:join([Dir, "RAND"]), [write]), - {A, B, C} = erlang:now(), - random:seed(A, B, C), - ok = file:write(IoDev, rand_bin(1024)), - file:close(IoDev). - -append_files(FileNames, ResultFileName) -> - {ok, ResultFile} = file:open(ResultFileName, [write]), - do_append_files(FileNames, ResultFile). - -do_append_files([], RF) -> - ok = file:close(RF); -do_append_files([F|Fs], RF) -> - {ok, Data} = file:read_file(F), - ok = file:write(RF, Data), - do_append_files(Fs, RF). - -setup_dist_opts(Name, PrivDir) -> - NodeDir = filename:join([PrivDir, Name]), - RGenDir = filename:join([NodeDir, "rand_gen"]), - ok = file:make_dir(NodeDir), - ok = file:make_dir(RGenDir), - make_randfile(RGenDir), - make_certs:all(RGenDir, NodeDir), - SDir = filename:join([NodeDir, "server"]), - SC = filename:join([SDir, "cert.pem"]), - SK = filename:join([SDir, "key.pem"]), - SKC = filename:join([SDir, "keycert.pem"]), - append_files([SK, SC], SKC), - CDir = filename:join([NodeDir, "client"]), - CC = filename:join([CDir, "cert.pem"]), - CK = filename:join([CDir, "key.pem"]), - CKC = filename:join([CDir, "keycert.pem"]), - append_files([CK, CC], CKC), - "-proto_dist inet_ssl " - ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " " - ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " " -.% ++ "-ssl_dist_opt verify 1 depth 1". - -%% -%% Start scripts etc... -%% - -add_ssl_opts_config(Config) -> - %% - %% Start with boot scripts if on an installed system; otherwise, - %% just point out ssl ebin with -pa. - %% - try - Dir = ?config(priv_dir, Config), - LibDir = code:lib_dir(), - Apps = application:which_applications(), - {value, {stdlib, _, STDL_VSN}} = lists:keysearch(stdlib, 1, Apps), - {value, {kernel, _, KRNL_VSN}} = lists:keysearch(kernel, 1, Apps), - StdlDir = filename:join([LibDir, "stdlib-" ++ STDL_VSN]), - KrnlDir = filename:join([LibDir, "kernel-" ++ KRNL_VSN]), - {ok, _} = file:read_file_info(StdlDir), - {ok, _} = file:read_file_info(KrnlDir), - SSL_VSN = vsn(ssl), - VSN_CRYPTO = vsn(crypto), - VSN_PKEY = vsn(public_key), - - SslDir = filename:join([LibDir, "ssl-" ++ SSL_VSN]), - {ok, _} = file:read_file_info(SslDir), - %% We are using an installed otp system, create the boot script. - Script = filename:join(Dir, atom_to_list(?MODULE)), - {ok, RelFile} = file:open(Script ++ ".rel", [write]), - io:format(RelFile, - "{release, ~n" - " {\"SSL distribution test release\", \"~s\"},~n" - " {erts, \"~s\"},~n" - " [{kernel, \"~s\"},~n" - " {stdlib, \"~s\"},~n" - " {crypto, \"~s\"},~n" - " {public_key, \"~s\"},~n" - " {ssl, \"~s\"}]}.~n", - [case catch erlang:system_info(otp_release) of - {'EXIT', _} -> "R11B"; - Rel -> Rel - end, - erlang:system_info(version), - KRNL_VSN, - STDL_VSN, - VSN_CRYPTO, - VSN_PKEY, - SSL_VSN]), - ok = file:close(RelFile), - ok = systools:make_script(Script, []), - [{ssl_opts, "-boot " ++ Script} | Config] - catch - _:_ -> - [{ssl_opts, "-pa " ++ filename:dirname(code:which(ssl))} - | add_comment_config( - "Bootscript wasn't used since the test wasn't run on an " - "installed OTP system.", - Config)] - end. - -%% -%% Add common comments to config -%% - -add_comment_config(Comment, []) -> - [{comment, Comment}]; -add_comment_config(Comment, [{comment, OldComment} | Cs]) -> - [{comment, Comment ++ " " ++ OldComment} | Cs]; -add_comment_config(Comment, [C|Cs]) -> - [C|add_comment_config(Comment, Cs)]. - -%% -%% Call when test case success -%% - -success(Config) -> - case lists:keysearch(comment, 1, Config) of - {value, {comment, _} = Res} -> Res; - _ -> ok - end. - -vsn(App) -> - application:start(App), - try - {value, - {ssl, - _, - VSN}} = lists:keysearch(App, - 1, - application:which_applications()), - VSN - after - application:stop(ssl) - end. diff --git a/lib/ssl/test/old_ssl_misc_SUITE.erl b/lib/ssl/test/old_ssl_misc_SUITE.erl deleted file mode 100644 index ea03e83867..0000000000 --- a/lib/ssl/test/old_ssl_misc_SUITE.erl +++ /dev/null @@ -1,117 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2011. 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(old_ssl_misc_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - seed/1, - app/1 - ]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - --define(MANYCONNS, 5). - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [seed, app]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains."; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto!"} - end. - -end_per_suite(doc) -> - "This test case has no mission other than closing the conf case"; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -seed(doc) -> - "Test that ssl:seed/1 works."; -seed(suite) -> - []; -seed(Config) when list(Config) -> - process_flag(trap_exit, true), - LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config), - - LCmds = [{seed, "tjosan"}, - {sockopts, [{backlog, NConns}, {active, once}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ?line test_server_only(NConns, LCmds, [], Timeout, ?MODULE, - Config). - -app(doc) -> - "Test that the ssl app file is ok"; -app(suite) -> - []; -app(Config) when list(Config) -> - ?line ok = test_server:app_test(ssl). - - diff --git a/lib/ssl/test/old_ssl_passive_SUITE.erl b/lib/ssl/test/old_ssl_passive_SUITE.erl deleted file mode 100644 index 7b54fe876a..0000000000 --- a/lib/ssl/test/old_ssl_passive_SUITE.erl +++ /dev/null @@ -1,382 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2011. 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(old_ssl_passive_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, - end_per_suite/1, init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - server_accept_timeout/1, - cinit_return_chkclose/1, - sinit_return_chkclose/1, - cinit_big_return_chkclose/1, - sinit_big_return_chkclose/1, - cinit_big_echo_chkclose/1, - sinit_big_echo_chkclose/1, - cinit_few_echo_chkclose/1, - cinit_many_echo_chkclose/1, - cinit_cnocert/1 - ]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). - --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - --define(MANYCONNS, ssl_test_MACHINE:many_conns()). - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [server_accept_timeout, cinit_return_chkclose, - sinit_return_chkclose, cinit_big_return_chkclose, - sinit_big_return_chkclose, cinit_big_echo_chkclose, - sinit_big_echo_chkclose, cinit_few_echo_chkclose, - cinit_many_echo_chkclose, cinit_cnocert]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains."; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto"} - end. - -end_per_suite(doc) -> - "This test case has no mission other than closing the conf case"; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -server_accept_timeout(doc) -> - "Server has one pending accept with timeout. Checks that return " - "value is {error, timeout}."; -server_accept_timeout(suite) -> - []; -server_accept_timeout(Config) when list(Config) -> - process_flag(trap_exit, true), - LPort = 3456, - Timeout = 40000, NConns = 1, - AccTimeout = 3000, - - ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, AccTimeout}, - accept_timeout], - ?line test_server_only(NConns, LCmds, ACmds, Timeout, ?MODULE, Config). - -cinit_return_chkclose(doc) -> - "Client sends 1000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -cinit_return_chkclose(suite) -> - []; -cinit_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_return_chkclose(doc) -> - "Server sends 1000 bytes to client, that receives them, sends them " - "back, and closes. Server waits for close. Both have certs."; -sinit_return_chkclose(suite) -> - []; -sinit_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {recv, DataSize}, {send, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_big_return_chkclose(doc) -> - "Client sends 50000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -cinit_big_return_chkclose(suite) -> - []; -cinit_big_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_big_return_chkclose(doc) -> - "Server sends 50000 bytes to client, that receives them, sends them " - "back, and closes. Server waits for close. Both have certs."; -sinit_big_return_chkclose(suite) -> - []; -sinit_big_return_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {recv, DataSize}, {send, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_big_echo_chkclose(doc) -> - "Client sends 50000 bytes to server, that echoes them back " - "and closes. Client waits for close. Both have certs."; -cinit_big_echo_chkclose(suite) -> - []; -cinit_big_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -sinit_big_echo_chkclose(doc) -> - "Server sends 50000 bytes to client, that echoes them back " - "and closes. Server waits for close. Both have certs."; -sinit_big_echo_chkclose(suite) -> - []; -sinit_big_echo_chkclose(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 50000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {send, DataSize}, {recv, DataSize}, - await_close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {echo, DataSize}, - close], - - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - - -cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7). - -cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS). - -cinit_many_echo_chkclose(doc, _NConns) -> - "clients send 10000 bytes to server, that echoes them back " - "and closes. Clients wait for close. All have certs."; -cinit_many_echo_chkclose(suite, _NConns) -> - []; -cinit_many_echo_chkclose(Config, NConns) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 10000, LPort = 3456, - Timeout = 80000, - - io:format("~w connections", [NConns]), - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {echo, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - -cinit_cnocert(doc) -> - "Client sends 1000 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Client has no cert, " - "but server has."; -cinit_cnocert(suite) -> - []; -cinit_cnocert(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3457, - Timeout = 40000, NConns = 1, - - ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}, {active, false}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, {send, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sockopts, [{active, false}]}, - {connect, {Host, LPort}}, - {send, DataSize}, {recv, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE, - Config). - diff --git a/lib/ssl/test/old_ssl_peer_cert_SUITE.erl b/lib/ssl/test/old_ssl_peer_cert_SUITE.erl deleted file mode 100644 index ee19bad175..0000000000 --- a/lib/ssl/test/old_ssl_peer_cert_SUITE.erl +++ /dev/null @@ -1,191 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2011. 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(old_ssl_peer_cert_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - cinit_plain/1, - cinit_both_verify/1, - cinit_cnocert/1 - ]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [cinit_plain, cinit_both_verify, cinit_cnocert]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains."; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto"} - end. - -end_per_suite(doc) -> - "This test case has no mission other than closing the conf case"; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -cinit_plain(doc) -> - "Server closes after accept, Client waits for close. Both have certs " - "but both use the defaults for verify and depth, but still tries " - "to retreive each others certificates."; -cinit_plain(suite) -> - []; -cinit_plain(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config), - - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - nopeercert, - {recv, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - peercert, - {send, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, - ?MODULE, Config). - -cinit_both_verify(doc) -> - "Server closes after accept, Client waits for close. Both have certs " - "and both verify each other."; -cinit_both_verify(suite) -> - []; -cinit_both_verify(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts0, SsslOpts0}} = mk_ssl_cert_opts(Config), - ?line CsslOpts = [{verify, 2}, {depth, 2} | CsslOpts0], - ?line SsslOpts = [{verify, 2}, {depth, 3} | SsslOpts0], - - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - peercert, - {recv, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - peercert, - {send, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, - ?MODULE, Config). - -cinit_cnocert(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close."; -cinit_cnocert(suite) -> - []; -cinit_cnocert(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3457, - Timeout = 40000, NConns = 1, - - ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config), - ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0], - - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {connect, {Host, LPort}}, - peercert, - {send, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, - ?MODULE, Config). - - diff --git a/lib/ssl/test/old_ssl_protocol_SUITE.erl b/lib/ssl/test/old_ssl_protocol_SUITE.erl deleted file mode 100644 index 9b9937c210..0000000000 --- a/lib/ssl/test/old_ssl_protocol_SUITE.erl +++ /dev/null @@ -1,185 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. 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(old_ssl_protocol_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, end_per_testcase/2, - sslv2/1, sslv3/1, tlsv1/1, sslv2_sslv3/1, - sslv2_tlsv1/1, sslv3_tlsv1/1, sslv2_sslv3_tlsv1/1]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - - -init_per_testcase(_Case, Config) -> - WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [sslv2, sslv3, tlsv1, sslv2_sslv3, sslv2_tlsv1, - sslv3_tlsv1, sslv2_sslv3_tlsv1]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains."; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto"} - end. - -end_per_suite(doc) -> - "This test case has no other purpose than closing the conf case."; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -%%%%% - -sslv2(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose SSLv2."; -sslv2(suite) -> - []; -sslv2(Config) when list(Config) -> - do_run_test(Config, [sslv2]). - -sslv3(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose SSLv3."; -sslv3(suite) -> - []; -sslv3(Config) when list(Config) -> - do_run_test(Config, [sslv3]). - -tlsv1(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose TLSv1."; -tlsv1(suite) -> - []; -tlsv1(Config) when list(Config) -> - do_run_test(Config, [tlsv1]). - -sslv2_sslv3(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose between SSLv2 and SSLv3."; -sslv2_sslv3(suite) -> - []; -sslv2_sslv3(Config) when list(Config) -> - do_run_test(Config, [sslv2, sslv3]). - -sslv2_tlsv1(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose between SSLv2 and TLSv1."; -sslv2_tlsv1(suite) -> - []; -sslv2_tlsv1(Config) when list(Config) -> - do_run_test(Config, [sslv2, tlsv1]). - -sslv3_tlsv1(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose between SSLv3 and TLSv1."; -sslv3_tlsv1(suite) -> - []; -sslv3_tlsv1(Config) when list(Config) -> - do_run_test(Config, [sslv3, tlsv1]). - -sslv2_sslv3_tlsv1(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close. " - "Client and server choose between SSLv2, SSLv3, and TLSv1."; -sslv2_sslv3_tlsv1(suite) -> - []; -sslv2_sslv3_tlsv1(Config) when list(Config) -> - do_run_test(Config, [sslv2, sslv3, tlsv1]). - -%%%% - -do_run_test(Config0, Protocols) -> - process_flag(trap_exit, true), - LPort = 3456, - Timeout = 40000, NConns = 1, - DataSize = 10, - - ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config0), - ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0], - - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - connection_info, - {recv, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {connect, {Host, LPort}}, - connection_info, - {send, DataSize}, - await_close], - Config1 = [{env, [{protocol_version, Protocols}]} | Config0], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, - ?MODULE, Config1). - - diff --git a/lib/ssl/test/old_ssl_verify_SUITE.erl b/lib/ssl/test/old_ssl_verify_SUITE.erl deleted file mode 100644 index 4c11ea6850..0000000000 --- a/lib/ssl/test/old_ssl_verify_SUITE.erl +++ /dev/null @@ -1,153 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2011. 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(old_ssl_verify_SUITE). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - cinit_both_verify/1, - cinit_cnocert/1 - ]). - --import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). --include_lib("test_server/include/test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT), - [{watchdog, WatchDog}| Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [cinit_both_verify, cinit_cnocert]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_suite(doc) -> - "Want to se what Config contains."; -init_per_suite(suite) -> - []; -init_per_suite(Config) -> - io:format("Config: ~p~n", [Config]), - - %% Check if SSL exists. If this case fails, all other cases are skipped - case catch crypto:start() of - ok -> - application:start(public_key), - case ssl:start() of - ok -> ssl:stop(); - {error, {already_started, _}} -> ssl:stop(); - Error -> ?t:fail({failed_starting_ssl,Error}) - end, - Config; - _Else -> - {skip,"Could not start crypto"} - end. - -end_per_suite(doc) -> - "This test case has no mission other than closing the conf case"; -end_per_suite(suite) -> - []; -end_per_suite(Config) -> - crypto:stop(), - Config. - -cinit_both_verify(doc) -> - "Server closes after accept, Client waits for close. Both have certs " - "and both verify each other."; -cinit_both_verify(suite) -> - []; -cinit_both_verify(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3456, - Timeout = 40000, NConns = 1, - - ?line {ok, {CsslOpts0, SsslOpts0}} = mk_ssl_cert_opts(Config), - ?line CsslOpts = [{verify, 2}, {depth, 2} | CsslOpts0], - ?line SsslOpts = [{verify, 2}, {depth, 3} | SsslOpts0], - - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {sslopts, CsslOpts}, - {connect, {Host, LPort}}, - {send, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, - ?MODULE, Config). - -cinit_cnocert(doc) -> - "Client has no cert. Nor the client, nor the server is verifying its " - "peer. Server closes, client waits for close."; -cinit_cnocert(suite) -> - []; -cinit_cnocert(Config) when list(Config) -> - process_flag(trap_exit, true), - DataSize = 1000, LPort = 3457, - Timeout = 40000, NConns = 1, - - ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config), - ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0], - - ?line {ok, Host} = inet:gethostname(), - - LCmds = [{sockopts, [{backlog, NConns}]}, - {sslopts, SsslOpts}, - {listen, LPort}, - wait_sync, - lclose], - ACmds = [{timeout, Timeout}, - accept, - {recv, DataSize}, - close], - CCmds = [{timeout, Timeout}, - {connect, {Host, LPort}}, - {send, DataSize}, - await_close], - ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, - ?MODULE, Config). - - diff --git a/lib/ssl/test/old_transport_accept_SUITE.erl b/lib/ssl/test/old_transport_accept_SUITE.erl deleted file mode 100644 index 6f0c8e456b..0000000000 --- a/lib/ssl/test/old_transport_accept_SUITE.erl +++ /dev/null @@ -1,258 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2011. 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(old_transport_accept_SUITE). --include_lib("common_test/include/ct.hrl"). --include("test_server_line.hrl"). - -%% Default timetrap timeout (set in init_per_testcase). --define(default_timeout, ?t:minutes(1)). --define(application, ssh). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - config/1, - echo_once/1, - echo_twice/1, - close_before_ssl_accept/1, - server/5, - tolerant_server/5, - client/5 - ]). - -init_per_testcase(_Case, Config) -> - WatchDog = ssl_test_lib:timetrap(?default_timeout), - [{watchdog, WatchDog}, {protomod, gen_tcp}, {serialize_accept, true}| - Config]. - -end_per_testcase(_Case, Config) -> - WatchDog = ?config(watchdog, Config), - test_server:timetrap_cancel(WatchDog). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [config, echo_once, echo_twice, close_before_ssl_accept]. - -groups() -> - []. - -init_per_suite(Config) -> - try crypto:start() of - ok -> - Config - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(_Config) -> - application:stop(crypto), - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -config(doc) -> - "Want to se what Config contains."; -config(suite) -> - []; -config(Config) -> - io:format("Config: ~p~n", [Config]), - ok. - -echo_once(doc) -> - "Client sends 256 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -echo_once(suite) -> - []; -echo_once(Config) when list(Config) -> - process_flag(trap_exit, true), - LPort = 3456, - {ok, Host} = inet:gethostname(), - {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config), - N = 1, - Msg = lists:seq(0, 255), - Self = self(), - Params = "-pa " ++ filename:dirname(code:which(?MODULE)), - Node = start_node(server, Params), - CNode = start_node(client, Params), - Server = spawn_link(Node, ?MODULE, server, [Self, LPort, SOpts, Msg, N]), - Client = spawn_link(Node, ?MODULE, client, [Host, LPort, COpts, Msg, N]), - ok = receive - {Server, listening} -> - Client ! {Server, listening}, - ok; - E -> - io:format("bad receive (1) ~p\n", [E]), - E - end, - receive - {Server, done} -> - ok - end, - test_server:stop_node(Node), - test_server:stop_node(CNode). - -close_before_ssl_accept(doc) -> - "Client sends 256 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -close_before_ssl_accept(suite) -> - []; -close_before_ssl_accept(Config) when list(Config) -> - process_flag(trap_exit, true), - LPort = 3456, - {ok, Host} = inet:gethostname(), - {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config), - Msg = lists:seq(0, 255), - Self = self(), - Params = "-pa " ++ filename:dirname(code:which(?MODULE)), - Node = start_node(server, Params), - CNode = start_node(client, Params), - Server = spawn_link(Node, ?MODULE, tolerant_server, - [Self, LPort, SOpts, Msg, 2]), - Client = spawn_link(Node, ?MODULE, client, - [Host, LPort, COpts, Msg, 1]), - ok = receive - {Server, listening} -> - {ok, S} = gen_tcp:connect(Host, LPort, []), - gen_tcp:close(S), - Client ! {Server, listening}, - ok; - E -> - io:format("bad receive (1) ~p\n", [E]), - E - end, - receive - {Server, done} -> - ok - end, - test_server:stop_node(Node), - test_server:stop_node(CNode). - -client(Host, LPort, COpts, Msg, N) -> - ok = receive - {_Server, listening} -> - ok; - E -> - io:format("bad receive (2) ~p\n", [E]), - E - end, - Opts = COpts ++ [{packet, raw}, {active, false}], - app(), - lists:foreach(fun(_) -> - {ok, S} = ssl:connect(Host, LPort, Opts), - ssl:send(S, Msg), - {ok, Msg} = ssl:recv(S, length(Msg)), - ssl:close(S) - end, lists:seq(1, N)). - -echo_twice(doc) -> - "Two clients sends 256 bytes to server, that receives them, sends them " - "back, and closes. Client waits for close. Both have certs."; -echo_twice(suite) -> - []; -echo_twice(Config) when list(Config) -> - process_flag(trap_exit, true), - LPort = 3456, - {ok, Host} = inet:gethostname(), - {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config), - N = 2, - Msg = lists:seq(0, 255), - Self = self(), - Params = "-pa " ++ filename:dirname(code:which(?MODULE)), - Node = start_node(server, Params), - CNode = start_node(client, Params), - Server = spawn_link(Node, ?MODULE, server, - [Self, LPort, SOpts, Msg, N]), - Client = spawn_link(Node, ?MODULE, client, - [Host, LPort, COpts, Msg, N]), - ok = receive - {Server, listening} -> - Client ! {Server, listening}, - ok; - E -> - io:format("bad receive (3) ~p\n", [E]), - E - end, - receive - {Server, done} -> - ok - end, - test_server:stop_node(Node), - test_server:stop_node(CNode). - -server(Client, Port, SOpts, Msg, N) -> - app(), - process_flag(trap_exit, true), - Opts = SOpts ++ [{packet, raw}, {active, false}], - {ok, LSock} = ssl:listen(Port, Opts), - Client ! {self(), listening}, - server_loop(Client, LSock, Msg, N). - -server_loop(Client, _, _, 0) -> - Client ! {self(), done}; -server_loop(Client, LSock, Msg, N) -> - {ok, S} = ssl:transport_accept(LSock), - ok = ssl:ssl_accept(S), - %% P = ssl:controlling_process(S, Proxy), - {ok, Msg} = ssl:recv(S, length(Msg)), - ok = ssl:send(S, Msg), - ok = ssl:close(S), - server_loop(Client, LSock, Msg, N-1). - -tolerant_server(Client, Port, SOpts, Msg, N) -> - app(), - process_flag(trap_exit, true), - Opts = SOpts ++ [{packet, raw}, {active, false}], - {ok, LSock} = ssl:listen(Port, Opts), - Client ! {self(), listening}, - tolerant_server_loop(Client, LSock, Msg, N). - -tolerant_server_loop(Client, _, _, 0) -> - Client ! {self(), done}; -tolerant_server_loop(Client, LSock, Msg, N) -> - {ok, S} = ssl:transport_accept(LSock), - case ssl:ssl_accept(S) of - ok -> - %% P = ssl:controlling_process(S, Proxy), - {ok, Msg} = ssl:recv(S, length(Msg)), - ok = ssl:send(S, Msg), - ok = ssl:close(S); - E -> - io:format("ssl_accept error: ~p\n", [E]) - end, - tolerant_server_loop(Client, LSock, Msg, N-1). - -app() -> - crypto:start(), - application:start(public_key), - ssl:start(). - -start_node(Kind, Params) -> - S = atom_to_list(?MODULE)++"_" ++ atom_to_list(Kind), - {ok, Node} = test_server:start_node(list_to_atom(S), slave, [{args, Params}]), - Node. - diff --git a/lib/ssl/test/ssl.cover b/lib/ssl/test/ssl.cover index 60774cc0f1..6b13e07a37 100644 --- a/lib/ssl/test/ssl.cover +++ b/lib/ssl/test/ssl.cover @@ -1,21 +1,4 @@ {incl_app,ssl,details}. -{excl_mods, ssl, [ssl_pkix_oid, - 'PKIX1Algorithms88', - 'PKIX1Explicit88', - 'PKIX1Implicit88', - 'PKIXAttributeCertificate', - 'SSL-PKIX', - ssl_pem, - ssl_pkix, - ssl_base64, - ssl_broker, - ssl_broker_int, - ssl_broker_sup, - ssl_debug, - ssl_server, - ssl_prim, - inet_ssl_dist, - 'OTP-PKIX' - ]}. +{excl_mods, ssl, [ssl_debug]}. diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 37a021e7cf..832431b1ed 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -28,7 +28,6 @@ -include_lib("public_key/include/public_key.hrl"). -include("ssl_alert.hrl"). --include("ssl_int.hrl"). -include("ssl_internal.hrl"). -include("ssl_record.hrl"). @@ -207,7 +206,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [app, alerts, connection_info, protocol_versions, empty_protocol_versions, controlling_process, - controller_dies, client_closes_socket, peercert, + controller_dies, client_closes_socket, connect_dist, peername, sockname, socket_options, invalid_inet_get_option, invalid_inet_get_option_not_list, invalid_inet_get_option_improper_list, @@ -583,50 +582,6 @@ client_closes_socket(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, {error,closed}). -%%-------------------------------------------------------------------- - -peercert(doc) -> - [""]; - -peercert(suite) -> - []; - -peercert(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, peercert_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, peercert_result, []}}, - {options, ClientOpts}]), - - CertFile = proplists:get_value(certfile, ServerOpts), - [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), - ErlCert = public_key:pkix_decode_cert(BinCert, otp), - - ServerMsg = {{error, no_peercert}, {error, no_peercert}}, - ClientMsg = {{ok, BinCert}, {ok, ErlCert}}, - - test_server:format("Testcase ~p, Client ~p Server ~p ~n", - [self(), Client, Server]), - - ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -peercert_result(Socket) -> - Result1 = ssl:peercert(Socket), - Result2 = ssl:peercert(Socket, [ssl]), - {Result1, Result2}. - %%-------------------------------------------------------------------- connect_dist(doc) -> ["Test a simple connect as is used by distribution"]; @@ -1528,7 +1483,6 @@ eoptions(Config) when is_list(Config) -> end, TestOpts = [{versions, [sslv2, sslv3]}, - {ssl_imp, cool}, {verify, 4}, {verify_fun, function}, {fail_if_no_peer_cert, 0}, diff --git a/lib/ssl/test/ssl_test_MACHINE.erl b/lib/ssl/test/ssl_test_MACHINE.erl deleted file mode 100644 index e0ffa15d80..0000000000 --- a/lib/ssl/test/ssl_test_MACHINE.erl +++ /dev/null @@ -1,940 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2010. 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(ssl_test_MACHINE). - --export([many_conns/0, mk_ssl_cert_opts/1, test_one_listener/7, - test_server_only/6]). - --export([process_init/3, do_start/1]). - - --include("test_server.hrl"). --include("ssl_test_MACHINE.hrl"). - --define(WAIT_TIMEOUT, 10000). --define(CLOSE_WAIT, 1000). - -%% -%% many_conns() -> ManyConnections -%% -%% Choose a suitable number of "many connections" depending on platform -%% and current limit for file descriptors. -%% -many_conns() -> - case os:type() of - {unix,_} -> many_conns_1(); - _ -> 10 - end. - -many_conns_1() -> - N0 = os:cmd("ulimit -n"), - N1 = lists:reverse(N0), - N2 = lists:dropwhile(fun($\r) -> true; - ($\n) -> true; - (_) -> false - end, N1), - N = list_to_integer(lists:reverse(N2)), - lists:min([(N - 10) div 2, 501]). - -%% -%% mk_ssl_cert_opts(Config) -> {ok, {COpts, SOpts}} -%% -%% -mk_ssl_cert_opts(_Config) -> - Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]), - COpts = [{ssl_imp, old}, - {cacertfile, filename:join([Dir, "client", "cacerts.pem"])}, - {certfile, filename:join([Dir, "client", "cert.pem"])}, - {keyfile, filename:join([Dir, "client", "key.pem"])}], - SOpts = [{ssl_imp, old}, - {cacertfile, filename:join([Dir, "server", "cacerts.pem"])}, - {certfile, filename:join([Dir, "server", "cert.pem"])}, - {keyfile, filename:join([Dir, "server", "key.pem"])}], - {ok, {COpts, SOpts}}. - -%% -%% Cmds: -%% {protomod, gen_tcp | ssl} default = ssl -%% {serialize_accept, true | false} default = false -%% {timeout, Timeout} -%% {sockopts, Opts} -%% {sslopts, Opts} -%% {protocols, Protocols} [sslv2|sslv3|tlsv1] -%% {listen, Port} -%% {lsock, LSock} listen socket for acceptor -%% peercert -%% accept -%% {connect, {Host, Port}} -%% {recv, N} -%% {send, N} -%% {echo, N} async echo back -%% close close connection socket -%% {close, Time} wait time and then close socket -%% lclose close listen socket -%% await_close wait for close -%% wait_sync listener's wait for sync from parent -%% connection_info -%% {exit, Reason} exit -%% -%% -%% We cannot have more than `backlog' acceptors at the same time. -%% - - -%% -%% test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, Suite, Config) -%% -%% Creates one client and one server node, and runs one listener on -%% the server node (according to LCmds), and creates NConns acceptors -%% on the server node, and the same number of connectors on the client -%% node. The acceptors and and connectors execute according to ACmds -%% and CCmds, respectively. -%% -%% It is a good idea to have the backlog size in LCmds set to -%% be at least as large as NConns. -%% -test_one_listener(NConns, LCmds0, ACmds0, CCmds0, Timeout, Suite, Config) -> - ProtoMod = get_protomod(Config), - SerializeAccept = get_serialize_accept(Config), - ?line {ok, {CNode, SNode}} = start_client_server_nodes(Suite), - case ProtoMod of - ssl -> - ?line ok = start_ssl([CNode, SNode], Config); - gen_tcp -> - ok - end, - LCmds = [{protomod, ProtoMod}| LCmds0], - ACmds = [{protomod, ProtoMod}, {serialize_accept, SerializeAccept}| - ACmds0], - CCmds = [{protomod, ProtoMod}| CCmds0], - - ?line {ok, Listener} = start_process(SNode, self(), LCmds, listener), - ?line {ok, LSock} = wait_lsock(Listener, ?WAIT_TIMEOUT), - ?line {ok, Accs0} = start_processes(NConns, SNode, self(), - [{lsock, LSock}| ACmds], acceptor), - Accs = case ProtoMod of - gen_tcp -> - [Acc1| Accs1] = Accs0, - Acc1 ! {continue_accept, self()}, - Accs1; - ssl -> - Accs0 - end, - ?line {ok, Conns} = start_processes(NConns, CNode, self(), - CCmds, connector), - ?line case wait_ack(Accs, Accs0 ++ Conns, Timeout) of - ok -> - ?line sync([Listener]), - ?line wait_ack([], [Listener], ?WAIT_TIMEOUT); - {error, Reason} -> - ?line stop_node(SNode), - ?line stop_node(CNode), - exit(Reason) - end, - ?line stop_node(SNode), - ?line stop_node(CNode), - ok. - -%% -%% test_server_only(NConns, LCmds, ACmds, Timeout, Suite, Config) -%% -%% Creates only one server node, and runs one listener on -%% the server node (according to LCmds), and creates NConns acceptors -%% on the server node. The acceptors execute according to ACmds. -%% There are no connectors. -%% -test_server_only(NConns, LCmds0, ACmds0, Timeout, Suite, Config) -> - ProtoMod = get_protomod(Config), - ?line {ok, SNode} = start_server_node(Suite), - case ProtoMod of - ssl -> - ?line ok = start_ssl([SNode], Config); - gen_tcp -> - ok - end, - LCmds = [{protomod, ProtoMod}| LCmds0], - ACmds = [{protomod, ProtoMod}| ACmds0], - ?line {ok, Listener} = start_process(SNode, self(), LCmds, listener), - ?line {ok, LSock} = wait_lsock(Listener, ?WAIT_TIMEOUT), - ?line {ok, Accs0} = start_processes(NConns, SNode, self(), - [{lsock, LSock}| ACmds], acceptor), - Accs = case ProtoMod of - gen_tcp -> - [Acc1| Accs1] = Accs0, - Acc1 ! {continue_accept, self()}, - Accs1; - ssl -> - Accs0 - end, - ?line case wait_ack(Accs, Accs0, Timeout) of - ok -> - ?line sync([Listener]), - ?line wait_ack([], [Listener], ?WAIT_TIMEOUT); - {error, Reason} -> - ?line stop_node(SNode), - exit(Reason) - end, - ?line stop_node(SNode), - ok. - -%% -%% start_client_server_nodes(Suite) -> {ok, {CNode, SNode}} -%% -start_client_server_nodes(Suite) -> - {ok, CNode} = start_client_node(Suite), - {ok, SNode} = start_server_node(Suite), - {ok, {CNode, SNode}}. - -start_client_node(Suite) -> - start_node(lists:concat([Suite, "_client"])). - -start_server_node(Suite) -> - start_node(lists:concat([Suite, "_server"])). - -%% -%% start_ssl(Nodes, Config) -%% -start_ssl(Nodes, Config) -> - Env0 = lists:flatten([Env00 || {env, Env00} <- Config]), - Env1 = case os:getenv("SSL_DEBUG") of - false -> - []; - _ -> - Dir = ?config(priv_dir, Config), - [{debug, true}, {debugdir, Dir}] - end, - Env = Env0 ++ Env1, - lists:foreach( - fun(Node) -> rpc:call(Node, ?MODULE, do_start, [Env]) end, Nodes), - ok. - -do_start(Env) -> - application:start(crypto), - application:start(public_key), - application:load(ssl), - lists:foreach( - fun({Par, Val}) -> application:set_env(ssl, Par, Val) end, Env), - application:start(ssl). - - -%% -%% start_node(Name) -> {ok, Node} -%% start_node(Name, ExtraParams) -> {ok, Node} -%% -start_node(Name) -> - start_node(Name, []). -start_node(Name, ExtraParams) -> - Params = "-pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ - ExtraParams, - test_server:start_node(Name, slave, [{args, Params}]). - -stop_node(Node) -> - test_server:stop_node(Node). - -%% -%% start_processes(N, Node, Parent, Cmds, Type) -> {ok, Pids} -%% -start_processes(M, Node, Parent, Cmds, Type) -> - start_processes1(0, M, Node, Parent, Cmds, Type, []). -start_processes1(M, M, _, _, _, _, Pids) -> - {ok, lists:reverse(Pids)}; -start_processes1(N, M, Node, Parent, Cmds, Type, Pids) -> - {ok, Pid} = start_process(Node, Parent, Cmds, {Type, N + 1}), - start_processes1(N + 1, M, Node, Parent, Cmds, Type, [Pid| Pids]). - -%% -%% start_process(Node, Parent, Cmds, Type) -> {ok, Pid} -%% -start_process(Node, Parent, Cmds0, Type) -> - Cmds = case os:type() of - {win32, _} -> - lists:map(fun(close) -> {close, ?CLOSE_WAIT}; - (Term) -> Term end, Cmds0); - _ -> - Cmds0 - end, - Pid = spawn_link(Node, ?MODULE, process_init, [Parent, Cmds, Type]), - {ok, Pid}. - -process_init(Parent, Cmds, Type) -> - ?debug("#### ~w start~n", [{Type, self()}]), - pre_main_loop(Cmds, #st{parent = Parent, type = Type}). - -%% -%% pre_main_loop -%% -pre_main_loop([], St) -> - ?debug("#### ~w end~n", [{St#st.type, self()}]), - main_loop([], St); -pre_main_loop(Cmds, St) -> - ?debug("#### ~w -> ~w~n", - [{St#st.type, self(), St#st.sock, St#st.port, - St#st.peer, St#st.active}, hd(Cmds)]), - main_loop(Cmds, St). - -%% -%% main_loop(Cmds, St) -%% -main_loop([{protomod, ProtoMod}| Cmds], St) -> - pre_main_loop(Cmds, St#st{protomod = ProtoMod}); - -main_loop([{serialize_accept, Bool}| Cmds], St) -> - pre_main_loop(Cmds, St#st{serialize_accept = Bool}); - -main_loop([{sockopts, Opts}| Cmds], St) -> - pre_main_loop(Cmds, St#st{sockopts = Opts}); - -main_loop([{sslopts, Opts}| Cmds], St) -> - pre_main_loop(Cmds, St#st{sslopts = Opts}); - -main_loop([{protocols, Protocols}| Cmds], St) -> - pre_main_loop(Cmds, St#st{protocols = Protocols}); - -main_loop([{timeout, T}| Cmds], St) -> - pre_main_loop(Cmds, St#st{timeout = T}); - -main_loop([{lsock, LSock}| Cmds], St) -> - pre_main_loop(Cmds, St#st{lsock = LSock}); - -main_loop([{seed, Data}| Cmds], St) -> - case ssl:seed("tjosan") of - ok -> - pre_main_loop(Cmds, St); - {error, Reason} -> - ?error("#### ~w(~w) in seed: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([{listen, Port}| Cmds], St) -> - case listen(St, Port) of - {ok, LSock} -> - ack_lsock(St#st.parent, LSock), - NSt = get_active(St#st{port = Port, sock = LSock, lsock = LSock}), - pre_main_loop(Cmds, St); - {error, Reason} -> - ?error("#### ~w(~w) in listen: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([accept| Cmds], St) -> - case St#st.serialize_accept of - true -> - Parent = St#st.parent, - receive - {continue_accept, Parent} -> - ok - end; - false -> - ok - end, - case accept(St) of - {ok, Sock, Port, Peer} -> - case St#st.serialize_accept of - true -> - St#st.parent ! {one_accept_done, self()}; - false -> - ok - end, - NSt = get_active(St#st{sock = Sock, port = Port, peer = Peer}), - pre_main_loop(Cmds, NSt); - {error, Reason} -> - ?error("#### ~w(~w) in accept: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([accept_timeout| Cmds], St) -> - case accept(St) of - {error, timeout} -> - pre_main_loop(Cmds, St); - {error, Reason} -> - ?error("#### ~w(~w) in accept_timeout: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - - -main_loop([{connect, {Host, Port}}| Cmds], St) -> - case connect(St, Host, Port) of - {ok, Sock, LPort, Peer} -> - NSt = get_active(St#st{sock = Sock, port = LPort, peer = Peer}), - pre_main_loop(Cmds, NSt); - {error, Reason} -> - ?error("#### ~w(~w) in connect: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([connection_info| Cmds], St) -> - case connection_info(St) of - {ok, ProtoInfo} -> - io:fwrite("Got connection_info:~n~p~n", [ProtoInfo]), - pre_main_loop(Cmds, St); - {error, Reason} -> - ?error("#### ~w(~w) in connection_info: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([peercert| Cmds], St) -> - case peercert(St) of - {ok, Cert} -> - io:fwrite("Got cert:~n~p~n", [Cert]), - pre_main_loop(Cmds, St); - {error, Reason} -> - ?error("#### ~w(~w) in peercert: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([nopeercert| Cmds], St) -> - case peercert(St) of - {error, Reason} -> - io:fwrite("Got no cert as expected. reason:~n~p~n", [Reason]), - pre_main_loop(Cmds, St); - {ok, Cert} -> - ?error("#### ~w(~w) in peercert: error: got cert: ~p~n", - [St#st.type, self(), Cert]), - exit(peercert) - end; - -main_loop([{recv, N}| Cmds], St) -> - recv_loop([{recv, N}| Cmds], fun recv/1, St); % Returns to main_loop/2. - -main_loop([{send, N}| Cmds], St) -> - Msg = mk_msg(N), - case send(St, Msg) of - ok -> - pre_main_loop(Cmds, St); - {error, Reason} -> - ?error("#### ~w(~w) in send: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([{echo, N}| Cmds], St) -> - recv_loop([{echo, N}| Cmds], fun echo/1, St); % Returns to main_loop/2. - -main_loop([{close, WaitTime}| Cmds], St) -> - wait(WaitTime), - pre_main_loop([close| Cmds], St); - -main_loop([close| Cmds], St) -> - case close(St) of - ok -> - pre_main_loop(Cmds, St#st{sock = nil}); - {error, Reason} -> - ?error("#### ~w(~w) in close: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([lclose| Cmds], St) -> - case lclose(St) of - ok -> - pre_main_loop(Cmds, St#st{lsock = nil}); - {error, Reason} -> - ?error("#### ~w(~w) in lclose: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([await_close| Cmds], St) -> - case await_close(St) of - ok -> - pre_main_loop(Cmds, St#st{sock = nil}); - {error, Reason} -> - ?error("#### ~w(~w) in await_close: error: ~w~n", - [St#st.type, self(), Reason]), - exit(Reason) - end; - -main_loop([wait_sync| Cmds], St) -> - wait_sync(St), - pre_main_loop(Cmds, St); - -main_loop({exit, Reason}, _St) -> - exit(Reason); - -main_loop([], _St) -> - ok. - -%% -%% recv_loop(Cmds, F, St) -%% -%% F = recv/1 | echo/1 -%% -recv_loop([{_Tag, 0}| Cmds], _, St) -> - pre_main_loop(Cmds, St); -recv_loop([{_Tag, N}| _Cmds], _, St) when N < 0 -> - ?error("#### ~w(~w) in recv_loop: error: too much: ~w~n", - [St#st.type, self(), N]), - exit(toomuch); % XXX or {error, Reason}? -recv_loop([{Tag, N}| Cmds], F, St) -> - case F(St) of - {ok, Len} -> - NSt = St#st{active = new_active(St#st.active)}, - if - Len == N -> - pre_main_loop(Cmds, NSt); - true -> - ?debug("#### ~w -> ~w~n", - [{NSt#st.type, self(), NSt#st.sock, NSt#st.port, - NSt#st.peer, NSt#st.active}, {Tag, N - Len}]), - recv_loop([{Tag, N - Len}| Cmds], F, NSt) - end; - {error, Reason} -> - ?error("#### ~w(~w) in recv_loop: error: ~w, ~w bytes remain~n", - [St#st.type, self(), Reason, N]), - exit(Reason) - end. - -new_active(once) -> - false; -new_active(A) -> - A. - -get_active(St) -> - A = case proplists:get_value(active, St#st.sockopts, undefined) of - undefined -> - Mod = case St#st.protomod of - ssl -> - ssl; - gen_tcp -> - inet - end, - {ok, [{active, Ax}]} = Mod:getopts(St#st.sock, [active]), - Ax; - Ay -> - Ay - end, - ?debug("#### ~w(~w) get_active: ~p\n", [St#st.type, self(), A]), - St#st{active = A}. - - -%% -%% SOCKET FUNCTIONS -%% - -%% -%% ssl -%% - -%% -%% listen(St, LPort) -> {ok, LSock} | {error, Reason} -%% -listen(St, LPort) -> - case St#st.protomod of - ssl -> - ssl:listen(LPort, [{ssl_imp, old} | St#st.sockopts ++ St#st.sslopts]); - gen_tcp -> - gen_tcp:listen(LPort, St#st.sockopts) - end. - -%% -%% accept(St) -> {ok, Sock} | {error, Reason} -%% -accept(St) -> - case St#st.protomod of - ssl -> - case ssl:transport_accept(St#st.lsock, St#st.timeout) of - {ok, Sock} -> - case ssl:ssl_accept(Sock, St#st.timeout) of - ok -> - {ok, Port} = ssl:sockname(Sock), - {ok, Peer} = ssl:peername(Sock), - {ok, Sock, Port, Peer}; - Other -> - Other - end; - Other -> - Other - end; - gen_tcp -> - case gen_tcp:accept(St#st.lsock, St#st.timeout) of - {ok, Sock} -> - {ok, Port} = inet:port(Sock), - {ok, Peer} = inet:peername(Sock), - {ok, Sock, Port, Peer}; - Other -> - Other - end - end. - -%% -%% connect(St, Host, Port) -> {ok, Sock} | {error, Reason} -%% -connect(St, Host, Port) -> - - case St#st.protomod of - ssl -> - case ssl:connect(Host, Port, - [{ssl_imp, old} | St#st.sockopts ++ St#st.sslopts], - St#st.timeout) of - {ok, Sock} -> - {ok, LPort} = ssl:sockname(Sock), - {ok, Peer} = ssl:peername(Sock), - {ok, Sock, LPort, Peer}; - Other -> - Other - end; - gen_tcp -> - case gen_tcp:connect(Host, Port, St#st.sockopts, St#st.timeout) of - {ok, Sock} -> - {ok, LPort} = inet:port(Sock), - {ok, Peer} = inet:peername(Sock), - {ok, Sock, LPort, Peer}; - Other -> - Other - end - end. - -%% -%% peercert(St) -> {ok, Cert} | {error, Reason} -%% -peercert(St) -> - case St#st.protomod of - ssl -> - ssl:peercert(St#st.sock, [ssl]); - gen_tcp -> - {ok, <<>>} - end. - -%% -%% connection_info(St) -> {ok, ProtoInfo} | {error, Reason} -%% -connection_info(St) -> - case St#st.protomod of - ssl -> - case ssl:connection_info(St#st.sock) of - Res = {ok, {Proto, _}} -> - case St#st.protocols of - [] -> - Res; - Protocols -> - case lists:member(Proto, Protocols) of - true -> - Res; - false -> - {error, Proto} - end - end; - Error -> - Error - end; - gen_tcp -> - {ok, <<>>} - end. - -%% -%% close(St) -> ok | {error, Reason} -%% - -close(St) -> - Mod = St#st.protomod, - case St#st.sock of - nil -> - ok; - _ -> - Mod:close(St#st.sock) - end. - -%% -%% lclose(St) -> ok | {error, Reason} -%% -lclose(St) -> - Mod = St#st.protomod, - case St#st.lsock of - nil -> - ok; - _ -> - Mod:close(St#st.lsock) - end. - -%% -%% recv(St) = {ok, Len} | {error, Reason} -%% -recv(St) -> - case do_recv(St) of - {ok, Msg} -> - {ok, length(Msg)}; - {error, Reason} -> - {error, Reason} - end. - -do_recv(St) when St#st.active == false -> - %% First check that we do *not* have any ssl/gen_tcp messages in the - %% message queue, then call the receive function. - Sock = St#st.sock, - case St#st.protomod of - ssl -> - receive - M = {ssl, Sock, _Msg} -> - {error, {unexpected_messagex, M}}; - M = {ssl_closed, Sock} -> - {error, {unexpected_message, M}}; - M = {ssl_error, Sock, _Reason} -> - {error, {unexpected_message, M}} - after 0 -> - ssl:recv(St#st.sock, 0, St#st.timeout) - end; - gen_tcp -> - receive - M = {tcp, Sock, _Msg} -> - {error, {unexpected_message, M}}; - M = {tcp_closed, Sock} -> - {error, {unexpected_message, M}}; - M = {tcp_error, Sock, _Reason} -> - {error, {unexpected_message, M}} - after 0 -> - gen_tcp:recv(St#st.sock, 0, St#st.timeout) - end - end; -do_recv(St) -> - Sock = St#st.sock, - Timeout = St#st.timeout, - case St#st.protomod of - ssl -> - receive - {ssl, Sock, Msg} -> - {ok, Msg}; - {ssl_closed, Sock} -> - {error, closed}; - {ssl_error, Sock, Reason} -> - {error, Reason} - after Timeout -> - {error, timeout} - end; - gen_tcp -> - receive - {tcp, Sock, Msg} -> - {ok, Msg}; - {tcp_closed, Sock} -> - {error, closed}; - {tcp_error, Sock, Reason} -> - {error, Reason} - after Timeout -> - {error, timeout} - end - end. - -%% -%% echo(St) = {ok, Len} | {error, Reason} -%% -echo(St) -> - Sock = St#st.sock, - case do_recv(St) of - {ok, Msg} -> - Mod = St#st.protomod, - case Mod:send(Sock, Msg) of - ok -> - {ok, length(Msg)}; - {error, Reason} -> - {error, Reason} - end; - {error, Reason} -> - {error, Reason} - end. - -%% -%% send(St, Msg) -> ok | {error, Reason} -%% -send(St, Msg) -> - Mod = St#st.protomod, - Mod:send(St#st.sock, Msg). - -%% -%% await_close(St) -> ok | {error, Reason} -%% -await_close(St) when St#st.active == false -> - %% First check that we do *not* have any ssl/gen_tcp messages in the - %% message queue, then call the receive function. - Sock = St#st.sock, - Res = case St#st.protomod of - ssl -> - receive - M = {ssl, Sock, _Msg0} -> - {error, {unexpected_message, M}}; - M = {ssl_closed, Sock} -> - {error, {unexpected_message, M}}; - M = {ssl_error, Sock, _Reason} -> - {error, {unexpected_message, M}} - after 0 -> - ok - end; - gen_tcp -> - receive - M = {tcp, Sock, _Msg0} -> - {error, {unexpected_message, M}}; - M = {tcp_closed, Sock} -> - {error, {unexpected_message, M}}; - M = {tcp_error, Sock, _Reason} -> - {error, {unexpected_message, M}} - after 0 -> - ok - end - end, - case Res of - ok -> - Mod = St#st.protomod, - case Mod:recv(St#st.sock, 0, St#st.timeout) of - {ok, _Msg} -> - {error, toomuch}; - {error, _} -> - ok - end; - _ -> - Res - end; -await_close(St) -> - Sock = St#st.sock, - Timeout = St#st.timeout, - case St#st.protomod of - ssl -> - receive - {ssl, Sock, _Msg} -> - {error, toomuch}; - {ssl_closed, Sock} -> - ok; - {ssl_error, Sock, Reason} -> - {error, Reason} - after Timeout -> - {error, timeout} - end; - gen_tcp -> - receive - {tcp, Sock, _Msg} -> - {error, toomuch}; - {tcp_closed, Sock} -> - ok; - {tcp_error, Sock, Reason} -> - {error, Reason} - after Timeout -> - {error, timeout} - end - end. - - -%% -%% HELP FUNCTIONS -%% - -wait_ack(_, [], _) -> - ok; -wait_ack(AccPids0, Pids, Timeout) -> - ?debug("#### CONTROLLER: waiting for ~w~n", [Pids]), - receive - {one_accept_done, Pid} -> - case lists:delete(Pid, AccPids0) of - [] -> - wait_ack([], Pids, Timeout); - [AccPid| AccPids1] -> - AccPid ! {continue_accept, self()}, - wait_ack(AccPids1, Pids, Timeout) - end; - {'EXIT', Pid, normal} -> - wait_ack(AccPids0, lists:delete(Pid, Pids), Timeout); - {'EXIT', Pid, Reason} -> - ?error("#### CONTROLLER got abnormal exit: ~w, ~w~n", - [Pid, Reason]), - {error, Reason} - after Timeout -> - ?error("#### CONTROLLER exiting because of timeout = ~w~n", - [Timeout]), - {error, Timeout} - end. - - -%% -%% ack_lsock(Pid, LSock) -%% -ack_lsock(Pid, LSock) -> - Pid ! {lsock, self(), LSock}. - -wait_lsock(Pid, Timeout) -> - receive - {lsock, Pid, LSock} -> - {ok, LSock} - after Timeout -> - exit(timeout) - end. - -%% -%% sync(Pids) -%% -sync(Pids) -> - lists:foreach(fun (Pid) -> Pid ! {self(), sync} end, Pids). - -%% -%% wait_sync(St) -%% -wait_sync(St) -> - Pid = St#st.parent, - receive - {Pid, sync} -> - ok - end. - -%% -%% wait(Time) -%% -wait(Time) -> - receive - after Time -> - ok - end. - -%% -%% mk_msg(Size) -%% -mk_msg(Size) -> - mk_msg(0, Size, []). - -mk_msg(_, 0, Acc) -> - Acc; -mk_msg(Pos, Size, Acc) -> - C = (((Pos + Size) rem 256) - 1) band 255, - mk_msg(Pos, Size - 1, [C| Acc]). - -%% -%% get_protomod(Config) -%% -get_protomod(Config) -> - case lists:keysearch(protomod, 1, Config) of - {value, {_, ProtoMod}} -> - ProtoMod; - false -> - ssl - end. - -%% -%% get_serialize_accept(Config) -%% -get_serialize_accept(Config) -> - case lists:keysearch(serialize_accept, 1, Config) of - {value, {_, Val}} -> - Val; - false -> - false - end. - diff --git a/lib/ssl/test/ssl_test_MACHINE.hrl b/lib/ssl/test/ssl_test_MACHINE.hrl deleted file mode 100644 index e78b33f505..0000000000 --- a/lib/ssl/test/ssl_test_MACHINE.hrl +++ /dev/null @@ -1,39 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2010. 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% -%% - --record(st, {protomod = ssl, - serialize_accept = false, - parent = nil, - type = nil, - active = nil, - port = 0, - peer = nil, - lsock = nil, - sock = nil, - timeout = infinity, - sockopts = [], - sslopts = [], - protocols = []}). - -%%-define(debug(X, Y), io:format(X, Y)). --define(debug(X, Y), ok). --define(error(X, Y), io:format(X, Y)). - --define(DEFAULT_TIMEOUT, 240000). - -- cgit v1.2.3 From ff371b3b33e435f63962615be06404f6f8af3d5e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 19 Sep 2011 11:36:35 +0200 Subject: erts: Fix bug SCTP send can only be called from controlling process Conflicts: lib/kernel/test/gen_sctp_SUITE.erl --- erts/emulator/drivers/common/inet_drv.c | 5 ++--- lib/kernel/test/gen_sctp_SUITE.erl | 34 +++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index c6e23ee647..3c4be8eea4 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. 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 @@ -6425,8 +6425,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, i = LOAD_TUPLE(spec, i, 3); /* Now, convert "spec" into the returnable term: */ - /* desc->caller = 0; What does it mean? */ - driver_output_term(desc->port, spec, i); + driver_send_term(desc->port, driver_caller(desc->port), spec, i); FREE(spec); (*dest)[0] = INET_REP_SCTP; diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index fad8c7398b..da2f533097 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. 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 @@ -172,7 +172,9 @@ xfer_active(Config) when is_list(Config) -> ?line test_server:fail({unexpected,flush()}) end, ?line io:format("SbAssocId=~p~n", [SbAssocId]), - ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), + ?line ok = + do_from_other_process( + fun () -> gen_sctp:send(Sa, SaAssocId, 0, Data) end), ?line receive {sctp,Sb,Loopback,Pa, {[#sctp_sndrcvinfo{stream=Stream, @@ -382,3 +384,31 @@ api_connect_init(Config) when is_list(Config) -> ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), ok. + + + +do_from_other_process(Fun) -> + Parent = self(), + Ref = make_ref(), + Child = + spawn(fun () -> + try Fun() of + Result -> + Parent ! {Ref,Result} + catch + Class:Reason -> + Stacktrace = erlang:get_stacktrace(), + Parent ! {Ref,Class,Reason,Stacktrace} + end + end), + Mref = erlang:monitor(process, Child), + receive + {Ref,Result} -> + receive {'DOWN',Mref,_,_,_} -> Result end; + {Ref,Class,Reason,Stacktrace} -> + receive {'DOWN',Mref,_,_,_} -> + erlang:raise(Class, Reason, Stacktrace) + end; + {'DOWN',Mref,_,_,Reason} -> + erlang:exit(Reason) + end. -- cgit v1.2.3 From 0159f7a9598c1d88b2e184dcc442c254ef8f14c9 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 19 Sep 2011 12:10:46 +0200 Subject: erts,kernel: Bugfix - read SCTP socket options from right protocol layer Socket options 'sndbuf', 'recbuf' and 'linger were read from the SCTP protocol layer instead of from the socket protocol layer. Conflicts: lib/kernel/test/gen_sctp_SUITE.erl --- erts/emulator/drivers/common/inet_drv.c | 6 +++--- lib/kernel/test/gen_sctp_SUITE.erl | 21 +++++++++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 3c4be8eea4..2bff5bd4f7 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -5941,7 +5941,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, struct linger lg; unsigned int sz = sizeof(lg); - if (sock_getopt(desc->s, IPPROTO_SCTP, SO_LINGER, + if (sock_getopt(desc->s, SOL_SOCKET, SO_LINGER, &lg, &sz) < 0) continue; /* Fill in the response: */ PLACE_FOR(spec, i, @@ -5977,7 +5977,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, { case INET_OPT_RCVBUF : { - proto = IPPROTO_SCTP; + proto = SOL_SOCKET; type = SO_RCVBUF; is_int = 1; tag = am_recbuf; @@ -5985,7 +5985,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, } case INET_OPT_SNDBUF : { - proto = IPPROTO_SCTP; + proto = SOL_SOCKET; type = SO_SNDBUF; is_int = 1; tag = am_sndbuf; diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index da2f533097..9ba226864d 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -24,11 +24,11 @@ %%-compile(export_all). -export([all/1,init_per_testcase/2,fin_per_testcase/2, - basic/1,api_open_close/1,api_listen/1,api_connect_init/1, + basic/1,api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, xfer_min/1,xfer_active/1]). all(suite) -> - [basic,api_open_close,api_listen,api_connect_init,xfer_min,xfer_active]. + [basic,api_open_close,api_listen,api_connect_init,api_opts,xfer_min,xfer_active]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(15)), @@ -385,6 +385,23 @@ api_connect_init(Config) when is_list(Config) -> ?line ok = gen_sctp:close(Sb), ok. +api_opts(doc) -> + "Test socket options"; +api_opts(suite) -> + []; +api_opts(Config) when is_list(Config) -> + ?line Sndbuf = 32768, + ?line Recbuf = 65536, + ?line {ok,S} = gen_sctp:open(0), + ?line ok = inet:setopts(S, [{sndbuf,Sndbuf}]), + ?line ok = inet:setopts(S, [{recbuf,Recbuf}]), + ?line case inet:getopts(S, [sndbuf]) of + {ok,[{sndbuf,SB}]} when SB >= Sndbuf -> ok + end, + ?line case inet:getopts(S, [recbuf]) of + {ok,[{recbuf,RB}]} when RB >= Recbuf -> ok + end. + do_from_other_process(Fun) -> -- cgit v1.2.3 From f8b20b4a995727f0339074d23a0fae50712683d2 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Mon, 19 Sep 2011 12:24:34 +0200 Subject: Prepare release --- erts/doc/src/notes.xml | 18 ++++++++++++++++++ erts/vsn.mk | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 824ad6d94e..09950e865b 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,24 @@

This document describes the changes made to the ERTS application.

+
Erts 5.7.5.2 + +
Known Bugs and Problems + + +

+ Two bugs in gen_sctp has been corrected: getopts/setopts + hence also send could only be called from socket owner, + and options 'linger', 'rcvbuf' and 'sndbuf' was read from + wrong protocol layer hence read wrong values by getopts.

+

+ Own Id: OTP-9544

+
+
+
+ +
+
Erts 5.7.5.1
Fixed Bugs and Malfunctions diff --git a/erts/vsn.mk b/erts/vsn.mk index 14c6a3e4dd..4e6571c70b 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,7 +17,7 @@ # %CopyrightEnd% # -VSN = 5.7.5.1 +VSN = 5.7.5.2 SYSTEM_VSN = R13B04 # Port number 4365 in 4.2 -- cgit v1.2.3 From 1856a071183a3d0c546b2736dbec603f504298b2 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 21 Sep 2011 09:49:34 +0200 Subject: Skip update_cpu_info if 'taskset' cannot be found --- erts/emulator/test/scheduler_SUITE.erl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index f16d0ea429..3606b8a730 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -87,8 +87,17 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. - +init_per_testcase(update_cpu_info, Config) -> + case os:find_executable("taskset") of + false -> + {skip,"Could not find 'taskset' in path"}; + _ -> + init_per_tc(update_cpu_info, Config) + end; init_per_testcase(Case, Config) when is_list(Config) -> + init_per_tc(Case, Config). + +init_per_tc(Case, Config) -> Dog = ?t:timetrap(?DEFAULT_TIMEOUT), process_flag(priority, max), erlang:display({'------------', ?MODULE, Case, '------------'}), -- cgit v1.2.3 From 4508c35b9b5af75fcdd730d479c19e75c5102ae2 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 21 Sep 2011 10:24:08 +0200 Subject: Increase timeout in scheduler_suspend for slow platforms --- erts/emulator/test/scheduler_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index 3606b8a730..debb54579b 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -1039,7 +1039,7 @@ sbt_test(Config, CpuTCmd, ClBt, Bt, LP) -> ?line ok. scheduler_suspend(Config) when is_list(Config) -> - ?line Dog = ?t:timetrap(?t:minutes(2)), + ?line Dog = ?t:timetrap(?t:minutes(5)), ?line lists:foreach(fun (S) -> scheduler_suspend_test(Config, S) end, [64, 32, 16, default]), ?line ?t:timetrap_cancel(Dog), -- cgit v1.2.3 From 51b66111af55e26710d5e8e0a8c3f98c38bd7207 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Mon, 27 Jun 2011 12:55:56 +0200 Subject: [wx] Fix cleanup memory references Could cause a crash in later restarts --- lib/wx/c_src/wxe_impl.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index 95755978f1..70d4c4b29e 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -588,7 +588,7 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) { } else { delete_object(ptr, refd); } - if(type == 0 || type > 3) { + if(type == 0 || type > 2) { // Delete refs for leaks and non overridden allocs delete refd; ptr2ref.erase(it); @@ -602,13 +602,13 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) { } } } - // Assert ? -// for(ptrMap::iterator it = ptr2ref.begin(); it != ptr2ref.end(); it++) { -// wxeRefData *refd = it->second; -// if(refd->ref >= global_me->next) -// fprintf(stderr, "L %d %d\r\n", refd->ref, refd->alloc_in_erl); -// } -// fflush(stderr); +// // Assert ? +// for(ptrMap::iterator it = ptr2ref.begin(); it != ptr2ref.end(); it++) { +// wxeRefData *refd = it->second; +// if(refd->ref >= global_me->next) +// fprintf(stderr, "L %d %d %d\r\n", refd->ref, refd->type, refd->alloc_in_erl); +// } +// fflush(stderr); delete memenv; driver_pdl_dec_refc(Ecmd.pdl); refmap.erase((ErlDrvTermData) Ecmd.port); @@ -650,12 +650,12 @@ int WxeApp::getRef(void * ptr, wxeMemEnv *memenv) { ptrMap::iterator it = ptr2ref.find(ptr); if(it != ptr2ref.end()) { wxeRefData *refd = it->second; - if(refd->memenv == memenv) { + if(refd->memenv == memenv || refd->memenv == global_me) { // Found it return return refd->ref; } // else // Old reference to deleted object, release old and recreate in current memenv. - clearPtr(ptr); + ptr2ref.erase(it); } int ref; intList free = memenv->free; -- cgit v1.2.3 From 7359eb8c81adb6331be7df963e08ab7dd6ccbe0e Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Mon, 27 Jun 2011 12:59:00 +0200 Subject: [wx] Test colors in textctrl --- lib/wx/test/wx_class_SUITE.erl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index 00ef1289ab..b75b0cc74e 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -448,3 +448,25 @@ systemSettings(Config) -> wxWindow:show(Frame), wx_test_lib:wx_destroy(Frame,Config). + + +textCtrl(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +textCtrl(Config) -> + Wx = wx:new(), + Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame"), + + TC = ?mt(wxTextCtrl, wxTextCtrl:new(Frame, ?wxID_ANY, [{style, ?wxTE_MULTILINE bor ?wxTE_RICH2}])), + wxTextCtrl:appendText(TC, "This line is in default color\n"), + Attr = ?mt(wxTextAttr, wxTextAttr:new(?wxRED)), + wxTextCtrl:setDefaultStyle(TC, Attr), + wxTextCtrl:appendText(TC, "This line is in ?wxRED color\n"), + wxTextAttr:setTextColour(Attr, ?wxBLACK), + wxTextCtrl:setDefaultStyle(TC, Attr), + wxTextCtrl:appendText(TC, "This line is in ?wxBLACK color\n"), + Default = wxSystemSettings:getColour(?wxSYS_COLOUR_WINDOWTEXT), + wxTextAttr:setTextColour(Attr, Default), + wxTextCtrl:setDefaultStyle(TC, Attr), + wxTextCtrl:appendText(TC, "This line is in default color\n"), + wxTextAttr:destroy(Attr), + wxWindow:show(Frame), + wx_test_lib:wx_destroy(Frame,Config). -- cgit v1.2.3 From 9849688f10ab4536a856192c4f42af9ead5a3a77 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Mon, 27 Jun 2011 12:59:39 +0200 Subject: [wx] Fix trailing whitespace --- lib/wx/c_src/egl_impl.cpp | 54 +++++++-------- lib/wx/c_src/wxe_impl.cpp | 168 +++++++++++++++++++++++----------------------- 2 files changed, 111 insertions(+), 111 deletions(-) diff --git a/lib/wx/c_src/egl_impl.cpp b/lib/wx/c_src/egl_impl.cpp index e2dbbb73c4..6a551beed7 100644 --- a/lib/wx/c_src/egl_impl.cpp +++ b/lib/wx/c_src/egl_impl.cpp @@ -1,20 +1,20 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2010. All Rights Reserved. - * + * + * Copyright Ericsson AB 2011. 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% + * + * %CopyrightEnd% */ #include @@ -35,8 +35,8 @@ void init_tess(); void exit_tess(); int load_gl_functions(); -/* **************************************************************************** - * OPENGL INITIALIZATION +/* **************************************************************************** + * OPENGL INITIALIZATION *****************************************************************************/ int egl_initiated = 0; @@ -51,7 +51,7 @@ void * dlsym(HMODULE Lib, const char *func) { void * funcp; if((funcp = (void *) GetProcAddress(Lib, func))) return funcp; - else + else return (void *) wglGetProcAddress(func); } @@ -73,14 +73,14 @@ typedef char DL_CHAR; # define OPENGL_LIB "libGL.so" # define OPENGLU_LIB "libGLU.so" # endif -#endif +#endif extern "C" { -DRIVER_INIT(EGL_DRIVER) { +DRIVER_INIT(EGL_DRIVER) { return NULL; } } -int egl_init_opengl(void *erlCallbacks) +int egl_init_opengl(void *erlCallbacks) { #ifdef _WIN32 driver_init((TWinDynDriverCallbacks *) erlCallbacks); @@ -133,7 +133,7 @@ int load_gl_functions() { func = NULL; if(LIBhandle) { - for(i=0; glu_fns[i].name != NULL; i++) { + for(i=0; glu_fns[i].name != NULL; i++) { if((func = dlsym(LIBhandle, glu_fns[i].name))) { * (void **) (glu_fns[i].func) = func; } else { @@ -201,7 +201,7 @@ egl_ogla_error(GLenum errorCode) void CALLBACK egl_ogla_combine(GLdouble coords[3], void* vertex_data[4], - GLfloat w[4], + GLfloat w[4], void **dataOut) { GLdouble* vertex = tess_alloc_vertex; @@ -226,7 +226,7 @@ egl_ogla_combine(GLdouble coords[3], *dataOut = vertex; } -void init_tess() +void init_tess() { tess = gluNewTess(); @@ -237,7 +237,7 @@ void init_tess() } -void exit_tess() +void exit_tess() { gluDeleteTess(tess); } @@ -251,22 +251,22 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) int num_vertices; GLdouble *n; int n_pos, AP, res; - + num_vertices = * (int *) buff; buff += 8; /* Align */ n = (double *) buff; buff += 8*3; - bin = driver_alloc_binary(num_vertices*6*sizeof(GLdouble)); + bin = driver_alloc_binary(num_vertices*6*sizeof(GLdouble)); new_vertices = tess_coords = (double *) bin->orig_bytes; memcpy(tess_coords,buff,num_vertices*3*sizeof(GLdouble)); tess_alloc_vertex = tess_coords + num_vertices*3; #if 0 fprintf(stderr, "n=%d\r\n", num_vertices); -#endif +#endif vertices = (int *) driver_alloc(sizeof(int) * 16*num_vertices); - + tess_vertices = vertices; - + gluTessNormal(tess, n[0], n[1], n[2]); gluTessBeginPolygon(tess, 0); gluTessBeginContour(tess); @@ -275,9 +275,9 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) } gluTessEndContour(tess); gluTessEndPolygon(tess); - - n_pos = (tess_vertices - vertices); - + + n_pos = (tess_vertices - vertices); + AP = 0; ErlDrvTermData *rt; rt = (ErlDrvTermData *) driver_alloc(sizeof(ErlDrvTermData) * (13+n_pos*2)); rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_"); @@ -287,12 +287,12 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) }; rt[AP++] = ERL_DRV_NIL; rt[AP++] = ERL_DRV_LIST; rt[AP++] = n_pos+1; - rt[AP++] = ERL_DRV_BINARY; rt[AP++] = (ErlDrvTermData) bin; + rt[AP++] = ERL_DRV_BINARY; rt[AP++] = (ErlDrvTermData) bin; rt[AP++] = (tess_alloc_vertex-new_vertices)*sizeof(GLdouble); rt[AP++] = 0; - + rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin} rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple - + res = driver_send_term(port,caller,rt,AP); /* fprintf(stderr, "List %d: %d %d %d \r\n", */ /* res, */ diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index 70d4c4b29e..e430fbc7a2 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -14,7 +14,7 @@ * the License for the specific language governing rights and limitations * under the License. * - * %CopyrightEnd% + * %CopyrightEnd% */ #include @@ -49,7 +49,7 @@ DEFINE_EVENT_TYPE(wxeEVT_META_COMMAND) #define WXE_NORMAL 0 #define WXE_CALLBACK 1 -#define WXE_STORED 2 +#define WXE_STORED 2 ErlDrvTid wxe_thread; @@ -67,7 +67,7 @@ wxList * wxe_batch_cb_saved = NULL; ErlDrvTermData wxe_batch_caller = 0; ErlDrvTermData init_caller = 0; -// extern opengl +// extern opengl void gl_dispatch(int op, char *bp, ErlDrvTermData caller, WXEBinRef *bins[]); @@ -99,7 +99,7 @@ void *wxe_main_loop(void * ); * START AND STOP of driver thread * ************************************************************/ -int load_native_gui() +int load_native_gui() { return 1; } @@ -112,7 +112,7 @@ int start_native_gui(wxe_data *sd) wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m"); wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c"); - init_caller = driver_connected(sd->port); + init_caller = driver_connected(sd->port); #ifdef __DARWIN__ res = erl_drv_steal_main_thread((char *)"wxwidgets", @@ -152,9 +152,9 @@ void stop_native_gui(wxe_data *sd) erl_drv_cond_destroy(wxe_batch_locker_c); } -void unload_native_gui() +void unload_native_gui() { - + } /* ************************************************************ @@ -162,13 +162,13 @@ void unload_native_gui() * Called by emulator thread * ************************************************************/ -void push_command(int op,char * buf,int len, wxe_data *sd) -{ +void push_command(int op,char * buf,int len, wxe_data *sd) +{ // fprintf(stderr, "Op %d %d\r\n", op, (int) driver_caller(sd->port)),fflush(stderr); wxeCommand *Cmd = new wxeCommand(op, buf, len, sd); erl_drv_mutex_lock(wxe_batch_locker_m); wxe_batch->Append(Cmd); - + if(wxe_batch_caller > 0) { // wx-thread is waiting on batch end in cond_wait erl_drv_cond_signal(wxe_batch_locker_c); @@ -179,11 +179,11 @@ void push_command(int op,char * buf,int len, wxe_data *sd) } erl_drv_cond_signal(wxe_batch_locker_c); wxWakeUpIdle(); - } + } erl_drv_mutex_unlock(wxe_batch_locker_m); } -void meta_command(int what, wxe_data *sd) { +void meta_command(int what, wxe_data *sd) { if(what == PING_PORT) { erl_drv_mutex_lock(wxe_batch_locker_m); if(wxe_batch_caller > 0) { @@ -203,17 +203,17 @@ void meta_command(int what, wxe_data *sd) { } /* ************************************************************ - * wxWidgets Thread + * wxWidgets Thread * ************************************************************/ void *wxe_main_loop(void *vpdl) { - int result; + int result; int argc = 1; char * temp = (char *) "Erlang"; char * argv[] = {temp,NULL}; ErlDrvPDL pdl = (ErlDrvPDL) vpdl; - + driver_pdl_inc_refc(pdl); // ErlDrvSysInfo einfo; @@ -223,7 +223,7 @@ void *wxe_main_loop(void *vpdl) #ifndef _WIN32 erts_thread_disable_fpe(); #endif - + result = wxEntry(argc, argv); // fprintf(stderr, "WXWidgets quits main loop %d \r\n", result); if(result >= 0 && wxe_status == WXE_INITIATED) { @@ -240,17 +240,17 @@ void *wxe_main_loop(void *vpdl) erl_drv_cond_signal(wxe_status_c); erl_drv_mutex_unlock(wxe_status_m); driver_pdl_dec_refc(pdl); - return NULL; + return NULL; } } wxFrame * dummy_window; void create_dummy_window() { - dummy_window = new wxFrame(NULL,-1, wxT("wx driver"), - wxDefaultPosition, wxSize(5,5), + dummy_window = new wxFrame(NULL,-1, wxT("wx driver"), + wxDefaultPosition, wxSize(5,5), wxFRAME_NO_TASKBAR); - dummy_window->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW, + dummy_window->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW, (wxObjectEventFunction) (wxEventFunction) &WxeApp::dummy_close); } @@ -262,7 +262,7 @@ void WxeApp::dummy_close(wxEvent& Ev) { create_dummy_window(); } -// Init wx-widgets thread +// Init wx-widgets thread bool WxeApp::OnInit() { wxe_ps_init(); @@ -274,13 +274,13 @@ bool WxeApp::OnInit() wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); - this->Connect(wxID_ANY, wxEVT_IDLE, + this->Connect(wxID_ANY, wxEVT_IDLE, (wxObjectEventFunction) (wxEventFunction) &WxeApp::idle); - this->Connect(CREATE_PORT, wxeEVT_META_COMMAND, + this->Connect(CREATE_PORT, wxeEVT_META_COMMAND, (wxObjectEventFunction) (wxEventFunction) &WxeApp::newMemEnv); - this->Connect(DELETE_PORT, wxeEVT_META_COMMAND, + this->Connect(DELETE_PORT, wxeEVT_META_COMMAND, (wxObjectEventFunction) (wxEventFunction) &WxeApp::destroyMemEnv); - this->Connect(WXE_SHUTDOWN, wxeEVT_META_COMMAND, + this->Connect(WXE_SHUTDOWN, wxeEVT_META_COMMAND, (wxObjectEventFunction) (wxEventFunction) &WxeApp::shutdown); // fprintf(stderr, "Size void* %d: long %d long long %d int64 %d \r\n", @@ -288,9 +288,9 @@ bool WxeApp::OnInit() initEventTable(); wxInitAllImageHandlers(); - /* Create a dummy window so wxWidgets don't automagicly quits the main loop + /* Create a dummy window so wxWidgets don't automagicly quits the main loop after the last window */ - create_dummy_window(); + create_dummy_window(); init_nonconsts(global_me, init_caller); erl_drv_mutex_lock(wxe_status_m); @@ -309,19 +309,19 @@ void send_msg(const char * type, wxString * msg) { wxeReturn rt = wxeReturn(WXE_DRV_PORT, init_caller); rt.addAtom((char *) "wxe_driver"); rt.addAtom((char *) type); - rt.add(msg); + rt.add(msg); rt.addTupleCount(3); rt.send(); } /* ************************************************************ - * Erlang Command execution * + * Erlang Command execution * * ************************************************************/ -/* Callback from printer and event callbacks */ +/* Callback from printer and event callbacks */ void pre_callback() { - // no-op + // no-op } void handle_event_callback(ErlDrvPort port, ErlDrvTermData process) @@ -343,7 +343,7 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process) void WxeApp::idle(wxIdleEvent& event) { dispatch_cmds(); } - + void WxeApp::dispatch_cmds() { erl_drv_mutex_lock(wxe_batch_locker_m); int level = dispatch(wxe_batch_cb_saved, 0, WXE_STORED); @@ -352,14 +352,14 @@ void WxeApp::dispatch_cmds() { erl_drv_mutex_unlock(wxe_batch_locker_m); } -// Should have erl_drv_mutex_lock(wxe_batch_locker_m); -// when entering this function and it should be released +// Should have erl_drv_mutex_lock(wxe_batch_locker_m); +// when entering this function and it should be released // afterwards -int WxeApp::dispatch(wxList * batch, int blevel, int list_type) +int WxeApp::dispatch(wxList * batch, int blevel, int list_type) { int ping = 0; // erl_drv_mutex_lock(wxe_batch_locker_m); must be locked already - while(true) + while(true) { if (batch->size() > 0) { for( wxList::compatibility_iterator node = batch->GetFirst(); @@ -376,10 +376,10 @@ int WxeApp::dispatch(wxList * batch, int blevel, int list_type) {blevel++; } break; case WXE_DEBUG_PING: - // When in debugger we don't want to hang waiting for a BATCH_END + // When in debugger we don't want to hang waiting for a BATCH_END // that never comes, because a breakpoint have hit. ping++; - if(ping > 2) + if(ping > 2) blevel = 0; break; case WXE_CB_RETURN: @@ -391,7 +391,7 @@ int WxeApp::dispatch(wxList * batch, int blevel, int list_type) } return blevel; default: - erl_drv_mutex_unlock(wxe_batch_locker_m); + erl_drv_mutex_unlock(wxe_batch_locker_m); if(event->op < OPENGL_START) { // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel); wxe_dispatch(*event); @@ -430,10 +430,10 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) wxeCommand *event = (wxeCommand *)node->GetData(); wxeMemEnv *memenv = getMemEnv(event->port); batch->Erase(node); - if(event->caller == process || // Callbacks from CB process only + if(event->caller == process || // Callbacks from CB process only event->op == WXE_CB_START || // Recursive event callback allow // Allow connect_cb during CB i.e. msg from wxe_server. - (memenv && event->caller == memenv->owner)) + (memenv && event->caller == memenv->owner)) { switch(event->op) { case WXE_BATCH_END: @@ -461,7 +461,7 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) } erl_drv_mutex_lock(wxe_batch_locker_m); break; - if(callback_returned) + if(callback_returned) return; } delete event; @@ -491,13 +491,13 @@ void WxeApp::newMemEnv(wxeMetaCommand& Ecmd) { driver_pdl_inc_refc(Ecmd.pdl); for(int i = 0; i < global_me->next; i++) { - memenv->ref2ptr[i] = global_me->ref2ptr[i]; + memenv->ref2ptr[i] = global_me->ref2ptr[i]; } memenv->next = global_me->next; refmap[(ErlDrvTermData) Ecmd.port] = memenv; memenv->owner = Ecmd.caller; - ErlDrvTermData rt[] = {ERL_DRV_ATOM, driver_mk_atom((char *)"wx_port_initiated")}; + ErlDrvTermData rt[] = {ERL_DRV_ATOM, driver_mk_atom((char *)"wx_port_initiated")}; driver_send_term(WXE_DRV_PORT,Ecmd.caller,rt,2); } @@ -516,13 +516,13 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) { // pre-pass delete all dialogs first since they might crash erlang otherwise for(int i=1; i < memenv->next; i++) { wxObject * ptr = (wxObject *) memenv->ref2ptr[i]; - if(ptr) { + if(ptr) { ptrMap::iterator it = ptr2ref.find(ptr); if(it != ptr2ref.end()) { wxeRefData *refd = it->second; if(refd->alloc_in_erl) { if(refd->type == 2) { - wxDialog *win = (wxDialog *) ptr; + wxDialog *win = (wxDialog *) ptr; if(win->IsModal()) { win->EndModal(-1); } @@ -532,25 +532,25 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) { if(parentRef == ptr2ref.end()) { // The parent is already dead delete the parent ref win->SetParent(NULL); - } + } } delete win; - } + } } } } } - // First pass, delete all top parents/windows of all linked objects + // First pass, delete all top parents/windows of all linked objects // fprintf(stderr, "close port %x\r\n", Ecmd.port);fflush(stderr); for(int i=1; i < memenv->next; i++) { void * ptr = memenv->ref2ptr[i]; - if(ptr) { + if(ptr) { ptrMap::iterator it = ptr2ref.find(ptr); if(it != ptr2ref.end()) { wxeRefData *refd = it->second; if(refd->alloc_in_erl && refd->type == 0) { - parent = (wxWindow *) ptr; + parent = (wxWindow *) ptr; // fprintf(stderr, "window %x %d\r\n", (int) parent, refd->ref); while(parent->GetParent()) { parent = parent->GetParent(); @@ -570,7 +570,7 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) { // everything linked from windows should now be deleted for(int i=1; i < memenv->next; i++) { void * ptr = memenv->ref2ptr[i]; - if(ptr) { + if(ptr) { ptrMap::iterator it = ptr2ref.find(ptr); if(it != ptr2ref.end()) { wxeRefData *refd = it->second; @@ -582,26 +582,26 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) { wxString msg; if((refd->type == 0)) { // Maybe also class 1 wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo(); - msg.Printf(wxT("Memory leak: {wx_ref, %d, %s}"), + msg.Printf(wxT("Memory leak: {wx_ref, %d, %s}"), refd->ref, cinfo->GetClassName()); send_msg("error", &msg); } else { delete_object(ptr, refd); } if(type == 0 || type > 2) { - // Delete refs for leaks and non overridden allocs + // Delete refs for leaks and non overridden allocs delete refd; ptr2ref.erase(it); } // overridden allocs deletes meta-data in clearPtr } else { // Not alloced in erl just delete references if(refd->ref >= global_me->next) { // if it is not part of global ptrs - delete refd; + delete refd; ptr2ref.erase(it); } } } } - } + } // // Assert ? // for(ptrMap::iterator it = ptr2ref.begin(); it != ptr2ref.end(); it++) { // wxeRefData *refd = it->second; @@ -621,7 +621,7 @@ wxeMemEnv * WxeApp::getMemEnv(ErlDrvPort port) { int WxeApp::newPtr(void * ptr, int type, wxeMemEnv *memenv) { int ref; intList free = memenv->free; - + if(free.IsEmpty()) { ref = memenv->next++; } else { @@ -629,8 +629,8 @@ int WxeApp::newPtr(void * ptr, int type, wxeMemEnv *memenv) { }; if(ref >= memenv->max) { memenv->max *= 2; - memenv->ref2ptr = - (void **) driver_realloc(memenv->ref2ptr,memenv->max * sizeof(void*)); + memenv->ref2ptr = + (void **) driver_realloc(memenv->ref2ptr,memenv->max * sizeof(void*)); } memenv->ref2ptr[ref] = ptr; @@ -684,7 +684,7 @@ void WxeApp::clearPtr(void * ptr) { if(it != ptr2ref.end()) { wxeRefData *refd = it->second; intList free = refd->memenv->free; - int ref = refd->ref; + int ref = refd->ref; refd->memenv->ref2ptr[ref] = NULL; free.Append(ref); @@ -693,7 +693,7 @@ void WxeApp::clearPtr(void * ptr) { msg.Printf(wxT("Deleting {wx_ref, %d, unknown} at %p "), ref, ptr); send_msg("debug", &msg); } - + if(((int) refd->pid) != -1) { // Send terminate pid to owner wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->memenv->owner, false); @@ -706,30 +706,30 @@ void WxeApp::clearPtr(void * ptr) { if(refd->type == 1 && ((wxObject*)ptr)->IsKindOf(CLASSINFO(wxSizer))) { wxSizerItemList list = ((wxSizer*)ptr)->GetChildren(); for(wxSizerItemList::compatibility_iterator node = list.GetFirst(); - node; node = node->GetNext()) { + node; node = node->GetNext()) { wxSizerItem *item = node->GetData(); wxObject *content=NULL; - if((content = item->GetWindow())) + if((content = item->GetWindow())) if(ptr2ref.end() == ptr2ref.find(content)) { wxString msg; wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo(); msg.Printf(wxT("Double usage detected of window at %p in sizer {wx_ref, %d, %s}"), content, ref, cinfo->GetClassName()); send_msg("error", &msg); - ((wxSizer*)ptr)->Detach((wxWindow*)content); + ((wxSizer*)ptr)->Detach((wxWindow*)content); } - if((content = item->GetSizer())) + if((content = item->GetSizer())) if(ptr2ref.end() == ptr2ref.find(content)) { wxString msg; wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo(); msg.Printf(wxT("Double usage detected of sizer at %p in sizer {wx_ref, %d, %s}"), content, ref, cinfo->GetClassName()); send_msg("error", &msg); - ((wxSizer*)ptr)->Detach((wxSizer*)content); + ((wxSizer*)ptr)->Detach((wxSizer*)content); } } } - + delete refd; ptr2ref.erase(it); } @@ -750,7 +750,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) { void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) { int index = *(int *) bp; - if(!memenv) + if(!memenv) throw wxe_badarg(index); void * temp = memenv->ref2ptr[index]; if((index < memenv->next) && ((index == 0) || (temp > NULL))) { @@ -770,14 +770,14 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) { * Misc utility classes * ************************************************************/ -/* **************************************************************************** - * Memory handling +/* **************************************************************************** + * Memory handling * ****************************************************************************/ wxeMemEnv::wxeMemEnv() { - ref2ptr = (void **) driver_alloc(128*sizeof(void *)); + ref2ptr = (void **) driver_alloc(128*sizeof(void *)); ref2ptr[0] = NULL; - next = 1; + next = 1; max = 128; } @@ -785,12 +785,12 @@ wxeMemEnv::~wxeMemEnv() { driver_free(ref2ptr); } -/* **************************************************************************** +/* **************************************************************************** * Erlang Commands (don't need to be derived of wxEvent anymore should * be re-written to own class struct) * ****************************************************************************/ -wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd) +wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd) : wxObject() { WXEBinRef *temp, *start, *prev; @@ -806,12 +806,12 @@ wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd) if(cbuf) { buffer = (char *) driver_alloc(len); memcpy((void *) buffer, (void *) cbuf, len);; - + temp = sd->bin; - + prev = NULL; start = temp; - + while(temp) { if(caller == temp->from) { bin[n++] = temp; @@ -836,7 +836,7 @@ wxeCommand::~wxeCommand() { int n = 0; if(buffer) { while(bin[n]) { - if(bin[n]->bin) + if(bin[n]->bin) driver_free_binary(bin[n]->bin); driver_free(bin[n++]); } @@ -844,26 +844,26 @@ wxeCommand::~wxeCommand() { } } -/* **************************************************************************** - * TreeItemData +/* **************************************************************************** + * TreeItemData * ****************************************************************************/ -wxETreeItemData::wxETreeItemData(int sz, char * data) { +wxETreeItemData::wxETreeItemData(int sz, char * data) { size = sz; bin = (char *) driver_alloc(sz); memcpy(bin, data, sz); } -wxETreeItemData::~wxETreeItemData() +wxETreeItemData::~wxETreeItemData() { driver_free(bin); } -/* **************************************************************************** +/* **************************************************************************** * CallbackData * * ****************************************************************************/ -wxeCallbackData::wxeCallbackData(ErlDrvTermData caller,void * req, char *req_type, +wxeCallbackData::wxeCallbackData(ErlDrvTermData caller,void * req, char *req_type, int funcb, int skip_ev, wxeErlTerm * userData) : wxObject() { -- cgit v1.2.3 From 3ea678d6036f10a6be7a5ae8c8431e067104b32f Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Wed, 21 Sep 2011 12:43:21 +0200 Subject: [wx] Remove warning --- lib/wx/c_src/egl_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wx/c_src/egl_impl.cpp b/lib/wx/c_src/egl_impl.cpp index 6a551beed7..6d873abc44 100644 --- a/lib/wx/c_src/egl_impl.cpp +++ b/lib/wx/c_src/egl_impl.cpp @@ -95,7 +95,7 @@ int egl_init_opengl(void *erlCallbacks) } int load_gl_functions() { - DL_CHAR * DLName = OPENGL_LIB; + DL_CHAR * DLName = (DL_CHAR *) OPENGL_LIB; DL_LIB_P LIBhandle = dlopen(DLName, RTLD_LAZY); //fprintf(stderr, "Loading GL: %s\r\n", (const char*)DLName); void * func = NULL; @@ -127,7 +127,7 @@ int load_gl_functions() { fprintf(stderr, "Could NOT load OpenGL library: %s\r\n", DLName); }; - DLName = OPENGLU_LIB; + DLName = (DL_CHAR *) OPENGLU_LIB; LIBhandle = dlopen(DLName, RTLD_LAZY); // fprintf(stderr, "Loading GLU: %s\r\n", (const char*)DLName); func = NULL; -- cgit v1.2.3 From 069b2070ba2ff2b1de479847f0f557a2c61dda58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 25 Aug 2011 10:05:38 +0200 Subject: gs: Correct support for parallel make --- lib/gs/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gs/src/Makefile b/lib/gs/src/Makefile index b3f11fb71b..964966ba00 100644 --- a/lib/gs/src/Makefile +++ b/lib/gs/src/Makefile @@ -90,7 +90,7 @@ clean: # Special Build Targets # ---------------------------------------------------- -gstk_generic.hrl: gs_make.erl ../ebin/gs.$(EMULATOR) +gstk_generic.hrl: gs_make.erl ../ebin/gs_make.$(EMULATOR) ../ebin/gs.$(EMULATOR) $(ERL) -pa $(EBIN) -s gs_make -s erlang halt -noshell $(APP_TARGET): $(APP_SRC) ../vsn.mk -- cgit v1.2.3 From 361aec166c0aa81f2769b9e867e2bdf6ba315b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 2 Sep 2011 16:23:26 +0200 Subject: tools/c_src/Makefile.in: Support parallel make Force early creations of directories. See 8d3a2dfa646ab2ceb41905c673adb15e57bf9cfd for more details. --- lib/tools/c_src/Makefile.in | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in index 65a7f5f424..6921193154 100644 --- a/lib/tools/c_src/Makefile.in +++ b/lib/tools/c_src/Makefile.in @@ -142,7 +142,9 @@ EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o))) # Misc targets # -all: $(CREATE_DIRS) erts_lib $(PROGS) $(DRIVERS) +_create_dirs := $(shell mkdir -p $(CREATE_DIRS)) + +all: erts_lib $(PROGS) $(DRIVERS) erts_lib: cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) @@ -157,13 +159,6 @@ clean: .PHONY: all erts_lib docs clean -# -# Make dir targets -# - -$(CREATE_DIRS): - $(MKDIR) -p $@ - # # Object targets # -- cgit v1.2.3 From 6f5a8b438a92ae66b4aa02a97a2aae993c8b7da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 2 Sep 2011 16:23:26 +0200 Subject: odbc/c_src/Makefile.in: Support parallel make Force early creation of directories. See 8d3a2dfa646ab2ceb41905c673adb15e57bf9cfd for more details. --- lib/odbc/c_src/Makefile.in | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/odbc/c_src/Makefile.in b/lib/odbc/c_src/Makefile.in index ed3eeb1d42..dda896bcd2 100644 --- a/lib/odbc/c_src/Makefile.in +++ b/lib/odbc/c_src/Makefile.in @@ -89,9 +89,10 @@ TARGET_FLAGS = @TARGET_FLAGS@ # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(OBJ_DIR) $(BIN_DIR)) ifdef EXE_TARGET -opt debug: create_dirs $(EXE_TARGET) +opt debug: $(EXE_TARGET) else opt debug: endif @@ -119,10 +120,6 @@ endif $(OBJ_DIR)/odbcserver.o: odbcserver.c $(CC) $(CFLAGS) $(INCLUDES) $(TARGET_FLAGS) -o $@ -c odbcserver.c -create_dirs: - $(INSTALL_DIR) $(OBJ_DIR) - $(INSTALL_DIR) $(BIN_DIR) - # ---------------------------------------------------- # Release Target # ---------------------------------------------------- -- cgit v1.2.3 From 145138f8e2d0d8b1c0a6662a4195ced861759c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 21 Sep 2011 15:29:41 +0200 Subject: Support parallel make when running erl_interface tests --- lib/erl_interface/test/all_SUITE_data/Makefile.src | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.src b/lib/erl_interface/test/all_SUITE_data/Makefile.src index 9be2360656..42d4c6f27f 100644 --- a/lib/erl_interface/test/all_SUITE_data/Makefile.src +++ b/lib/erl_interface/test/all_SUITE_data/Makefile.src @@ -30,6 +30,8 @@ CHMOD=chmod all: $(ALL_OBJS) +$(EI_COMMON_OBJS): gccifier@exe@ + @IFEQ@ (@erl_interface_cross_compile@, true) gccifier@exe@: $(CP) gccifier.sh gccifier@exe@ -- cgit v1.2.3 From 8d44ffaa66bf096a6679a7720f1f85af33f82668 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 20 Sep 2011 20:40:00 +0200 Subject: Revert "Support 'md2' hash in crypto:rsa_sign/3 and crypto:rsa_verify/4" This reverts commit 82897cc8f399fab832148711b586215c9a3f7af1. --- lib/crypto/c_src/crypto.c | 58 +++++++++++++++++++--------------------- lib/crypto/doc/src/crypto.xml | 4 +-- lib/crypto/src/crypto.erl | 2 +- lib/crypto/test/crypto_SUITE.erl | 30 ++++++--------------- 4 files changed, 39 insertions(+), 55 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 83772d9023..c781ccb302 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -268,7 +267,6 @@ static ERL_NIF_TERM atom_true; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_sha; static ERL_NIF_TERM atom_md5; -static ERL_NIF_TERM atom_md2; static ERL_NIF_TERM atom_ripemd160; static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_rsa_pkcs1_padding; @@ -339,7 +337,6 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_false = enif_make_atom(env,"false"); atom_sha = enif_make_atom(env,"sha"); atom_md5 = enif_make_atom(env,"md5"); - atom_md2 = enif_make_atom(env,"md2"); atom_ripemd160 = enif_make_atom(env,"ripemd160"); atom_error = enif_make_atom(env,"error"); atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding"); @@ -1050,28 +1047,16 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return(i > 0) ? atom_true : atom_false; } -struct hash_def { - int type; - unsigned int m_len; - unsigned char * (*func) (const unsigned char *d, size_t n, unsigned char *md); -}; - -static const struct hash_def md2_hash_def = { NID_md2, MD2_DIGEST_LENGTH, &MD2}; -static const struct hash_def md5_hash_def = { NID_md5, MD5_DIGEST_LENGTH, &MD5}; -static const struct hash_def sha1_hash_def = { NID_sha1, SHA_DIGEST_LENGTH, &SHA1}; - static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type, Data, Signature, Key=[E,N]) */ ErlNifBinary data_bin, sign_bin; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; ERL_NIF_TERM head, tail, ret; - int i; + int i, is_sha; RSA* rsa = RSA_new(); - const struct hash_def *hash_def = NULL; - if (argv[0] == atom_sha) hash_def = &sha1_hash_def; - else if (argv[0] == atom_md5) hash_def = &md5_hash_def; - else if (argv[0] == atom_md2) hash_def = &md2_hash_def; + if (argv[0] == atom_sha) is_sha = 1; + else if (argv[0] == atom_md5) is_sha = 0; else goto badarg; if (!inspect_mpint(env, argv[1], &data_bin) @@ -1085,9 +1070,16 @@ static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ret = enif_make_badarg(env); } else { - (void) *hash_def->func(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(hash_def->type, hmacbuf, hash_def->m_len, - sign_bin.data+4, sign_bin.size-4, rsa); + if (is_sha) { + SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, + sign_bin.data+4, sign_bin.size-4, rsa); + } + else { + MD5(data_bin.data+4, data_bin.size-4, hmacbuf); + i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH, + sign_bin.data+4, sign_bin.size-4, rsa); + } ret = (i==1 ? atom_true : atom_false); } RSA_free(rsa); @@ -1229,12 +1221,10 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned rsa_s_len; RSA *rsa = RSA_new(); - int i; - const struct hash_def *hash_def = NULL; + int i, is_sha; - if (argv[0] == atom_sha) hash_def = &sha1_hash_def; - else if (argv[0] == atom_md5) hash_def = &md5_hash_def; - else if (argv[0] == atom_md2) hash_def = &md2_hash_def; + if (argv[0] == atom_sha) is_sha = 1; + else if (argv[0] == atom_md5) is_sha = 0; else goto badarg; if (!inspect_mpint(env,argv[1],&data_bin) @@ -1250,10 +1240,18 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar return enif_make_badarg(env); } enif_alloc_binary(RSA_size(rsa), &ret_bin); - (void) *hash_def->func(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, hash_def->m_len); - i = RSA_sign(hash_def->type, hmacbuf, hash_def->m_len, - ret_bin.data, &rsa_s_len, rsa); + if (is_sha) { + SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH); + i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, + ret_bin.data, &rsa_s_len, rsa); + } + else { + MD5(data_bin.data+4, data_bin.size-4, hmacbuf); + ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH); + i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH, + ret_bin.data, &rsa_s_len, rsa); + } RSA_free(rsa); if (i) { ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index b593958264..4c20f81cae 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -795,7 +795,7 @@ Mpint() = >]]> E, N, D = Mpint Where E is the public exponent, N is public modulus and D is the private exponent. - DigestType = md2 | md5 | sha + DigestType = md5 | sha The default DigestType is sha. Mpint = binary() Signature = binary() @@ -817,7 +817,7 @@ Mpint() = >]]> Key = [E, N] E, N = Mpint Where E is the public exponent and N is public modulus. - DigestType = md2 | md5 | sha + DigestType = md5 | sha The default DigestType is sha. Mpint = binary() diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index ddad00f4b4..c3e13d6b91 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -91,7 +91,7 @@ aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, info_lib]). --type rsa_digest_type() :: 'md2' | 'md5' | 'sha'. +-type rsa_digest_type() :: 'md5' | 'sha'. -type dss_digest_type() :: 'none' | 'sha'. -type crypto_integer() :: binary() | integer(). diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 2fa058c852..8d2f42469b 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1082,30 +1082,16 @@ rsa_sign_test(Config) when is_list(Config) -> PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], - ?line Sig = crypto:rsa_sign(sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig),PubKey), true), + ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey), + ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true), - ?line Sig_md2 = crypto:rsa_sign(md2, sized_binary(Msg), PrivKey), - ?line Sig_md5 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), - ?line Sig_sha = crypto:rsa_sign(sha, sized_binary(Msg), PrivKey), - - ?line m(Sig =:= Sig_sha, true), - ?line m(Sig_md2 =:= Sig_md5, false), - ?line m(Sig_md2 =:= Sig_sha, false), - ?line m(Sig_md5 =:= Sig_sha, false), + ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true), + + ?line m(Sig1 =:= Sig2, false), + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false), + ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true), - ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_md2),PubKey), true), - ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_md5),PubKey), false), - ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_sha),PubKey), false), - - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_md2),PubKey), false), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_md5),PubKey), true), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_sha),PubKey), false), - - ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_md2),PubKey), false), - ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_md5),PubKey), false), - ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_sha),PubKey), true), - ok. dsa_sign_test(doc) -> -- cgit v1.2.3 From 88653c79b3a6b8fe51e60d4b300ded1db041c181 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 20 Sep 2011 20:40:49 +0200 Subject: Revert "Support md2WithRSAEncryption certificates in public_key" This reverts commit c7e5f7576e213060cbb332be64a7c3798f6a2cc2. --- lib/public_key/doc/src/public_key.xml | 2 +- lib/public_key/src/pubkey_cert.erl | 4 +--- lib/public_key/src/public_key.erl | 10 +++------- lib/public_key/test/public_key_SUITE.erl | 5 +---- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index b3ce49e2ca..9a3832c68b 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -79,7 +79,7 @@

rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'

-

rsa_digest_type() = 'md2' | 'md5' | 'sha'

+

rsa_digest_type() = 'md5' | 'sha'

dss_digest_type() = 'none' | 'sha'

diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index 61082a1ec5..5ab9642279 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -38,7 +38,7 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec verify_data(DER::binary()) -> {md2 | md5 | sha, binary(), binary()}. +-spec verify_data(DER::binary()) -> {md5 | sha, binary(), binary()}. %% %% Description: Extracts data from DerCert needed to call public_key:verify/4. %%-------------------------------------------------------------------- @@ -378,8 +378,6 @@ digest_type(?sha1WithRSAEncryption) -> sha; digest_type(?md5WithRSAEncryption) -> md5; -digest_type(?md2WithRSAEncryption) -> - md2; digest_type(?'id-dsa-with-sha1') -> sha. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 940efffcd0..33fcce2c44 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -55,7 +55,7 @@ -type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. --type rsa_digest_type() :: 'md2' | 'md5' | 'sha'. +-type rsa_digest_type() :: 'md5' | 'sha'. -type dss_digest_type() :: 'none' | 'sha'. -define(UINT32(X), X:32/unsigned-big-integer). @@ -307,8 +307,7 @@ encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N, sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D}) when is_binary(PlainText), - (DigestType == md2 orelse - DigestType == md5 orelse + (DigestType == md5 orelse DigestType == sha) -> crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), @@ -336,10 +335,7 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) %%-------------------------------------------------------------------- verify(PlainText, DigestType, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) - when is_binary(PlainText), - (DigestType == md2 orelse - DigestType == md5 orelse - DigestType == sha) -> + when is_binary (PlainText), DigestType == sha; DigestType == md5 -> crypto:rsa_verify(DigestType, sized_binary(PlainText), sized_binary(Signature), diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index a9c198c581..b11e4d092a 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -537,10 +537,7 @@ rsa_sign_verify(Config) when is_list(Config) -> false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA), RSASign1 = public_key:sign(Msg, md5, PrivateRSA), - true = public_key:verify(Msg, md5, RSASign1, PublicRSA), - - RSASign2 = public_key:sign(Msg, md2, PrivateRSA), - true = public_key:verify(Msg, md2, RSASign2, PublicRSA). + true = public_key:verify(Msg, md5, RSASign1, PublicRSA). %%-------------------------------------------------------------------- -- cgit v1.2.3 From 38613c4190b386700a84b4f435fbe12823bbbbd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 21 Sep 2011 16:09:00 +0200 Subject: system documentation: Support parallel make --- system/doc/design_principles/Makefile | 2 ++ system/doc/efficiency_guide/Makefile | 2 ++ system/doc/embedded/Makefile | 2 ++ system/doc/getting_started/Makefile | 2 ++ system/doc/oam/Makefile | 2 ++ system/doc/programming_examples/Makefile | 2 ++ system/doc/reference_manual/Makefile | 2 ++ system/doc/system_architecture_intro/Makefile | 2 ++ system/doc/system_principles/Makefile | 2 ++ system/doc/tutorial/Makefile | 2 ++ 10 files changed, 20 insertions(+) diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile index b3fe136644..ae951ba8d4 100644 --- a/system/doc/design_principles/Makefile +++ b/system/doc/design_principles/Makefile @@ -79,6 +79,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ diff --git a/system/doc/efficiency_guide/Makefile b/system/doc/efficiency_guide/Makefile index f51313de84..2629285b42 100644 --- a/system/doc/efficiency_guide/Makefile +++ b/system/doc/efficiency_guide/Makefile @@ -85,6 +85,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/embedded/Makefile b/system/doc/embedded/Makefile index 5e68917fc2..70357efb1f 100644 --- a/system/doc/embedded/Makefile +++ b/system/doc/embedded/Makefile @@ -73,6 +73,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile index 5ca885d56e..5d85ca2adc 100644 --- a/system/doc/getting_started/Makefile +++ b/system/doc/getting_started/Makefile @@ -72,6 +72,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/oam/Makefile b/system/doc/oam/Makefile index e3288c9182..7732426ce6 100644 --- a/system/doc/oam/Makefile +++ b/system/doc/oam/Makefile @@ -69,6 +69,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile index 73512c9654..8aeead9f6a 100644 --- a/system/doc/programming_examples/Makefile +++ b/system/doc/programming_examples/Makefile @@ -70,6 +70,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/reference_manual/Makefile b/system/doc/reference_manual/Makefile index 34e5b7f555..2e1f8e71cb 100644 --- a/system/doc/reference_manual/Makefile +++ b/system/doc/reference_manual/Makefile @@ -82,6 +82,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/system_architecture_intro/Makefile b/system/doc/system_architecture_intro/Makefile index 0fff9bc4d5..8d677886b8 100644 --- a/system/doc/system_architecture_intro/Makefile +++ b/system/doc/system_architecture_intro/Makefile @@ -67,6 +67,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/system_principles/Makefile b/system/doc/system_principles/Makefile index b0698fec9d..da109be211 100644 --- a/system/doc/system_principles/Makefile +++ b/system/doc/system_principles/Makefile @@ -66,6 +66,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + docs: html local_docs: PDFDIR=../../pdf diff --git a/system/doc/tutorial/Makefile b/system/doc/tutorial/Makefile index efb380248e..d48082484c 100644 --- a/system/doc/tutorial/Makefile +++ b/system/doc/tutorial/Makefile @@ -88,6 +88,8 @@ DVIPS_FLAGS += # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(HTMLDIR)) + $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -- cgit v1.2.3 From a474b24b6121ef411a3a3bda3e50cd69b5fbec17 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 21 Sep 2011 16:09:00 +0200 Subject: Revert "Prepare for release" This reverts commit a3193f17e111492bf508057ae6a26d0d7c1bc4fc. --- lib/public_key/src/public_key.appup.src | 12 ------------ lib/public_key/vsn.mk | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index 18fae54d18..4986801dad 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,12 +1,6 @@ %% -*- erlang -*- {"%VSN%", [ - {"0.12", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []}, - ] - }, {"0.11", [ {update, public_key, soft, soft_purge, soft_purge, []}, @@ -41,12 +35,6 @@ } ], [ - {"0.12", - [ - {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []}, - ] - }, {"0.11", [ {update, public_key, soft, soft_purge, soft_purge, []}, diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 66ac78a65d..3c6b012152 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.13 +PUBLIC_KEY_VSN = 0.12 -- cgit v1.2.3 From 2a42a90da8497cbec2b2d6e6b39504bc0bffc869 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Wed, 21 Sep 2011 17:05:59 +0200 Subject: [wx] Remove optional shadowing clauses In some cases the non optional clause could make some clauses unreachable. i.e. in the following example the second clause will never be reached. prepend(This,Window) when is_record(This, wx_ref),is_record(Window, wx_ref) -> prepend(This,Window, []); prepend(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> ?CLASS(ThisT,wxSizer), ?CLASS(ItemT,wxSizerItem), wxe_util:call(?wxSizer_Prepend_1, <>). --- lib/wx/api_gen/wx_gen.erl | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl index b36653c570..209de48496 100644 --- a/lib/wx/api_gen/wx_gen.erl +++ b/lib/wx/api_gen/wx_gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -30,6 +30,12 @@ -compile(export_all). +-define(DBGCF(Class, Func, Format, Args), + case {get(current_class), get(current_func)} of + {Class, Func} -> io:format("~p:~p: " ++ Format, [?MODULE,?LINE] ++ Args); + _ -> ok + end). + code() -> safe(fun gen_code/0,true). xml() -> safe(fun gen_xml/0,true). @@ -957,17 +963,17 @@ erl_skip_opt(All=[Ms=[{_,{Len,_,_},_}|_]|R],Acc1=[{_,{N,_,_},_}|_], Acc2) -> end; erl_skip_opt([],Acc1,Acc2) -> [strip_ti(Acc1)|Acc2]. -erl_skip_opt2([F={_,{N,In,_},M=#method{where=Where}}|Ms],Acc1,Acc2,Check) -> +erl_skip_opt2([F={_,{N,In,_},M=#method{where=Where}}|Ms],Acc1,Acc2,Check) -> case N > 0 andalso lists:last(In) =:= opt_list of - true when Where =/= merged_c, Where =/= taylormade -> - case Check of - [] -> + true when Where =/= merged_c, Where =/= taylormade -> + case Check of + [] -> erl_skip_opt2(Ms,[F|Acc1],[M#method{where=erl_no_opt}|Acc2],[]); - _ -> + _ -> Skipped = reverse(tl(reverse(In))), T = fun({_,{_,Args,_},_}) -> true =:= types_differ(Skipped,Args) end, case lists:all(T, Check) of - true -> + true -> erl_skip_opt2(Ms,[F|Acc1], [M#method{where=erl_no_opt}|Acc2], Check); @@ -976,7 +982,7 @@ erl_skip_opt2([F={_,{N,In,_},M=#method{where=Where}}|Ms],Acc1,Acc2,Check) -> end end; _ -> - erl_skip_opt2(Ms,[F|Acc1],Acc2,[]) + erl_skip_opt2(Ms,[F|Acc1],Acc2,Check) end; erl_skip_opt2([],Acc1,Acc2,_) -> {Acc1,Acc2}. @@ -1025,7 +1031,6 @@ types_differ([{class,C1}|R1], [{class,C2}|R2]) -> true -> true; false -> -%% _ -> {class,C1,C2}; {class,C1,C2} -> {class,C1,C2}; -- cgit v1.2.3 From 9299708cb88b5ed000cf2278df420a23e249159a Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Wed, 21 Sep 2011 17:10:08 +0200 Subject: [wx] Re-generate code With the previous commited code-generator --- lib/wx/src/gen/wxBoxSizer.erl | 6 +++--- lib/wx/src/gen/wxFlexGridSizer.erl | 6 +++--- lib/wx/src/gen/wxGridBagSizer.erl | 6 +++--- lib/wx/src/gen/wxGridSizer.erl | 6 +++--- lib/wx/src/gen/wxSizer.erl | 26 +++----------------------- lib/wx/src/gen/wxStaticBoxSizer.erl | 6 +++--- lib/wx/src/gen/wxStdDialogButtonSizer.erl | 6 +++--- 7 files changed, 21 insertions(+), 41 deletions(-) diff --git a/lib/wx/src/gen/wxBoxSizer.erl b/lib/wx/src/gen/wxBoxSizer.erl index 1d5b1cf2fa..e6287945a9 100644 --- a/lib/wx/src/gen/wxBoxSizer.erl +++ b/lib/wx/src/gen/wxBoxSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -102,7 +102,7 @@ prepend(This,Width,Height, Options) -> wxSizer:prepend(This,Width,Height, Option %% @hidden prepend(This,Width,Height) -> wxSizer:prepend(This,Width,Height). %% @hidden -prepend(This,Window) -> wxSizer:prepend(This,Window). +prepend(This,Item) -> wxSizer:prepend(This,Item). %% @hidden layout(This) -> wxSizer:layout(This). %% @hidden @@ -118,7 +118,7 @@ insert(This,Index,Width,Height, Options) -> wxSizer:insert(This,Index,Width,Heig %% @hidden insert(This,Index,Width,Height) -> wxSizer:insert(This,Index,Width,Height). %% @hidden -insert(This,Index,Window) -> wxSizer:insert(This,Index,Window). +insert(This,Index,Item) -> wxSizer:insert(This,Index,Item). %% @hidden hide(This,Window, Options) -> wxSizer:hide(This,Window, Options). %% @hidden diff --git a/lib/wx/src/gen/wxFlexGridSizer.erl b/lib/wx/src/gen/wxFlexGridSizer.erl index 9471cc8a01..910cc78894 100644 --- a/lib/wx/src/gen/wxFlexGridSizer.erl +++ b/lib/wx/src/gen/wxFlexGridSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -222,7 +222,7 @@ prepend(This,Width,Height, Options) -> wxSizer:prepend(This,Width,Height, Option %% @hidden prepend(This,Width,Height) -> wxSizer:prepend(This,Width,Height). %% @hidden -prepend(This,Window) -> wxSizer:prepend(This,Window). +prepend(This,Item) -> wxSizer:prepend(This,Item). %% @hidden layout(This) -> wxSizer:layout(This). %% @hidden @@ -238,7 +238,7 @@ insert(This,Index,Width,Height, Options) -> wxSizer:insert(This,Index,Width,Heig %% @hidden insert(This,Index,Width,Height) -> wxSizer:insert(This,Index,Width,Height). %% @hidden -insert(This,Index,Window) -> wxSizer:insert(This,Index,Window). +insert(This,Index,Item) -> wxSizer:insert(This,Index,Item). %% @hidden hide(This,Window, Options) -> wxSizer:hide(This,Window, Options). %% @hidden diff --git a/lib/wx/src/gen/wxGridBagSizer.erl b/lib/wx/src/gen/wxGridBagSizer.erl index d8cc210d3b..cfc182cf89 100644 --- a/lib/wx/src/gen/wxGridBagSizer.erl +++ b/lib/wx/src/gen/wxGridBagSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -474,7 +474,7 @@ prepend(This,Width,Height, Options) -> wxSizer:prepend(This,Width,Height, Option %% @hidden prepend(This,Width,Height) -> wxSizer:prepend(This,Width,Height). %% @hidden -prepend(This,Window) -> wxSizer:prepend(This,Window). +prepend(This,Item) -> wxSizer:prepend(This,Item). %% @hidden layout(This) -> wxSizer:layout(This). %% @hidden @@ -490,7 +490,7 @@ insert(This,Index,Width,Height, Options) -> wxSizer:insert(This,Index,Width,Heig %% @hidden insert(This,Index,Width,Height) -> wxSizer:insert(This,Index,Width,Height). %% @hidden -insert(This,Index,Window) -> wxSizer:insert(This,Index,Window). +insert(This,Index,Item) -> wxSizer:insert(This,Index,Item). %% @hidden hide(This,Window, Options) -> wxSizer:hide(This,Window, Options). %% @hidden diff --git a/lib/wx/src/gen/wxGridSizer.erl b/lib/wx/src/gen/wxGridSizer.erl index 7b62774347..fd8580c70d 100644 --- a/lib/wx/src/gen/wxGridSizer.erl +++ b/lib/wx/src/gen/wxGridSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -174,7 +174,7 @@ prepend(This,Width,Height, Options) -> wxSizer:prepend(This,Width,Height, Option %% @hidden prepend(This,Width,Height) -> wxSizer:prepend(This,Width,Height). %% @hidden -prepend(This,Window) -> wxSizer:prepend(This,Window). +prepend(This,Item) -> wxSizer:prepend(This,Item). %% @hidden layout(This) -> wxSizer:layout(This). %% @hidden @@ -190,7 +190,7 @@ insert(This,Index,Width,Height, Options) -> wxSizer:insert(This,Index,Width,Heig %% @hidden insert(This,Index,Width,Height) -> wxSizer:insert(This,Index,Width,Height). %% @hidden -insert(This,Index,Window) -> wxSizer:insert(This,Index,Window). +insert(This,Index,Item) -> wxSizer:insert(This,Index,Item). %% @hidden hide(This,Window, Options) -> wxSizer:hide(This,Window, Options). %% @hidden diff --git a/lib/wx/src/gen/wxSizer.erl b/lib/wx/src/gen/wxSizer.erl index 716b2224b5..e9b83a7333 100644 --- a/lib/wx/src/gen/wxSizer.erl +++ b/lib/wx/src/gen/wxSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -298,18 +298,8 @@ hide(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Option wxe_util:call(WindowOP, <>). -%% @spec (This::wxSizer(),Index::integer(),X::term()) -> wxSizerItem:wxSizerItem() +%% @spec (This::wxSizer(), Index::integer(), Item::wxSizerItem:wxSizerItem()) -> wxSizerItem:wxSizerItem() %% @doc See external documentation. -%%
Alternatives: -%%

-%% insert(This::wxSizer(), Index::integer(), Window::wxWindow:wxWindow() | wxSizer()) -> insert(This,Index,Window, [])

-%%

-%% insert(This::wxSizer(), Index::integer(), Item::wxSizerItem:wxSizerItem()) -> wxSizerItem:wxSizerItem() -%%

- -insert(This,Index,Window) - when is_record(This, wx_ref),is_integer(Index),is_record(Window, wx_ref) -> - insert(This,Index,Window, []); insert(#wx_ref{type=ThisT,ref=ThisRef},Index,#wx_ref{type=ItemT,ref=ItemRef}) when is_integer(Index) -> ?CLASS(ThisT,wxSizer), @@ -437,18 +427,8 @@ layout(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:cast(?wxSizer_Layout, <>). -%% @spec (This::wxSizer(),X::term()) -> wxSizerItem:wxSizerItem() +%% @spec (This::wxSizer(), Item::wxSizerItem:wxSizerItem()) -> wxSizerItem:wxSizerItem() %% @doc See external documentation. -%%
Alternatives: -%%

-%% prepend(This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer()) -> prepend(This,Window, [])

-%%

-%% prepend(This::wxSizer(), Item::wxSizerItem:wxSizerItem()) -> wxSizerItem:wxSizerItem() -%%

- -prepend(This,Window) - when is_record(This, wx_ref),is_record(Window, wx_ref) -> - prepend(This,Window, []); prepend(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) -> ?CLASS(ThisT,wxSizer), ?CLASS(ItemT,wxSizerItem), diff --git a/lib/wx/src/gen/wxStaticBoxSizer.erl b/lib/wx/src/gen/wxStaticBoxSizer.erl index 5f346b7a1e..2cf9f64325 100644 --- a/lib/wx/src/gen/wxStaticBoxSizer.erl +++ b/lib/wx/src/gen/wxStaticBoxSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -130,7 +130,7 @@ prepend(This,Width,Height, Options) -> wxSizer:prepend(This,Width,Height, Option %% @hidden prepend(This,Width,Height) -> wxSizer:prepend(This,Width,Height). %% @hidden -prepend(This,Window) -> wxSizer:prepend(This,Window). +prepend(This,Item) -> wxSizer:prepend(This,Item). %% @hidden layout(This) -> wxSizer:layout(This). %% @hidden @@ -146,7 +146,7 @@ insert(This,Index,Width,Height, Options) -> wxSizer:insert(This,Index,Width,Heig %% @hidden insert(This,Index,Width,Height) -> wxSizer:insert(This,Index,Width,Height). %% @hidden -insert(This,Index,Window) -> wxSizer:insert(This,Index,Window). +insert(This,Index,Item) -> wxSizer:insert(This,Index,Item). %% @hidden hide(This,Window, Options) -> wxSizer:hide(This,Window, Options). %% @hidden diff --git a/lib/wx/src/gen/wxStdDialogButtonSizer.erl b/lib/wx/src/gen/wxStdDialogButtonSizer.erl index b0052ca2e1..3d31907275 100644 --- a/lib/wx/src/gen/wxStdDialogButtonSizer.erl +++ b/lib/wx/src/gen/wxStdDialogButtonSizer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -139,7 +139,7 @@ prepend(This,Width,Height, Options) -> wxSizer:prepend(This,Width,Height, Option %% @hidden prepend(This,Width,Height) -> wxSizer:prepend(This,Width,Height). %% @hidden -prepend(This,Window) -> wxSizer:prepend(This,Window). +prepend(This,Item) -> wxSizer:prepend(This,Item). %% @hidden layout(This) -> wxSizer:layout(This). %% @hidden @@ -155,7 +155,7 @@ insert(This,Index,Width,Height, Options) -> wxSizer:insert(This,Index,Width,Heig %% @hidden insert(This,Index,Width,Height) -> wxSizer:insert(This,Index,Width,Height). %% @hidden -insert(This,Index,Window) -> wxSizer:insert(This,Index,Window). +insert(This,Index,Item) -> wxSizer:insert(This,Index,Item). %% @hidden hide(This,Window, Options) -> wxSizer:hide(This,Window, Options). %% @hidden -- cgit v1.2.3 From 0075b97214d6c037eca3888bca29d68c9b5fbb74 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 8 Jul 2011 20:46:17 +0200 Subject: Modify start options and introduce CT profiles OTP-9155: Improve handling of start options in Common Test OTP-9428: Introduce first version of CT profiles (for evaluation) --- lib/common_test/src/ct_logs.erl | 21 ++- lib/common_test/src/ct_make.erl | 2 +- lib/common_test/src/ct_run.erl | 296 +++++++++++++++++++++++++++------------- lib/common_test/src/ct_util.erl | 111 ++++++++++++++- lib/common_test/src/ct_util.hrl | 3 + 5 files changed, 329 insertions(+), 104 deletions(-) diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index b839521e24..5c4eb88c1f 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -28,7 +28,7 @@ -module(ct_logs). --export([init/1,close/1,init_tc/0,end_tc/1]). +-export([init/1,close/2,init_tc/0,end_tc/1]). -export([get_log_dir/0,log/3,start_log/1,cont_log/2,end_log/0]). -export([set_stylesheet/2,clear_stylesheet/1]). -export([add_external_logs/1,add_link/3]). @@ -97,11 +97,11 @@ logdir_node_prefix() -> logdir_prefix()++"."++atom_to_list(node()). %%%----------------------------------------------------------------- -%%% @spec close(Info) -> ok +%%% @spec close(Info, StartDir) -> ok %%% %%% @doc Create index pages with test results and close the CT Log %%% (tool-internal use only). -close(Info) -> +close(Info, StartDir) -> make_last_run_index(), ct_event:notify(#event{name=stop_logging,node=node(),data=[]}), @@ -132,6 +132,21 @@ close(Info) -> make_all_suites_index(stop), make_all_runs_index(stop), + case ct_util:get_profile_data(browser, StartDir) of + undefined -> + ok; + BrowserData -> + case {proplists:get_value(prog, BrowserData), + proplists:get_value(args, BrowserData), + proplists:get_value(page, BrowserData)} of + {Prog,Args,Page} when is_list(Args), + is_list(Page) -> + URL = "file://" ++ ?abs(Page), + ct_util:open_url(Prog, Args, URL); + _ -> + ok + end + end, ok. %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/ct_make.erl b/lib/common_test/src/ct_make.erl index 233e45248e..40e9e99f37 100644 --- a/lib/common_test/src/ct_make.erl +++ b/lib/common_test/src/ct_make.erl @@ -177,7 +177,7 @@ members([],_MakefileMods,I,Rest) -> {I,Rest}. -%% Any flags that are not recognixed as make flags are passed directly +%% Any flags that are not recognised as make flags are passed directly %% to the compiler. %% So for example make:all([load,debug_info]) will make everything %% with the debug_info flag and load it. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 877ec9c7dd..00b5a53cf4 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -46,6 +46,7 @@ -define(testdir(Name, Suite), ct_util:get_testdir(Name, Suite)). -record(opts, {label, + profile, vts, shell, cover, @@ -161,6 +162,7 @@ script_start(Args) -> script_start1(Parent, Args) -> %% read general start flags Label = get_start_opt(label, fun([Lbl]) -> Lbl end, Args), + Profile = get_start_opt(profile, fun([Prof]) -> Prof end, Args), Vts = get_start_opt(vts, true, Args), Shell = get_start_opt(shell, true, Args), Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args), @@ -234,7 +236,8 @@ script_start1(Parent, Args) -> application:set_env(common_test, basic_html, true) end, - StartOpts = #opts{label = Label, vts = Vts, shell = Shell, cover = Cover, + StartOpts = #opts{label = Label, profile = Profile, + vts = Vts, shell = Shell, cover = Cover, logdir = LogDir, event_handlers = EvHandlers, ct_hooks = CTHooks, include = IncludeDirs, @@ -297,6 +300,9 @@ script_start2(StartOpts = #opts{vts = undefined, Label = choose_val(StartOpts#opts.label, SpecStartOpts#opts.label), + Profile = choose_val(StartOpts#opts.profile, + SpecStartOpts#opts.profile), + LogDir = choose_val(StartOpts#opts.logdir, SpecStartOpts#opts.logdir), @@ -317,6 +323,7 @@ script_start2(StartOpts = #opts{vts = undefined, application:set_env(common_test, include, AllInclude), {TS,StartOpts#opts{label = Label, + profile = Profile, testspecs = Specs, cover = Cover, logdir = LogDir, @@ -392,45 +399,67 @@ check_and_install_configfiles(Configs, LogDir, EvHandlers, CTHooks) -> end. script_start3(StartOpts, Args) -> - case proplists:get_value(dir, Args) of - [] -> + StartOpts1 = get_start_opt(step, + fun(Step) -> + StartOpts#opts{step = Step, + cover = undefined} + end, StartOpts, Args), + case {proplists:get_value(dir, Args), + proplists:get_value(suite, Args), + groups_and_cases(proplists:get_value(group, Args), + proplists:get_value(testcase, Args))} of + %% flag specified without data + {_,_,Error={error,_}} -> + Error; + {_,[],_} -> + {error,no_suite_specified}; + {[],_,_} -> {error,no_dir_specified}; - Dirs when is_list(Dirs) -> + + {Dirs,undefined,[]} when is_list(Dirs) -> script_start4(StartOpts#opts{tests = tests(Dirs)}, Args); - undefined -> - case proplists:get_value(suite, Args) of - [] -> - {error,no_suite_specified}; - Suites when is_list(Suites) -> - StartOpts1 = - get_start_opt(step, - fun(Step) -> - StartOpts#opts{step = Step, - cover = undefined} - end, StartOpts, Args), - DirMods = [suite_to_test(S) || S <- Suites], - case groups_and_cases(proplists:get_value(group, Args), - proplists:get_value(testcase, Args)) of - Error = {error,_} -> - Error; - [] when DirMods =/= [] -> - Ts = tests(DirMods), - script_start4(StartOpts1#opts{tests = Ts}, Args); - GroupsAndCases when length(DirMods) == 1 -> - Ts = tests(DirMods, GroupsAndCases), - script_start4(StartOpts1#opts{tests = Ts}, Args); - [_,_|_] when length(DirMods) > 1 -> - {error,multiple_suites_and_cases}; - _ -> - {error,incorrect_suite_option} - end; - undefined -> - if StartOpts#opts.vts ; StartOpts#opts.shell -> - script_start4(StartOpts#opts{tests = []}, Args); - true -> - script_usage(), - {error,incorrect_usage} - end + + {undefined,Suites,[]} when is_list(Suites) -> + Ts = tests([suite_to_test(S) || S <- Suites]), + script_start4(StartOpts1#opts{tests = Ts}, Args); + + {undefined,Suite,GsAndCs} when is_list(Suite) -> + case [suite_to_test(S) || S <- Suite] of + DirMods = [_] -> + Ts = tests(DirMods, GsAndCs), + script_start4(StartOpts1#opts{tests = Ts}, Args); + [_,_|_] -> + {error,multiple_suites_and_cases}; + _ -> + {error,incorrect_start_options} + end; + + {[_,_|_],Suite,[]} when is_list(Suite) -> + {error,multiple_dirs_and_suites}; + + {[Dir],Suite,GsAndCs} when is_list(Dir), is_list(Suite) -> + case [suite_to_test(Dir,S) || S <- Suite] of + DirMods when GsAndCs == [] -> + Ts = tests(DirMods), + script_start4(StartOpts1#opts{tests = Ts}, Args); + DirMods = [_] when GsAndCs /= [] -> + Ts = tests(DirMods, GsAndCs), + script_start4(StartOpts1#opts{tests = Ts}, Args); + [_,_|_] when GsAndCs /= [] -> + {error,multiple_suites_and_cases}; + _ -> + {error,incorrect_start_options} + end; + + {undefined,undefined,GsAndCs} when GsAndCs /= [] -> + {error,incorrect_start_options}; + + {undefined,undefined,_} -> + if StartOpts#opts.vts ; StartOpts#opts.shell -> + script_start4(StartOpts#opts{tests = []}, Args); + true -> + script_usage(), + {error,missing_start_options} end end. @@ -448,13 +477,17 @@ script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers, end, [], Config), vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), Tests); -script_start4(#opts{label = Label, shell = true, config = Config, +script_start4(#opts{label = Label, profile = Profile, + shell = true, config = Config, event_handlers = EvHandlers, ct_hooks = CTHooks, logdir = LogDir, testspecs = Specs}, _Args) -> %% label - used by ct_logs application:set_env(common_test, test_label, Label), + %% profile - used in ct_util + application:set_env(common_test, profile, Profile), + InstallOpts = [{config,Config},{event_handler,EvHandlers}, {ct_hooks, CTHooks}], if Config == [] -> @@ -649,6 +682,10 @@ run_test1(StartOpts) -> Label = get_start_opt(label, fun(Lbl) when is_list(Lbl) -> Lbl; (Lbl) when is_atom(Lbl) -> atom_to_list(Lbl) end, StartOpts), + %% profile + Profile = get_start_opt(profile, fun(Prof) when is_list(Prof) -> Prof; + (Prof) when is_atom(Prof) -> atom_to_list(Prof) + end, StartOpts), %% logdir LogDir = get_start_opt(logdir, fun(LD) when is_list(LD) -> LD end, StartOpts), @@ -750,7 +787,7 @@ run_test1(StartOpts) -> %% stepped execution Step = get_start_opt(step, value, StartOpts), - Opts = #opts{label = Label, + Opts = #opts{label = Label, profile = Profile, cover = Cover, step = Step, logdir = LogDir, config = CfgFiles, event_handlers = EvHandlers, ct_hooks = CTHooks, @@ -792,6 +829,8 @@ run_spec_file(Relaxed, SpecOpts = get_data_for_node(TS, node()), Label = choose_val(Opts#opts.label, SpecOpts#opts.label), + Profile = choose_val(Opts#opts.profile, + SpecOpts#opts.profile), LogDir = choose_val(Opts#opts.logdir, SpecOpts#opts.logdir), AllConfig = merge_vals([CfgFiles, SpecOpts#opts.config]), @@ -817,6 +856,7 @@ run_spec_file(Relaxed, AllCTHooks) of ok -> Opts1 = Opts#opts{label = Label, + profile = Profile, cover = Cover, logdir = which(logdir, LogDir), config = AllConfig, @@ -899,67 +939,99 @@ run_dir(Opts = #opts{logdir = LogDir, ok -> ok; {error,IReason} -> exit(IReason) end, - case lists:keysearch(dir, 1, StartOpts) of - {value,{_,Dirs=[Dir|_]}} when not is_integer(Dir), - length(Dirs)>1 -> - %% multiple dirs (no suite) - reformat_result(catch do_run(tests(Dirs), [], Opts1, StartOpts)); - false -> % no dir - %% fun for converting suite name to {Dir,Mod} tuple - S2M = fun(S) when is_list(S) -> - {filename:dirname(S), - list_to_atom(filename:rootname(filename:basename(S)))}; - (A) -> - {".",A} - end, - case lists:keysearch(suite, 1, StartOpts) of - {value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) -> - {Dir,Mod} = S2M(Suite), - case groups_and_cases(proplists:get_value(group, StartOpts), - proplists:get_value(testcase, StartOpts)) of - Error = {error,_} -> - exit(Error); + case {proplists:get_value(dir, StartOpts), + proplists:get_value(suite, StartOpts), + groups_and_cases(proplists:get_value(group, StartOpts), + proplists:get_value(testcase, StartOpts))} of + %% flag specified without data + {_,_,Error={error,_}} -> + Error; + {_,[],_} -> + {error,no_suite_specified}; + {[],_,_} -> + {error,no_dir_specified}; + + {Dirs=[Hd|_],undefined,[]} when is_list(Dirs), not is_integer(Hd) -> + Dirs1 = [if is_atom(D) -> atom_to_list(D); + true -> D end || D <- Dirs], + reformat_result(catch do_run(tests(Dirs1), [], Opts1, StartOpts)); + + {Dir=[Hd|_],undefined,[]} when is_list(Dir) and is_integer(Hd) -> + reformat_result(catch do_run(tests(Dir), [], Opts1, StartOpts)); + + {Dir,undefined,[]} when is_atom(Dir) -> + reformat_result(catch do_run(tests(atom_to_list(Dir)), + [], Opts1, StartOpts)); + + {undefined,Suites=[Hd|_],[]} when not is_integer(Hd) -> + Suites1 = [suite_to_test(S) || S <- Suites], + reformat_result(catch do_run(tests(Suites1), [], Opts1, StartOpts)); + + {undefined,Suite,[]} when is_atom(Suite) and + (Suite /= undefined) -> + {Dir,Mod} = suite_to_test(Suite), + reformat_result(catch do_run(tests(Dir, Mod), [], Opts1, StartOpts)); + + {undefined,Suite,GsAndCs} when is_atom(Suite) and + (Suite /= undefined) -> + {Dir,Mod} = suite_to_test(Suite), + reformat_result(catch do_run(tests(Dir, Mod, GsAndCs), + [], Opts1, StartOpts)); + + {undefined,[Hd,_|_],_GsAndCs} when not is_integer(Hd) -> + exit(multiple_suites_and_cases); + + {undefined,Suite=[Hd|Tl],GsAndCs} when is_integer(Hd) ; + (is_list(Hd) and (Tl == [])) ; + (is_atom(Hd) and (Tl == [])) -> + {Dir,Mod} = suite_to_test(Suite), + reformat_result(catch do_run(tests(Dir, Mod, GsAndCs), + [], Opts1, StartOpts)); + + {[Hd,_|_],_Suites,[]} when is_list(Hd) ; not is_integer(Hd) -> + exit(multiple_dirs_and_suites); + + {undefined,undefined,GsAndCs} when GsAndCs /= [] -> + exit(incorrect_start_options); + + {Dir,Suite,GsAndCs} when is_integer(hd(Dir)) ; + (is_atom(Dir) and (Dir /= undefined)) ; + ((length(Dir) == 1) and is_atom(hd(Dir))) ; + ((length(Dir) == 1) and is_list(hd(Dir))) -> + Dir1 = if is_atom(Dir) -> atom_to_list(Dir); + true -> Dir end, + if Suite == undefined -> + exit(incorrect_start_options); + + is_integer(hd(Suite)) ; + (is_atom(Suite) and (Suite /= undefined)) ; + ((length(Suite) == 1) and is_atom(hd(Suite))) ; + ((length(Suite) == 1) and is_list(hd(Suite))) -> + {Dir2,Mod} = suite_to_test(Dir1, Suite), + case GsAndCs of [] -> - reformat_result(catch do_run(tests(Dir, listify(Mod)), + reformat_result(catch do_run(tests(Dir2, Mod), [], Opts1, StartOpts)); - GsAndCs -> - reformat_result(catch do_run(tests(Dir, Mod, GsAndCs), + _ -> + reformat_result(catch do_run(tests(Dir2, Mod, GsAndCs), [], Opts1, StartOpts)) end; - {value,{_,Suites}} -> - reformat_result(catch do_run(tests(lists:map(S2M, Suites)), - [], Opts1, StartOpts)); - _ -> - exit(no_tests_specified) - end; - {value,{_,Dir}} -> - case lists:keysearch(suite, 1, StartOpts) of - {value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) -> - Mod = if is_atom(Suite) -> Suite; - true -> list_to_atom(Suite) - end, - case groups_and_cases(proplists:get_value(group, StartOpts), - proplists:get_value(testcase, StartOpts)) of - Error = {error,_} -> - exit(Error); - [] -> - reformat_result(catch do_run(tests(Dir, listify(Mod)), + + is_list(Suite) -> % multiple suites + case [suite_to_test(Dir1, S) || S <- Suite] of + [_,_|_] when GsAndCs /= [] -> + exit(multiple_suites_and_cases); + [{Dir2,Mod}] when GsAndCs /= [] -> + reformat_result(catch do_run(tests(Dir2, Mod, GsAndCs), [], Opts1, StartOpts)); - GsAndCs -> - reformat_result(catch do_run(tests(Dir, Mod, GsAndCs), + DirMods -> + reformat_result(catch do_run(tests(DirMods), [], Opts1, StartOpts)) - end; - {value,{_,Suites=[Suite|_]}} when is_list(Suite) -> - Mods = lists:map(fun(Str) -> list_to_atom(Str) end, Suites), - reformat_result(catch do_run(tests(delistify(Dir), Mods), - [], Opts1, StartOpts)); - {value,{_,Suites}} -> - reformat_result(catch do_run(tests(delistify(Dir), Suites), - [], Opts1, StartOpts)); - false -> % no suite, only dir - reformat_result(catch do_run(tests(listify(Dir)), - [], Opts1, StartOpts)) - end + end + end; + + {Dir,Suite,GsAndCs} -> + exit({incorrect_start_options,{Dir,Suite,GsAndCs}}) end. %%%----------------------------------------------------------------- @@ -1014,6 +1086,7 @@ run_testspec1(TestSpec) -> end. get_data_for_node(#testspec{label = Labels, + profile = Profiles, logdir = LogDirs, cover = CoverFs, config = Cfgs, @@ -1024,6 +1097,7 @@ get_data_for_node(#testspec{label = Labels, multiply_timetraps = MTs, scale_timetraps = STs}, Node) -> Label = proplists:get_value(Node, Labels), + Profile = proplists:get_value(Node, Profiles), LogDir = case proplists:get_value(Node, LogDirs) of undefined -> "."; Dir -> Dir @@ -1037,6 +1111,7 @@ get_data_for_node(#testspec{label = Labels, FiltCTHooks = [Hook || {N,Hook} <- CTHooks, N==Node], Include = [I || {N,I} <- Incl, N==Node], #opts{label = Label, + profile = Profile, logdir = LogDir, cover = Cover, config = ConfigFiles, @@ -1118,8 +1193,24 @@ reformat_result({user_error,Reason}) -> reformat_result(Result) -> Result. -suite_to_test(Suite) -> - {filename:dirname(Suite),list_to_atom(filename:rootname(filename:basename(Suite)))}. +suite_to_test(Suite) when is_atom(Suite) -> + suite_to_test(atom_to_list(Suite)); + +suite_to_test(Suite) when is_list(Suite) -> + {filename:dirname(Suite), + list_to_atom(filename:rootname(filename:basename(Suite)))}. + +suite_to_test(Dir, Suite) when is_atom(Suite) -> + suite_to_test(Dir, atom_to_list(Suite)); + +suite_to_test(Dir, Suite) when is_list(Suite) -> + case filename:dirname(Suite) of + "." -> + {Dir,list_to_atom(filename:rootname(Suite))}; + DirName -> % ignore Dir + File = filename:basename(Suite), + {DirName,list_to_atom(filename:rootname(File))} + end. groups_and_cases(Gs, Cs) when ((Gs == undefined) or (Gs == [])) and ((Cs == undefined) or (Cs == [])) -> @@ -1173,7 +1264,7 @@ do_run(Tests, Misc, LogDir) when is_list(Misc) -> do_run(Tests, [], Opts1#opts{logdir = LogDir}, []). do_run(Tests, Skip, Opts, Args) -> - #opts{label = Label, cover = Cover} = Opts, + #opts{label = Label, profile = Profile, cover = Cover} = Opts, %% label - used by ct_logs TestLabel = @@ -1184,6 +1275,15 @@ do_run(Tests, Skip, Opts, Args) -> end, application:set_env(common_test, test_label, TestLabel), + %% profile - used in ct_util + TestProfile = + if Profile == undefined -> undefined; + is_atom(Profile) -> atom_to_list(Profile); + is_list(Profile) -> Profile; + true -> undefined + end, + application:set_env(common_test, profile, TestProfile), + case code:which(test_server) of non_existing -> exit({error,no_path_to_test_server}); diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index b3e345b4e5..ef94c25364 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -47,7 +47,7 @@ -export([get_mode/0, create_table/3, read_opts/0]). --export([set_cwd/1, reset_cwd/0]). +-export([set_cwd/1, reset_cwd/0, get_start_dir/0]). -export([parse_table/1]). @@ -61,6 +61,9 @@ -export([warn_duplicates/1]). +-export([get_profile_data/0, get_profile_data/1, + get_profile_data/2, open_url/3]). + -include("ct_event.hrl"). -include("ct_util.hrl"). @@ -243,6 +246,9 @@ set_cwd(Dir) -> reset_cwd() -> call(reset_cwd). +get_start_dir() -> + call(get_start_dir). + loop(Mode,TestData,StartDir) -> receive {update_last_run_index,From} -> @@ -319,6 +325,9 @@ loop(Mode,TestData,StartDir) -> {reset_cwd,From} -> return(From,file:set_cwd(StartDir)), loop(From,TestData,StartDir); + {get_start_dir,From} -> + return(From,StartDir), + loop(From,TestData,StartDir); {{stop,Info},From} -> Time = calendar:local_time(), ct_event:sync_notify(#event{name=test_done, @@ -332,7 +341,7 @@ loop(Mode,TestData,StartDir) -> ets:delete(?conn_table), ets:delete(?board_table), ets:delete(?suite_table), - ct_logs:close(Info), + ct_logs:close(Info, StartDir), ct_event:stop(), ct_config:stop(), file:set_cwd(StartDir), @@ -727,6 +736,79 @@ warn_duplicates(Suites) -> lists:foreach(Warn, Suites), ok. +%%%----------------------------------------------------------------- +%%% @spec +%%% +%%% @doc +get_profile_data() -> + get_profile_data(all). + +get_profile_data(KeyOrStartDir) -> + if is_atom(KeyOrStartDir) -> + get_profile_data(KeyOrStartDir, get_start_dir()); + is_list(KeyOrStartDir) -> + get_profile_data(all, KeyOrStartDir) + end. + +get_profile_data(Key, StartDir) -> + Profile = case application:get_env(common_test, profile) of + {ok,undefined} -> default; + {ok,Prof} -> Prof; + _ -> default + end, + get_profile_data(Profile, Key, StartDir). + +get_profile_data(Profile, Key, StartDir) -> + File = case Profile of + default -> + ?ct_profile_file; + _ when is_list(Profile) -> + ?ct_profile_file ++ "." ++ Profile; + _ when is_atom(Profile) -> + ?ct_profile_file ++ "." ++ atom_to_list(Profile) + end, + FullNameWD = filename:join(StartDir, File), + {WhichFile,Result} = + case file:consult(FullNameWD) of + {error,enoent} -> + case init:get_argument(home) of + {ok,[[HomeDir]]} -> + FullNameHome = filename:join(HomeDir, File), + {FullNameHome,file:consult(FullNameHome)}; + _ -> + {File,{error,enoent}} + end; + Consulted -> + {FullNameWD,Consulted} + end, + case Result of + {error,enoent} when Profile /= default -> + io:format(user, "~nERROR! Missing profile file ~p~n", [File]), + undefined; + {error,enoent} when Profile == default -> + undefined; + {error,Reason} -> + io:format(user,"~nERROR! Error in profile file ~p: ~p~n", + [WhichFile,Reason]), + undefined; + {ok,Data} -> + Data1 = case Data of + [List] when is_list(List) -> + List; + _ when is_list(Data) -> + Data; + _ -> + io:format(user, + "~nERROR! Invalid profile data in ~p~n", + [WhichFile]), + [] + end, + if Key == all -> + Data1; + true -> + proplists:get_value(Key, Data) + end + end. %%%----------------------------------------------------------------- %%% Internal functions @@ -799,3 +881,28 @@ abs_name2([H|T],Acc) -> abs_name2(T,[H|Acc]); abs_name2([],Acc) -> filename:join(lists:reverse(Acc)). + +open_url(iexplore, Args, URL) -> + {ok,R} = win32reg:open([read]), + ok = win32reg:change_key(R,"applications\\iexplore.exe\\shell\\open\\command"), + case win32reg:values(R) of + {ok, Paths} -> + Path = proplists:get_value(default, Paths), + [Cmd | _] = string:tokens(Path, "%"), + Cmd1 = Cmd ++ " " ++ Args ++ " " ++ URL, + io:format(user, "~nOpening ~s with command:~n ~s~n", [URL,Cmd1]), + open_port({spawn,Cmd1}, []); + _ -> + io:format("~nNo path to iexplore.exe~n",[]) + end, + win32reg:close(R), + ok; + +open_url(Prog, Args, URL) -> + ProgStr = if is_atom(Prog) -> atom_to_list(Prog); + is_list(Prog) -> Prog + end, + Cmd = ProgStr ++ " " ++ Args ++ " " ++ URL, + io:format(user, "~nOpening ~s with command:~n ~s~n", [URL,Cmd]), + open_port({spawn,Cmd},[]), + ok. diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl index 556f88c84d..09060f3e8b 100644 --- a/lib/common_test/src/ct_util.hrl +++ b/lib/common_test/src/ct_util.hrl @@ -31,6 +31,7 @@ nodes=[], init=[], label=[], + profile=[], logdir=["."], cover=[], config=[], @@ -58,3 +59,5 @@ -define(missing_suites_info, "missing_suites.info"). -define(ct_config_txt, ct_config_plain). + +-define(ct_profile_file, ".common_test"). -- cgit v1.2.3 From e0440ea67e0b1ce05ca2305f7f4b52e4e23ce493 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Wed, 13 Jul 2011 10:45:39 +0200 Subject: Fix error with test_server not releasing SASL TTY handlers OTP-9311 --- lib/test_server/src/test_server_ctrl.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index f3445b742b..24069946ef 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -1297,6 +1297,7 @@ terminate(_Reason, State) -> end, kill_all_jobs(State#state.jobs), test_server_node:stop(State#state.target_info), + test_server_h:restore(), ok. kill_all_jobs([{_Name,JobPid}|Jobs]) -> -- cgit v1.2.3 From d3b636f97ce36e106ac53beb4cba0db13cd5656f Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Wed, 13 Jul 2011 17:20:45 +0200 Subject: Fix problem with automatically generated init & end-config functions for groups OTP-9369 --- lib/common_test/src/ct_framework.erl | 2 + lib/test_server/src/test_server_ctrl.erl | 78 +++++++++++++++++--------------- 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 2ebc6c311a..4f57736591 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1159,12 +1159,14 @@ error_in_suite(Config) -> %% if the group config functions are missing in the suite, %% use these instead ct_init_per_group(GroupName, Config) -> + ct:comment(io_lib:format("start of ~p", [GroupName])), ct_logs:log("WARNING", "init_per_group/2 for ~w missing " "in suite, using default.", [GroupName]), Config. ct_end_per_group(GroupName, _) -> + ct:comment(io_lib:format("end of ~p", [GroupName])), ct_logs:log("WARNING", "end_per_group/2 for ~w missing " "in suite, using default.", [GroupName]), diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 24069946ef..85686217f7 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -1665,6 +1665,11 @@ do_test_cases(TopCases, SkipCases, Config, TimetrapData) when is_list(TopCases), is_tuple(TimetrapData) -> start_log_file(), + FwMod = + case os:getenv("TEST_SERVER_FRAMEWORK") of + FW when FW =:= false; FW =:= "undefined" -> ?MODULE; + FW -> list_to_atom(FW) + end, case collect_all_cases(TopCases, SkipCases) of {error,Why} -> print(1, "Error starting: ~p", [Why]), @@ -1677,11 +1682,11 @@ do_test_cases(TopCases, SkipCases, put(test_server_cases, N), put(test_server_case_num, 0), TestSpec = - add_init_and_end_per_suite(TestSpec0, undefined, undefined), - + add_init_and_end_per_suite(TestSpec0, undefined, undefined, FwMod), TI = get_target_info(), - print(1, "Starting test~s", [print_if_known(N, {", ~w test cases",[N]}, - {" (with repeated test cases)",[]})]), + print(1, "Starting test~s", + [print_if_known(N, {", ~w test cases",[N]}, + {" (with repeated test cases)",[]})]), Test = get(test_server_name), test_server_sup:framework_call(report, [tests_start,{Test,N}]), @@ -1710,13 +1715,12 @@ do_test_cases(TopCases, SkipCases, print(html, "
Used Erlang ~s in ~s.\n", [erlang:system_info(version), code:root_dir()]), - case os:getenv("TEST_SERVER_FRAMEWORK") of - FW when FW =:= false; FW =:= "undefined" -> + if FwMod == ?MODULE -> print(html, "

Target:
\n"), print_who(TI#target_info.host, TI#target_info.username), print(html, "
Used Erlang ~s in ~s.\n", [TI#target_info.version, TI#target_info.root_dir]); - _ -> + true -> case test_server_sup:framework_call(target_info, []) of TargetInfo when is_list(TargetInfo), length(TargetInfo) > 0 -> @@ -2006,54 +2010,54 @@ copy_html_file(Src, DestDir) -> end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% add_init_and_end_per_suite(TestSpec, Mod, Ref) -> NewTestSpec +%% add_init_and_end_per_suite(TestSpec, Mod, Ref, FwMod) -> NewTestSpec %% %% Expands TestSpec with an initial init_per_suite, and a final %% end_per_suite element, per each discovered suite in the list. -add_init_and_end_per_suite([{make,_,_}=Case|Cases], LastMod, LastRef) -> - [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)]; -add_init_and_end_per_suite([{skip_case,{{Mod,all},_}}=Case|Cases], LastMod, LastRef) - when Mod =/= LastMod -> +add_init_and_end_per_suite([{make,_,_}=Case|Cases], LastMod, LastRef, FwMod) -> + [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; +add_init_and_end_per_suite([{skip_case,{{Mod,all},_}}=Case|Cases], LastMod, + LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_end_per_suite_and_skip(LastMod, LastRef, Mod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)]; -add_init_and_end_per_suite([{skip_case,{{Mod,_},_}}=Case|Cases], LastMod, LastRef) - when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; +add_init_and_end_per_suite([{skip_case,{{Mod,_},_}}=Case|Cases], LastMod, + LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)]; -add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_}}=Case|Cases], LastMod, LastRef) - when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; +add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_}}=Case|Cases], LastMod, + LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)]; -add_init_and_end_per_suite([{skip_case,_}=Case|Cases], LastMod, LastRef) -> - [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)]; -add_init_and_end_per_suite([{conf,_,_,{Mod,_}}=Case|Cases], LastMod, LastRef) - when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; +add_init_and_end_per_suite([{skip_case,_}=Case|Cases], LastMod, LastRef, FwMod) -> + [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; +add_init_and_end_per_suite([{conf,_,_,{Mod,_}}=Case|Cases], LastMod, + LastRef, FwMod) when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)]; -add_init_and_end_per_suite([{conf,_,_,_}=Case|Cases], LastMod, LastRef) -> - [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)]; -add_init_and_end_per_suite([{Mod,_}=Case|Cases], LastMod, LastRef) - when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; +add_init_and_end_per_suite([{conf,_,_,_}=Case|Cases], LastMod, LastRef, FwMod) -> + [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; +add_init_and_end_per_suite([{Mod,_}=Case|Cases], LastMod, LastRef, FwMod) + when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)]; -add_init_and_end_per_suite([{Mod,_,_}=Case|Cases], LastMod, LastRef) - when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; +add_init_and_end_per_suite([{Mod,_,_}=Case|Cases], LastMod, LastRef, FwMod) + when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef)]; -add_init_and_end_per_suite([Case|Cases], LastMod, LastRef)-> - [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef)]; -add_init_and_end_per_suite([], _LastMod, undefined) -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; +add_init_and_end_per_suite([Case|Cases], LastMod, LastRef, FwMod)-> + [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; +add_init_and_end_per_suite([], _LastMod, undefined, _FwMod) -> []; -add_init_and_end_per_suite([], _LastMod, skipped_suite) -> +add_init_and_end_per_suite([], _LastMod, skipped_suite, _FwMod) -> []; -add_init_and_end_per_suite([], LastMod, LastRef) -> +add_init_and_end_per_suite([], LastMod, LastRef, _FwMod) -> [{conf,LastRef,[],{LastMod,end_per_suite}}]. do_add_init_and_end_per_suite(LastMod, LastRef, Mod) -> -- cgit v1.2.3 From f703d6512219431fa7fe61e5ddd1a9ed32506daa Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Wed, 13 Jul 2011 18:17:36 +0200 Subject: Fix problem with logdir string and some other minor bugs OTP-9370: Fix problem with crash if logdir contains multiple dirs OTP-9155: Fix some minor remaining bugs --- lib/common_test/src/ct_logs.erl | 40 ++++++++++++++++++++-------------------- lib/common_test/src/ct_run.erl | 13 +++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 5c4eb88c1f..761b906392 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -124,27 +124,27 @@ close(Info, StartDir) -> ok; Error -> io:format("Warning! Cleanup failed: ~p~n", [Error]) - end; + end, + make_all_suites_index(stop), + make_all_runs_index(stop); true -> - file:set_cwd("..") - end, - - make_all_suites_index(stop), - make_all_runs_index(stop), - - case ct_util:get_profile_data(browser, StartDir) of - undefined -> - ok; - BrowserData -> - case {proplists:get_value(prog, BrowserData), - proplists:get_value(args, BrowserData), - proplists:get_value(page, BrowserData)} of - {Prog,Args,Page} when is_list(Args), - is_list(Page) -> - URL = "file://" ++ ?abs(Page), - ct_util:open_url(Prog, Args, URL); - _ -> - ok + file:set_cwd(".."), + make_all_suites_index(stop), + make_all_runs_index(stop), + case ct_util:get_profile_data(browser, StartDir) of + undefined -> + ok; + BrowserData -> + case {proplists:get_value(prog, BrowserData), + proplists:get_value(args, BrowserData), + proplists:get_value(page, BrowserData)} of + {Prog,Args,Page} when is_list(Args), + is_list(Page) -> + URL = "\"file://" ++ ?abs(Page) ++ "\"", + ct_util:open_url(Prog, Args, URL); + _ -> + ok + end end end, ok. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 00b5a53cf4..418e212fd1 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -157,6 +157,7 @@ script_start(Args) -> end, stop_trace(Tracing), timer:sleep(1000), + io:nl(), Res. script_start1(Parent, Args) -> @@ -2155,6 +2156,18 @@ get_start_opt(Key, IfExists, Args) -> get_start_opt(Key, IfExists, undefined, Args). get_start_opt(Key, IfExists, IfNotExists, Args) -> + try try_get_start_opt(Key, IfExists, IfNotExists, Args) of + Result -> + Result + catch + error:_ -> + exit({user_error,{bad_argument,Key}}) + end. + +try_get_start_opt(Key, IfExists, Args) -> + try_get_start_opt(Key, IfExists, undefined, Args). + +try_get_start_opt(Key, IfExists, IfNotExists, Args) -> case lists:keysearch(Key, 1, Args) of {value,{Key,Val}} when is_function(IfExists) -> IfExists(Val); -- cgit v1.2.3 From 021b0dcb2a3a86ec0e07b0de8dc7cde9be0924ba Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 14 Jul 2011 14:18:57 +0200 Subject: Introduce new 'logopts' flag Introduce new 'logopts' flag and make it possible to modify the default logging behaviour OTP-9372 OTP-9396 --- lib/common_test/src/ct.erl | 4 ++- lib/common_test/src/ct_framework.erl | 12 ++++++- lib/common_test/src/ct_run.erl | 61 ++++++++++++++++++++++++-------- lib/common_test/src/ct_testspec.erl | 22 ++++++++++++ lib/common_test/src/ct_util.hrl | 1 + lib/common_test/src/vts.erl | 18 +++++----- lib/test_server/src/test_server_ctrl.erl | 34 +++++++++++++----- 7 files changed, 119 insertions(+), 33 deletions(-) diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 66da3ef742..4c215d1b1e 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -148,7 +148,7 @@ run(TestDirs) -> %%% {auto_compile,Bool} | {multiply_timetraps,M} | {scale_timetraps,Bool} | %%% {repeat,N} | {duration,DurTime} | {until,StopTime} | %%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} | -%%% {refresh_logs,LogDir} | {basic_html,Bool} | +%%% {refresh_logs,LogDir} | {logopts,LogOpts} | {basic_html,Bool} | %%% {ct_hooks, CTHs} %%% TestDirs = [string()] | string() %%% Suites = [string()] | string() @@ -177,6 +177,8 @@ run(TestDirs) -> %%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile} %%% DecryptKey = string() %%% DecryptFile = string() +%%% LogOpts = [LogOpt] +%%% LogOpt = no_nl | no_src %%% CTHs = [CTHModule | {CTHModule, CTHInitArgs}] %%% CTHModule = atom() %%% CTHInitArgs = term() diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 4f57736591..0910b39b72 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -27,7 +27,7 @@ -export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, report/2, warn/1]). -export([error_notification/4]). --export([overview_html_header/1]). +-export([get_logopts/0, overview_html_header/1]). -export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]). @@ -1333,6 +1333,16 @@ add_data_dir(File,Config) when is_list(File) -> File end. +%%%----------------------------------------------------------------- +%%% @spec get_logopts +get_logopts() -> + case ct_util:get_testdata(logopts) of + undefined -> + []; + LogOpts -> + LogOpts + end. + %%%----------------------------------------------------------------- %%% @spec overview_html_header(TestName) -> Header overview_html_header(TestName) -> diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 418e212fd1..4bb555bb9e 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -33,7 +33,7 @@ %% Exported for VTS --export([run_make/3,do_run/3,tests/1,tests/2,tests/3]). +-export([run_make/3,do_run/4,tests/1,tests/2,tests/3]). %% Misc internal functions @@ -53,6 +53,7 @@ coverspec, step, logdir, + logopts = [], config = [], event_handlers = [], ct_hooks = [], @@ -168,6 +169,8 @@ script_start1(Parent, Args) -> Shell = get_start_opt(shell, true, Args), Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args), LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args), + LogOpts = get_start_opt(logopts, fun(Os) -> [list_to_atom(O) || O <- Os] end, + [], Args), MultTT = get_start_opt(multiply_timetraps, fun([MT]) -> list_to_integer(MT) end, 1, Args), ScaleTT = get_start_opt(scale_timetraps, @@ -239,7 +242,8 @@ script_start1(Parent, Args) -> StartOpts = #opts{label = Label, profile = Profile, vts = Vts, shell = Shell, cover = Cover, - logdir = LogDir, event_handlers = EvHandlers, + logdir = LogDir, logopts = LogOpts, + event_handlers = EvHandlers, ct_hooks = CTHooks, include = IncludeDirs, silent_connections = SilentConns, @@ -307,6 +311,9 @@ script_start2(StartOpts = #opts{vts = undefined, LogDir = choose_val(StartOpts#opts.logdir, SpecStartOpts#opts.logdir), + AllLogOpts = merge_vals([StartOpts#opts.logopts, + SpecStartOpts#opts.logopts]), + Cover = choose_val(StartOpts#opts.cover, SpecStartOpts#opts.cover), MultTT = choose_val(StartOpts#opts.multiply_timetraps, @@ -328,6 +335,7 @@ script_start2(StartOpts = #opts{vts = undefined, testspecs = Specs, cover = Cover, logdir = LogDir, + logopts = AllLogOpts, config = SpecStartOpts#opts.config, event_handlers = AllEvHs, ct_hooks = AllCTHooks, @@ -465,7 +473,7 @@ script_start3(StartOpts, Args) -> end. script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers, - tests = Tests, logdir = LogDir}, _Args) -> + tests = Tests, logdir = LogDir, logopts = LogOpts}, _Args) -> ConfigFiles = lists:foldl(fun({ct_config_plain,CfgFiles}, AllFiles) when is_list(hd(CfgFiles)) -> @@ -476,13 +484,15 @@ script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers, (_, AllFiles) -> AllFiles end, [], Config), - vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), Tests); + vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), LogOpts, Tests); script_start4(#opts{label = Label, profile = Profile, shell = true, config = Config, event_handlers = EvHandlers, ct_hooks = CTHooks, - logdir = LogDir, testspecs = Specs}, _Args) -> + logdir = LogDir, + logopts = LogOpts, + testspecs = Specs}, _Args) -> %% label - used by ct_logs application:set_env(common_test, test_label, Label), @@ -499,6 +509,7 @@ script_start4(#opts{label = Label, profile = Profile, case install(InstallOpts) of ok -> ct_util:start(interactive, LogDir), + ct_util:set_testdata(logopts, LogOpts), log_ts_names(Specs), io:nl(), ok; @@ -539,6 +550,7 @@ script_usage() -> "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]" "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |" "\n\t[-suite Suite [-case Case]]" + "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]" "\n\t[-include InclDir1 InclDir2 .. InclDirN]" "\n\t[-no_auto_compile]" "\n\t[-multiply_timetraps N]" @@ -555,8 +567,9 @@ script_usage() -> "\n\t[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]" "\n\t[-stylesheet CSSFile]" "\n\t[-cover CoverCfgFile]" - "\n\t[-event_handler EvHandler1 and EvHandler2 .. EvHandlerN]" - "\n\t[-ct_hooks CTHook1 and CTHook2 .. CTHookN]" + "\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]" + "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]" + "\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]" "\n\t[-include InclDir1 InclDir2 .. InclDirN]" "\n\t[-no_auto_compile]" "\n\t[-multiply_timetraps N]" @@ -574,8 +587,9 @@ script_usage() -> "\n\t[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]" "\n\t[-stylesheet CSSFile]" "\n\t[-cover CoverCfgFile]" - "\n\t[-event_handler EvHandler1 and EvHandler2 .. EvHandlerN]" - "\n\t[-ct_hooks CTHook1 and CTHook2 .. CTHookN]" + "\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]" + "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]" + "\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]" "\n\t[-include InclDir1 InclDir2 .. InclDirN]" "\n\t[-no_auto_compile]" "\n\t[-multiply_timetraps N]" @@ -690,6 +704,9 @@ run_test1(StartOpts) -> %% logdir LogDir = get_start_opt(logdir, fun(LD) when is_list(LD) -> LD end, StartOpts), + %% logopts + LogOpts = get_start_opt(logopts, value, [], StartOpts), + %% config & userconfig CfgFiles = ct_config:get_config_file_list(StartOpts), @@ -789,7 +806,8 @@ run_test1(StartOpts) -> Step = get_start_opt(step, value, StartOpts), Opts = #opts{label = Label, profile = Profile, - cover = Cover, step = Step, logdir = LogDir, config = CfgFiles, + cover = Cover, step = Step, logdir = LogDir, + logopts = LogOpts, config = CfgFiles, event_handlers = EvHandlers, ct_hooks = CTHooks, include = Include, @@ -834,6 +852,8 @@ run_spec_file(Relaxed, SpecOpts#opts.profile), LogDir = choose_val(Opts#opts.logdir, SpecOpts#opts.logdir), + AllLogOpts = merge_vals([Opts#opts.logopts, + SpecOpts#opts.logopts]), AllConfig = merge_vals([CfgFiles, SpecOpts#opts.config]), Cover = choose_val(Opts#opts.cover, SpecOpts#opts.cover), @@ -860,6 +880,7 @@ run_spec_file(Relaxed, profile = Profile, cover = Cover, logdir = which(logdir, LogDir), + logopts = AllLogOpts, config = AllConfig, event_handlers = AllEvHs, include = AllInclude, @@ -1089,6 +1110,7 @@ run_testspec1(TestSpec) -> get_data_for_node(#testspec{label = Labels, profile = Profiles, logdir = LogDirs, + logopts = LogOptsList, cover = CoverFs, config = Cfgs, userconfig = UsrCfgs, @@ -1103,6 +1125,10 @@ get_data_for_node(#testspec{label = Labels, undefined -> "."; Dir -> Dir end, + LogOpts = case proplists:get_value(Node, LogOptsList) of + undefined -> []; + LOs -> LOs + end, Cover = proplists:get_value(Node, CoverFs), MT = proplists:get_value(Node, MTs), ST = proplists:get_value(Node, STs), @@ -1114,6 +1140,7 @@ get_data_for_node(#testspec{label = Labels, #opts{label = Label, profile = Profile, logdir = LogDir, + logopts = LogOpts, cover = Cover, config = ConfigFiles, event_handlers = EvHandlers, @@ -1245,9 +1272,11 @@ tests(TestDirs) when is_list(TestDirs), is_list(hd(TestDirs)) -> [{?testdir(TestDir,all),all,all} || TestDir <- TestDirs]. do_run(Tests, Misc) when is_list(Misc) -> - do_run(Tests, Misc, "."). + do_run(Tests, Misc, ".", []). -do_run(Tests, Misc, LogDir) when is_list(Misc) -> +do_run(Tests, Misc, LogDir, LogOpts) when is_list(Misc), + is_list(LogDir), + is_list(LogOpts) -> Opts = case proplists:get_value(step, Misc) of undefined -> @@ -1262,9 +1291,9 @@ do_run(Tests, Misc, LogDir) when is_list(Misc) -> CoverFile -> Opts#opts{cover = CoverFile} end, - do_run(Tests, [], Opts1#opts{logdir = LogDir}, []). + do_run(Tests, [], Opts1#opts{logdir = LogDir}, []); -do_run(Tests, Skip, Opts, Args) -> +do_run(Tests, Skip, Opts, Args) when is_record(Opts, opts) -> #opts{label = Label, profile = Profile, cover = Cover} = Opts, %% label - used by ct_logs @@ -1319,6 +1348,8 @@ do_run(Tests, Skip, Opts, Args) -> _Pid -> %% save stylesheet info ct_util:set_testdata({stylesheet,Opts#opts.stylesheet}), + %% save logopts + ct_util:set_testdata({logopts,Opts#opts.logopts}), %% enable silent connections case Opts#opts.silent_connections of [] -> @@ -2339,6 +2370,8 @@ opts2args(EnvStartOpts) -> end, EHs), [_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)), [{event_handler_init,lists:reverse(StrsR)}]; + ({logopts,LOs}) when is_list(LOs) -> + [{logopts,[atom_to_list(LO) || LO <- LOs]}]; ({ct_hooks,[]}) -> []; ({ct_hooks,CTHs}) when is_list(CTHs) -> diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index d845358bb2..bf1dfa24ea 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -481,6 +481,26 @@ add_tests([{logdir,Node,Dir}|Ts],Spec) -> add_tests([{logdir,Dir}|Ts],Spec) -> add_tests([{logdir,all_nodes,Dir}|Ts],Spec); +%% --- logopts --- +add_tests([{logopts,all_nodes,Opts}|Ts],Spec) -> + LogOpts = Spec#testspec.logopts, + Tests = [{logopts,N,Opts} || + N <- list_nodes(Spec), + lists:keymember(ref2node(N,Spec#testspec.nodes),1, + LogOpts) == false], + add_tests(Tests++Ts,Spec); +add_tests([{logopts,Nodes,Opts}|Ts],Spec) when is_list(Nodes) -> + Ts1 = separate(Nodes,logopts,[Opts],Ts,Spec#testspec.nodes), + add_tests(Ts1,Spec); +add_tests([{logopts,Node,Opts}|Ts],Spec) -> + LogOpts = Spec#testspec.logopts, + LogOpts1 = [{ref2node(Node,Spec#testspec.nodes),Opts} | + lists:keydelete(ref2node(Node,Spec#testspec.nodes), + 1,LogOpts)], + add_tests(Ts,Spec#testspec{logopts=LogOpts1}); +add_tests([{logopts,Opts}|Ts],Spec) -> + add_tests([{logopts,all_nodes,Opts}|Ts],Spec); + %% --- label --- add_tests([{label,all_nodes,Lbl}|Ts],Spec) -> Labels = Spec#testspec.label, @@ -1097,6 +1117,8 @@ valid_terms() -> {merge_tests,1}, {logdir,2}, {logdir,3}, + {logopts,2}, + {logopts,3}, {label,2}, {label,3}, {event_handler,2}, diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl index 09060f3e8b..73898fe371 100644 --- a/lib/common_test/src/ct_util.hrl +++ b/lib/common_test/src/ct_util.hrl @@ -33,6 +33,7 @@ label=[], profile=[], logdir=["."], + logopts=[], cover=[], config=[], userconfig=[], diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index f0bf090804..9eb11c23cc 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.erl @@ -20,7 +20,7 @@ -module(vts). -export([start/0, - init_data/4, + init_data/5, stop/0, report/2]). @@ -56,7 +56,7 @@ -record(state,{tests=[],config=[],event_handler=[],test_runner, running=0,reload_results=false,start_dir,current_log_dir, - total=0,ok=0,fail=0,skip=0,testruns=[]}). + logopts=[],total=0,ok=0,fail=0,skip=0,testruns=[]}). %%%----------------------------------------------------------------- @@ -65,8 +65,8 @@ start() -> webtool:start(), webtool:start_tools([],"app=vts"). -init_data(ConfigFiles,EvHandlers,LogDir,Tests) -> - call({init_data,ConfigFiles,EvHandlers,LogDir,Tests}). +init_data(ConfigFiles,EvHandlers,LogDir,LogOpts,Tests) -> + call({init_data,ConfigFiles,EvHandlers,LogDir,LogOpts,Tests}). stop() -> webtool:stop_tools([],"app=vts"), @@ -160,10 +160,11 @@ init(Parent) -> loop(State) -> receive - {{init_data,Config,EvHandlers,LogDir,Tests},From} -> + {{init_data,Config,EvHandlers,LogDir,LogOpts,Tests},From} -> %% ct:pal("State#state.current_log_dir=~p", [State#state.current_log_dir]), NewState = State#state{config=Config,event_handler=EvHandlers, - current_log_dir=LogDir,tests=Tests}, + current_log_dir=LogDir, + logopts=LogOpts,tests=Tests}, ct_install(NewState), return(From,ok), loop(NewState); @@ -270,10 +271,11 @@ return({To,Ref},Result) -> To ! {Ref, Result}. -run_test1(State=#state{tests=Tests,current_log_dir=LogDir}) -> +run_test1(State=#state{tests=Tests,current_log_dir=LogDir, + logopts=LogOpts}) -> Self=self(), RunTest = fun() -> - case ct_run:do_run(Tests,[],LogDir) of + case ct_run:do_run(Tests,[],LogDir,LogOpts) of {error,_Reason} -> aborted(); _ -> diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 85686217f7..b7b25fcf72 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -1350,6 +1350,10 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, put(test_server_minor_level, MinLev), put(test_server_random_seed, proplists:get_value(random_seed, ExtraTools)), put(test_server_testcase_callback, TCCallback), + %% before first print, read and set logging options + LogOpts = test_server_sup:framework_call(get_logopts, [], []), + put(test_server_logopts, LogOpts), + put(test_server_log_nl, not lists:member(no_nl, LogOpts)), StartedExtraTools = start_extra_tools(ExtraTools), {TimeMy,Result} = ts_tc(Mod, Func, Args), put(test_server_common_io_handler, undefined), @@ -1889,11 +1893,12 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) -> []), SrcListing = downcase(cast_to_list(Mod)) ++ ?src_listing_ext, - case filelib:is_file(filename:join(LogDir, SrcListing)) of - true -> + case {filelib:is_file(filename:join(LogDir, SrcListing)), + lists:member(no_src, get(test_server_logopts))} of + {true,false} -> print(Lev, "source code for ~p:~p/1\n", [SrcListing,Func,Mod,Func]); - false -> ok + _ -> ok end, io:fwrite(Fd, "

\n", []),
@@ -2106,7 +2111,12 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
 
     maybe_open_job_sock(),
 
-    html_convert_modules(TestSpec, Config),
+    case lists:member(no_src, get(test_server_logopts)) of
+	true ->
+	    ok;
+	false ->
+	    html_convert_modules(TestSpec, Config)
+    end,
 
     run_test_cases_loop(TestSpec, [Config], TimetrapData, [], []),
 
@@ -2315,7 +2325,8 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
 		    handle_test_case_io_and_status(),
 		    set_io_buffering(undefined),
 		    {Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, false, SkipMode),
-		    test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+		    test_server_sup:framework_call(report, [tc_auto_skip,
+							    {?pl2a(Mod),Func,Comment}]),
 		    run_test_cases_loop(Cases, Config, TimetrapData, ParentMode,
 					delete_status(Ref, Status));
 		_ ->
@@ -2323,7 +2334,8 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
 		    %% parallel group (io buffering is active)
 		    wait_for_cases(Ref),
 		    {Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, true, SkipMode),
-		    test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+		    test_server_sup:framework_call(report, [tc_auto_skip,
+							    {?pl2a(Mod),Func,Comment}]),
 		    case CurrIOHandler of
 			{Ref,_} ->
 			    %% current_io_handler was set by start conf of this
@@ -4350,14 +4362,18 @@ output_to_fd(Fd, [$=|Msg], internal) ->
     io:put_chars(Fd, [$=]),
     io:put_chars(Fd, Msg),
     io:put_chars(Fd, "\n");
+
 output_to_fd(Fd, Msg, internal) ->
     io:put_chars(Fd, [$=,$=,$=,$ ]),
     io:put_chars(Fd, Msg),
     io:put_chars(Fd, "\n");
+
 output_to_fd(Fd, Msg, _Sender) ->
     io:put_chars(Fd, Msg),
-    io:put_chars(Fd, "\n").
-
+    case get(test_server_log_nl) of
+	false -> ok;
+	_     -> io:put_chars(Fd, "\n")
+    end.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% timestamp_filename_get(Leader) -> string()
@@ -4670,7 +4686,7 @@ collect_case_invoke(Mod, Case, MFA, St) ->
 		    collect_subcases(Mod, Case, MFA, St, Suite)
 	    end;
 	_ ->
-	    Suite = test_server_sup:framework_call(get_suite, [?pl2a(Mod),Case],[]),
+	    Suite = test_server_sup:framework_call(get_suite, [?pl2a(Mod),Case], []),
 	    collect_subcases(Mod, Case, MFA, St, Suite)
     end.
 
-- 
cgit v1.2.3


From 8618bb8eab726ab5652b40751bdca928b49eca7f Mon Sep 17 00:00:00 2001
From: Peter Andersson 
Date: Thu, 14 Jul 2011 16:10:31 +0200
Subject: Fix incorrect module name arg to FW:end_tc/3

OTP-9379
---
 lib/common_test/src/ct_run.erl          | 3 ---
 lib/test_server/src/test_server.erl     | 4 ++--
 lib/test_server/src/test_server_sup.erl | 2 +-
 lib/test_server/src/ts_erl_config.erl   | 5 -----
 4 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 4bb555bb9e..c3b0348b26 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -2195,9 +2195,6 @@ get_start_opt(Key, IfExists, IfNotExists, Args) ->
 	    exit({user_error,{bad_argument,Key}})
     end.
 
-try_get_start_opt(Key, IfExists, Args) ->
-    try_get_start_opt(Key, IfExists, undefined, Args).
-
 try_get_start_opt(Key, IfExists, IfNotExists, Args) ->
     case lists:keysearch(Key, 1, Args) of
 	{value,{Key,Val}} when is_function(IfExists) ->
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 591329b361..d3fa3c8b87 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -1218,8 +1218,8 @@ do_end_tc_call(M,F,Res,Return) ->
 		    NewReturn
 	    end;
 	Other ->
-	    case test_server_sup:framework_call(
-		   end_tc, [Other,F,Res], Ref) of
+	    case test_server_sup:framework_call(Other, end_tc,
+						[?pl2a(M),F,Res], Ref) of
 		{fail,FWReason} ->
 		    {failed,FWReason};
 		_Else ->
diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl
index 53dfb45e3a..e846a4c14a 100644
--- a/lib/test_server/src/test_server_sup.erl
+++ b/lib/test_server/src/test_server_sup.erl
@@ -26,7 +26,7 @@
 	 cleanup_crash_dumps/0, crash_dump_dir/0, tar_crash_dumps/0,
 	 get_username/0, get_os_family/0, 
 	 hostatom/0, hostatom/1, hoststr/0, hoststr/1,
-	 framework_call/2,framework_call/3,
+	 framework_call/2,framework_call/3,framework_call/4,
 	 format_loc/1, package_str/1, package_atom/1,
 	 call_trace/1]).
 -include("test_server_internal.hrl").
diff --git a/lib/test_server/src/ts_erl_config.erl b/lib/test_server/src/ts_erl_config.erl
index 640c8ddc9f..3b41f90d55 100644
--- a/lib/test_server/src/ts_erl_config.erl
+++ b/lib/test_server/src/ts_erl_config.erl
@@ -222,7 +222,6 @@ erl_interface(Vars,OsType) ->
 		end,
     CrossCompile = case OsType of
 		       vxworks -> "true";
-		       ose ->     "true";
 		       _ ->       "false"
 		   end,
     [{erl_interface_libpath, filename:nativename(LibPath)},
@@ -329,8 +328,6 @@ sock_libraries({win32, _}) ->
 sock_libraries({unix, _}) ->
     "";	% Included in general libraries if needed.
 sock_libraries(vxworks) ->
-    "";
-sock_libraries(ose) ->
     "".
 
 link_library(LibName,{win32, _}) ->
@@ -339,8 +336,6 @@ link_library(LibName,{unix, _}) ->
     "lib" ++ LibName ++ ".a";
 link_library(LibName,vxworks) ->
     "lib" ++ LibName ++ ".a";
-link_library(_LibName,ose) ->
-    "";
 link_library(_LibName,_Other) ->
     exit({link_library, not_supported}).
 
-- 
cgit v1.2.3


From bd56af6214c451b9c7d0ab455b2597021299ecaa Mon Sep 17 00:00:00 2001
From: Peter Andersson 
Date: Thu, 14 Jul 2011 16:56:36 +0200
Subject: Introduce new framework callback function to read info about color of
 comments

OTP-9237
---
 lib/common_test/src/ct_framework.erl     | 9 +++++++--
 lib/test_server/src/test_server.erl      | 9 ++++++---
 lib/test_server/src/test_server_ctrl.erl | 7 +++++--
 3 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 0910b39b72..a683822977 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -27,7 +27,7 @@
 -export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, report/2, warn/1]).
 -export([error_notification/4]).
 
--export([get_logopts/0, overview_html_header/1]).
+-export([get_logopts/0, format_comment/1, overview_html_header/1]).
 
 -export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]).
 
@@ -1334,7 +1334,7 @@ add_data_dir(File,Config) when is_list(File) ->
     end.
 
 %%%-----------------------------------------------------------------
-%%% @spec get_logopts
+%%% @spec get_logopts() -> [LogOpt]
 get_logopts() ->
     case ct_util:get_testdata(logopts) of
 	undefined ->
@@ -1343,6 +1343,11 @@ get_logopts() ->
 	    LogOpts
     end.
 
+%%%-----------------------------------------------------------------
+%%% @spec format_comment(Comment) -> HtmlComment
+format_comment(Comment) ->
+    "" ++ Comment ++ "".
+
 %%%-----------------------------------------------------------------
 %%% @spec overview_html_header(TestName) -> Header
 overview_html_header(TestName) ->
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index d3fa3c8b87..f5f795e082 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -733,14 +733,18 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 	    print(Detail,Format,Args),
 	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
 	{comment,NewComment} ->
+	    NewComment1 = test_server_ctrl:to_string(NewComment),
+	    NewComment2 = test_server_sup:framework_call(format_comment,
+							 [NewComment1],
+							 NewComment1),
 	    Terminate1 =
 		case Terminate of
 		    {true,{Time,Value,Loc,Opts,_OldComment}} ->
-			{true,{Time,Value,mod_loc(Loc),Opts,NewComment}};
+			{true,{Time,Value,mod_loc(Loc),Opts,NewComment2}};
 		    Other ->
 			Other
 		end,
-	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment,CurrConf);
+	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment2,CurrConf);
 	{set_curr_conf,NewCurrConf} ->
 	    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,NewCurrConf);
 	{'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} ->
@@ -2283,7 +2287,6 @@ comment(String) ->
     group_leader() ! {comment,String},
     ok.
 
-
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% os_type() -> OsType
 %%
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index b7b25fcf72..7554a31530 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -173,7 +173,7 @@
 %%% TEST_SERVER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 -export([output/2, print/2, print/3, print_timestamp/2]).
 -export([start_node/3, stop_node/1, wait_for_node/1, is_release_available/1]).
--export([format/1, format/2, format/3]).
+-export([format/1, format/2, format/3, to_string/1]).
 -export([get_target_info/0]).
 -export([get_hosts/0]).
 -export([get_target_os_type/0]).
@@ -3976,8 +3976,11 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
 	case RetVal of
 	    {comment,RetComment} ->
 		String = to_string(RetComment),
+		HtmlCmt = test_server_sup:framework_call(format_comment,
+							 [String],
+							 String),
 		print(major, "=result        ok: ~s", [String]),
-		"" ++ String ++ "";
+		"" ++ HtmlCmt ++ "";
 	    _ ->
 		print(major, "=result        ok", []),
 		case Comment0 of
-- 
cgit v1.2.3


From f7ed0bf5212de281c4456f8ec7735ff22a06c371 Mon Sep 17 00:00:00 2001
From: Peter Andersson 
Date: Thu, 14 Jul 2011 17:55:53 +0200
Subject: Fix error with incorrect test case status when end_per_testcase times
 out

OTP-9397
---
 lib/test_server/src/test_server.erl | 117 +++++++++++++++++++++---------------
 1 file changed, 67 insertions(+), 50 deletions(-)

diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index f5f795e082..52fb4fba6b 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -757,7 +757,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 		    case mod_loc(Loc) of
 			{FwMod,FwFunc,framework} ->
 			    %% timout during framework call
-			    spawn_fw_call(FwMod,FwFunc,Pid,
+			    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
 					  {framework_error,{timetrap,TVal}},
 					  unknown,self(),Comment),
 			    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,
@@ -783,7 +783,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 					%% group leader process or io will cause deadlock,
 					%% so we spawn a dedicated process for the operation
 					%% and let the group leader go back to handle io.
-					spawn_fw_call(Mod,Func,Pid,{timetrap_timeout,TVal},
+					spawn_fw_call(Mod,Func,CurrConf,Pid,
+						      {timetrap_timeout,TVal},
 						      Loc1,self(),Comment),
 					undefined
 				end,
@@ -794,12 +795,13 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 		    case mod_loc(Loc) of
 			{FwMod,FwFunc,framework} ->
 			    %% timout during framework call
-			    spawn_fw_call(FwMod,FwFunc,Pid,
+			    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
 					  {framework_error,{timetrap,TVal}},
 					  unknown,self(),Comment);
 			Loc1 ->
 			    {Mod,_Func} = get_mf(Loc1),
-			    spawn_fw_call(Mod,InitOrEnd,Pid,{timetrap_timeout,TVal},
+			    spawn_fw_call(Mod,InitOrEnd,CurrConf,Pid,
+					  {timetrap_timeout,TVal},
 					  Loc1,self(),Comment)
 		    end,
 		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
@@ -808,7 +810,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 		    case mod_loc(AbortLoc) of
 			{FwMod,FwFunc,framework} ->
 			    %% abort during framework call
-			    spawn_fw_call(FwMod,FwFunc,Pid,
+			    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
 					  {framework_error,ErrorMsg},
 					  unknown,self(),Comment),
 			    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,
@@ -832,7 +834,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 							  TVal),
 					{EndConfPid,{Mod,Func},Conf};
 				    _ ->
-					spawn_fw_call(Mod,Func,Pid,ErrorMsg,
+					spawn_fw_call(Mod,Func,CurrConf,Pid,ErrorMsg,
 						      Loc1,self(),Comment),
 					undefined
 				end,
@@ -843,17 +845,18 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 		    %% result of an exit(TestCase,kill) call, which is the
 		    %% only way to abort a testcase process that traps exits
 		    %% (see abort_current_testcase)
-		    spawn_fw_call(undefined,undefined,Pid,testcase_aborted_or_killed,
+		    spawn_fw_call(undefined,undefined,CurrConf,Pid,
+				  testcase_aborted_or_killed,
 				  unknown,self(),Comment),
 		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
 		{fw_error,{FwMod,FwFunc,FwError}} ->
-		    spawn_fw_call(FwMod,FwFunc,Pid,{framework_error,FwError},
+		    spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,{framework_error,FwError},
 				  unknown,self(),Comment),
 		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf);
 		_Other ->
 		    %% the testcase has terminated because of Reason (e.g. an exit
 		    %% because a linked process failed)
-		    spawn_fw_call(undefined,undefined,Pid,Reason,
+		    spawn_fw_call(undefined,undefined,CurrConf,Pid,Reason,
 				  unknown,self(),Comment),
 		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf)
 	    end;
@@ -861,7 +864,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
 	    case CurrConf of
 		{EndConfPid,{Mod,Func},_Conf} ->
 		    {_Mod,_Func,TCPid,TCExitReason,Loc} = Data,
-		    spawn_fw_call(Mod,Func,TCPid,TCExitReason,Loc,self(),Comment),
+		    spawn_fw_call(Mod,Func,CurrConf,TCPid,TCExitReason,Loc,self(),Comment),
 		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,undefined);
 		_ ->
 		    run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf)
@@ -932,7 +935,7 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
 				    ok
 			    end,
 			    Supervisor ! {self(),end_conf}
-		       end,
+		    end,
 		Pid = spawn_link(EndConfApply),
 		receive
 		    {Pid,end_conf} ->
@@ -945,50 +948,59 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
 	end,
     spawn_link(EndConfProc).
 
-spawn_fw_call(Mod,{init_per_testcase,Func},Pid,{timetrap_timeout,TVal}=Why,
+spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why,
 	      Loc,SendTo,Comment) ->
     FwCall =
 	fun() ->
-	    Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
-	    %% if init_per_testcase fails, the test case
-	    %% should be skipped
-	    case catch do_end_tc_call(Mod,Func,{Pid,Skip,[[]]},Why) of
-		{'EXIT',FwEndTCErr} ->
-		    exit({fw_notify_done,end_tc,FwEndTCErr});
-		_ ->
-		    ok
-	    end,
-	    %% finished, report back
-	    SendTo ! {self(),fw_notify_done,
-		      {TVal/1000,Skip,Loc,[],Comment}}
+		Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
+		%% if init_per_testcase fails, the test case
+		%% should be skipped
+		case catch do_end_tc_call(Mod,Func,{Pid,Skip,[[]]},Why) of
+		    {'EXIT',FwEndTCErr} ->
+			exit({fw_notify_done,end_tc,FwEndTCErr});
+		    _ ->
+			ok
+		end,
+		%% finished, report back
+		SendTo ! {self(),fw_notify_done,
+			  {TVal/1000,Skip,Loc,[],Comment}}
 	end,
     spawn_link(FwCall);
 
-spawn_fw_call(Mod,{end_per_testcase,Func},Pid,{timetrap_timeout,TVal}=Why,
-	      Loc,SendTo,_Comment) ->
+spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
+	      {timetrap_timeout,TVal}=Why,_Loc,SendTo,Comment) ->
     FwCall =
 	fun() ->
-	    Conf = [{tc_status,ok}],
-	    %% if end_per_testcase fails, the test case should be
-	    %% reported successful with a warning printed as comment
-	    case catch do_end_tc_call(Mod,Func,{Pid,
-						{failed,{Mod,end_per_testcase,Why}},
-						[Conf]}, Why) of
-		{'EXIT',FwEndTCErr} ->
-		    exit({fw_notify_done,end_tc,FwEndTCErr});
-		_ ->
-		    ok
-	    end,
-	    %% finished, report back
-	    SendTo ! {self(),fw_notify_done,
-		      {TVal/1000,{error,{Mod,end_per_testcase,Why}},Loc,[],
-		       [""
-			"WARNING: end_per_testcase timed out!"
-			""]}}
+		%% if end_per_testcase fails a warning should be
+		%% printed as comment
+		case catch do_end_tc_call(Mod,Func,{Pid,
+						    {failed,{Mod,
+							     end_per_testcase,
+							     Why}},
+						    [EndConf]}, Why) of
+		    {'EXIT',FwEndTCErr} ->
+			exit({fw_notify_done,end_tc,FwEndTCErr});
+		    _ ->
+			ok
+		end,
+		RetVal = case proplists:get_value(tc_status, EndConf) of
+			     undefined -> {failed,{Mod,end_per_testcase,Why}};
+			     Result -> Result
+			 end,
+		FailLoc = proplists:get_value(tc_fail_loc, EndConf),
+		Comment1 = if Comment == "" -> "";
+			      true -> Comment ++ "
" + end, + %% finished, report back + SendTo ! {self(),fw_notify_done, + {TVal/1000,RetVal,FailLoc,[], + [Comment1,"" + "WARNING: end_per_testcase timed out!" + ""]}} end, spawn_link(FwCall); -spawn_fw_call(FwMod,FwFunc,_Pid,{framework_error,FwError},_,SendTo,_Comment) -> +spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo,_Comment) -> FwCall = fun() -> test_server_sup:framework_call(report, [framework_error, @@ -1003,7 +1015,7 @@ spawn_fw_call(FwMod,FwFunc,_Pid,{framework_error,FwError},_,SendTo,_Comment) -> end, spawn_link(FwCall); -spawn_fw_call(Mod,Func,Pid,Error,Loc,SendTo,Comment) -> +spawn_fw_call(Mod,Func,_,Pid,Error,Loc,SendTo,Comment) -> FwCall = fun() -> case catch fw_error_notify(Mod,Func,[], @@ -1140,25 +1152,28 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> {EndConf,TSReturn,FWReturn} = case Return of {E,TCError} when E=='EXIT' ; E==failed -> + ModLoc = mod_loc(Loc), fw_error_notify(Mod, Func, NewConf1, - TCError, mod_loc(Loc)), - {[{tc_status,{failed,TCError}}|NewConf1], + TCError, ModLoc), + {[{tc_status,{failed,TCError}}, + {tc_fail_loc,ModLoc}|NewConf1], Return,{error,TCError}}; SaveCfg={save_config,_} -> {[{tc_status,ok},SaveCfg|NewConf1],Return,ok}; {skip_and_save,Why,SaveCfg} -> Skip = {skip,Why}, - {[{tc_status,{skipped,Why}},{save_config,SaveCfg}|NewConf1], + {[{tc_status,{skipped,Why}}, + {save_config,SaveCfg}|NewConf1], Skip,Skip}; {skip,Why} -> {[{tc_status,{skipped,Why}}|NewConf1],Return,Return}; _ -> {[{tc_status,ok}|NewConf1],Return,ok} end, - %% clear current state in controller loop - group_leader() ! {set_curr_conf,undefined}, %% call user callback function if defined EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf), + %% update current state in controller loop + group_leader() ! {set_curr_conf,EndConf1}, {FWReturn1,TSReturn1,EndConf2} = case end_per_testcase(Mod, Func, EndConf1) of SaveCfg1={save_config,_} -> @@ -1172,6 +1187,8 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> _ -> {FWReturn,TSReturn,EndConf1} end, + %% clear current state in controller loop + group_leader() ! {set_curr_conf,undefined}, put(test_server_init_or_end_conf,undefined), case do_end_tc_call(Mod, Func, {FWReturn1,[EndConf2]}, TSReturn1) of {failed,Reason} = NewReturn -> -- cgit v1.2.3 From 16eaecc29b5f314fbc8f60880688049bcf074896 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 15 Jul 2011 00:41:43 +0200 Subject: Fix problem with end_tc being called with incorrect Suite argument OTP-9398: Fix error with end_tc being called with incorrect Suite argument after timeout in lib function OTP-9397: Fix problem with true error not reported to FW --- lib/common_test/src/ct_framework.erl | 3 + lib/test_server/src/test_server.erl | 118 +++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 41 deletions(-) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index a683822977..375e2875e0 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -452,6 +452,9 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> false -> ok end, +%%! --- Thu Jul 14 23:45:00 2011 --- peppe was here! + io:format(user, "MOD:FUNC = ~p:~p = ~p~n", [Mod,Func,Result]), + %% save the testcase process pid so that it can be used %% to look up the attached trace window later case ct_util:get_testdata(interpret) of diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 52fb4fba6b..337bc1d6d7 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -955,7 +955,7 @@ spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why, Skip = {skip,{failed,{Mod,init_per_testcase,Why}}}, %% if init_per_testcase fails, the test case %% should be skipped - case catch do_end_tc_call(Mod,Func,{Pid,Skip,[[]]},Why) of + case catch do_end_tc_call(Mod,Func, Loc, {Pid,Skip,[[]]}, Why) of {'EXIT',FwEndTCErr} -> exit({fw_notify_done,end_tc,FwEndTCErr}); _ -> @@ -971,23 +971,26 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, {timetrap_timeout,TVal}=Why,_Loc,SendTo,Comment) -> FwCall = fun() -> - %% if end_per_testcase fails a warning should be - %% printed as comment - case catch do_end_tc_call(Mod,Func,{Pid, - {failed,{Mod, - end_per_testcase, - Why}}, - [EndConf]}, Why) of + {RetVal,Report} = + case proplists:get_value(tc_status, EndConf) of + undefined -> + E = {failed,{Mod,end_per_testcase,Why}}, + {E,E}; + E = {failed,Reason} -> + {E,{error,Reason}}; + Result -> + {Result,Result} + end, + FailLoc = proplists:get_value(tc_fail_loc, EndConf), + case catch do_end_tc_call(Mod,Func, FailLoc, + {Pid,Report,[EndConf]}, Why) of {'EXIT',FwEndTCErr} -> exit({fw_notify_done,end_tc,FwEndTCErr}); _ -> ok end, - RetVal = case proplists:get_value(tc_status, EndConf) of - undefined -> {failed,{Mod,end_per_testcase,Why}}; - Result -> Result - end, - FailLoc = proplists:get_value(tc_fail_loc, EndConf), + %% if end_per_testcase fails a warning should be + %% printed as comment Comment1 = if Comment == "" -> ""; true -> Comment ++ "
" end, @@ -1027,7 +1030,8 @@ spawn_fw_call(Mod,Func,_,Pid,Error,Loc,SendTo,Comment) -> ok end, Conf = [{tc_status,{failed,timetrap_timeout}}], - case catch do_end_tc_call(Mod,Func,{Pid,Error,[Conf]},Error) of + case catch do_end_tc_call(Mod,Func, Loc, + {Pid,Error,[Conf]},Error) of {'EXIT',FwEndTCErr} -> exit({fw_notify_done,end_tc,FwEndTCErr}); _ -> @@ -1097,22 +1101,26 @@ run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit, {ok,Args} -> run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback); Error = {error,_Reason} -> - NewResult = do_end_tc_call(Mod,Func,{Error,Args0}, + Where = {Mod,Func}, + NewResult = do_end_tc_call(Mod,Func, Where, {Error,Args0}, {skip,{failed,Error}}), - {{0,NewResult},{Mod,Func},[]}; + {{0,NewResult},Where,[]}; {fail,Reason} -> Conf = [{tc_status,{failed,Reason}} | hd(Args0)], + Where = {Mod,Func}, fw_error_notify(Mod, Func, Conf, Reason), - NewResult = do_end_tc_call(Mod,Func, {{error,Reason},[Conf]}, + NewResult = do_end_tc_call(Mod,Func, Where, {{error,Reason},[Conf]}, {fail,Reason}), - {{0,NewResult},{Mod,Func},[]}; + {{0,NewResult},Where,[]}; Skip = {skip,_Reason} -> - NewResult = do_end_tc_call(Mod,Func,{Skip,Args0},Skip), - {{0,NewResult},{Mod,Func},[]}; + Where = {Mod,Func}, + NewResult = do_end_tc_call(Mod,Func, Where, {Skip,Args0}, Skip), + {{0,NewResult},Where,[]}; {auto_skip,Reason} -> - NewResult = do_end_tc_call(Mod, Func, {{skip,Reason},Args0}, + Where = {Mod,Func}, + NewResult = do_end_tc_call(Mod,Func, Where, {{skip,Reason},Args0}, {skip,{fw_auto_skip,Reason}}), - {{0,NewResult},{Mod,Func},[]} + {{0,NewResult},Where,[]} end, exit({Ref,Time,Value,Loc,Opts}). @@ -1126,18 +1134,19 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> Skip = {skip,Reason} -> Line = get_loc(), Conf = [{tc_status,{skipped,Reason}}], - NewRes = do_end_tc_call(Mod,Func,{Skip,[Conf]}, Skip), + NewRes = do_end_tc_call(Mod,Func, Line, {Skip,[Conf]}, Skip), {{0,NewRes},Line,[]}; {skip_and_save,Reason,SaveCfg} -> Line = get_loc(), Conf = [{tc_status,{skipped,Reason}},{save_config,SaveCfg}], - NewRes = do_end_tc_call(Mod, Func, {{skip,Reason},[Conf]}, - {skip, Reason}), + NewRes = do_end_tc_call(Mod,Func, Line, {{skip,Reason},[Conf]}, + {skip,Reason}), {{0,NewRes},Line,[]}; FailTC = {fail,Reason} -> % user fails the testcase EndConf = [{tc_status,{failed,Reason}} | hd(Args)], fw_error_notify(Mod, Func, EndConf, Reason), - NewRes = do_end_tc_call(Mod, Func, {{error,Reason},[EndConf]}, + NewRes = do_end_tc_call(Mod,Func, {Mod,Func}, + {{error,Reason},[EndConf]}, FailTC), {{0,NewRes},{Mod,Func},[]}; {ok,NewConf} -> @@ -1190,7 +1199,8 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> %% clear current state in controller loop group_leader() ! {set_curr_conf,undefined}, put(test_server_init_or_end_conf,undefined), - case do_end_tc_call(Mod, Func, {FWReturn1,[EndConf2]}, TSReturn1) of + case do_end_tc_call(Mod,Func, Loc, + {FWReturn1,[EndConf2]}, TSReturn1) of {failed,Reason} = NewReturn -> fw_error_notify(Mod,Func,EndConf2, Reason), {{T,NewReturn},{Mod,Func},[]}; @@ -1218,14 +1228,39 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> {{T,Return2},Loc,Opts} end. -do_end_tc_call(M,F,Res,Return) -> +do_end_tc_call(M,F, Loc, Res, Return) -> + FwMod = os:getenv("TEST_SERVER_FRAMEWORK"), + {Mod,Func} = + if FwMod == M ; FwMod == "undefined"; FwMod == false -> + {M,F}; + is_list(Loc) and (length(Loc)>1) -> + %% If failure in other module (M) than suite, try locate + %% suite name in Loc list and call end_tc with Suite:TestCase + %% instead of M:F. + GetSuite = fun(S,TC) -> + case lists:reverse(atom_to_list(S)) of + [$E,$T,$I,$U,$S,$_|_] -> [{S,TC}]; + _ -> [] + end + end, + case lists:flatmap(fun({S,TC,_}) -> GetSuite(S,TC); + ({{S,TC},_}) -> GetSuite(S,TC); + ({S,TC}) -> GetSuite(S,TC); + (_) -> [] + end, Loc) of + [] -> + {M,F}; + [FoundSuite|_] -> + FoundSuite + end; + true -> + {M,F} + end, + Ref = make_ref(), - case os:getenv("TEST_SERVER_FRAMEWORK") of - FW when FW == "ct_framework"; - FW == "undefined"; - FW == false -> + if FwMod == "ct_framework" ; FwMod == "undefined"; FwMod == false -> case test_server_sup:framework_call( - end_tc, [?pl2a(M),F,Res, Return], ok) of + end_tc, [?pl2a(Mod),Func,Res, Return], ok) of {fail,FWReason} -> {failed,FWReason}; ok -> @@ -1238,9 +1273,9 @@ do_end_tc_call(M,F,Res,Return) -> NewReturn -> NewReturn end; - Other -> - case test_server_sup:framework_call(Other, end_tc, - [?pl2a(M),F,Res], Ref) of + true -> + case test_server_sup:framework_call(FwMod, end_tc, + [?pl2a(Mod),Func,Res], Ref) of {fail,FWReason} -> {failed,FWReason}; _Else -> @@ -1263,7 +1298,7 @@ process_return_val([Return], M,F,A, Loc, Final) when is_list(Return) -> true -> % must be return value from end conf case process_return_val1(Return, M,F,A, Loc, Final, []); false -> % must be Config value from init conf case - case do_end_tc_call(M,F,{ok,A}, Return) of + case do_end_tc_call(M, F, Loc, {ok,A}, Return) of {failed, FWReason} = Failed -> fw_error_notify(M,F,A, FWReason), {Failed, []}; @@ -1280,8 +1315,9 @@ process_return_val1([Failed={E,TCError}|_], M,F,A=[Args], Loc, _, SaveOpts) when E=='EXIT'; E==failed -> fw_error_notify(M,F,A, TCError, mod_loc(Loc)), - case do_end_tc_call(M,F,{{error,TCError}, - [[{tc_status,{failed,TCError}}|Args]]}, Failed) of + case do_end_tc_call(M,F, Loc, {{error,TCError}, + [[{tc_status,{failed,TCError}}|Args]]}, + Failed) of {failed,FWReason} -> {{failed,FWReason},SaveOpts}; NewReturn -> @@ -1298,8 +1334,8 @@ process_return_val1([RetVal={Tag,_}|Opts], M,F,A, Loc, _, SaveOpts) when Tag==sk process_return_val1(Opts, M,F,A, Loc, RetVal, SaveOpts); process_return_val1([_|Opts], M,F,A, Loc, Final, SaveOpts) -> process_return_val1(Opts, M,F,A, Loc, Final, SaveOpts); -process_return_val1([], M,F,A, _Loc, Final, SaveOpts) -> - case do_end_tc_call(M,F,{Final,A}, Final) of +process_return_val1([], M,F,A, Loc, Final, SaveOpts) -> + case do_end_tc_call(M,F, Loc, {Final,A}, Final) of {failed,FWReason} -> {{failed,FWReason},SaveOpts}; NewReturn -> -- cgit v1.2.3 From 8d9b760e7fafec40787be6de5994240f1540d12a Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 15 Jul 2011 14:38:51 +0200 Subject: Fix problem with incorrect src links OTP-9396 --- lib/common_test/src/ct_framework.erl | 4 ---- lib/test_server/src/test_server_sup.erl | 10 ++++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 375e2875e0..b730f1e46e 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -451,10 +451,6 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> {value,{watchdog,Dog}} -> test_server:timetrap_cancel(Dog); false -> ok end, - -%%! --- Thu Jul 14 23:45:00 2011 --- peppe was here! - io:format(user, "MOD:FUNC = ~p:~p = ~p~n", [Mod,Func,Result]), - %% save the testcase process pid so that it can be used %% to look up the attached trace window later case ct_util:get_testdata(interpret) of diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl index e846a4c14a..77d364d5cb 100644 --- a/lib/test_server/src/test_server_sup.erl +++ b/lib/test_server/src/test_server_sup.erl @@ -540,8 +540,9 @@ format_loc({Mod,Func}) when is_atom(Func) -> format_loc({Mod,Line}) when is_integer(Line) -> %% ?line macro is used ModStr = package_str(Mod), - case lists:reverse(ModStr) of - [$E,$T,$I,$U,$S,$_|_] -> + case {lists:member(no_src, get(test_server_logopts)), + lists:reverse(ModStr)} of + {false,[$E,$T,$I,$U,$S,$_|_]} -> io_lib:format("{~s,~w}", [ModStr,downcase(ModStr),?src_listing_ext, round_to_10(Line),Line]); @@ -557,8 +558,9 @@ format_loc1([{Mod,Func,Line}|Rest]) -> [" ",format_loc1({Mod,Func,Line}),",\n"|format_loc1(Rest)]; format_loc1({Mod,Func,Line}) -> ModStr = package_str(Mod), - case lists:reverse(ModStr) of - [$E,$T,$I,$U,$S,$_|_] -> + case {lists:member(no_src, get(test_server_logopts)), + lists:reverse(ModStr)} of + {false,[$E,$T,$I,$U,$S,$_|_]} -> io_lib:format("{~s,~w,~w}", [ModStr,Func,downcase(ModStr),?src_listing_ext, round_to_10(Line),Line]); -- cgit v1.2.3 From 6668a91b365b8390d8eb369f7d6c6294711a1fef Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 1 Sep 2011 16:32:36 +0200 Subject: Various corrections and updates to improve error handling and reporting OTP-8933 --- lib/common_test/doc/src/config_file_chapter.xml | 6 +-- lib/common_test/src/ct_config.erl | 40 ++++++++--------- lib/common_test/src/ct_config_plain.erl | 24 ++++++----- lib/common_test/src/ct_config_xml.erl | 48 ++++++++++----------- lib/common_test/src/ct_framework.erl | 19 ++++++++- lib/common_test/src/ct_logs.erl | 4 +- lib/common_test/src/ct_run.erl | 57 +++++++++++++++++++------ lib/common_test/src/ct_testspec.erl | 8 +++- lib/common_test/src/ct_util.erl | 24 ++++++++--- 9 files changed, 148 insertions(+), 82 deletions(-) diff --git a/lib/common_test/doc/src/config_file_chapter.xml b/lib/common_test/doc/src/config_file_chapter.xml index 59151a73ec..6fc6638bf7 100644 --- a/lib/common_test/doc/src/config_file_chapter.xml +++ b/lib/common_test/doc/src/config_file_chapter.xml @@ -285,7 +285,7 @@ {ok, Config} - if the configuration variables are read successfully, - {error, Error, ErrorDetails} - if the callback module fails to + {error, {Error, ErrorDetails}} - if the callback module fails to proceed with the given configuration parameters. @@ -422,14 +422,14 @@ stop()-> call(Client, Request)-> case whereis(?REGISTERED_NAME) of undefined-> - {error, not_started, Request}; + {error, {not_started, Request}}; Pid-> Pid ! {Client, Request}, receive Reply-> {ok, Reply} after 4000-> - {error, timeout, Request} + {error, {timeout, Request}} end end. diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index 6b75937668..fc51aea7f3 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -204,9 +204,9 @@ get_config_file_list(Opts) -> DefaultConfigs = process_default_configs(Opts), CfgFiles = if - DefaultConfigs == []-> + DefaultConfigs == [] -> []; - true-> + true -> [{?ct_config_txt, DefaultConfigs}] end ++ process_user_configs(Opts, []), @@ -240,12 +240,12 @@ read_config_files(Opts) -> end, ConfigFiles = case lists:keyfind(config, 1, Opts) of - {config,ConfigLists}-> + {config,ConfigLists} -> lists:foldr(fun({Callback,Files}, Acc) -> AddCallback(Callback,Files) ++ Acc end,[],ConfigLists); - false-> + false -> [] end, read_config_files_int(ConfigFiles, fun store_config/3). @@ -255,7 +255,9 @@ read_config_files_int([{Callback, File}|Files], FunToSave) -> {ok, Config} -> FunToSave(Config, Callback, File), read_config_files_int(Files, FunToSave); - {error, ErrorName, ErrorDetail}-> + {error, {ErrorName, ErrorDetail}} -> + {user_error, {ErrorName, File, ErrorDetail}}; + {error, ErrorName, ErrorDetail} -> {user_error, {ErrorName, File, ErrorDetail}} end; read_config_files_int([], _FunToSave) -> @@ -283,7 +285,7 @@ rewrite_config(Config, Callback, File) -> config=File,_='_'}), Updater = fun({Key, Value}) -> case keyfindall(Key, #ct_conf.key, OldRows) of - []-> + [] -> ets:insert(?attr_table, #ct_conf{key=Key, value=Value, @@ -453,9 +455,9 @@ update_conf(Name, NewConfig) -> reload_conf(KeyOrName) -> case lookup_handler_for_config(KeyOrName) of - []-> + [] -> undefined; - HandlerList-> + HandlerList -> HandlerList2 = lists:usort(HandlerList), read_config_files_int(HandlerList2, fun rewrite_config/3), get_config(KeyOrName) @@ -711,13 +713,13 @@ random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]). check_callback_load(Callback) -> case code:is_loaded(Callback) of - {file, _Filename}-> + {file, _Filename} -> check_exports(Callback); - false-> + false -> case code:load_file(Callback) of - {module, Callback}-> + {module, Callback} -> check_exports(Callback); - {error, Error}-> + {error, Error} -> {error, Error} end end. @@ -745,14 +747,14 @@ check_config_files(Configs) -> end, Files) end; - {error, Why}-> + {error, Why} -> {error, {callback, {Callback,Why}}} end; ({Callback, []}) -> case check_callback_load(Callback) of - {ok, Callback}-> + {ok, Callback} -> Callback:check_parameter([]); - {error, Why}-> + {error, Why} -> {error, {callback, {Callback,Why}}} end end, @@ -773,15 +775,15 @@ prepare_user_configs([], Acc, _) -> prepare_config_list(Args) -> ConfigFiles = case lists:keysearch(ct_config, 1, Args) of - {value,{ct_config,Files}}-> + {value,{ct_config,Files}} -> [{?ct_config_txt,[filename:absname(F) || F <- Files]}]; - false-> + false -> [] end, UserConfigs = case lists:keysearch(userconfig, 1, Args) of - {value,{userconfig,UserConfigFiles}}-> + {value,{userconfig,UserConfigFiles}} -> prepare_user_configs(UserConfigFiles, [], new); - false-> + false -> [] end, ConfigFiles ++ UserConfigs. diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl index 3fbc8af9fb..6698332379 100644 --- a/lib/common_test/src/ct_config_plain.erl +++ b/lib/common_test/src/ct_config_plain.erl @@ -29,7 +29,7 @@ read_config(ConfigFile) -> {ok,Config} -> {ok, Config}; {error,enoent} -> - {error, config_file_error, enoent}; + {error,{config_file_error,file:format_error(enoent)}}; {error,Reason} -> Key = case application:get_env(common_test, decrypt) of @@ -45,23 +45,27 @@ read_config(ConfigFile) -> end, case Key of {error,no_crypt_file} -> - {error, config_file_error, Reason}; + {error,{config_file_error, + lists:flatten( + io_lib:format("~s",[file:format_error(Reason)]))}}; {error,CryptError} -> - {error, decrypt_file_error, CryptError}; + {error,{decrypt_file_error,CryptError}}; _ when is_list(Key) -> - case ct_config:decrypt_config_file(ConfigFile, undefined, {key,Key}) of + case ct_config:decrypt_config_file(ConfigFile, + undefined, + {key,Key}) of {ok,CfgBin} -> case read_config_terms(CfgBin) of {error,ReadFail} -> - {error, config_file_error, ReadFail}; + {error,{config_file_error,ReadFail}}; Config -> - {ok, Config} + {ok,Config} end; {error,DecryptFail} -> - {error, decrypt_config_error, DecryptFail} + {error,{decrypt_config_error,DecryptFail}} end; _ -> - {error, bad_decrypt_key, Key} + {error,{bad_decrypt_key,Key}} end end. @@ -69,9 +73,9 @@ read_config(ConfigFile) -> check_parameter(File)-> case filelib:is_file(File) of true-> - {ok, {file, File}}; + {ok,{file,File}}; false-> - {error, {nofile, File}} + {error,{nofile,File}} end. read_config_terms(Bin) when is_binary(Bin) -> diff --git a/lib/common_test/src/ct_config_xml.erl b/lib/common_test/src/ct_config_xml.erl index 8a6e75e635..794174e663 100644 --- a/lib/common_test/src/ct_config_xml.erl +++ b/lib/common_test/src/ct_config_xml.erl @@ -27,30 +27,30 @@ % read config file read_config(ConfigFile) -> case catch do_read_xml_config(ConfigFile) of - {ok, Config}-> - {ok, Config}; - {error, Error, ErroneousString}-> - {error, Error, ErroneousString} + {ok,Config} -> + {ok,Config}; + Error = {error,_} -> + Error end. % check file exists -check_parameter(File)-> +check_parameter(File) -> case filelib:is_file(File) of - true-> - {ok, {file, File}}; - false-> - {error, {nofile, File}} + true -> + {ok,{file,File}}; + false -> + {error,{nofile,File}} end. % actual reading of the config -do_read_xml_config(ConfigFile)-> +do_read_xml_config(ConfigFile) -> case catch xmerl_sax_parser:file(ConfigFile, - [{event_fun, fun event/3}, - {event_state, []}]) of - {ok, EntityList, _}-> - {ok, lists:reverse(transform_entity_list(EntityList))}; - Oops-> - {error, parsing_failed, Oops} + [{event_fun,fun event/3}, + {event_state,[]}]) of + {ok,EntityList,_} -> + {ok,lists:reverse(transform_entity_list(EntityList))}; + Oops -> + {error,{parsing_failed,Oops}} end. % event callback for xmerl_sax_parser @@ -92,18 +92,18 @@ tag(_El, State) -> State. % transform of the ugly deeply nested entity list to the key-value "tree" -transform_entity_list(EntityList)-> +transform_entity_list(EntityList) -> lists:map(fun transform_entity/1, EntityList). % transform entity from {list(), list()} to {atom(), term()} transform_entity({Tag, [Value|Rest]}) when - is_tuple(Value)-> + is_tuple(Value) -> {list_to_atom(Tag), transform_entity_list(lists:reverse([Value|Rest]))}; -transform_entity({Tag, String})-> +transform_entity({Tag, String}) -> case list_to_term(String) of - {ok, Value}-> + {ok, Value} -> {list_to_atom(Tag), Value}; - Error-> + Error -> throw(Error) end. @@ -111,8 +111,8 @@ transform_entity({Tag, String})-> list_to_term(String) -> {ok, T, _} = erl_scan:string(String++"."), case catch erl_parse:parse_term(T) of - {ok, Term} -> - {ok, Term}; + {ok,Term} -> + {ok,Term}; Error -> - {error, Error, String} + {error,{Error,String}} end. diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index b730f1e46e..29caa27d94 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -245,7 +245,12 @@ add_defaults(Mod,Func,FuncInfo,DoInit) -> Error = {error,_} -> {SuiteInfo,Error}; MergedInfo -> {SuiteInfo,MergedInfo} end; - {'EXIT',Reason} -> + {'EXIT',Reason} -> + ErrStr = io_lib:format("~n*** ERROR *** " + "~w:suite/0 failed: ~p~n", + [Mod,Reason]), + io:format(ErrStr, []), + io:format(user, ErrStr, []), {suite0_failed,{exited,Reason}}; SuiteInfo when is_list(SuiteInfo) -> case lists:all(fun(E) when is_tuple(E) -> true; @@ -261,9 +266,19 @@ add_defaults(Mod,Func,FuncInfo,DoInit) -> MergedInfo -> {SuiteInfo1,MergedInfo} end; false -> + ErrStr = io_lib:format("~n*** ERROR *** " + "Invalid return value from " + "~w:suite/0: ~p~n", [Mod,SuiteInfo]), + io:format(ErrStr, []), + io:format(user, ErrStr, []), {suite0_failed,bad_return_value} end; - _ -> + SuiteInfo -> + ErrStr = io_lib:format("~n*** ERROR *** " + "Invalid return value from " + "~w:suite/0: ~p~n", [Mod,SuiteInfo]), + io:format(ErrStr, []), + io:format(user, ErrStr, []), {suite0_failed,bad_return_value} end. diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 761b906392..f34eb83afa 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -484,8 +484,8 @@ logger_loop(State) -> [Str,Args]), %% stop the testcase, we need %% to see the fault - exit(Pid,logging_failed), - ok; + exit(Pid,{log_printout_error,Str,Args}), + []; IoStr when IoList == [] -> [IoStr]; IoStr -> diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index c3b0348b26..4ff062c2fa 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -667,6 +667,16 @@ run_test(StartOpt) when is_tuple(StartOpt) -> run_test([StartOpt]); run_test(StartOpts) when is_list(StartOpts) -> + CTPid = spawn(fun() -> run_test1(StartOpts) end), + Ref = monitor(process, CTPid), + receive + {'DOWN',Ref,process,CTPid,{user_error,Error}} -> + Error; + {'DOWN',Ref,process,CTPid,Other} -> + Other + end. + +run_test1(StartOpts) when is_list(StartOpts) -> case proplists:get_value(refresh_logs, StartOpts) of undefined -> Tracing = start_trace(StartOpts), @@ -675,7 +685,7 @@ run_test(StartOpts) when is_list(StartOpts) -> Res = case ct_repeat:loop_test(func, StartOpts) of false -> - case catch run_test1(StartOpts) of + case catch run_test2(StartOpts) of {'EXIT',Reason} -> file:set_cwd(Cwd), {error,Reason}; @@ -686,13 +696,13 @@ run_test(StartOpts) when is_list(StartOpts) -> Result end, stop_trace(Tracing), - Res; + exit(Res); RefreshDir -> refresh_logs(?abs(RefreshDir)), - ok + exit(done) end. -run_test1(StartOpts) -> +run_test2(StartOpts) -> %% label Label = get_start_opt(label, fun(Lbl) when is_list(Lbl) -> Lbl; (Lbl) when is_atom(Lbl) -> atom_to_list(Lbl) @@ -981,7 +991,7 @@ run_dir(Opts = #opts{logdir = LogDir, {Dir=[Hd|_],undefined,[]} when is_list(Dir) and is_integer(Hd) -> reformat_result(catch do_run(tests(Dir), [], Opts1, StartOpts)); - {Dir,undefined,[]} when is_atom(Dir) -> + {Dir,undefined,[]} when is_atom(Dir) and (Dir /= undefined) -> reformat_result(catch do_run(tests(atom_to_list(Dir)), [], Opts1, StartOpts)); @@ -1052,6 +1062,9 @@ run_dir(Opts = #opts{logdir = LogDir, end end; + {undefined,undefined,[]} -> + exit(no_test_specified); + {Dir,Suite,GsAndCs} -> exit({incorrect_start_options,{Dir,Suite,GsAndCs}}) end. @@ -1064,19 +1077,38 @@ run_dir(Opts = #opts{logdir = LogDir, %%% the same as those used in test specification files. %%% @equiv ct:run_testspec/1 %%%----------------------------------------------------------------- - run_testspec(TestSpec) -> + CTPid = spawn(fun() -> run_testspec1(TestSpec) end), + Ref = monitor(process, CTPid), + receive + {'DOWN',Ref,process,CTPid,{user_error,Error}} -> + Error; + {'DOWN',Ref,process,CTPid,Other} -> + Other + end. + +run_testspec1(TestSpec) -> {ok,Cwd} = file:get_cwd(), io:format("~nCommon Test starting (cwd is ~s)~n~n", [Cwd]), - case catch run_testspec1(TestSpec) of + case catch run_testspec2(TestSpec) of {'EXIT',Reason} -> file:set_cwd(Cwd), - {error,Reason}; + exit({error,Reason}); Result -> - Result + exit(Result) end. -run_testspec1(TestSpec) -> +run_testspec2(File) when is_list(File), is_integer(hd(File)) -> + case file:read_file_info(File) of + {ok,_} -> + exit("Bad argument, " + "use ct:run_test([{spec," ++ File ++ "}])"); + _ -> + exit("Bad argument, list of tuples expected, " + "use ct:run_test/1 for test specification files") + end; + +run_testspec2(TestSpec) -> case catch ct_testspec:collect_tests_from_list(TestSpec, false) of {E,CTReason} when E == error ; E == 'EXIT' -> exit(CTReason); @@ -1295,7 +1327,6 @@ do_run(Tests, Misc, LogDir, LogOpts) when is_list(Misc), do_run(Tests, Skip, Opts, Args) when is_record(Opts, opts) -> #opts{label = Label, profile = Profile, cover = Cover} = Opts, - %% label - used by ct_logs TestLabel = if Label == undefined -> undefined; @@ -2478,8 +2509,8 @@ start_trace(Args) -> false end; {_,Error} -> - io:format("Warning! Tracing not started. Reason: ~p~n~n", - [Error]), + io:format("Warning! Tracing not started. Reason: ~s~n~n", + [file:format_error(Error)]), false end; false -> diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index bf1dfa24ea..2cba1d8410 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -249,11 +249,15 @@ collect_tests_from_file1([Spec|Specs],TestSpec,Relaxed) -> SpecDir = filename:dirname(filename:absname(Spec)), case file:consult(Spec) of {ok,Terms} -> - TestSpec1 = collect_tests(Terms,TestSpec#testspec{spec_dir=SpecDir}, + TestSpec1 = collect_tests(Terms, + TestSpec#testspec{spec_dir=SpecDir}, Relaxed), collect_tests_from_file1(Specs,TestSpec1,Relaxed); {error,Reason} -> - throw({error,{Spec,Reason}}) + ReasonStr = + lists:flatten(io_lib:format("~s", + [file:format_error(Reason)])), + throw({error,{Spec,ReasonStr}}) end; collect_tests_from_file1([],TS=#testspec{config=Cfgs,event_handler=EvHs, include=Incl,tests=Tests},_) -> diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index ef94c25364..f393ea103d 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -124,13 +124,15 @@ do_start(Parent,Mode,LogDir) -> ok -> ok; E -> exit(E) end, + DoExit = fun(Reason) -> file:set_cwd(StartDir), exit(Reason) end, Opts = case read_opts() of {ok,Opts1} -> Opts1; Error -> Parent ! {self(),Error}, - exit(Error) + DoExit(Error) end, + %% start an event manager (if not already started by master) case ct_event:start_link() of {error,{already_started,_}} -> @@ -143,16 +145,23 @@ do_start(Parent,Mode,LogDir) -> ct_event:add_handler([{vts,VtsPid}]) end end, + %% start ct_config server - ct_config:start(Mode), + try ct_config:start(Mode) of + _ -> ok + catch + _Class:CfgError -> + DoExit(CfgError) + end, + %% add user event handlers case lists:keysearch(event_handler,1,Opts) of {value,{_,Handlers}} -> Add = fun({H,Args}) -> case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of ok -> ok; - {'EXIT',Why} -> exit(Why); - Other -> exit({event_handler,Other}) + {'EXIT',Why} -> DoExit(Why); + Other -> DoExit({event_handler,Other}) end end, case catch lists:foreach(Add,Handlers) of @@ -171,10 +180,11 @@ do_start(Parent,Mode,LogDir) -> data={StartTime, lists:flatten(TestLogDir)}}), %% Initialize ct_hooks - case catch ct_hooks:init(Opts) of + try ct_hooks:init(Opts) of ok -> - Parent ! {self(),started}; - {_,CTHReason} -> + Parent ! {self(),started} + catch + _:CTHReason -> ct_logs:tc_print('Suite Callback',CTHReason,[]), self() ! {{stop,{self(),{user_error,CTHReason}}}, {Parent,make_ref()}} -- cgit v1.2.3 From e91ba727f534553a34c05ad54247a0485e2429ff Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Mon, 5 Sep 2011 19:51:59 +0200 Subject: Implement support for running suites with test case groups through the debugger OTP-9518 --- lib/common_test/doc/src/run_test_chapter.xml | 5 +- lib/common_test/src/ct_framework.erl | 35 ++++++++++++- lib/common_test/src/ct_run.erl | 75 +++++++++++++++++----------- 3 files changed, 81 insertions(+), 34 deletions(-) diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index e668568795..e944f215f6 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -322,8 +322,9 @@ are to be executed by Common Test, and those functions only. If the step option config is specified, breakpoints will also be initially set on the configuration functions in the suite, i.e. - init_per_suite/1, end_per_suite/1, init_per_testcase/2 - and end_per_testcase/2.

+ init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + init_per_testcase/2 and end_per_testcase/2.

Common Test enables the Debugger auto attach feature, which means that for every new interpreted test case function that starts to execute, a new trace window will automatically pop up. (This is because each test diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 29caa27d94..089d5be871 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -24,8 +24,8 @@ -module(ct_framework). --export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, report/2, warn/1]). --export([error_notification/4]). +-export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, get_all_cases/1]). +-export([report/2, warn/1, error_notification/4]). -export([get_logopts/0, format_comment/1, overview_html_header/1]). @@ -781,6 +781,37 @@ get_suite(Mod, Name) -> %%%----------------------------------------------------------------- +get_all_cases(Suite) -> + case get_suite(Suite, all) of + [{?MODULE,error_in_suite,[[{error,_}=Error]]}] -> + Error; + [{?MODULE,error_in_suite,[[Error]]}] -> + {error,Error}; + Tests -> + Cases = get_all_cases1(Suite, Tests), + lists:reverse( + lists:foldl(fun(TC, TCs) -> + case lists:member(TC, TCs) of + true -> TCs; + false -> [TC | TCs] + end + end, [], Cases)) + end. + +get_all_cases1(Suite, [{conf,_Props,_Init,GrTests,_End} | Tests]) -> + get_all_cases1(Suite, GrTests) ++ get_all_cases1(Suite, Tests); + +get_all_cases1(Suite, [Test | Tests]) when is_atom(Test) -> + [{Suite,Test} | get_all_cases1(Suite, Tests)]; + +get_all_cases1(Suite, [Test | Tests]) -> + [Test | get_all_cases1(Suite, Tests)]; + +get_all_cases1(_, []) -> + []. + +%%%----------------------------------------------------------------- + find_groups(Mod, Name, TCs, GroupDefs) -> Found = find(Mod, Name, TCs, GroupDefs, [], GroupDefs, false), trim(Found). diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 4ff062c2fa..2dd6ba08aa 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -2148,7 +2148,14 @@ maybe_interpret1(Suite, Cases, StepOpts) when is_list(Cases) -> maybe_interpret2(Suite, Cases, StepOpts) -> set_break_on_config(Suite, StepOpts), - [i:ib(Suite, Case, 1) || Case <- Cases], + [begin try i:ib(Suite, Case, 1) of + _ -> ok + catch + _:_Error -> + io:format(user, "Invalid breakpoint: ~w:~w/1~n", + [Suite,Case]) + end + end || Case <- Cases, is_atom(Case)], test_server_ctrl:multiply_timetraps(infinity), WinOp = case lists:member(keep_inactive, ensure_atom(StepOpts)) of true -> no_kill; @@ -2161,10 +2168,18 @@ maybe_interpret2(Suite, Cases, StepOpts) -> set_break_on_config(Suite, StepOpts) -> case lists:member(config, ensure_atom(StepOpts)) of true -> - i:ib(Suite, init_per_suite, 1), - i:ib(Suite, init_per_testcase, 2), - i:ib(Suite, end_per_testcase, 2), - i:ib(Suite, end_per_suite, 1); + SetBPIfExists = fun(F,A) -> + case erlang:function_exported(Suite, F, A) of + true -> i:ib(Suite, F, A); + false -> ok + end + end, + SetBPIfExists(init_per_suite, 1), + SetBPIfExists(init_per_group, 2), + SetBPIfExists(init_per_testcase, 2), + SetBPIfExists(end_per_testcase, 2), + SetBPIfExists(end_per_group, 2), + SetBPIfExists(end_per_suite, 1); false -> ok end. @@ -2463,32 +2478,32 @@ is_suite(ModOrFile) when is_list(ModOrFile) -> end. get_all_testcases(Suite) -> - %%! this needs to be updated to handle testcase groups later!! - case catch Suite:all() of - {'EXIT',Why} -> - {error,Why}; - {skip,_} -> - []; - Cases -> - AllCases = - lists:foldl(fun({sequence,SeqName}, All) -> - case catch Suite:sequences() of - {'EXIT',_} -> - All; - Seqs -> - case proplists:get_value(SeqName, Seqs) of - undefined -> - All; - SeqCases -> - lists:reverse(SeqCases) ++ All - end - end; - (Case,All) -> - [Case|All] - end, [], Cases), - lists:reverse(AllCases) + try ct_framework:get_all_cases(Suite) of + {error,_Reason} = Error -> + Error; + SuiteCases -> + Cases = [C || {_S,C} <- SuiteCases], + Cases1 = + try Suite:sequences() of + [] -> + Cases; + Seqs -> + TCs1 = lists:flatten([TCs || {_,TCs} <- Seqs]), + lists:reverse( + lists:foldl(fun(TC, Acc) -> + case lists:member(TC, Acc) of + true -> Acc; + false -> [TC | Acc] + end + end, [], Cases ++ TCs1)) + catch + _:_ -> + Cases + end + catch + _:Error -> + {error,Error} end. - %% Internal tracing support. If {ct_trace,TraceSpec} is present, the %% TraceSpec file will be consulted and dbg used to trace function -- cgit v1.2.3 From 36f1e1898a2ea08d591739cc2e9ff8e7fbb0ea6b Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 6 Sep 2011 23:33:43 +0200 Subject: Repair and improve the vts mode OTP-9429 --- lib/common_test/src/ct_run.erl | 33 ++++++------ lib/common_test/src/vts.erl | 115 ++++++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 59 deletions(-) diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 2dd6ba08aa..4ec3ac589d 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -2483,23 +2483,22 @@ get_all_testcases(Suite) -> Error; SuiteCases -> Cases = [C || {_S,C} <- SuiteCases], - Cases1 = - try Suite:sequences() of - [] -> - Cases; - Seqs -> - TCs1 = lists:flatten([TCs || {_,TCs} <- Seqs]), - lists:reverse( - lists:foldl(fun(TC, Acc) -> - case lists:member(TC, Acc) of - true -> Acc; - false -> [TC | Acc] - end - end, [], Cases ++ TCs1)) - catch - _:_ -> - Cases - end + try Suite:sequences() of + [] -> + Cases; + Seqs -> + TCs1 = lists:flatten([TCs || {_,TCs} <- Seqs]), + lists:reverse( + lists:foldl(fun(TC, Acc) -> + case lists:member(TC, Acc) of + true -> Acc; + false -> [TC | Acc] + end + end, [], Cases ++ TCs1)) + catch + _:_ -> + Cases + end catch _:Error -> {error,Error} diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index 9eb11c23cc..cc8a932887 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.erl @@ -32,6 +32,7 @@ menu_frame/2, welcome_frame/2, config_frame/2, + browse_config_file/2, add_config_file/2, remove_config_file/2, run_frame/2, @@ -119,6 +120,8 @@ menu_frame(_Env,_Input) -> call(menu_frame). config_frame(_Env,_Input) -> call(config_frame). +browse_config_file(_Env,Input) -> + call({browse_config_file,Input}). add_config_file(_Env,Input) -> call({add_config_file,Input}). remove_config_file(_Env,Input) -> @@ -183,6 +186,9 @@ loop(State) -> {config_frame,From} -> return(From,config_frame1(State)), loop(State); + {{browse_config_file,_Input},From} -> + return(From,ok), + loop(State); {{add_config_file,Input},From} -> {Return,State1} = add_config_file1(Input,State), ct_install(State1), @@ -242,10 +248,12 @@ loop(State) -> return(From,ok); {'EXIT',Pid,Reason} -> case State#state.test_runner of - Pid -> io:format("ERROR: test runner crashed: ~p\n",[Reason]); - _ -> ignore - end, - loop(State); + Pid -> + io:format("Test run error: ~p\n",[Reason]), + loop(State); + _ -> + loop(State) + end; {{test_info,_Type,_Data},From} -> return(From,ok), loop(State) @@ -284,17 +292,18 @@ run_test1(State=#state{tests=Tests,current_log_dir=LogDir, unlink(Self) end, Pid = spawn_link(RunTest), - Total = + {Total,Tests1} = receive {{test_info,start_info,{_,_,Cases}},From} -> return(From,ok), - Cases; + {Cases,Tests}; EXIT = {'EXIT',_,_} -> - self() ! EXIT + self() ! EXIT, + {0,[]} after 30000 -> - 0 + {0,[]} end, - State#state{test_runner=Pid,running=length(Tests), + State#state{test_runner=Pid,running=length(Tests1), total=Total,ok=0,fail=0,skip=0,testruns=[]}. @@ -358,22 +367,32 @@ config_frame1(State) -> config_body(State) -> Entry = [input("TYPE=file NAME=browse SIZE=40"), input("TYPE=hidden NAME=file")], + BrowseForm = + form( + "NAME=read_file_form METHOD=post ACTION=\"./browse_config_file\"", + table( + "BORDER=0", + [tr(td("1. Locate config file")), + tr(td(Entry))])), AddForm = form( - "NAME=read_file_form METHOD=post ACTION=\"./add_config_file\"", + "NAME=add_file_form METHOD=post ACTION=\"./add_config_file\"", table( "BORDER=0", - [tr( - [td(Entry), + [tr(td("2. Paste full config file name here")), + tr( + [td(input("TYPE=text NAME=file SIZE=40")), td("ALIGN=center", input("TYPE=submit onClick=\"file.value=browse.value;\"" " VALUE=\"Add\""))])])), + {Text,RemoveForm} = case State#state.config of [] -> - T = "To be able to run any tests, one or more configuration " - "files must be added. Enter the name of the configuration " - "file below and click the \"Add\" button.", + T = "Before running the tests, one or more configuration " + "files may be added. Locate the config file, copy its " + "full name, paste this into the text field below, then " + "click the \"Add\" button.", R = "", {T,R}; Files -> @@ -396,20 +415,24 @@ config_body(State) -> input("TYPE=submit VALUE=\"Remove\"")))])), {T,R} end, - + [h1("ALIGN=center","Config"), table( - "WIDTH=600 ALIGN=center CELLPADDING=5", + "WIDTH=450 ALIGN=center CELLPADDING=5", [tr(td(["BGCOLOR=",?INFO_BG_COLOR],Text)), - tr(td("ALIGN=center",AddForm)), - tr(td("ALIGN=center",RemoveForm))])]. - + tr(td("")), + tr(td("")), + tr(td("ALIGN=left",BrowseForm)), + tr(td("ALIGN=left",AddForm)), + tr(td("ALIGN=left",RemoveForm))])]. add_config_file1(Input,State) -> State1 = case get_input_data(Input,"file") of - "" -> State; - File -> State#state{config=[File|State#state.config]} + "" -> + State; + File -> + State#state{config=[File|State#state.config]} end, Return = config_frame1(State1), {Return,State1}. @@ -429,10 +452,17 @@ run_body(#state{running=Running}) when Running>0 -> [h1("ALIGN=center","Run Test"), p(["Test are ongoing: ",href("./result_frameset","Results")])]; run_body(State) -> - ConfigList = ul([li(File) || File <- State#state.config]), + ConfigList = + case State#state.config of + [] -> + ul(["none"]); + CfgFiles -> + ul([li(File) || File <- CfgFiles]) + end, ConfigFiles = [h3("Config Files"), ConfigList], - + {ok,CWD} = file:get_cwd(), + CurrWD = [h3("Current Working Directory"), ul(CWD)], AddDirForm = form( "NAME=add_dir_form METHOD=post ACTION=\"./add_test_dir\"", @@ -444,7 +474,6 @@ run_body(State) -> td("ALIGN=center", input("TYPE=submit onClick=\"dir.value=browse.value;\"" " VALUE=\"Add Test Dir\""))])])), - {LoadedTestsTable,Submit} = case create_testdir_entries(State#state.tests,1) of [] -> {"",""}; @@ -456,22 +485,20 @@ run_body(State) -> {table("CELLPADDING=5",[Heading,TestDirs]), submit_button()} end, - - %% It should be ok to have no config-file! Body = - %% case State#state.config of %% [] -> %% p("ALIGN=center", - %% href("./config_frame","Please select one or - %% more config files")); %% _ -> table( - "WIDTH=100%", - [tr(td(ConfigFiles)), + "WIDTH=450 ALIGN=center", + [tr(td("")), + tr(td("")), + tr(td(ConfigFiles)), + tr(td("")), + tr(td(CurrWD)), tr(td("")), tr(td(AddDirForm)), tr(td("")), tr(td(LoadedTestsTable)), - tr(td(Submit))]), - %% end, - + tr(td(Submit)) + ]), [h1("ALIGN=center","Run Test"), Body]. create_testdir_entries([{Dir,Suite,Case}|Tests],N) -> @@ -558,18 +585,17 @@ options([Element|Elements],Selected,N,Func) -> options([],_Selected,_N,_Func) -> []. -add_test_dir1(Input,State) -> +add_test_dir1(Input, State) -> State1 = case get_input_data(Input,"dir") of "" -> State; Dir0 -> Dir = case ct_util:is_test_dir(Dir0) of - true -> - Dir0; - false -> filename:join(Dir0,"test") + true -> Dir0; + false -> ct_util:get_testdir(Dir0, all) end, case filelib:is_dir(Dir) of - true -> + true -> Test = ct_run:tests(Dir), State#state{tests=State#state.tests++Test}; false -> @@ -579,8 +605,6 @@ add_test_dir1(Input,State) -> Return = run_frame1(State1), {Return,State1}. - - remove_test_dir1(Input,State) -> N = list_to_integer(get_input_data(Input,"dir")), State1 = State#state{tests=delete_test(N,State#state.tests)}, @@ -643,6 +667,9 @@ result_frameset2(State) -> "./redirect_to_result_log_frame"; {_Dir,0} -> filename:join(["/log_dir","index.html"]); + {_Dir,_} when State#state.testruns == [] -> + %% crash before first test + "./no_result_log_frame"; {_Dir,_} -> {_,CurrentLog} = hd(State#state.testruns), CurrentLog @@ -751,6 +778,8 @@ report1(tc_done,{_Suite,_Case,{skipped,_Reason}},State) -> State#state{skip=State#state.skip+1}; report1(tc_user_skip,{_Suite,_Case,_Reason},State) -> State#state{skip=State#state.skip+1}; +report1(tc_auto_skip,{_Suite,_Case,_Reason},State) -> + State#state{skip=State#state.skip+1}; report1(loginfo,_,State) -> State. @@ -852,6 +881,8 @@ h2(Text) -> ["

",Text,"

\n"]. h3(Text) -> ["

",Text,"

\n"]. +%%h4(Text) -> +%% ["

",Text,"

\n"]. font(Args,Text) -> ["\n",Text,"\n\n"]. p(Text) -> -- cgit v1.2.3 From b21b1f63bce0ad705671e0f7622d017be464ed67 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 16 Sep 2011 23:37:29 +0200 Subject: Implement support for MFA and Fun as timetrap value OTP-9501 --- lib/test_server/src/test_server.erl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 337bc1d6d7..039ea720a8 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -1905,8 +1905,28 @@ time_ms({Other,_N}) -> exit({invalid_time_spec,Other}); time_ms(Ms) when is_integer(Ms) -> Ms; time_ms(infinity) -> infinity; +time_ms(Fun) when is_function(Fun) -> + try Fun() of + Val -> time_ms1(Val) + catch + _:Error -> + exit({timetrap_error,Error}) + end; +time_ms({M,F,A}) when is_atom(M), is_atom(F), is_list(A) -> + try apply(M, F, A) of + Val -> time_ms1(Val) + catch + _:Error -> + exit({timetrap_error,Error}) + end; time_ms(Other) -> exit({invalid_time_spec,Other}). +time_ms1(MFA = {M,F,A}) when is_atom(M), is_atom(F), is_list(A) -> + exit({invalid_time_spec,MFA}); +time_ms1(Fun) when is_function(Fun) -> + exit({invalid_time_spec,Fun}); +time_ms1(Other) -> + time_ms(Other). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% timetrap_cancel(Handle) -> ok -- cgit v1.2.3 From 8d051d91b86f08877038af1983c8eb5f3f9a7ddb Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Mon, 19 Sep 2011 17:50:29 +0200 Subject: Improve test suite --- lib/test_server/test/test_server_SUITE.erl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl index 4c344717f0..a8532b08ab 100644 --- a/lib/test_server/test/test_server_SUITE.erl +++ b/lib/test_server/test/test_server_SUITE.erl @@ -119,6 +119,11 @@ test_server_conf02_SUITE(Config) -> run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc, NUsrSkip, NAutoSkip, NActualSkip, NActualFail, NActualSucc, Config) -> + + ct:log("See test case log files under:~n~p~n", + [filename:join([proplists:get_value(priv_dir, Config), + SuiteName++".logs"])]), + Node = proplists:get_value(node, Config), {ok,_Pid} = rpc:call(Node,test_server_ctrl, start, []), rpc:call(Node, @@ -132,6 +137,7 @@ run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc, end), rpc:call(Node,test_server_ctrl, stop, []), + {ok,#suite{ n_cases = NCases, n_cases_failed = NFail, n_cases_expected = NExpected, -- cgit v1.2.3 From 4c8664f1983a57c8d71ada937381b5fc5791446d Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 20 Sep 2011 16:26:49 +0200 Subject: Fix incorrect call to end_tc when tc_status=ok and end_per_testcase times out OTP-9397 --- lib/common_test/test/ct_error_SUITE.erl | 24 ++++++++++++------------ lib/common_test/test/ct_repeat_1_SUITE.erl | 2 +- lib/common_test/test/ct_skip_SUITE.erl | 2 +- lib/test_server/src/test_server.erl | 11 +++++++---- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index 6867e59b60..6231e27644 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -285,7 +285,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}, + {test_server,run_test_case_eval,9}]}}}}}, {?eh,tc_auto_skip, {cfg_error_2_SUITE,tc1, {failed,{cfg_error_2_SUITE,init_per_suite, @@ -294,7 +294,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,test_stats,{0,0,{0,3}}}, {?eh,tc_auto_skip, {cfg_error_2_SUITE,tc2, @@ -304,7 +304,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,test_stats,{0,0,{0,4}}}, {?eh,tc_auto_skip, {cfg_error_2_SUITE,end_per_suite, @@ -314,7 +314,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,tc_start,{cfg_error_3_SUITE,init_per_suite}}, {?eh,tc_done, @@ -378,7 +378,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}, + {test_server,run_test_case_eval,9}]}}}}}, {?eh,tc_start,{cfg_error_7_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_7_SUITE,init_per_suite,ok}}, @@ -432,7 +432,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}, + {test_server,run_test_case_eval,9}]}}}}}, {?eh,tc_auto_skip, {cfg_error_8_SUITE,tc1, {failed,{cfg_error_8_SUITE,init_per_group, @@ -441,7 +441,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,test_stats,{4,0,{0,13}}}, {?eh,tc_auto_skip, {cfg_error_8_SUITE,end_per_group, @@ -451,7 +451,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}], + {test_server,run_test_case_eval,9}]}}}}}}], [{?eh,tc_start,{cfg_error_8_SUITE,{init_per_group,g4,[]}}}, {?eh,tc_done,{cfg_error_8_SUITE,{init_per_group,g4,[]},ok}}, @@ -525,7 +525,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,init_per_testcase,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,test_stats,{9,0,{0,17}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc4}}, {?eh,tc_done, @@ -562,7 +562,7 @@ test_events(cfg_error) -> {test_server,my_apply,3}, {test_server,do_end_per_testcase,4}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,test_stats,{12,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc14}}, {?eh,tc_done, @@ -646,7 +646,7 @@ test_events(lib_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}, + {test_server,run_test_case_eval,9}]}}}}}, {?eh,test_stats,{0,1,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,lines_exit}}, {?eh,tc_done, @@ -671,7 +671,7 @@ test_events(lib_error) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}, + {test_server,run_test_case_eval,9}]}}}}}, {?eh,test_stats,{0,5,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,no_lines_exit}}, {?eh,tc_done, diff --git a/lib/common_test/test/ct_repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE.erl index 4e842bd6d6..99e3b83ea9 100644 --- a/lib/common_test/test/ct_repeat_1_SUITE.erl +++ b/lib/common_test/test/ct_repeat_1_SUITE.erl @@ -565,7 +565,7 @@ test_events(repeat_cs_until_any_fail) -> {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}, + {test_server,run_test_case_eval,9}]}}}}}, {?eh,test_stats,{5,2,{0,0}}}, {?eh,tc_start,{repeat_1_SUITE,tc_fail_2}}, {?eh,tc_done, diff --git a/lib/common_test/test/ct_skip_SUITE.erl b/lib/common_test/test/ct_skip_SUITE.erl index 4ba4479208..6a8c57a6bd 100644 --- a/lib/common_test/test/ct_skip_SUITE.erl +++ b/lib/common_test/test/ct_skip_SUITE.erl @@ -369,7 +369,7 @@ test_events(auto_skip) -> {test_server,my_apply,3}, {test_server,init_per_testcase,3}, {test_server,run_test_case_eval1,6}, - {test_server,run_test_case_eval,8}]}}}}}}, + {test_server,run_test_case_eval,9}]}}}}}}, {?eh,tc_start, {auto_skip_9_SUITE,{end_per_group,g5,[parallel]}}}, {?eh,tc_done, diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 039ea720a8..ea55b22603 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -612,6 +612,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> print(minor, "Current directory is ~p\n", [Cwd]), print_timestamp(minor,"Started at "), TCCallback = get(test_server_testcase_callback), + LogOpts = get(test_server_logopts), Ref = make_ref(), OldGLeader = group_leader(), %% Set ourself to group leader for the spawned process @@ -621,7 +622,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> fun() -> run_test_case_eval(Mod, Func, Args, Name, Ref, RunInit, TimetrapData, - TCCallback) + LogOpts, TCCallback) end), group_leader(OldGLeader, self()), put(test_server_detected_fail, []), @@ -979,7 +980,8 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, E = {failed,Reason} -> {E,{error,Reason}}; Result -> - {Result,Result} + E = {failed,{Mod,end_per_testcase,Why}}, + {Result,E} end, FailLoc = proplists:get_value(tc_fail_loc, EndConf), case catch do_end_tc_call(Mod,Func, FailLoc, @@ -1092,8 +1094,9 @@ job_proxy_msgloop() -> %% or sends a message {failed, File, Line} to it's group_leader run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit, - TimetrapData, TCCallback) -> - put(test_server_multiply_timetraps,TimetrapData), + TimetrapData, LogOpts, TCCallback) -> + put(test_server_multiply_timetraps, TimetrapData), + put(test_server_logopts, LogOpts), {{Time,Value},Loc,Opts} = case test_server_sup:framework_call(init_tc,[?pl2a(Mod),Func,Args0], -- cgit v1.2.3 From 942e776f874a5eecf392c917ce6e847a7bef9c85 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Wed, 21 Sep 2011 17:17:31 +0200 Subject: Add cases to check test case status versus end_per_testcase failure --- .../error/test/cfg_error_9_SUITE.erl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl index c4e0d72948..f292985c0c 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl @@ -76,7 +76,7 @@ init_per_testcase(tc1, Config) -> Config; init_per_testcase(tc2, Config) -> ct:comment("init_per_testcase(tc2) timeout"), - timer:sleep(5000), + ct:sleep(5000), Config; init_per_testcase(tc3, Config) -> badmatch = ?config(void, Config), @@ -96,22 +96,20 @@ init_per_testcase(_, Config) -> %%-------------------------------------------------------------------- end_per_testcase(tc11, _Config) -> ct:comment("A warning should be printed"), - exit(warning_should_be_printed), - done; + exit(warning_should_be_printed); end_per_testcase(tc12, _Config) -> ct:comment("A warning should be printed"), - timer:sleep(5000), - done; + ct:sleep(5000); end_per_testcase(tc13, Config) -> ct:comment("A warning should be printed"), - badmatch = ?config(void, Config), - done; + badmatch = ?config(void, Config); end_per_testcase(tc14, Config) -> ok = ?config(tc_status, Config), {fail,tc14_should_be_failed}; end_per_testcase(tc15, Config) -> - {failed,byebye} = ?config(tc_status, Config), - ok; + exit(kaboom); +end_per_testcase(tc16, Config) -> + ct:sleep(5000); end_per_testcase(_TestCase, _Config) -> done. @@ -139,7 +137,7 @@ groups() -> %%-------------------------------------------------------------------- all() -> [tc1,tc2,tc3,tc4,tc5,tc6,tc7, - tc11,tc12,tc13,tc14]. + tc11,tc12,tc13,tc14,tc15,tc16]. tc1(_) -> fini. @@ -189,4 +187,6 @@ tc14(_) -> ct:comment("This one should be failed by eptc"), yes. tc15(_) -> - exit(byebye). + exit(this_error_must_show). +tc16(_) -> + exit(this_error_must_show). -- cgit v1.2.3 From d7391d973f453de4749857291680380b60330bc7 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Wed, 21 Sep 2011 23:14:34 +0200 Subject: Fix problem with error message not being printed correctly --- lib/test_server/src/test_server.erl | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index ea55b22603..ae54925c2e 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -746,6 +746,9 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) -> Other end, run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate1,NewComment2,CurrConf); + {read_comment,From} -> + From ! {self(),read_comment,Comment}, + run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf); {set_curr_conf,NewCurrConf} -> run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,NewCurrConf); {'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} -> @@ -1443,9 +1446,13 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> {'$test_server_ok',_} -> ok; {'EXIT',Reason} = Why -> - comment(io_lib:format("" + Comment0 = case read_comment() of + "" -> ""; + Cmt -> Cmt ++ "
" + end, + comment(io_lib:format("~s" "WARNING: ~w crashed!" - "\n",[EndFunc])), + "
\n",[Comment0,EndFunc])), group_leader() ! {printout,12, "WARNING: ~w crashed!\n" "Reason: ~p\n" @@ -1455,9 +1462,13 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> mod_loc(get_loc()))]}, {failed,{Mod,end_per_testcase,Why}}; Other -> - comment(io_lib:format("" + Comment0 = case read_comment() of + "" -> ""; + Cmt -> Cmt ++ "
" + end, + comment(io_lib:format("~s" "WARNING: ~w thrown!" - "\n",[EndFunc])), + "
\n",[Comment0,EndFunc])), group_leader() ! {printout,12, "WARNING: ~w thrown!\n" "Reason: ~p\n" @@ -2363,6 +2374,22 @@ comment(String) -> group_leader() ! {comment,String}, ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% read_comment() -> string() +%% +%% Read the current comment string stored in +%% state during test case execution. +read_comment() -> + MsgLooper = group_leader(), + MsgLooper ! {read_comment,self()}, + receive + {MsgLooper,read_comment,Comment} -> + Comment + after + 5000 -> + "" + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% os_type() -> OsType %% -- cgit v1.2.3 From 11107d76a34667ec87668b2624a0f3df43dea655 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 22 Sep 2011 12:46:12 +0200 Subject: Fix error with incorrect notification after end_per_testcase craches --- lib/common_test/test/ct_error_SUITE.erl | 29 +++++++++++++++++------------ lib/test_server/src/test_server.erl | 9 +++++++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index 6231e27644..c3c77d17cd 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -260,7 +260,7 @@ test_events(cfg_error) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{14,14,43}}, + {?eh,start_info,{14,14,45}}, {?eh,tc_start,{cfg_error_1_SUITE,init_per_suite}}, {?eh,tc_done, @@ -567,8 +567,13 @@ test_events(cfg_error) -> {?eh,tc_start,{cfg_error_9_SUITE,tc14}}, {?eh,tc_done, {cfg_error_9_SUITE,tc14,{failed,{error,tc14_should_be_failed}}}}, - {?eh,test_stats,{12,4,{0,18}}}, - + {?eh,tc_start,{cfg_error_9_SUITE,tc15}}, + {?eh,tc_done, + {cfg_error_9_SUITE,tc15,{failed,{error,this_error_must_show}}}}, + {?eh,tc_start,{cfg_error_9_SUITE,tc16}}, + {?eh,tc_done, + {cfg_error_9_SUITE,tc16,{failed,{error,this_error_must_show}}}}, + {?eh,test_stats,{12,6,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_9_SUITE,end_per_suite,ok}}, @@ -578,7 +583,7 @@ test_events(cfg_error) -> {?eh,tc_auto_skip,{cfg_error_10_SUITE,tc1, {failed,{cfg_error_10_SUITE,init_per_suite, {failed,fail_init_per_suite}}}}}, - {?eh,test_stats,{12,4,{0,19}}}, + {?eh,test_stats,{12,6,{0,19}}}, {?eh,tc_auto_skip,{cfg_error_10_SUITE,end_per_suite, {failed,{cfg_error_10_SUITE,init_per_suite, {failed,fail_init_per_suite}}}}}, @@ -587,40 +592,40 @@ test_events(cfg_error) -> {?eh,tc_start,{cfg_error_11_SUITE,tc1}}, {?eh,tc_done,{cfg_error_11_SUITE,tc1, {skipped,{config_name_already_in_use,[dummy0]}}}}, - {?eh,test_stats,{12,4,{1,19}}}, + {?eh,test_stats,{12,6,{1,19}}}, {?eh,tc_start,{cfg_error_11_SUITE,tc2}}, {?eh,tc_done,{cfg_error_11_SUITE,tc2,ok}}, - {?eh,test_stats,{13,4,{1,19}}}, + {?eh,test_stats,{13,6,{1,19}}}, {?eh,tc_start,{cfg_error_11_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_11_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_12_SUITE,tc1}}, {?eh,tc_done,{cfg_error_12_SUITE,tc1,{failed,{timetrap_timeout,500}}}}, - {?eh,test_stats,{13,5,{1,19}}}, + {?eh,test_stats,{13,7,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc2}}, {?eh,tc_done,{cfg_error_12_SUITE,tc2,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{14,5,{1,19}}}, + {?eh,test_stats,{14,7,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc3}}, {?eh,tc_done,{cfg_error_12_SUITE,tc3,ok}}, - {?eh,test_stats,{15,5,{1,19}}}, + {?eh,test_stats,{15,7,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc4}}, {?eh,tc_done,{cfg_error_12_SUITE,tc4,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{16,5,{1,19}}}, + {?eh,test_stats,{16,7,{1,19}}}, {?eh,tc_start,{cfg_error_13_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_13_SUITE,tc1}}, {?eh,tc_done,{cfg_error_13_SUITE,tc1,ok}}, - {?eh,test_stats,{17,5,{1,19}}}, + {?eh,test_stats,{17,7,{1,19}}}, {?eh,tc_start,{cfg_error_13_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,tc1}}, {?eh,tc_done,{cfg_error_14_SUITE,tc1,ok}}, - {?eh,test_stats,{18,5,{1,19}}}, + {?eh,test_stats,{18,7,{1,19}}}, {?eh,tc_start,{cfg_error_14_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,end_per_suite, {comment, diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index ae54925c2e..303ee3ae95 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -1194,12 +1194,17 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> SaveCfg1={save_config,_} -> {FWReturn,TSReturn,[SaveCfg1|lists:keydelete(save_config,1, EndConf1)]}; - {fail,ReasonToFail} -> % user has failed the testcase + {fail,ReasonToFail} -> + %% user has failed the testcase fw_error_notify(Mod, Func, EndConf1, ReasonToFail), {{error,ReasonToFail},{failed,ReasonToFail},EndConf1}; - {failed,{_,end_per_testcase,_}} = Failure -> % unexpected termination + {failed,{_,end_per_testcase,_}} = Failure when FWReturn == ok -> + %% unexpected termination in end_per_testcase + %% report this as the result to the framework {Failure,TSReturn,EndConf1}; _ -> + %% test case result should be reported to framework + %% no matter the status of end_per_testcase {FWReturn,TSReturn,EndConf1} end, %% clear current state in controller loop -- cgit v1.2.3 From 57a84ad4a044a74b19d8b956121feb943bbd5b3a Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 22 Sep 2011 13:01:31 +0200 Subject: Correct error in test suite --- lib/common_test/test/ct_error_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index c3c77d17cd..ebbf6f3bf3 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -659,7 +659,7 @@ test_events(lib_error) -> {?eh,test_stats,{0,2,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,lines_hang}}, {?eh,tc_done, - {lib_lines,do_hang,{failed,{timetrap_timeout,3000}}}}, + {lib_error_1_SUITE,lines_hang,{failed,{timetrap_timeout,3000}}}}, {?eh,test_stats,{0,3,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,lines_throw}}, {?eh,tc_done, -- cgit v1.2.3 From 178940b2184bb3cdaa79d9d51b09c54fbfe68300 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 22 Sep 2011 16:40:52 +0200 Subject: Fix crash when CTHook init fails --- lib/common_test/src/ct_util.erl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index f393ea103d..3b6ad6f98d 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -182,7 +182,11 @@ do_start(Parent,Mode,LogDir) -> %% Initialize ct_hooks try ct_hooks:init(Opts) of ok -> - Parent ! {self(),started} + Parent ! {self(),started}; + {fail,CTHReason} -> + ct_logs:tc_print('Suite Callback',CTHReason,[]), + self() ! {{stop,{self(),{user_error,CTHReason}}}, + {Parent,make_ref()}} catch _:CTHReason -> ct_logs:tc_print('Suite Callback',CTHReason,[]), -- cgit v1.2.3 From c7d6fa638a635a9abc7c2f10071f755032ba3617 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 22 Sep 2011 18:48:56 +0200 Subject: Fix problem with location value when init config func calls help func --- .../test_server_if/test/ts_if_1_SUITE.erl | 2 +- lib/test_server/src/test_server.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common_test/test/ct_test_server_if_1_SUITE_data/test_server_if/test/ts_if_1_SUITE.erl b/lib/common_test/test/ct_test_server_if_1_SUITE_data/test_server_if/test/ts_if_1_SUITE.erl index 47cea190dd..bda7d91161 100644 --- a/lib/common_test/test/ct_test_server_if_1_SUITE_data/test_server_if/test/ts_if_1_SUITE.erl +++ b/lib/common_test/test/ct_test_server_if_1_SUITE_data/test_server_if/test/ts_if_1_SUITE.erl @@ -143,7 +143,7 @@ tc1(_) -> exit(should_have_been_skipped). tc2(_) -> - exit(should_have_been_skipped). + timeout_in_end_per_testcase. tc3(_) -> timer:sleep(5000). diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 303ee3ae95..e1a139af6f 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -1235,7 +1235,7 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> %% call user callback function if defined Return1 = user_callback(TCCallback, Mod, Func, 'end', Return), {Return2,Opts} = process_return_val([Return1], Mod, Func, - Args1, Loc, Return1), + Args1, {Mod,Func}, Return1), {{T,Return2},Loc,Opts} end. -- cgit v1.2.3 From 18a662a84f65ffd9e8bea60a2948d9b42c3c81f7 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 22 Sep 2011 18:50:19 +0200 Subject: Add link to last executed test suite on index page OTP-9520 --- lib/common_test/src/ct_logs.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index f34eb83afa..0580a814c4 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -509,6 +509,7 @@ logger_loop(State) -> print_style(GL, State#logger_state.stylesheet), set_evmgr_gl(GL), TCGLs = add_tc_gl(TCPid,GL,State), + make_last_run_index(State#logger_state.start_time), return(From,ok), logger_loop(State#logger_state{tc_groupleaders=TCGLs}); {{end_tc,TCPid},From} -> -- cgit v1.2.3 From 22feee99b91818456ee2fcb70fb065b4dee0536e Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 22 Sep 2011 22:24:20 +0200 Subject: Change order of include files --- lib/common_test/test/ct_test_support.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 31381abc40..a396a9fad8 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -23,8 +23,8 @@ %%% -module(ct_test_support). --include_lib("test_server/include/test_server.hrl"). -include_lib("common_test/include/ct_event.hrl"). +-include_lib("common_test/include/ct.hrl"). -export([init_per_suite/1, init_per_suite/2, end_per_suite/1, init_per_testcase/2, end_per_testcase/2, -- cgit v1.2.3 From b2a37fbc00f29ee6208b0f02b36e9d2f919ecef7 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 23 Sep 2011 17:14:03 +0200 Subject: Enhance logging performance OTP-9575 --- lib/common_test/src/ct_framework.erl | 13 ++++++++----- lib/common_test/src/ct_logs.erl | 17 ++++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 089d5be871..63a7c37fa6 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -116,7 +116,7 @@ init_tc1(Mod,Func,[Config0],DoInit) when is_list(Config0) -> Config = lists:keydelete(watchdog,1,Config1), if Func /= init_per_suite, DoInit /= true -> ok; - true -> + true -> %% delete all default values used in previous suite ct_config:delete_default_config(suite), %% release all name -> key bindings (once per suite) @@ -133,7 +133,7 @@ init_tc1(Mod,Func,[Config0],DoInit) when is_list(Config0) -> ct_config:delete_default_config(testcase), case add_defaults(Mod,Func,TestCaseInfo,DoInit) of Error = {suite0_failed,_} -> - ct_logs:init_tc(), + ct_logs:init_tc(false), FuncSpec = group_or_func(Func,Config0), ct_event:notify(#event{name=tc_start, node=node(), @@ -143,7 +143,7 @@ init_tc1(Mod,Func,[Config0],DoInit) when is_list(Config0) -> {SuiteInfo,MergeResult} -> case MergeResult of {error,Reason} when DoInit == false -> - ct_logs:init_tc(), + ct_logs:init_tc(false), FuncSpec = group_or_func(Func,Config0), ct_event:notify(#event{name=tc_start, node=node(), @@ -194,8 +194,11 @@ init_tc2(Mod,Func,SuiteInfo,MergeResult,Config,DoInit) -> Conns -> ct_util:silence_connections(Conns) end, - - ct_logs:init_tc(), + if Func /= init_per_suite, DoInit /= true -> + ct_logs:init_tc(false); + true -> + ct_logs:init_tc(true) + end, FuncSpec = group_or_func(Func,Config), ct_event:notify(#event{name=tc_start, node=node(), diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 0580a814c4..3798f26f7b 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -28,7 +28,7 @@ -module(ct_logs). --export([init/1,close/2,init_tc/0,end_tc/1]). +-export([init/1,close/2,init_tc/1,end_tc/1]). -export([get_log_dir/0,log/3,start_log/1,cont_log/2,end_log/0]). -export([set_stylesheet/2,clear_stylesheet/1]). -export([add_external_logs/1,add_link/3]). @@ -197,15 +197,14 @@ cast(Msg) -> ?MODULE ! Msg end. - %%%----------------------------------------------------------------- -%%% @spec init_tc() -> ok +%%% @spec init_tc(RefreshLog) -> ok %%% %%% @doc Test case initiation (tool-internal use only). %%% %%%

This function is called by ct_framework:init_tc/3

-init_tc() -> - call({init_tc,self(),group_leader()}), +init_tc(RefreshLog) -> + call({init_tc,self(),group_leader(),RefreshLog}), ok. %%%----------------------------------------------------------------- @@ -505,11 +504,15 @@ logger_loop(State) -> [begin io:format(Fd,Str,Args),io:nl(Fd) end || {Str,Args} <- List], logger_loop(State#logger_state{tc_groupleaders=TCGLs}) end; - {{init_tc,TCPid,GL},From} -> + {{init_tc,TCPid,GL,RefreshLog},From} -> print_style(GL, State#logger_state.stylesheet), set_evmgr_gl(GL), TCGLs = add_tc_gl(TCPid,GL,State), - make_last_run_index(State#logger_state.start_time), + if not RefreshLog -> + ok; + true -> + make_last_run_index(State#logger_state.start_time) + end, return(From,ok), logger_loop(State#logger_state{tc_groupleaders=TCGLs}); {{end_tc,TCPid},From} -> -- cgit v1.2.3 From cf69b30f660149c0f39e9cc22b00fb3a90c613b8 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 23 Sep 2011 17:15:42 +0200 Subject: Update vsn.mk for common_test and test_server --- lib/common_test/vsn.mk | 2 +- lib/test_server/vsn.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index f77629b4d1..4782a32933 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1,3 +1,3 @@ -COMMON_TEST_VSN = 1.5.4 +COMMON_TEST_VSN = 1.5.5 diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk index 1dd4a84ce9..563c1b6db6 100644 --- a/lib/test_server/vsn.mk +++ b/lib/test_server/vsn.mk @@ -1,2 +1,2 @@ -TEST_SERVER_VSN = 3.4.4 +TEST_SERVER_VSN = 3.4.5 -- cgit v1.2.3 From ec17d32dffaed75da4e6f1bb6d4e14ff40d59a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 21 Sep 2011 19:44:34 +0200 Subject: Remove static ssl linking in crypto for otp_build --- erts/configure.in | 2 +- otp_build | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/erts/configure.in b/erts/configure.in index fac07f8b6a..9dce264e2d 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3535,7 +3535,7 @@ AC_SUBST(STATIC_KERBEROS_LIBS) AC_SUBST(SSL_LINK_WITH_ZLIB) AC_SUBST(STATIC_ZLIB_LIBS) -std_ssl_locations="/usr/local /usr/sfw /opt/local /usr /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/openssl /usr/local/ssl /usr/lib/ssl /usr/ssl" +std_ssl_locations="/usr/local /usr/sfw /usr /opt/local /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/openssl /usr/local/ssl /usr/lib/ssl /usr/ssl" AC_ARG_WITH(ssl-zlib, AS_HELP_STRING([--with-ssl-zlib=PATH], diff --git a/otp_build b/otp_build index ed4609435f..de27fbc288 100755 --- a/otp_build +++ b/otp_build @@ -186,15 +186,15 @@ set_config_flags () if target_contains free_source; then CONFIG_FLAGS="$CONFIG_FLAGS --host=$TARGET" fi - # Link SSL static for all binary distributions if not overridden - # Even for win32 starting with R14B03 - XX=`echo $* | grep -v dynamic-ssl-lib` - if [ "$*" = "$XX" ]; then - CONFIG_FLAGS="--disable-dynamic-ssl-lib $CONFIG_FLAGS" - fi + # Link SSL static for win32 binary distributions if not overridden if target_contains win32; then + XX=`echo $* | grep -v dynamic-ssl-lib` + if [ "$*" = "$XX" ]; then + CONFIG_FLAGS="--disable-dynamic-ssl-lib $CONFIG_FLAGS" + fi CONFIG_FLAGS="--build=$BUILDSYS build_alias=win32 --host=win32 --target=win32 $CONFIG_FLAGS" fi + if [ "x$OVERRIDE_CONFIG_CACHE" = "x" ]; then CONFIG_FLAGS="$CONFIG_FLAGS --cache-file=/dev/null" -- cgit v1.2.3 From b8a50348bf4c0ceb8c7839bb243871fd96f0ea7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 22 Sep 2011 14:28:30 +0200 Subject: Change static link test of ssl to dynamic Only used for commercial builds --- lib/crypto/test/crypto_SUITE.erl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 283aadb6ea..10b1737a91 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -138,14 +138,15 @@ link_test_2(Drv) -> Libs = os:cmd(Cmd), io:format("~p\n", [Libs]), case string:str(Libs, "libcrypto") of - 0 -> ok; - _ -> + 0 -> case ?t:is_commercial() of true -> - ?t:fail({libcrypto,not_statically_linked}); + ?t:fail({libcrypto,statically_linked}); false -> - {comment,"Not statically linked (OK for open-source platform)"} - end + {comment,"Statically linked (OK for open-source platform)"} + end; + _ -> + ok end end. -- cgit v1.2.3 From 756f30146091d0383566b5291a85cc6c4198869b Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 19 Jul 2011 12:05:29 +0200 Subject: removed files that should not be checked in --- lib/eunit/AUTHORS | 2 - lib/eunit/doc/.gitignore | 4 + lib/eunit/doc/edoc-info | 3 - lib/eunit/doc/erlang.png | Bin 2109 -> 0 bytes lib/eunit/doc/eunit.html | 71 --- lib/eunit/doc/eunit_surefire.html | 78 --- lib/eunit/doc/index.html | 17 - lib/eunit/doc/modules-frame.html | 13 - lib/eunit/doc/overview-summary.html | 1032 ----------------------------------- lib/eunit/doc/packages-frame.html | 11 - lib/eunit/doc/stylesheet.css | 55 -- 11 files changed, 4 insertions(+), 1282 deletions(-) delete mode 100644 lib/eunit/AUTHORS create mode 100644 lib/eunit/doc/.gitignore delete mode 100644 lib/eunit/doc/edoc-info delete mode 100644 lib/eunit/doc/erlang.png delete mode 100644 lib/eunit/doc/eunit.html delete mode 100644 lib/eunit/doc/eunit_surefire.html delete mode 100644 lib/eunit/doc/index.html delete mode 100644 lib/eunit/doc/modules-frame.html delete mode 100644 lib/eunit/doc/overview-summary.html delete mode 100644 lib/eunit/doc/packages-frame.html delete mode 100644 lib/eunit/doc/stylesheet.css diff --git a/lib/eunit/AUTHORS b/lib/eunit/AUTHORS deleted file mode 100644 index b7c1426aff..0000000000 --- a/lib/eunit/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Richard Carlsson -Mickaël Rémond diff --git a/lib/eunit/doc/.gitignore b/lib/eunit/doc/.gitignore new file mode 100644 index 0000000000..7fcda5db42 --- /dev/null +++ b/lib/eunit/doc/.gitignore @@ -0,0 +1,4 @@ +*.html +stylesheet.css +erlang.png +edoc-info diff --git a/lib/eunit/doc/edoc-info b/lib/eunit/doc/edoc-info deleted file mode 100644 index 1c04b2ed1a..0000000000 --- a/lib/eunit/doc/edoc-info +++ /dev/null @@ -1,3 +0,0 @@ -{application,eunit}. -{packages,[]}. -{modules,[eunit,eunit_surefire]}. diff --git a/lib/eunit/doc/erlang.png b/lib/eunit/doc/erlang.png deleted file mode 100644 index 987a618e24..0000000000 Binary files a/lib/eunit/doc/erlang.png and /dev/null differ diff --git a/lib/eunit/doc/eunit.html b/lib/eunit/doc/eunit.html deleted file mode 100644 index a181d12ce3..0000000000 --- a/lib/eunit/doc/eunit.html +++ /dev/null @@ -1,71 +0,0 @@ - - - -Module eunit - - - - -
- -

Module eunit

-This module is the main EUnit user interface. -

Copyright © 2004-2009 Mickaël Rémond, Richard Carlsson

- -

Version: 2.1.1, Apr 22 2009 22:37:19

-

Authors: Mickaël Rémond (mickael.remond@process-one.net) [web site: http://www.process-one.net/], Richard Carlsson (richardc@it.uu.se) [web site: http://user.it.uu.se/~richardc/].

- -

Description

This module is the main EUnit user interface. -

Function Index

- - - - -
start/0Starts the EUnit server.
stop/0Stops the EUnit server.
test/1Equivalent to test(Tests, []). -
test/2Runs a set of tests.
- -

Function Details

- -

start/0

-
-

start() -> any()

-

Starts the EUnit server. Normally, you don't need to call this - function; it is started automatically.

- -

stop/0

-
-

stop() -> any()

-

Stops the EUnit server. Normally, you don't need to call this - function.

- -

test/1

-
-

test(Tests) -> any()

-

Equivalent to test(Tests, []).

- - -

test/2

-
-

test(Tests::term(), Options::[term()]) -> ok | {error, term()}

-

Runs a set of tests. The format of Tests is described in the - section EUnit test - representation of the overview.

- - Example:
  eunit:test(fred)

runs all tests in the module fred - and also any tests in the module fred_tests, if that module exists.

- - Options: -
-
verbose
-
Displays more details about the running tests.
-
- - Options in the environment variable EUNIT are also included last in - the option list, i.e., have lower precedence than those in Options.

-

See also: test/1.

-
- - -

Generated by EDoc, Apr 22 2009, 22:37:19.

- - diff --git a/lib/eunit/doc/eunit_surefire.html b/lib/eunit/doc/eunit_surefire.html deleted file mode 100644 index f2ecbae572..0000000000 --- a/lib/eunit/doc/eunit_surefire.html +++ /dev/null @@ -1,78 +0,0 @@ - - - -Module eunit_surefire - - - - -
- -

Module eunit_surefire

-Surefire reports for EUnit (Format used by Maven and Atlassian -Bamboo for example to integrate test results). -

Copyright © 2009 Mickaël Rémond, Paul Guyot

- -

Behaviours: eunit_listener.

-

Authors: Mickaël Rémond (mremond@process-one.net).

-

See also: eunit.

- -

Description

Surefire reports for EUnit (Format used by Maven and Atlassian -Bamboo for example to integrate test results). Based on initial code -from Paul Guyot.

- - Example: Generate XML result file in the current directory: -
     eunit:test([fib, eunit_examples],
-                [{report,{eunit_surefire,[{dir,"."}]}}]).
-

Function Index

- - - - - - - -
handle_begin/3
handle_cancel/3
handle_end/3
init/1
start/0
start/1
terminate/2
- -

Function Details

- -

handle_begin/3

-
-

handle_begin(X1, Data, St) -> any()

-
- -

handle_cancel/3

-
-

handle_cancel(X1, Data, St) -> any()

-
- -

handle_end/3

-
-

handle_end(X1, Data, St) -> any()

-
- -

init/1

-
-

init(Options) -> any()

-
- -

start/0

-
-

start() -> any()

-
- -

start/1

-
-

start(Options) -> any()

-
- -

terminate/2

-
-

terminate(X1, St) -> any()

-
-
- - -

Generated by EDoc, Apr 22 2009, 22:37:19.

- - diff --git a/lib/eunit/doc/index.html b/lib/eunit/doc/index.html deleted file mode 100644 index 9bd8e8cf6b..0000000000 --- a/lib/eunit/doc/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - -The eunit application - - - - - - -<h2>This page uses frames</h2> -<p>Your browser does not accept frames. -<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. -</p> - - - \ No newline at end of file diff --git a/lib/eunit/doc/modules-frame.html b/lib/eunit/doc/modules-frame.html deleted file mode 100644 index a484e99d4c..0000000000 --- a/lib/eunit/doc/modules-frame.html +++ /dev/null @@ -1,13 +0,0 @@ - - - -The eunit application - - - -

Modules

- - -
eunit
eunit_surefire
- - \ No newline at end of file diff --git a/lib/eunit/doc/overview-summary.html b/lib/eunit/doc/overview-summary.html deleted file mode 100644 index ea7beba8b3..0000000000 --- a/lib/eunit/doc/overview-summary.html +++ /dev/null @@ -1,1032 +0,0 @@ - - - -EUnit - a Lightweight Unit Testing Framework for Erlang - - - - - -

EUnit - a Lightweight Unit Testing Framework for Erlang -

-

Copyright © 2004-2007 Mickaël Rémond, Richard Carlsson

-

Version: 2.1.1, Apr 22 2009 22:37:19 -

-

Authors: Richard Carlsson (richardc@it.uu.se) [web site: http://user.it.uu.se/~richardc/], Mickaël Rémond (mickael.remond@process-one.net) [web site: http://www.process-one.net/].

-

EUnit is a unit testing framework for Erlang. It is very powerful -and flexible, is easy to use, and has small syntactical overhead.

- - - -

EUnit builds on ideas from the family of unit testing frameworks for -Object Oriented languages that originated with JUnit by Beck and Gamma -(and Beck's previous framework SUnit for Smalltalk). However, EUnit uses -techniques more adapted to functional and concurrent programming, and is -typically less verbose than its relatives.

- -

Although EUnit uses many preprocessor macros, they have been designed to -be as nonintrusive as possible, and should not cause conflicts with -existing code. Adding EUnit tests to a module should thus not normally -require changing existing code. Furthermore, tests that only exercise -the exported functions of a module can always be placed in a completely -separate module, avoiding any conflicts entirely.

- -

Unit testing

- -

Unit Testing is testing of individual program "units" in relative -isolation. There is no particular size requirement: a unit can be a -function, a module, a process, or even a whole application, but the most -typical testing units are individual functions or modules. In order to -test a unit, you specify a set of individual tests, set up the smallest -necessary environment for being able to run those tests (often, you -don't need to do any setup at all), you run the tests and collect the -results, and finally you do any necessary cleanup so that the test can -be run again later. A Unit Testing Framework tries to help you in each -stage of this process, so that it is easy to write tests, easy to run -them, and easy to see which tests failed (so you can fix the bugs).

- -

Advantages of unit testing

- -
-
Reduces the risks of changing the program
-
Most programs will be modified during their lifetime: bugs will be - fixed, features will be added, optimizations may become necessary, or - the code will need to be refactored or cleaned up in other ways to - make it easier to work with. But every change to a working program is - a risk of introducing new bugs - or reintroducing bugs that had - previously been fixed. Having a set of unit tests that you can run - with very little effort makes it easy to know that the code still - works as it should (this use is called regression testing; - see Terminology). This goes a long way to reduce the - resistance to changing and refactoring code.
-
Helps guide and speed up the development process
-
By focusing on getting the code to pass the tests, the programmer - can become more productive, not overspecify or get lost in premature - optimizations, and create code that is correct from the very beginning - (so-called test-driven development; see Terminology).
-
Helps separate interface from implementation
-
When writing tests, the programmer may discover dependencies - (in order to get the tests to run) that ought not to be there, and - which need to be abstracted away to get a cleaner design. This helps - eliminate bad dependencies before they spread throughout the - code.
-
Makes component integration easier
-
By testing in a bottom-up fashion, beginning with the smallest - program units and creating a confidence in that they work as they - should, it becomes easier to test that a higher-level component, - consisting of several such units, also behaves according to - specification (known as integration testing; see Terminology).
-
Is self-documenting
-
The tests can be read as documentation, typically showing both - examples of correct and incorrect usage, along with the expected - consequences.
-
- -

Terminology

- -
-
Unit testing
-
Testing that a program unit behaves as it is supposed to do (in - itself), according to its specifications. Unit tests have an important - function as regression tests, when the program later is modified for - some reason, since they check that the program still behaves according - to specification.
-
Regression testing
-
Running a set of tests after making changes to a program, to check - that the program behaves as it did before the changes (except, of - course, for any intentional changes in behaviour). Unit tests are - important as regression tests, but regression testing can involve more - than just unit testing, and may also test behaviour that might not be - part of the normal specification (such as bug-for-bug-compatibility). -
-
Integration testing
-
Testing that a number of individually developed program units - (assumed to already have been separately unit tested) work together as - expected. Depending on the system being developed, integration testing - may be as simple as "just another level of unit testing", but might - also involve other kinds of tests (compare system testing). -
-
System testing
-
Testing that a complete system behaves according to its - specification. Specifically, system testing should not require knowing - any details about the implementation. It typically involves testing - many different aspects of the system behaviour apart from the basic - functionality, such as performance, usability, and reliability.
-
Test-driven development
-
A program development technique where you continuously write tests - before you implement the code that is supposed to pass those - tests. This can help you focus on solving the right problems, and not - make a more complicated implementation than necessary, by letting the - unit tests determine when a program is "done": if it fulfils its - specifications, there is no need to keep adding functionality.
-
Mock object
-
Sometimes, testing some unit A (e.g., a function) requires that - it collaborates somehow with some other unit B (perhaps being passed - as an argument, or by reference) - but B has not been implemented - yet. A "mock object" - an object which, for the purposes of testing - A, looks and behaves like a real B - might then be used instead. - (This is of course only useful if it would be significantly more work - to implement a real B than to create a mock object.)
-
Test case
-
A single, well-defined test, that somehow can be uniquely - identified. When executed, the test case either passes or - fails; the test report should identify exactly which test - cases failed.
-
Test suite
-
A collection of test cases, generally with a specific, common - target for testing, such as a single function, module, or subsystem. A - test suite may also be recursively composed by smaller test - suites.
-
- -

Getting started

- - -

Including the EUnit header file

- -The simplest way to use EUnit in an Erlang module is to add the -following line at the beginning of the module (after the -module -declaration, but before any function definitions): -
   -include_lib("eunit/include/eunit.hrl").
- -This will have the following effect: -
    -
  • Creates an exported function test() (unless testing is turned - off, and the module does not already contain a test() function), that - can be used to run all the unit tests defined in the module
  • -
  • Causes all functions whose names match ..._test() or ..._test_() - to be automatically exported from the module (unless testing is - turned off, or the EUNIT_NOAUTO macro is defined)
  • -
  • Makes all the preprocessor macros of EUnit available, to help - writing tests
  • -
- -Note: For -include_lib(...) to work, the Erlang -module search path must contain a directory whose name ends in -eunit/ebin (pointing to the ebin subdirectory of the EUnit -installation directory). If EUnit is installed as lib/eunit under your -Erlang/OTP system directory, its ebin subdirectory will be -automatically added to the search path when Erlang starts. Otherwise, -you need to add the directory explicitly, by passing a -pa flag to the -erl or erlc command. For example, a Makefile could contain the -following action for compiling .erl files: -
   erlc -pa "path/to/eunit/ebin" $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
-or if you want Eunit to always be available when you run Erlang -interactively, you can add a line like the following to your -$HOME/.erlang file: -
   code:add_path("/path/to/eunit/ebin").
- -

Writing simple test functions

- -

The EUnit framework makes it extremely easy to write unit tests in -Erlang. There are a few different ways of writing them, though, so we -start with the simplest:

- -

A function with a name ending in ..._test() is recognized by EUnit as -a simple test function - it takes no arguments, and its execution either -succeeds (returning some arbitrary value that EUnit will throw away), or -fails by throwing an exception of some kind (or by not terminating, in -which case it will be aborted after a while).

- -An example of a simple test function could be the following: -
   reverse_test() -> lists:reverse([1,2,3]).

-This just tests that the function lists:reverse(List) does not crash -when List is [1,2,3]. It is not a great test, but many people write -simple functions like this one to test the basic functionality of their -code, and those tests can be used directly by EUnit, without changes, -as long as their function names match.

- -
Use exceptions to signal failure
- -To write more interesting tests, we need to make them crash (throw an -exception) when they don't get the result they expect. A simple way of -doing this is to use pattern matching with =, as in the following -examples: -
   reverse_nil_test() -> [] = lists:reverse([]).
-   reverse_one_test() -> [1] = lists:reverse([1]).
-   reverse_two_test() -> [2,1] = lists:reverse([1,2]).

-If there was some bug in lists:reverse/1 that made it return something -other than [2,1] when it got [1,2] as input, then the last test -above would throw a badmatch error. The first two (we assume they do -not get a badmatch) would simply return [] and [1], respectively, -so both succeed. (Note that EUnit is not psychic: if you write a test -that returns a value, even if it is the wrong value, EUnit will consider -it a success. You must make sure that the test is written so that it -causes a crash if the result is not what it should be.)

- -
Using assert macros
- -If you want to use Boolean operators for your tests, the assert -macro comes in handy (see EUnit macros for details): -
   length_test() -> ?assert(length([1,2,3]) =:= 3).

-The ?assert(Expression) macro will evaluate Expression, and if that -does not evaluate to true, it will throw an exception; otherwise it -just returns ok. In the above example, the test will thus fail if the -call to length does not return 3.

- -

Running EUnit

- -

If you have added the declaration --include_lib("eunit/include/eunit.hrl") to your module, as described -above, you only need to compile the module, and run the automatically -exported function test(). For example, if your module was named m, -then calling m:test() will run EUnit on all the tests defined in the -module. You do not need to write -export declarations for the test -functions. This is all done by magic.

- -

You can also use the function eunit:test/1 to run arbitrary -tests, for example to try out some more advanced test descriptors (see -EUnit test representation). For example, running -eunit:test(m) does the same thing as the auto-generated function -m:test(), while eunit:test({inparallel, m}) runs the same test -cases but executes them all in parallel.

- -
Putting tests in separate modules
- -

If you want to separate your test code from your normal code (at least -for testing the exported functions), you can simply write the test -functions in a module named m_tests (note: not m_test), if your -module is named m. Then, whenever you ask EUnit to test the module -m, it will also look for the module m_tests and run those tests as -well. See ModuleName in the section Primitives for details.

- -
EUnit captures standard output
- -

If your test code writes to the standard output, you may be surprised to -see that the text does not appear on the console when the tests are -running. This is because EUnit captures all standard output from test -functions (this also includes setup and cleanup functions, but not -generator functions), so that it can be included in the test report if -errors occur. To bypass EUnit and print text directly to the console -while testing, you can write to the user output stream, as in -io:format(user, "~w", [Term]). The recommended way of doing this is to -use the EUnit Debugging macros, which make it much simpler.

- -

Writing test generating functions

- -

A drawback of simple test functions is that you must write a separate -function (with a separate name) for each test case. A more compact way -of writing tests (and much more flexible, as we shall see), is to write -functions that return tests, instead of being tests.

- -

A function with a name ending in ..._test_() (note the final -underscore) is recognized by EUnit as a test generator -function. Test generators return a representation of a set -of tests to be executed by EUnit.

- -
Representing a test as data
- -The most basic representation of a test is a single fun-expression that -takes no arguments. For example, the following test generator: -
   basic_test_() ->
-       fun () -> ?assert(1 + 1 =:= 2) end.
-will have the same effect as the following simple test: -
   simple_test() ->
-       ?assert(1 + 1 =:= 2).

-(in fact, EUnit will handle all simple tests just like it handles -fun-expressions: it will put them in a list, and run them one by one).

- -
Using macros to write tests
- -To make tests more compact and readable, as well as automatically add -information about the line number in the source code where a test -occurred (and reduce the number of characters you have to type), you can -use the _test macro (note the initial underscore character), like -this: -
   basic_test_() ->
-       ?_test(?assert(1 + 1 =:= 2)).

-The _test macro takes any expression (the "body") as argument, and -places it within a fun-expression (along with some extra information). -The body can be any kind of test expression, just like the body of a -simple test function.

- -
Underscore-prefixed macros create test objects
- -But this example can be made even shorter! Most test macros, such as the -family of assert macros, have a corresponding form with an initial -underscore character, which automatically adds a ?_test(...) wrapper. -The above example can then simply be written: -
   basic_test_() ->
-       ?_assert(1 + 1 =:= 2).

-which has exactly the same meaning (note the _assert instead of -assert). You can think of the initial underscore as signalling -test object.

- -

An example

- -Sometimes, an example says more than a thousand words. The following -small Erlang module shows how EUnit can be used in practice. -
   -module(fib).
-   -export([fib/1]).
-   -include_lib("eunit/include/eunit.hrl").
-
-   fib(0) -> 1;
-   fib(1) -> 1;
-   fib(N) when N > 1 -> fib(N-1) + fib(N-2).
-
-   fib_test_() ->
-       [?_assert(fib(0) =:= 1),
-	?_assert(fib(1) =:= 1),
-	?_assert(fib(2) =:= 2),
-	?_assert(fib(3) =:= 3),
-	?_assert(fib(4) =:= 5),
-	?_assert(fib(5) =:= 8),
-	?_assertException(error, function_clause, fib(-1)),
-	?_assert(fib(31) =:= 2178309)
-       ].
- -

(Author's note: When I first wrote this example, I happened to write a -* instead of + in the fib function. Of course, this showed up -immediately when I ran the tests.)

- -

See EUnit test representation for a full list of all the ways -you can specify test sets in EUnit.

- -

Disabling testing

- -Testing can be turned off by defining the NOTEST macro when compiling, -for example as an option to erlc, as in: -
   erlc -DNOTEST my_module.erl
-or by adding a macro definition to the code, before the EUnit header -file is included: -
   -define(NOTEST, 1).

-(the value is not important, but should typically be 1 or true). -Note that unless the EUNIT_NOAUTO macro is defined, disabling testing -will also automatically strip all test functions from the code, except -for any that are explicitly declared as exported.

- -For instance, to use EUnit in your application, but with testing turned -off by default, put the following lines in a header file: -
   -define(NOTEST, true).
-   -include_lib("eunit/include/eunit.hrl").
-and then make sure that every module of your application includes that -header file. This means that you have a only a single place to modify in -order to change the default setting for testing. To override the NOTEST -setting without modifying the code, you can define TEST in a compiler -option, like this: -
   erlc -DTEST my_module.erl
- -

See Compilation control macros for details about these -macros.

- -

Avoiding compile-time dependency on EUnit

- -If you are distributing the source code for your application for other -people to compile and run, you probably want to ensure that the code -compiles even if EUnit is not available. Like the example in the -previous section, you can put the following lines in a common header -file: -
   -ifdef(TEST).
-   -include_lib("eunit/include/eunit.hrl").
-   -endif.

-and, of course, also make sure that you place all test code that uses -EUnit macros within -ifdef(TEST) or -ifdef(EUNIT) sections.

- - -

EUnit macros

- -

Although all the functionality of EUnit is avaliable even without the -use of preprocessor macros, the EUnit header file defines a number of -such macros in order to make it as easy as possible to write unit tests -as compactly as possible and without getting too many details in the -way.

- -

Except where explicitly stated, using EUnit macros will never introduce -run-time dependencies on the EUnit library code, regardless of whether -your code is compiled with testing enabled or disabled.

- - - -

Basic macros

- -
-
_test(Expr)
-
Turns Expr into a "test object", by wrapping it in a -fun-expression and a source line number. Technically, this is the same -as {?LINE, fun () -> (Expr) end}. -
-
- -

Compilation control macros

- -
-
EUNIT
-
This macro is always defined to true whenever EUnit is enabled at -compile time. This is typically used to place testing code within -conditional compilation, as in: -
   -ifdef(EUNIT).
-       % test code here
-       ...
-   -endif.
-e.g., to ensure that the code can be compiled without including the -EUnit header file, when testing is disabled. See also the macros TEST -and NOTEST. -
- -
EUNIT_NOAUTO
-
If this macro is defined, the automatic exporting or stripping of -test functions will be disabled. -
- -
TEST
-

This macro is always defined (to true, unless previously defined -by the user to have another value) whenever EUnit is enabled at compile -time. This can be used to place testing code within conditional -compilation; see also the macros NOTEST and EUNIT.

- -

For testing code that is strictly dependent on EUnit, it may be -preferable to use the EUNIT macro for this purpose, while for code -that uses more generic testing conventions, using the TEST macro may -be preferred.

- -The TEST macro can also be used to override the NOTEST macro. If -TEST is defined before the EUnit header file is -included (even if NOTEST is also defined), then the code will be -compiled with EUnit enabled. -
- -
NOTEST
-

This macro is always defined (to true, unless previously defined -by the user to have another value) whenever EUnit is disabled -at compile time. (Compare the TEST macro.)

- -This macro can also be used for conditional compilation, but is more -typically used to disable testing: If NOTEST is defined -before the EUnit header file is included, and TEST -is not defined, then the code will be compiled with EUnit -disabled. See also Disabling testing. -
- -
NOASSERT
-
If this macro is defined, the assert macros will have no effect, -when testing is also disabled. See Assert macros. When -testing is enabled, the assert macros are always enabled automatically -and cannot be disabled. -
- -
ASSERT
-
If this macro is defined, it overrides the NOASSERT macro, forcing -the assert macros to always be enabled regardless of other settings. -
- -
NODEBUG
-
If this macro is defined, the debugging macros will have no effect. -See Debugging macros. NODEBUG also implies NOASSERT, -unless testing is enabled. -
- -
DEBUG
-
If this macro is defined, it overrides the NODEBUG macro, forcing -the debugging macros to be enabled. -
-
- -

Utility macros

- -

The following macros can make tests more compact and readable:

- -
-
LET(Var,Arg,Expr)
-
Creates a local binding Var = Arg in Expr. (This is the same as -(fun(Var)->(Expr)end)(Arg).) Note that the binding is not exported -outside of Expr, and that within Expr, this binding of Var will -shadow any binding of Var in the surrounding scope. -
-
IF(Cond,TrueCase,FalseCase)
-
Evaluates TrueCase if Cond evaluates to true, or otherwise -evaluates FalseCase if Cond evaluates to false. (This is the same -as (case (Cond) of true->(TrueCase); false->(FalseCase) end).) Note -that it is an error if Cond does not yield a boolean value. -
-
- -

Assert macros

- -

(Note that these macros also have corresponding forms which start with -an "_" (underscore) character, as in ?_assert(BoolExpr), that create -a "test object" instead of performing the test immediately. This is -equivalent to writing ?_test(assert(BoolExpr)), etc.)

- -

If the macro NOASSERT is defined before the EUnit header file is -included, these macros have no effect when testing is also disabled; see -Compilation control macros for details.

- -
-
assert(BoolExpr)
-

Evaluates the expression BoolExpr, if testing is enabled. Unless -the result is true, an informative exception will be generated. If -there is no exception, the result of the macro expression is the atom -ok, and the value of BoolExpr is discarded. If testing is disabled, -the macro will not generate any code except the atom ok, and -BoolExpr will not be evaluated.

- -Typical usage: -
   ?assert(f(X, Y) =:= [])
- -The assert macro can be used anywhere in a program, not just in unit -tests, to check pre/postconditions and invariants. For example: -
   some_recursive_function(X, Y, Z) ->
-       ?assert(X + Y > Z),
-       ...
-
-
assertNot(BoolExpr)
-
Equivalent to assert(not (BoolExpr)). -
-
assertMatch(GuardedPattern, Expr)
-

Evaluates Expr and matches the result against GuardedPattern, if -testing is enabled. If the match fails, an informative exception will be -generated; see the assert macro for further details. GuardedPattern -can be anything that you can write on the left hand side of the -> -symbol in a case-clause, except that it cannot contain comma-separated -guard tests.

- -

The main reason for using assertMatch also for simple matches, instead -of matching with =, is that it produces more detailed error messages.

- -Examples: -
   ?assertMatch({found, {fred, _}}, lookup(bloggs, Table))
-
   ?assertMatch([X|_] when X > 0, binary_to_list(B))
-
-
assertEqual(Expect, Expr)
-

Evaluates the expressions Expect and Expr and compares the -results for equality, if testing is enabled. If the values are not -equal, an informative exception will be generated; see the assert -macro for further details.

- -

assertEqual is more suitable than than assertMatch when the -left-hand side is a computed value rather than a simple pattern, and -gives more details than ?assert(Expect =:= Expr).

- -Examples: -
   ?assertEqual("b" ++ "a", lists:reverse("ab"))
-
   ?assertEqual(foo(X), bar(Y))
-
-
assertException(ClassPattern, TermPattern, Expr)
-
assertError(TermPattern, Expr)
-
assertExit(TermPattern, Expr)
-
assertThrow(TermPattern, Expr)
-

Evaluates Expr, catching any exception and testing that it matches -the expected ClassPattern:TermPattern. If the match fails, or if no -exception is thrown by Expr, an informative exception will be -generated; see the assert macro for further details. The -assertError, assertExit, and assertThrow macros, are equivalent to -using assertException with a ClassPattern of error, exit, or -throw, respectively.

- -Examples: -
   ?assertError(badarith, X/0)
-
   ?assertExit(normal, exit(normal))
-
   ?assertException(throw, {not_found,_}, throw({not_found,42}))
-
-
- -

Macros for running external commands

- -

Keep in mind that external commands are highly dependent on the -operating system. You can use the standard library function os:type() -in test generator functions, to produce different sets of tests -depending on the current operating system.

- -

Note: these macros introduce a run-time dependency on the EUnit library -code, if compiled with testing enabled.

- -
-
assertCmd(CommandString)
-

Runs CommandString as an external command, if testing is enabled. -Unless the returned status value is 0, an informative exception will be -generated. If there is no exception, the result of the macro expression -is the atom ok. If testing is disabled, the macro will not generate -any code except the atom ok, and the command will not be executed.

- -Typical usage: -
   ?assertCmd("mkdir foo")
-
-
assertCmdStatus(N, CommandString)
-
Like the assertCmd(CommandString) macro, but generates an -exception unless the returned status value is N. -
-
assertCmdOutput(Text, CommandString)
-
Runs CommandString as an external command, if testing is enabled. -Unless the output produced by the command exactly matches the specified -string Text, an informative exception will be generated. (Note that -the output is normalized to use a single LF character as line break on -all platforms.) If there is no exception, the result of the macro -expression is the atom ok. If testing is disabled, the macro will not -generate any code except the atom ok, and the command will not be -executed. -
-
cmd(CommandString)
-

Runs CommandString as an external command. Unless the returned -status value is 0 (indicating success), an informative exception will be -generated; otherwise, the result of the macro expression is the output -produced by the command, as a flat string. The output is normalized to -use a single LF character as line break on all platforms.

- -

This macro is useful in the setup and cleanup sections of fixtures, -e.g., for creating and deleting files or perform similar operating -system specific tasks, to make sure that the test system is informed of -any failures.

- -A Unix-specific example: -
   {setup,
-    fun () -> ?cmd("mktemp") end,
-    fun (FileName) -> ?cmd("rm " ++ FileName) end,
-    ...}
-
-
- -

Debugging macros

- -

To help with debugging, EUnit defines several useful macros for printing -messages directly to the console (rather than to the standard output). -Furthermore, these macros all use the same basic format, which includes -the file and line number where they occur, making it possible in some -development environments (e.g., when running Erlang in an Emacs buffer) -to simply click on the message and jump directly to the corresponding -line in the code.

- -

If the macro NODEBUG is defined before the EUnit header file is -included, these macros have no effect; see -Compilation control macros for details.

- -
-
debugHere
-
Just prints a marker showing the current file and line number. Note -that this is an argument-less macro. The result is always ok.
-
debugMsg(Text)
-
Outputs the message Text (which can be a plain string, an IO-list, -or just an atom). The result is always ok.
-
debugFmt(FmtString, Args)
-
This formats the text like io:format(FmtString, Args) and outputs -it like debugMsg. The result is always ok.
-
debugVal(Expr)
-
Prints both the source code for Expr and its current value. E.g., -?debugVal(f(X)) might be displayed as "f(X) = 42". (Large terms are -shown truncated.) The result is always the value of Expr, so this -macro can be wrapped around any expression to display its value when -the code is compiled with debugging enabled.
-
debugTime(Text,Expr)
-
Prints Text and the wall clock time for evaluation of Expr. The -result is always the value of Expr, so this macro can be wrapped -around any expression to show its run time when the code is compiled -with debugging enabled. For example, List1 = ?debugTime("sorting", -lists:sort(List)) might show as "sorting: 0.015 s".
- -
- - -

EUnit test representation

- -

The way EUnit represents tests and test sets as data is flexible, -powerful, and concise. This section describes the representation in -detail.

- - - -

Simple test objects

- -A simple test object is one of the following: -
    -
  • A nullary functional value (i.e., a fun that takes zero - arguments). Examples: -
       fun () -> ... end
    -
       fun some_function/0
    -
       fun some_module:some_function/0
    -
  • -
  • A pair of atoms {ModuleName, FunctionName}, referring to the - function ModuleName:FunctionName/0
  • -
  • A pair {LineNumber, SimpleTest}, where LineNumber is a - nonnegative integer and SimpleTest is another simple test - object. LineNumber should indicate the source line of the test. - Pairs like this are usually only created via ?_test(...) macros; - see Basic macros.
  • -

-In brief, a simple test object consists of a single function that takes -no arguments (possibly annotated with some additional metadata, i.e., a -line number). Evaluation of the function either succeeds, by -returning some value (which is ignored), or fails, by throwing -an exception.

- -

Test sets and deep lists

- -

A test set can be easily created by placing a sequence of test objects -in a list. If T_1, ..., T_N are individual test objects, then [T_1, -..., T_N] is a test set consisting of those objects (in that order).

- -

Test sets can be joined in the same way: if S_1, ..., S_K are test -sets, then [S_1, ..., S_K] is also a test set, where the tests of -S_i are ordered before those of S_(i+1), for each subset S_i.

- -

Thus, the main representation of test sets is deep lists, and -a simple test object can be viewed as a test set containing only a -single test; there is no difference between T and [T].

- -

A module can also be used to represent a test set; see ModuleName -under Primitives below.

- -

Titles

- -

Any test or test set T can be annotated with a title, by wrapping it -in a pair {Title, T}, where Title is a string. For convenience, any -test which is normally represented using a tuple can simply be given a -title string as the first element, i.e., writing {"The Title", ...} -instead of adding an extra tuple wrapper as in {"The Title", {...}}.

- - -

Primitives

- -The following are primitives, which do not contain other test sets as -arguments: -
-
ModuleName::atom() -
-
A single atom represents a module name, and is equivalent to -{module, ModuleName}. This is often used as in the call -eunit:test(some_module). -
-
{module, ModuleName::atom()} -
-

This composes a test set from the exported test functions of the -named module, i.e., those functions with arity zero whose names end -with _test or _test_. Basically, the ..._test() functions become -simple tests, while the ..._test_() functions become generators.

- -In addition, EUnit will also look for another module whose name is -ModuleName plus the suffix _tests, and if it exists, all the tests -from that module will also be added. (If ModuleName already contains -the suffix _tests, this is not done.) E.g., the specification -{module, mymodule} will run all tests in the modules mymodule and -mymodule_tests. Typically, the _tests module should only contain -test cases that use the public interface of the main module (and no -other code). -
-
{application, AppName::atom(), Info::list()} -
-
This is a normal Erlang/OTP application descriptor, as found in an - .app file. The resulting test set consists of the modules listed in - the modules entry in Info. -
-
{application, AppName::atom()} -
-
This creates a test set from all the modules belonging to the -specified application, by consulting the application's .app file -(see {file, FileName}), or if no such file exists, by testing all -object files in the application's ebin-directory (see {dir, -Path}); if that does not exist, the code:lib_dir(AppName) directory -is used. -
-
Path::string() -
-
A single string represents the path of a file or directory, and is -equivalent to {file, Path}, or {dir, Path}, respectively, depending -on what Path refers to in the file system. -
-
{file, FileName::string()} -
-

If FileName has a suffix that indicates an object file (.beam), -EUnit will try to reload the module from the specified file and test it. -Otherwise, the file is assumed to be a text file containing test -specifications, which will be read using the standard library function -file:path_consult/2.

- -Unless the file name is absolute, the file is first searched for -relative to the current directory, and then using the normal search path -(code:get_path()). This means that the names of typical "app" files -can be used directly, without a path, e.g., "mnesia.app". -
-
{dir, Path::string()} -
-
This tests all object files in the specified directory, as if they -had been individually specified using {file, FileName}. -
-
{generator, GenFun::(() -> Tests)} -
-
The generator function GenFun is called to produce a test -set. -
-
{generator, ModuleName::atom(), FunctionName::atom()} -
-
The function ModuleName:FunctionName() is called to produce a test -set. -
-
{with, X::any(), [AbstractTestFun::((any()) -> any())]} -
-
Distributes the value X over the unary functions in the list, -turning them into nullary test functions. An AbstractTestFun is like -an ordinary test fun, but takes one argument instead of zero - it's -basically missing some information before it can be a proper test. In -practice, {with, X, [F_1, ..., F_N]} is equivalent to [fun () -> -F_1(X) end, ..., fun () -> F_N(X) end]. This is particularly useful if -your abstract test functions are already implemented as proper -functions: {with, FD, [fun filetest_a/1, fun filetest_b/1, fun -filetest_c/1]} is equivalent to [fun () -> filetest_a(FD) end, fun () --> filetest_b(FD) end, fun () -> filetest_c(FD) end], but much more -compact. See also Fixtures, below. -
-
- -

Control

- -The following representations control how and where tests are executed: -
-
{spawn, Tests}
-
Runs the specified tests in a separate subprocess, while the current -test process waits for it to finish. This is useful for tests that need -a fresh, isolated process state. (Note that EUnit always starts at least -one such a subprocess automatically; tests are never executed by the -caller's own process.)
-
{spawn, Node::atom(), Tests}
-
Like {spawn, Tests}, but runs the specified tests on the given -Erlang node.
-
{timeout, Time::number(), Tests}
-
Runs the specified tests under the given timeout. Time is in -seconds; e.g., 60 means one minute and 0.1 means 1/10th of a second. If -the timeout is exceeded, the unfinished tests will be forced to -terminate. Note that if a timeout is set around a fixture, it includes -the time for setup and cleanup, and if the timeout is triggered, the -entire fixture is abruptly terminated (without running the -cleanup).
-
{inorder, Tests}
-
Runs the specified tests in strict order. Also see {inparallel, -Tests}. By default, tests are neither marked as inorder or -inparallel, but may be executed as the test framework chooses.
-
{inparallel, Tests}
-
Runs the specified tests in parallel (if possible). Also see -{inorder, Tests}.
-
{inparallel, N::integer(), Tests}
-
Like {inparallel, Tests}, but running no more than N subtests -simultaneously.
-
- -

Fixtures

- -

A "fixture" is some state that is necessary for a particular set of -tests to run. EUnit's support for fixtures makes it easy to set up such -state locally for a test set, and automatically tear it down again when -the test set is finished, regardless of the outcome (success, failures, -timeouts, etc.).

- -

To make the descriptions simpler, we first list some definitions: -

- - - - - - - - - - - - - - - - - - - -
Setup() -> (R::any())
SetupX(X::any()) -> (R::any())
Cleanup(R::any()) -> any()
CleanupX(X::any(), R::any()) -> any()
Instantiator((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -> any())]}
Wherelocal | spawn | {spawn, Node::atom()}
-
-(these are explained in more detail further below.)

- -The following representations specify fixture handling for test sets: -
-
{setup, Setup, Tests | Instantiator}
-
{setup, Setup, Cleanup, Tests | Instantiator}
-
{setup, Where, Setup, Tests | Instantiator}
-
{setup, Where, Setup, Cleanup, Tests | Instantiator}
-
setup sets up a single fixture for running all of the specified -tests, with optional teardown afterwards. The arguments are described in -detail below. -
-
{node, Node::atom(), Tests | Instantiator}
-
{node, Node::atom(), Args::string(), Tests | Instantiator}
-
node is like setup, but with a built-in behaviour: it starts a -slave node for the duration of the tests. The atom Node should have -the format nodename@full.machine.name, and Args are the optional -arguments to the new node; see slave:start_link/3 for details. -
-
{foreach, Where, Setup, Cleanup, [Tests | Instantiator]}
-
{foreach, Setup, Cleanup, [Tests | Instantiator]}
-
{foreach, Where, Setup, [Tests | Instantiator]}
-
{foreach, Setup, [Tests | Instantiator]}
-
foreach is used to set up a fixture and optionally tear it down -afterwards, repeated for each single one of the specified test sets. -
-
{foreachx, Where, SetupX, CleanupX, - Pairs::[{X::any(), ((X::any(), R::any()) -> Tests)}]}
-
{foreachx, SetupX, CleanupX, Pairs}
-
{foreachx, Where, SetupX, Pairs}
-
{foreachx, SetupX, Pairs}
-
foreachx is like foreach, but uses a list of pairs, each -containing an extra argument X and an extended instantiator function. -
-
- -

A Setup function is executed just before any of the specified tests -are run, and a Cleanup function is executed when no more of the -specified tests will be run, regardless of the reason. A Setup -function takes no argument, and returns some value which will be passed -as it is to the Cleanup function. A Cleanup function should do -whatever necessary and return some arbitrary value, such as the atom -ok. (SetupX and CleanupX functions are similar, but receive one -additional argument: some value X, which depends on the context.) When -no Cleanup function is specified, a dummy function is used which has -no effect.

- -

An Instantiator function receives the same value as the Cleanup -function, i.e., the value returned by the Setup function. It should -then behave much like a generator (see Primitives), and -return a test set whose tests have been instantiated with the -given value. A special case is the syntax {with, [AbstractTestFun]} -which represents an instantiator function that distributes the value -over a list of unary functions; see Primitives: {with, X, -[...]} for more details.

- -A Where term controls how the specified tests are executed. The -default is spawn, which means that the current process handles the -setup and teardown, while the tests are executed in a subprocess. -{spawn, Node} is like spawn, but runs the subprocess on the -specified node. local means that the current process will handle both -setup/teardown and running the tests - the drawback is that if a test -times out so that the process is killed, the cleanup will not be -performed; hence, avoid this for persistent fixtures such as file -operations. In general, 'local' should only be used when: -
    -
  • the setup/teardown needs to be executed by the process that will - run the tests;
  • -
  • no further teardown needs to be done if the process is killed - (i.e., no state outside the process was affected by the setup)
  • -
- -

Lazy generators

- -

Sometimes, it can be convenient not to produce the whole set of test -descriptions before the testing begins; for example, if you want to -generate a huge amount of tests that would take up too much space to -keep in memory all at once.

- -

It is fairly easy to write a generator which, each time it is called, -either produces an empty list if it is done, or otherwise produces a -list containing a single test case plus a new generator which will -produce the rest of the tests. This demonstrates the basic pattern:

- -
   lazy_test_() ->
-       lazy_gen(10000).
-
-   lazy_gen(N) ->
-       {generator,
-        fun () ->
-            if N > 0 ->
-                   [?_test(...)
-                    | lazy_gen(N-1)];
-               true ->
-                   []
-            end
-        end}.
- -

When EUnit traverses the test representation in order to run the tests, -the new generator will not be called to produce the next test until the -previous test has been executed.

- -Note that it is easiest to write this kind of recursive generator using -a help function, like the lazy_gen/1 function above. It can also be -written using a recursive fun, if you prefer to not clutter your -function namespace and are comfortable with writing that kind of code. - -
- -

Generated by EDoc, Apr 22 2009, 22:37:19.

- - diff --git a/lib/eunit/doc/packages-frame.html b/lib/eunit/doc/packages-frame.html deleted file mode 100644 index 52b45534f5..0000000000 --- a/lib/eunit/doc/packages-frame.html +++ /dev/null @@ -1,11 +0,0 @@ - - - -The eunit application - - - -

Packages

-
- - \ No newline at end of file diff --git a/lib/eunit/doc/stylesheet.css b/lib/eunit/doc/stylesheet.css deleted file mode 100644 index e426a90483..0000000000 --- a/lib/eunit/doc/stylesheet.css +++ /dev/null @@ -1,55 +0,0 @@ -/* standard EDoc style sheet */ -body { - font-family: Verdana, Arial, Helvetica, sans-serif; - margin-left: .25in; - margin-right: .2in; - margin-top: 0.2in; - margin-bottom: 0.2in; - color: #000000; - background-color: #ffffff; -} -h1,h2 { - margin-left: -0.2in; -} -div.navbar { - background-color: #add8e6; - padding: 0.2em; -} -h2.indextitle { - padding: 0.4em; - background-color: #add8e6; -} -h3.function,h3.typedecl { - background-color: #add8e6; - padding-left: 1em; -} -div.spec { - margin-left: 2em; - background-color: #eeeeee; -} -a.module,a.package { - text-decoration:none -} -a.module:hover,a.package:hover { - background-color: #eeeeee; -} -ul.definitions { - list-style-type: none; -} -ul.index { - list-style-type: none; - background-color: #eeeeee; -} - -/* - * Minor style tweaks - */ -ul { - list-style-type: square; -} -table { - border-collapse: collapse; -} -td { - padding: 3 -} -- cgit v1.2.3 From 33b9fe219788bb8658cc160620ad6a6757312ea6 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 19 Jul 2011 11:16:27 +0200 Subject: removed cvs keywords from files --- lib/eunit/Makefile | 2 -- lib/eunit/examples/Makefile | 2 -- lib/eunit/include/eunit.hrl | 2 -- lib/eunit/src/eunit.erl | 2 -- lib/eunit/src/eunit_autoexport.erl | 2 -- lib/eunit/src/eunit_data.erl | 2 -- lib/eunit/src/eunit_internal.hrl | 2 -- lib/eunit/src/eunit_lib.erl | 2 -- lib/eunit/src/eunit_listener.erl | 2 -- lib/eunit/src/eunit_proc.erl | 2 -- lib/eunit/src/eunit_serial.erl | 2 -- lib/eunit/src/eunit_server.erl | 2 -- lib/eunit/src/eunit_striptests.erl | 2 -- lib/eunit/src/eunit_surefire.erl | 2 -- lib/eunit/src/eunit_test.erl | 2 -- lib/eunit/src/eunit_tests.erl | 2 -- lib/eunit/src/eunit_tty.erl | 2 -- 17 files changed, 34 deletions(-) diff --git a/lib/eunit/Makefile b/lib/eunit/Makefile index ee69d5e8e0..cd85dff06a 100644 --- a/lib/eunit/Makefile +++ b/lib/eunit/Makefile @@ -13,8 +13,6 @@ # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings # AB. All Rights Reserved.'' # -# $Id$ -# include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk diff --git a/lib/eunit/examples/Makefile b/lib/eunit/examples/Makefile index d1b5bac224..48ec2ebf2b 100644 --- a/lib/eunit/examples/Makefile +++ b/lib/eunit/examples/Makefile @@ -13,8 +13,6 @@ # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings # AB. All Rights Reserved.'' # -# $Id$ -# include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl index 493ba60a2d..db68d8ae60 100644 --- a/lib/eunit/include/eunit.hrl +++ b/lib/eunit/include/eunit.hrl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit.hrl 337 2009-03-09 08:38:28Z rcarlsson $ -%% %% Copyright (C) 2004-2006 Mickaël Rémond, Richard Carlsson %% Including this file turns on testing and defines TEST, unless NOTEST diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl index 15fc3bdf32..cba0e6790a 100644 --- a/lib/eunit/src/eunit.erl +++ b/lib/eunit/src/eunit.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit.erl 339 2009-04-05 14:10:47Z rcarlsson $ -%% %% @copyright 2004-2009 Mickaël Rémond, Richard Carlsson %% @author Mickaël Rémond %% [http://www.process-one.net/] diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl index 7b153c1194..f08096a9f2 100644 --- a/lib/eunit/src/eunit_autoexport.erl +++ b/lib/eunit/src/eunit_autoexport.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_autoexport.erl 329 2009-03-01 11:23:32Z rcarlsson $ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index 288dd74ddf..d281a1d872 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_internal.hrl b/lib/eunit/src/eunit_internal.hrl index 8d0ac30bd7..80890102d0 100644 --- a/lib/eunit/src/eunit_internal.hrl +++ b/lib/eunit/src/eunit_internal.hrl @@ -1,8 +1,6 @@ %% ------------------------------------------------------------------- %% File: eunit_internal.hrl %% -%% $Id: eunit_internal.hrl 329 2009-03-01 11:23:32Z rcarlsson $ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @doc diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index 45d2387e7b..3385602913 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_lib.erl 339 2009-04-05 14:10:47Z rcarlsson $ -%% %% @copyright 2004-2007 Mickaël Rémond, Richard Carlsson %% @author Mickaël Rémond %% [http://www.process-one.net/] diff --git a/lib/eunit/src/eunit_listener.erl b/lib/eunit/src/eunit_listener.erl index 20faecbf01..2783fc85af 100644 --- a/lib/eunit/src/eunit_listener.erl +++ b/lib/eunit/src/eunit_listener.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% %% @author Richard Carlsson %% @copyright 2009 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl index e2d51d8bd5..5440046d11 100644 --- a/lib/eunit/src/eunit_proc.erl +++ b/lib/eunit/src/eunit_proc.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_serial.erl b/lib/eunit/src/eunit_serial.erl index d9ccae86f9..83193ca57a 100644 --- a/lib/eunit/src/eunit_serial.erl +++ b/lib/eunit/src/eunit_serial.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_server.erl b/lib/eunit/src/eunit_server.erl index 2cdfef2668..9135fcd691 100644 --- a/lib/eunit/src/eunit_server.erl +++ b/lib/eunit/src/eunit_server.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_server.erl 267 2008-10-19 18:48:03Z rcarlsson $ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_striptests.erl b/lib/eunit/src/eunit_striptests.erl index 606e44b286..ed2c60f219 100644 --- a/lib/eunit/src/eunit_striptests.erl +++ b/lib/eunit/src/eunit_striptests.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_striptests.erl 329 2009-03-01 11:23:32Z rcarlsson $ -%% %% @author Richard Carlsson %% @author Eric Merritt %% @copyright 2006 Richard Carlsson, Eric Merritt diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index 6e0a447105..af7cc2f17f 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: $ -%% %% @author Mickaël Rémond %% @copyright 2009 Mickaël Rémond, Paul Guyot %% @see eunit diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl index 9ac1d1e7d9..bde5c462b3 100644 --- a/lib/eunit/src/eunit_test.erl +++ b/lib/eunit/src/eunit_test.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_test.erl 336 2009-03-06 14:43:21Z rcarlsson $ -%% %% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl index a63d102d98..9bd9726a78 100644 --- a/lib/eunit/src/eunit_tests.erl +++ b/lib/eunit/src/eunit_tests.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_tests.erl 238 2007-11-15 10:23:54Z mremond $ -%% %% @author Richard Carlsson %% @copyright 2007 Richard Carlsson %% @private diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl index 5fe0140559..08c39004c2 100644 --- a/lib/eunit/src/eunit_tty.erl +++ b/lib/eunit/src/eunit_tty.erl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_tty.erl 330 2009-03-01 16:28:02Z rcarlsson $ -%% %% @author Richard Carlsson %% @copyright 2006-2009 Richard Carlsson %% @private -- cgit v1.2.3 From fde5038d0304b0e6020eae134dbc6bc3b452c867 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 19 Jul 2011 11:45:28 +0200 Subject: updated author e-mails and homepages --- lib/eunit/doc/overview.edoc | 3 +-- lib/eunit/src/eunit.erl | 3 +-- lib/eunit/src/eunit_autoexport.erl | 2 +- lib/eunit/src/eunit_data.erl | 2 +- lib/eunit/src/eunit_internal.hrl | 4 +--- lib/eunit/src/eunit_lib.erl | 3 +-- lib/eunit/src/eunit_listener.erl | 2 +- lib/eunit/src/eunit_proc.erl | 2 +- lib/eunit/src/eunit_serial.erl | 2 +- lib/eunit/src/eunit_server.erl | 2 +- lib/eunit/src/eunit_striptests.erl | 4 ++-- lib/eunit/src/eunit_surefire.erl | 2 +- lib/eunit/src/eunit_test.erl | 2 +- lib/eunit/src/eunit_tests.erl | 2 +- lib/eunit/src/eunit_tty.erl | 2 +- 15 files changed, 16 insertions(+), 21 deletions(-) diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc index 2583f0be25..ad449cb6fc 100644 --- a/lib/eunit/doc/overview.edoc +++ b/lib/eunit/doc/overview.edoc @@ -5,8 +5,7 @@ @title EUnit - a Lightweight Unit Testing Framework for Erlang -@author Richard Carlsson - [http://user.it.uu.se/~richardc/] +@author Richard Carlsson @author Mickaël Rémond [http://www.process-one.net/] @copyright 2004-2007 Mickaël Rémond, Richard Carlsson diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl index cba0e6790a..95857e83c8 100644 --- a/lib/eunit/src/eunit.erl +++ b/lib/eunit/src/eunit.erl @@ -16,8 +16,7 @@ %% @copyright 2004-2009 Mickaël Rémond, Richard Carlsson %% @author Mickaël Rémond %% [http://www.process-one.net/] -%% @author Richard Carlsson -%% [http://user.it.uu.se/~richardc/] +%% @author Richard Carlsson %% @version {@version}, {@date} {@time} %% @doc This module is the main EUnit user interface. diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl index f08096a9f2..099bcb222e 100644 --- a/lib/eunit/src/eunit_autoexport.erl +++ b/lib/eunit/src/eunit_autoexport.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index d281a1d872..392d378a0e 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_internal.hrl b/lib/eunit/src/eunit_internal.hrl index 80890102d0..92694ec39b 100644 --- a/lib/eunit/src/eunit_internal.hrl +++ b/lib/eunit/src/eunit_internal.hrl @@ -1,9 +1,7 @@ %% ------------------------------------------------------------------- %% File: eunit_internal.hrl %% -%% @author Richard Carlsson -%% @copyright 2006 Richard Carlsson -%% @doc +%% Copyright (C) 2006 Richard Carlsson -define(SERVER, eunit_server). -define(DEFAULT_TEST_SUFFIX, "_test"). diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index 3385602913..1c41e229c5 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -16,8 +16,7 @@ %% @copyright 2004-2007 Mickaël Rémond, Richard Carlsson %% @author Mickaël Rémond %% [http://www.process-one.net/] -%% @author Richard Carlsson -%% [http://user.it.uu.se/~richardc/] +%% @author Richard Carlsson %% @private %% @see eunit %% @doc Utility functions for eunit diff --git a/lib/eunit/src/eunit_listener.erl b/lib/eunit/src/eunit_listener.erl index 2783fc85af..ecaac424a2 100644 --- a/lib/eunit/src/eunit_listener.erl +++ b/lib/eunit/src/eunit_listener.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2009 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl index 5440046d11..ec7d93fd48 100644 --- a/lib/eunit/src/eunit_proc.erl +++ b/lib/eunit/src/eunit_proc.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_serial.erl b/lib/eunit/src/eunit_serial.erl index 83193ca57a..80e79116e3 100644 --- a/lib/eunit/src/eunit_serial.erl +++ b/lib/eunit/src/eunit_serial.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_server.erl b/lib/eunit/src/eunit_server.erl index 9135fcd691..2002930abb 100644 --- a/lib/eunit/src/eunit_server.erl +++ b/lib/eunit/src/eunit_server.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_striptests.erl b/lib/eunit/src/eunit_striptests.erl index ed2c60f219..c6ade389ba 100644 --- a/lib/eunit/src/eunit_striptests.erl +++ b/lib/eunit/src/eunit_striptests.erl @@ -13,8 +13,8 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson -%% @author Eric Merritt +%% @author Richard Carlsson +%% @author Eric Merritt %% @copyright 2006 Richard Carlsson, Eric Merritt %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index af7cc2f17f..607f0871d9 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Mickaël Rémond +%% @author Mickaël Rémond %% @copyright 2009 Mickaël Rémond, Paul Guyot %% @see eunit %% @doc Surefire reports for EUnit (Format used by Maven and Atlassian diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl index bde5c462b3..bca49ae626 100644 --- a/lib/eunit/src/eunit_test.erl +++ b/lib/eunit/src/eunit_test.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl index 9bd9726a78..47ea0aaf46 100644 --- a/lib/eunit/src/eunit_tests.erl +++ b/lib/eunit/src/eunit_tests.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2007 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl index 08c39004c2..e3e7b710b2 100644 --- a/lib/eunit/src/eunit_tty.erl +++ b/lib/eunit/src/eunit_tty.erl @@ -13,7 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2006-2009 Richard Carlsson %% @private %% @see eunit -- cgit v1.2.3 From c78dae078936252a605630170b81dcd3e09382fa Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Fri, 23 Sep 2011 22:13:23 +0200 Subject: removed some never-matching clauses reported by dialyzer --- lib/eunit/src/eunit_surefire.erl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index 607f0871d9..2a6cbca14d 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -56,7 +56,7 @@ { name :: chars(), description :: chars(), - result :: ok | {failed, tuple()} | {aborted, tuple()} | {skipped, tuple()}, + result :: ok | {failed, tuple()} | {aborted, tuple()} | {skipped, term()}, time :: integer(), output :: binary() }). @@ -309,7 +309,6 @@ write_testcase( output = Output}, FileDescriptor) -> DescriptionAttr = case Description of - <<>> -> []; [] -> []; _ -> [<<" description=\"">>, escape_attr(Description), <<"\"">>] end, @@ -318,7 +317,6 @@ write_testcase( <<"\" name=\"">>, escape_attr(Name), <<"\"">>, DescriptionAttr], ContentAndEndTag = case {Result, Output} of - {ok, []} -> [<<"/>">>, ?NEWLINE]; {ok, <<>>} -> [<<"/>">>, ?NEWLINE]; _ -> [<<">">>, ?NEWLINE, format_testcase_result(Result), format_testcase_output(Output), ?INDENT, <<"">>, ?NEWLINE] end, @@ -367,7 +365,6 @@ format_testcase_result({skipped, Term}) -> %% Empty output is simply the empty string. %% Other output is inside a xml tag. %% ---------------------------------------------------------------------------- -format_testcase_output([]) -> []; format_testcase_output(Output) -> [?INDENT, ?INDENT, <<"">>, escape_text(Output), ?NEWLINE, ?INDENT, ?INDENT, <<"">>, ?NEWLINE]. @@ -385,8 +382,6 @@ format_time_s([Digit1, Digit2, Digit3 | Tail]) -> [lists:reverse(Tail), $., Digi %% Escape a suite's name to generate the filename. %% Remark: we might overwrite another testsuite's file. %% ---------------------------------------------------------------------------- -escape_suitename([Head | _T] = List) when is_list(Head) -> - escape_suitename(lists:flatten(List)); escape_suitename(Binary) when is_binary(Binary) -> escape_suitename(binary_to_list(Binary)); escape_suitename("module '" ++ String) -> @@ -394,7 +389,6 @@ escape_suitename("module '" ++ String) -> escape_suitename(String) -> escape_suitename(String, []). -escape_suitename(Binary, Acc) when is_binary(Binary) -> escape_suitename(binary_to_list(Binary), Acc); escape_suitename([], Acc) -> lists:reverse(Acc); escape_suitename([$ | Tail], Acc) -> escape_suitename(Tail, [$_ | Acc]); escape_suitename([$' | Tail], Acc) -> escape_suitename(Tail, Acc); -- cgit v1.2.3 From d11d6acb3cea2cb750b69e23811b31f6248aac80 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 2 Aug 2011 21:55:33 +0200 Subject: recognize some more URI schemas in wiki text, in particular https --- lib/edoc/src/edoc_wiki.erl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl index 2f2d14853c..33e687fe63 100644 --- a/lib/edoc/src/edoc_wiki.erl +++ b/lib/edoc/src/edoc_wiki.erl @@ -249,10 +249,20 @@ expand_triple([], L, _, L0) -> expand_uri("http:/" ++ Cs, L, As) -> expand_uri(Cs, L, "/:ptth", As); +expand_uri("https:/" ++ Cs, L, As) -> + expand_uri(Cs, L, "/:sptth", As); expand_uri("ftp:/" ++ Cs, L, As) -> expand_uri(Cs, L, "/:ptf", As); expand_uri("file:/" ++ Cs, L, As) -> expand_uri(Cs, L, "/:elif", As); +expand_uri("mailto:/" ++ Cs, L, As) -> + expand_uri(Cs, L, "/:otliam", As); +expand_uri("nfs:/" ++ Cs, L, As) -> + expand_uri(Cs, L, "/:sfn", As); +expand_uri("shttp:/" ++ Cs, L, As) -> + expand_uri(Cs, L, "/:ptths", As); +expand_uri("xmpp:/" ++ Cs, L, As) -> + expand_uri(Cs, L, "/:ppmx", As); expand_uri(Cs, L, As) -> expand(Cs, L, [$[ | As]). -- cgit v1.2.3 From 766d0f0b20d672e90f2672c6b4b9a441497f5ea5 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Sat, 6 Aug 2011 16:55:07 +0200 Subject: updated author e-mail --- lib/edoc/doc/overview.edoc | 8 ++++---- lib/edoc/include/edoc_doclet.hrl | 2 +- lib/edoc/src/edoc.erl | 2 +- lib/edoc/src/edoc.hrl | 2 +- lib/edoc/src/edoc_data.erl | 2 +- lib/edoc/src/edoc_doclet.erl | 2 +- lib/edoc/src/edoc_extract.erl | 2 +- lib/edoc/src/edoc_layout.erl | 2 +- lib/edoc/src/edoc_lib.erl | 2 +- lib/edoc/src/edoc_macros.erl | 2 +- lib/edoc/src/edoc_parser.yrl | 4 ++-- lib/edoc/src/edoc_refs.erl | 2 +- lib/edoc/src/edoc_report.erl | 2 +- lib/edoc/src/edoc_run.erl | 2 +- lib/edoc/src/edoc_scanner.erl | 2 +- lib/edoc/src/edoc_tags.erl | 2 +- lib/edoc/src/edoc_types.erl | 2 +- lib/edoc/src/edoc_types.hrl | 2 +- lib/edoc/src/edoc_wiki.erl | 2 +- lib/edoc/src/otpsgml_layout.erl | 2 +- 20 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/edoc/doc/overview.edoc b/lib/edoc/doc/overview.edoc index fa699c6f08..2af425272e 100644 --- a/lib/edoc/doc/overview.edoc +++ b/lib/edoc/doc/overview.edoc @@ -3,7 +3,7 @@ EDoc overview page -@author Richard Carlsson +@author Richard Carlsson @copyright 2003-2006 Richard Carlsson @version {@version} @title Welcome to EDoc @@ -277,12 +277,12 @@ The following tags can be used before a module declaration: Examples: ```%% @author Richard Carlsson''' -```%% @author Richard Carlsson +```%% @author Richard Carlsson %% [http://user.it.uu.se/~richardc/]''' -```%% @author ''' +```%% @author ''' -```%% @author richardc@it.uu.se [http://user.it.uu.se/~richardc/]''' +```%% @author carlsson.richard@gmail.com [http://user.it.uu.se/~richardc/]'''
`@copyright'
diff --git a/lib/edoc/include/edoc_doclet.hrl b/lib/edoc/include/edoc_doclet.hrl index a99ff1fbab..60ec7f44e4 100644 --- a/lib/edoc/include/edoc_doclet.hrl +++ b/lib/edoc/include/edoc_doclet.hrl @@ -18,7 +18,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% Author contact: richardc@it.uu.se +%% Author contact: carlsson.richard@gmail.com %% ===================================================================== -define(NO_APP, []). diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl index a279f7dcb3..544465b14a 100644 --- a/lib/edoc/src/edoc.erl +++ b/lib/edoc/src/edoc.erl @@ -15,7 +15,7 @@ %% USA %% %% @copyright 2001-2007 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @version {@version} %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl index 31cf45ade9..98debba4ab 100644 --- a/lib/edoc/src/edoc.hrl +++ b/lib/edoc/src/edoc.hrl @@ -18,7 +18,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% Author contact: richardc@it.uu.se +%% Author contact: carlsson.richard@gmail.com %% ===================================================================== %% Note: Documentation in this file is included by edoc_extract.erl diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl index e3b5a0d51b..aad0b14371 100644 --- a/lib/edoc/src/edoc_data.erl +++ b/lib/edoc/src/edoc_data.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl index c66be9d7c7..385d20e9ae 100644 --- a/lib/edoc/src/edoc_doclet.erl +++ b/lib/edoc/src/edoc_doclet.erl @@ -15,7 +15,7 @@ %% USA %% %% @copyright 2003-2006 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl index 1209d86fe5..bdda09db1c 100644 --- a/lib/edoc/src/edoc_extract.erl +++ b/lib/edoc/src/edoc_extract.erl @@ -15,7 +15,7 @@ %% USA %% %% @copyright 2001-2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl index 1c0841815f..951cec121c 100644 --- a/lib/edoc/src/edoc_layout.erl +++ b/lib/edoc/src/edoc_layout.erl @@ -14,7 +14,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @copyright 2001-2006 Richard Carlsson %% @see edoc %% @end diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl index 6c698e83ef..df929ebf04 100644 --- a/lib/edoc/src/edoc_lib.erl +++ b/lib/edoc/src/edoc_lib.erl @@ -15,7 +15,7 @@ %% USA %% %% @copyright 2001-2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl index 5b512cb53a..70fb38bf0a 100644 --- a/lib/edoc/src/edoc_macros.erl +++ b/lib/edoc/src/edoc_macros.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2001-2005 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl index 3ce4cde4fb..2871846c04 100644 --- a/lib/edoc/src/edoc_parser.yrl +++ b/lib/edoc/src/edoc_parser.yrl @@ -22,7 +22,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% Author contact: richardc@it.uu.se +%% Author contact: carlsson.richard@gmail.com %% ===================================================================== Nonterminals @@ -255,7 +255,7 @@ throws -> etype where_defs: %% "%% USA" %% "%%" %% "%% @private" -%% "%% @author Richard Carlsson " +%% "%% @author Richard Carlsson " %% "%% ====================================================================" %% . diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl index b974cf77c1..1f578a3b83 100644 --- a/lib/edoc/src/edoc_refs.erl +++ b/lib/edoc/src/edoc_refs.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @see edoc_parse_ref %% @end diff --git a/lib/edoc/src/edoc_report.erl b/lib/edoc/src/edoc_report.erl index f082513bee..9bec08ab97 100644 --- a/lib/edoc/src/edoc_report.erl +++ b/lib/edoc/src/edoc_report.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2001-2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_run.erl b/lib/edoc/src/edoc_run.erl index 1355db840f..48b6137ac1 100644 --- a/lib/edoc/src/edoc_run.erl +++ b/lib/edoc/src/edoc_run.erl @@ -15,7 +15,7 @@ %% USA %% %% @copyright 2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_scanner.erl b/lib/edoc/src/edoc_scanner.erl index 8e895ad1ad..754fcef643 100644 --- a/lib/edoc/src/edoc_scanner.erl +++ b/lib/edoc/src/edoc_scanner.erl @@ -16,7 +16,7 @@ %% @private %% @copyright Richard Carlsson 2001-2003. Portions created by Ericsson %% are Copyright 1999, Ericsson Utvecklings AB. All Rights Reserved. -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl index 80989428ce..2d986988c2 100644 --- a/lib/edoc/src/edoc_tags.erl +++ b/lib/edoc/src/edoc_tags.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2001-2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl index a54544868c..60c6cecb97 100644 --- a/lib/edoc/src/edoc_types.erl +++ b/lib/edoc/src/edoc_types.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2001-2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/edoc_types.hrl b/lib/edoc/src/edoc_types.hrl index 1353bfb93a..05c61d70ff 100644 --- a/lib/edoc/src/edoc_types.hrl +++ b/lib/edoc/src/edoc_types.hrl @@ -18,7 +18,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% Author contact: richardc@it.uu.se +%% Author contact: carlsson.richard@gmail.com %% ===================================================================== %% Type specification data structures diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl index 33e687fe63..5c71658af5 100644 --- a/lib/edoc/src/edoc_wiki.erl +++ b/lib/edoc/src/edoc_wiki.erl @@ -16,7 +16,7 @@ %% %% @private %% @copyright 2001-2003 Richard Carlsson -%% @author Richard Carlsson +%% @author Richard Carlsson %% @see edoc %% @end %% ===================================================================== diff --git a/lib/edoc/src/otpsgml_layout.erl b/lib/edoc/src/otpsgml_layout.erl index d425dc0ed8..2c4cd919bb 100644 --- a/lib/edoc/src/otpsgml_layout.erl +++ b/lib/edoc/src/otpsgml_layout.erl @@ -14,7 +14,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% @author Richard Carlsson +%% @author Richard Carlsson %% @author Kenneth Lundin %% @copyright 2001-2004 Richard Carlsson %% @see edoc_layout -- cgit v1.2.3 From 10f76823b8c71ecc84f51bf9f93514d6d25a4a77 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Thu, 18 Aug 2011 14:32:36 +0200 Subject: URI-escape bytes as two hex digits always (reported by Alfonso De Gregorio) --- lib/edoc/src/edoc_lib.erl | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl index df929ebf04..7fd8358add 100644 --- a/lib/edoc/src/edoc_lib.erl +++ b/lib/edoc/src/edoc_lib.erl @@ -403,8 +403,13 @@ escape_uri([C | Cs]) -> escape_uri([]) -> []. -escape_byte(C) -> - "%" ++ hex_octet(C). +escape_byte(C) when C >= 0, C =< 255 -> + [$%, hex_digit(C bsr 4), hex_digit(C band 15)]. + +hex_digit(N) when N >= 0, N =< 9 -> + N + $0; +hex_digit(N) when N > 9, N =< 15 -> + N + $a - 10. % utf8([C | Cs]) when C > 16#7f -> % [((C band 16#c0) bsr 6) + 16#c0, C band 16#3f ++ 16#80 | utf8(Cs)]; @@ -413,13 +418,6 @@ escape_byte(C) -> % utf8([]) -> % []. -hex_octet(N) when N =< 9 -> - [$0 + N]; -hex_octet(N) when N > 15 -> - hex_octet(N bsr 4) ++ hex_octet(N band 15); -hex_octet(N) -> - [N - 10 + $a]. - %% Please note that URI are *not* file names. Don't use the stdlib %% 'filename' module for operations on (any parts of) URI. -- cgit v1.2.3 From 530d3b1c4b242d31fa035a3d3865ced2576ef1bb Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 24 Aug 2011 14:38:01 +0200 Subject: Fix macro expansion in comments following Erlang types Macros in comments following Erlang types were not expanded. An example: -type t() :: integer(). %% This type is used in {@link foo/0}. The link to foo/0 was not created. --- lib/edoc/src/edoc_extract.erl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl index bdda09db1c..5a79e127f6 100644 --- a/lib/edoc/src/edoc_extract.erl +++ b/lib/edoc/src/edoc_extract.erl @@ -75,7 +75,7 @@ source(Forms, Comments, File, Env, Opts) when is_list(Forms) -> source(Forms1, Comments, File, Env, Opts); source(Forms, Comments, File, Env, Opts) -> Tree = erl_recomment:quick_recomment_forms(Forms, Comments), - TypeDocs = find_type_docs(Forms, Comments), + TypeDocs = find_type_docs(Forms, Comments, Env, File), source1(Tree, File, Env, Opts, TypeDocs). %% @spec source(Forms, File::filename(), Env::edoc_env(), @@ -111,7 +111,7 @@ source(Forms, Comments, File, Env, Opts) -> source(Forms, File, Env, Opts) when is_list(Forms) -> source(erl_syntax:form_list(Forms), File, Env, Opts); source(Tree, File0, Env, Opts) -> - TypeDocs = find_type_docs(Tree, []), + TypeDocs = find_type_docs(Tree, [], Env, File0), source1(Tree, File0, Env, Opts, TypeDocs). %% Forms0 and Comments is used for extracting Erlang type documentation. @@ -635,14 +635,17 @@ file_macros(_Context, Env) -> %% The same thing using -type: %% -type t() :: t1(). % Some docs of t/0; %% Further docs of t/0. -find_type_docs(Forms0, Comments) -> +find_type_docs(Forms0, Comments, Env, File) -> Tree = erl_recomment:recomment_forms(Forms0, Comments), Forms = preprocess_forms(Tree), - edoc_specs:docs(Forms, fun find_fun/2). + Env1 = add_macro_defs(edoc_macros:std_macros(Env), [], Env), + F = fun(C, Line) -> find_fun(C, Line, Env1, File) end, + edoc_specs:docs(Forms, F). -find_fun(C0, Line) -> +find_fun(C0, Line, Env, File) -> C1 = comment_text(C0), Text = lists:append([C#comment.text || C <- C1]), Comm = #comment{line = Line, text = Text}, [Tag | _] = scan_tags([Comm]), - Tag. + [Tag1] = edoc_macros:expand_tags([Tag], Env, File), + Tag1. -- cgit v1.2.3 From 823f01895f33e559d737880d9207054a20dcc2f8 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Fri, 23 Sep 2011 22:19:10 +0200 Subject: removed some never-matching clauses reported by dialyzer --- lib/edoc/src/edoc_parser.yrl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl index 2871846c04..4d6428f75b 100644 --- a/lib/edoc/src/edoc_parser.yrl +++ b/lib/edoc/src/edoc_parser.yrl @@ -455,8 +455,6 @@ parse_throws(S, L) -> -spec throw_error(term(), erl_scan:line()) -> no_return(). -throw_error({L, M, D}, _L0) -> - throw({error,L,{format_error,M,D}}); throw_error({parse_spec, E}, L) -> throw_error({"specification", E}, L); throw_error({parse_typedef, E}, L) -> @@ -468,7 +466,4 @@ throw_error({parse_throws, E}, L) -> throw_error(parse_param, L) -> throw({error, L, "missing parameter name"}); throw_error({Where, E}, L) when is_list(Where) -> - throw({error,L,{"unknown error parsing ~s: ~P.",[Where,E,15]}}); -throw_error(E, L) -> - %% Just in case. - throw({error,L,{"unknown parse error: ~P.",[E,15]}}). + throw({error,L,{"unknown error parsing ~s: ~P.",[Where,E,15]}}). -- cgit v1.2.3 From df2063c1e436cfb2bb9283df074c4eaa87aeec91 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Sun, 25 Sep 2011 20:33:33 +0200 Subject: bumped revision --- lib/edoc/vsn.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk index 30cf191ffc..22f225dd9b 100644 --- a/lib/edoc/vsn.mk +++ b/lib/edoc/vsn.mk @@ -1 +1 @@ -EDOC_VSN = 0.7.8 +EDOC_VSN = 0.7.9 -- cgit v1.2.3 From ee205b29f7a2bb92aeef55ca88fccc8c91f22ec0 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Mon, 19 Sep 2011 15:36:08 +0200 Subject: Correct XML files --- erts/doc/src/erl_prim_loader.xml | 6 +- erts/doc/src/erlang.xml | 8 +-- erts/doc/src/erts_alloc.xml | 28 ++++---- .../src/CosFileTransfer_FileTransferSession.xml | 4 +- lib/erl_interface/doc/src/erl_format.xml | 4 +- lib/kernel/doc/src/app.xml | 4 +- lib/kernel/doc/src/code.xml | 4 +- lib/kernel/doc/src/disk_log.xml | 3 +- lib/kernel/doc/src/erl_ddll.xml | 2 +- lib/kernel/doc/src/file.xml | 20 +++--- lib/kernel/doc/src/gen_sctp.xml | 77 +++++++--------------- lib/kernel/doc/src/net_kernel.xml | 8 +-- lib/megaco/doc/src/megaco.xml | 6 +- lib/mnesia/doc/src/mnesia.xml | 4 +- lib/mnesia/doc/src/mnesia_frag_hash.xml | 2 +- lib/odbc/doc/src/odbc.xml | 6 +- lib/orber/doc/src/orber_ifr.xml | 4 +- lib/parsetools/doc/src/yecc.xml | 4 +- lib/stdlib/doc/src/beam_lib.xml | 1 - lib/stdlib/doc/src/dets.xml | 3 +- lib/stdlib/doc/src/erl_tar.xml | 60 ++++++++--------- lib/stdlib/doc/src/ets.xml | 15 ++--- lib/stdlib/doc/src/gb_sets.xml | 1 - lib/stdlib/doc/src/gen_fsm.xml | 3 +- lib/stdlib/doc/src/notes.xml | 3 +- lib/stdlib/doc/src/qlc.xml | 1 - lib/stdlib/doc/src/supervisor.xml | 1 - lib/stdlib/doc/src/timer.xml | 13 ++-- lib/stdlib/doc/src/zip.xml | 22 +++---- lib/test_server/doc/src/ts.xml | 2 +- lib/wx/src/gen/wxRegion.erl | 4 +- lib/wx/src/gen/wxWindow.erl | 6 +- 32 files changed, 136 insertions(+), 193 deletions(-) diff --git a/erts/doc/src/erl_prim_loader.xml b/erts/doc/src/erl_prim_loader.xml index fa3daaeecc..9f5b3f385b 100644 --- a/erts/doc/src/erl_prim_loader.xml +++ b/erts/doc/src/erl_prim_loader.xml @@ -101,7 +101,7 @@ Bin is the contents of the file as a binary.

The Filename can also be a file in an archive. For example - /otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin/mnesia_backup.beam. + $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin/mnesia.beam. See code(3) about archive files.

@@ -124,7 +124,7 @@ the names of all the files in the directory. The names are not sorted.

The Dir can also be a directory in an archive. For example - /otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin. + $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin. See code(3) about archive files.

@@ -143,7 +143,7 @@

See file(3) for more info about the record file_info.

The Filename can also be a file in an archive. For example - /otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin/mnesia_backup.beam. + $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin/mnesia. See code(3) about archive files.

diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 2fabc6d62d..aef31f5b98 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -2898,11 +2898,11 @@ os_prompt%
stdlib users guide for details.

- The characters in the name (if given as a list) +

The characters in the name (if given as a list) can only be > 255 if the Erlang VM is started in Unicode file name translation mode, otherwise the name of the executable is limited to the ISO-latin-1 - character set. + character set.

If the Command cannot be run, an error exception, with the posix error code as the reason, is @@ -3015,11 +3015,11 @@ os_prompt% Unicode translation of arguments, they can be supplied as binaries in whatever encoding is deemed appropriate.

- The characters in the arguments (if given as a +

The characters in the arguments (if given as a list of characters) can only be > 255 if the Erlang VM is started in Unicode file name mode, otherwise the arguments are limited to the - ISO-latin-1 character set. + ISO-latin-1 character set.

If one, for any reason, wants to explicitly set the program name in the argument vector, the arg0 diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml index 90347824d5..86e1e5168a 100644 --- a/erts/doc/src/erts_alloc.xml +++ b/erts/doc/src/erts_alloc.xml @@ -4,7 +4,7 @@

- 20022010 + 20022011 Ericsson AB. All Rights Reserved. @@ -126,9 +126,8 @@ carrier". Main multiblock carriers are never deallocated. The size of the main multiblock carrier is determined by the value of the mmbcs parameter.

-

- - Sizes of multiblock carriers allocated via mseg_alloc are +

Sizes of multiblock carriers + allocated via mseg_alloc are decided based on the values of the largest multiblock carrier size (lmbcs), the smallest multiblock carrier size (smbcs), @@ -157,9 +156,8 @@

Coalescing of free blocks are always performed immediately. Boundary tags (headers and footers) in free blocks are used which makes the time complexity for coalescing constant.

-

- - The memory allocation strategy used for multiblock carriers by an +

The memory allocation strategy + used for multiblock carriers by an allocator is configurable via the as parameter. Currently the following strategies are available:

@@ -445,10 +443,10 @@ in "the alloc_util framework" section. t true|false|]]> - Multiple, thread specific instances of the allocator. - This option will only have any effect on the runtime system - with SMP support. Default behaviour on the runtime system with - SMP support (N equals the number of scheduler threads): +

Multiple, thread specific instances of the allocator. + This option will only have any effect on the runtime system + with SMP support. Default behaviour on the runtime system with + SMP support (N equals the number of scheduler threads):

temp_alloc N + 1 instances. @@ -459,10 +457,10 @@ 16. 16 instances when N is greater than 16.
- temp_alloc will always use N + 1 instances when - this option has been enabled regardless of the amount passed. - Other allocators will use the same amount of instances as the - amount passed as long as it isn't greater than N. +

temp_alloc will always use N + 1 instances when + this option has been enabled regardless of the amount passed. + Other allocators will use the same amount of instances as the + amount passed as long as it isn't greater than N.

Currently the following flags are available for configuration of diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml index 5ac2c61c92..918f0bf9f7 100644 --- a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml @@ -159,7 +159,7 @@ insert(FTS, SourceFile, DestinationFile, Offset) -> Return - Insert the SourceFileinto the DestinationFileOffsetbytes from the start of the file + Insert the SourceFileinto the DestinationFile Offsetbytes from the start of the file FTS = SourceFile = DestinationFile = #objref Offset = long() @@ -168,7 +168,7 @@

This operation behaves almost like the append/3 operation. The difference is that the SourceFile will be inserted into the - DestinationFileOffset bytes from the start of the file.

+ DestinationFile Offset bytes from the start of the file.

Currently, it is not possible to use this operation when the target object represents FTP.

diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml index 5699485845..f036b12879 100644 --- a/lib/erl_interface/doc/src/erl_format.xml +++ b/lib/erl_interface/doc/src/erl_format.xml @@ -4,7 +4,7 @@
- 19962009 + 19962011 Ericsson AB. All Rights Reserved. @@ -105,7 +105,7 @@ erl_format("[{name,~a},{age,~i},{data,~w}]", values in .

If and can be matched, the function returns a non-zero value and binds any unbound - variables in . If do + variables in . If do not match, the function returns 0. For example:

- 19972009 + 19972011 Ericsson AB. All Rights Reserved. @@ -170,7 +170,6 @@ Phases [{Phase,PhaseArgs}] undefined start phase defined by the start_phases key, and only after this extended start procedure will application:start(Application) return.

-

Start phases may be used to synchronize startup of an application and its included applications. In this case, the mod key must be specified as:

@@ -182,7 +181,6 @@ Phases [{Phase,PhaseArgs}] undefined for the primary application) both for the primary application and for each of its included application, for which the start phase is defined.

-

This implies that for an included application, the set of start phases must be a subset of the set of phases defined for the primary application. Refer to OTP Design Principles for more information.

diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 98cdd416b0..6b89711924 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -177,9 +177,9 @@ archives. But the functions in erl_prim_loader may also be used by other applications to read files from archives. For example, the call - erl_prim_loader:list_dir("/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)" + erl_prim_loader:list_dir( "/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)" would list the contents of a directory inside an archive. - See erl_prim_loader(3)

+ See erl_prim_loader(3)

.

An application archive file and a regular application directory may coexist. This may be useful when there is a need of having diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml index 9721907162..d278d54d93 100644 --- a/lib/kernel/doc/src/disk_log.xml +++ b/lib/kernel/doc/src/disk_log.xml @@ -475,8 +475,7 @@ Close a disk log. -

-The function close/1 closes a +

The function close/1 closes a local or distributed disk log properly. An internally formatted log must be closed before the Erlang system is stopped, otherwise the log is regarded as unclosed and the diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index f9514dda2f..1911fb628e 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -989,7 +989,7 @@ {ok, pending_driver} or {ok, pending_process}.

-

The pending_driverMonitorOption is by far +

The pending_driver MonitorOption is by far the most useful and it has to be used to ensure that the driver has really been unloaded and the ports closed whenever the kill_ports option is used or the diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 861c582211..7db20e6343 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -60,11 +60,13 @@ converted, why the Unicode mode for file names is not default on systems having completely transparent file naming.

- As of R14B01, the most basic file handling modules - (file, prim_file, filelib and - filename) accept raw file names, but the rest of OTP is not - guaranteed to handle them, why Unicode file naming on systems - where it is not default is still considered experimental. + +

As of R14B01, the most basic file handling modules + (file, prim_file, filelib and + filename) accept raw file names, but the rest of OTP is not + guaranteed to handle them, why Unicode file naming on systems + where it is not default is still considered experimental.

+

Raw file names is a new feature in OTP R14B01, which allows the user to supply completely uninterpreted file names to the @@ -249,11 +251,9 @@

Example:

- -f.txt: {person, "kalle", 25}. +f.txt: {person, "kalle", 25}. {person, "pelle", 30}. -
-1> file:consult("f.txt").
+
1> file:consult("f.txt").
 {ok,[{person,"kalle",25},{person,"pelle",30}]}
@@ -362,7 +362,6 @@ f.txt: {person, "kalle", 25}.

In a future release, a bad type for the Filename argument will probably generate an exception.

-

@@ -1523,7 +1522,6 @@ f.txt: {person, "kalle", 25}.

In a future release, a bad type for the Dir argument will probably generate an exception.

-

diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index cc49090386..688cd0f78f 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -47,8 +47,7 @@ SUSE Linux Enterprise Server 10 Service Pack 1 (x86_64) kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7.

Record definitions for the gen_sctp module can be found using:

-
-  -include_lib("kernel/include/inet_sctp.hrl").    
+
  -include_lib("kernel/include/inet_sctp.hrl").    

These record definitions use the "new" spelling 'adaptation', not the deprecated 'adaption', regardless of which spelling the underlying C API uses.

@@ -152,8 +151,7 @@ The result of connect/* is an #sctp_assoc_change{} event which contains, in particular, the new Association ID.

-
-  #sctp_assoc_change{
+
   #sctp_assoc_change{
         state             = atom(),
         error             = atom(),
         outbound_streams  = integer(),
@@ -163,8 +161,7 @@
         

The number of outbound and inbound streams can be set by giving an sctp_initmsg option to connect as in:

-
-  connect(Socket, Ip, Port,
+
  connect(Socket, Ip, Port,
         [{sctp_initmsg,#sctp_initmsg{num_ostreams=OutStreams,
                                      max_instreams=MaxInStreams}}])        

All options Opt are set on the socket before the @@ -340,8 +337,7 @@

#sctp_assoc_change{};

-
-  #sctp_paddr_change{
+
  #sctp_paddr_change{
         addr      = {ip_address(),port()},
         state     = atom(),
         error     = integer(),
@@ -378,8 +374,7 @@
               converted into a string using error_string/1.

-
-  #sctp_send_failed{
+
  #sctp_send_failed{
         flags     = true | false,
         error     = integer(),
         info      = #sctp_sndrcvinfo{},
@@ -399,8 +394,7 @@
               returned by recv/*.

-
-  #sctp_adaptation_event{
+
  #sctp_adaptation_event{
         adaptation_ind = integer(),
         assoc_id       = assoc_id()
   }            
@@ -411,8 +405,7 @@ the Erlang/SCTP binding, this event is disabled by default.

-
-  #sctp_pdapi_event{
+
  #sctp_pdapi_event{
         indication = sctp_partial_delivery_aborted,
         assoc_id   = assoc_id()
   }            
@@ -469,7 +462,7 @@ - {mode, list|binary}or just list or binary. + {mode, list|binary} or just list or binary

Determines the type of data returned from gen_sctp:recv/1,2.

@@ -562,8 +555,7 @@
{sctp_rtoinfo, #sctp_rtoinfo{}} -
-  #sctp_rtoinfo{
+
  #sctp_rtoinfo{
         assoc_id = assoc_id(),
         initial  = integer(),
         max      = integer(),
@@ -577,8 +569,7 @@
       
       {sctp_associnfo, #sctp_assocparams{}}
       
-        
-  #sctp_assocparams{
+
  #sctp_assocparams{
         assoc_id                 = assoc_id(),
         asocmaxrxt               = integer(),
         number_peer_destinations = integer(),
@@ -593,8 +584,7 @@
       
       {sctp_initmsg, #sctp_initmsg{}}
       
-        
-  #sctp_initmsg{
+
  #sctp_initmsg{
        num_ostreams   = integer(),
        max_instreams  = integer(),
        max_attempts   = integer(),
@@ -622,7 +612,6 @@
               for establishing an association.

-

{sctp_autoclose, integer() >= 0} @@ -657,8 +646,7 @@ {sctp_primary_addr, #sctp_prim{}} -
-  #sctp_prim{
+
  #sctp_prim{
         assoc_id = assoc_id(),
         addr     = {IP, Port}
   }
@@ -671,8 +659,7 @@
       
       {sctp_set_peer_primary_addr, #sctp_setpeerprim{}}
       
-        
-  #sctp_setpeerprim{
+
  #sctp_setpeerprim{
         assoc_id = assoc_id(),
         addr     = {IP, Port}
   }
@@ -686,8 +673,7 @@
       {sctp_adaptation_layer, #sctp_setadaptation{}}
       
         
-        
-  #sctp_setadaptation{
+
  #sctp_setadaptation{
         adaptation_ind = integer()
   }        

When set, requests that the local endpoint uses the value given by @@ -698,8 +684,7 @@ {sctp_peer_addr_params, #sctp_paddrparams{}} -

-  #sctp_paddrparams{
+
  #sctp_paddrparams{
         assoc_id   = assoc_id(),
         address    = {IP, Port},
         hbinterval = integer(),
@@ -756,16 +741,13 @@
                 

sackdelay_disable: disable SAC delay.

-

-

{sctp_default_send_param, #sctp_sndrcvinfo{}} -
-  #sctp_sndrcvinfo{
+
  #sctp_sndrcvinfo{
         stream     = integer(),
         ssn        = integer(),
         flags      = list(),
@@ -807,20 +789,17 @@
                   association, with flushing of unsent data.

-

Other fields are rarely used. See RFC2960 and Sockets API Extensions for SCTP for full information.

-

{sctp_events, #sctp_event_subscribe{}} -
-  #sctp_event_subscribe{
+
  #sctp_event_subscribe{
           data_io_event          = true | false,
           association_event      = true | false,
           address_event          = true | false,
@@ -845,8 +824,7 @@
       
       {sctp_delayed_ack_time, #sctp_assoc_value{}}
       
-        
-  #sctp_assoc_value{
+
  #sctp_assoc_value{
         assoc_id    = assoc_id(),
         assoc_value = integer()
   }        
@@ -857,8 +835,7 @@ {sctp_status, #sctp_status{}} -
-  #sctp_status{
+
  #sctp_status{
         assoc_id            = assoc_id(),
         state               = atom(),
         rwnd                = integer(),
@@ -930,14 +907,12 @@
               address (see below for the format of #sctp_paddrinfo{}).

-

{sctp_get_peer_addr_info, #sctp_paddrinfo{}} -
-  #sctp_paddrinfo{
+
  #sctp_paddrinfo{
         assoc_id  = assoc_id(),
         address   = {IP, Port},
         state     = inactive | active,
@@ -968,8 +943,7 @@
       
         

Example of an Erlang SCTP Server which receives SCTP messages and prints them on the standard output:

-
-  -module(sctp_server).
+
  -module(sctp_server).
   
   -export([server/0,server/1,server/2]).
   -include_lib("kernel/include/inet.hrl").
@@ -998,7 +972,6 @@
           io:format("Received: ~p~n", [Data])
       end,
       server_loop(S).        
-

Example of an Erlang SCTP Client which interacts with the above Server. @@ -1008,8 +981,7 @@ over Stream 5 fails. The client then aborts the association, which results in the corresponding Event being received on the Server side.

-
-  -module(sctp_client).
+
  -module(sctp_client).
   
   -export([client/0, client/1, client/2]).
   -include_lib("kernel/include/inet.hrl").
@@ -1042,13 +1014,11 @@
       
       timer:sleep(1000),
       gen_sctp:close(S).        
-

A very simple Erlang SCTP Client which uses the connect_init API.

-
--module(ex3).
+
-module(ex3).
 
 -export([client/4]).
 -include_lib("kernel/include/inet.hrl").
@@ -1101,7 +1071,6 @@ client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) ->
             ok
     end.
 
-

diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index 96e2aa665d..3b7a710664 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -37,13 +37,10 @@ monitoring of the network.

An Erlang node is started using the command line flag -name or -sname:

-
-$ erl -sname foobar
+
$ erl -sname foobar

It is also possible to call net_kernel:start([foobar]) directly from the normal Erlang shell prompt:

-

-
-1> net_kernel:start([foobar, shortnames]).
+
1> net_kernel:start([foobar, shortnames]).
 {ok,<0.64.0>}
 (foobar@gringotts)2>

If the node is started with the command line flag -sname, @@ -226,7 +223,6 @@ $ erl -sname foobar

NetTicktime seconds. TransitionPeriod defaults to 60.

Some definitions:

-

The minimum transition traffic interval (MTTI) diff --git a/lib/megaco/doc/src/megaco.xml b/lib/megaco/doc/src/megaco.xml index b9bf414299..5dd622368c 100644 --- a/lib/megaco/doc/src/megaco.xml +++ b/lib/megaco/doc/src/megaco.xml @@ -4,7 +4,7 @@
- 20002010 + 20002011 Ericsson AB. All Rights Reserved. @@ -646,7 +646,7 @@ megaco_incr_timer() = #megaco_incr_timer{} segments has not yet been received.

When the timer finally expires, a "megaco segments not received" (459) error message is sent to the other side - and the user is notified with a in either the + and the user is notified with a in either the handle_trans_reply callback function or the return value of the call function.

@@ -1165,7 +1165,7 @@ megaco_incr_timer() = #megaco_incr_timer{}

When the timer finally expires, a "megaco segments not received" (459) error message is sent to the other side and the user is notified with a - in either the + in either the handle_trans_reply callback function or the return value of the diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml index 7a8f796cee..19ec70118f 100644 --- a/lib/mnesia/doc/src/mnesia.xml +++ b/lib/mnesia/doc/src/mnesia.xml @@ -246,7 +246,7 @@ If a new item is inserted with the same key as

-

{max,MaxTabs}MaxTabs is a list of +

{max,MaxTabs}. MaxTabs is a list of tables that should be included in the checkpoint. The default is []. For these tables, the redundancy will be maximized and checkpoint information will be retained together @@ -274,7 +274,7 @@ If a new item is inserted with the same key as

-

{ram_overrides_dump,Bool} Only applicable +

{ram_overrides_dump,Bool}. Only applicable for ram_copies. Bool allows you to choose to backup the table state as it is in RAM, or as it is on disc. true means that the latest committed diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml index 73162c3974..665796f20d 100644 --- a/lib/mnesia/doc/src/mnesia_frag_hash.xml +++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml @@ -64,7 +64,7 @@

Note that the add_frag/2 function will be invoked one time each for the rest of the fragments (all but number 1) as a part of the table creation procedure.

-

State is the initial value of the hash_statefrag_property. The NewState will be stored as +

State is the initial value of the hash_state frag_property. The NewState will be stored as hash_state among the other frag_properties.

diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml index 11ca97f743..8a58dc2848 100644 --- a/lib/odbc/doc/src/odbc.xml +++ b/lib/odbc/doc/src/odbc.xml @@ -4,7 +4,7 @@
- 19992010 + 19992011 Ericsson AB. All Rights Reserved. @@ -138,7 +138,7 @@ Opens a connection to the database. ConnectStr = string() - An example of a connection string:"DSN=sql-server;UID=aladdin;PWD=sesame"where DSN is your ODBC Data Source Name, UID is a database user id and PWD is the password for that user. These are usually the attributes required in the connection string, but some drivers have other driver specific attributes, for example"DSN=Oracle8;DBQ=gandalf;UID=aladdin;PWD=sesame"where DBQ is your TNSNAMES.ORA entry name e.g. some Oracle specific configuration attribute. + An example of a connection string: "DSN=sql-server;UID=aladdin;PWD=sesame" where DSN is your ODBC Data Source Name, UID is a database user id and PWD is the password for that user. These are usually the attributes required in the connection string, but some drivers have other driver specific attributes, for example "DSN=Oracle8;DBQ=gandalf;UID=aladdin;PWD=sesame" where DBQ is your TNSNAMES.ORA entry name e.g. some Oracle specific configuration attribute. Options = [] | [option()] All options has default values. option() = {auto_commit, on | off} | {timeout, milliseconds()} @@ -432,7 +432,7 @@

Selects N consecutive rows of the result set. If Position is next it is semantically equivalent - of calling next/[1,2]N times. If + of calling next/[1,2] N times. If Position is {relative, Pos}, Pos will be used as an offset from the current cursor position to determine the first selected row. If Position is diff --git a/lib/orber/doc/src/orber_ifr.xml b/lib/orber/doc/src/orber_ifr.xml index 021082e101..2d47d57476 100644 --- a/lib/orber/doc/src/orber_ifr.xml +++ b/lib/orber/doc/src/orber_ifr.xml @@ -4,7 +4,7 @@

- 19972009 + 19972011 Ericsson AB. All Rights Reserved. @@ -297,7 +297,7 @@ - describe_contents(Objref,Limit_type,Exclude_inherited,Max_returned_objs) -> Return + describe_contents(Objref, Limit_type, Exclude_inherited, Max_returned_objs) -> Return Return a list of descriptions of the IFR objects contained by the target Container object Objref = #IFR_objref diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml index 1d2a985d7d..66bc6f4795 100644 --- a/lib/parsetools/doc/src/yecc.xml +++ b/lib/parsetools/doc/src/yecc.xml @@ -4,7 +4,7 @@
- 19962009 + 19962011 Ericsson AB. All Rights Reserved. @@ -336,7 +336,7 @@ element -> list : '$1'. {cons, {atom, 1, a,} {cons, {atom, 1, b}, {cons, {atom, 1, c}, nil}}} -

The associated code contains pseudo variables'$1', '$2', '$3', etc. which refer to (are +

The associated code contains pseudo variables '$1', '$2', '$3', etc. which refer to (are bound to) the values associated previously by the parser with the symbols of the right hand side of the rule. When these symbols are terminal categories, the values are token tuples of diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml index 013e94c393..db65eb3848 100644 --- a/lib/stdlib/doc/src/beam_lib.xml +++ b/lib/stdlib/doc/src/beam_lib.xml @@ -88,7 +88,6 @@ it is recommended that it contains at least 32 characters and that both upper and lower case letters as well as digits and special characters are used.

-

The default type -- and currently the only type -- of crypto algorithm is des3_cbc, three rounds of DES. The key string will be scrambled using erlang:md5/1 to generate diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml index 54fefbe2b8..215ec154ed 100644 --- a/lib/stdlib/doc/src/dets.xml +++ b/lib/stdlib/doc/src/dets.xml @@ -1006,8 +1006,7 @@ ok Return a QLC query handle. -

- Returns a QLC (Query List +

Returns a QLC (Query List Comprehension) query handle. The module qlc implements a query language aimed mainly at Mnesia but Ets tables, Dets tables, and lists are also recognized by qlc diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml index 929620bb88..fe166dbd01 100644 --- a/lib/stdlib/doc/src/erl_tar.xml +++ b/lib/stdlib/doc/src/erl_tar.xml @@ -4,7 +4,7 @@

- 20032009 + 20032011 Ericsson AB. All Rights Reserved. @@ -89,9 +89,8 @@ Reason = term() -

The -add/3 function adds a file to a tar file - that has been opened for writing by +

The add/3 function adds + a file to a tar file that has been opened for writing by open/1.

dereference @@ -138,8 +137,8 @@ TarDescriptor = term() -

The -close/1 function closes a tar file +

The close/1 function + closes a tar file opened by open/1.

@@ -151,11 +150,12 @@ FileList = [Filename|{NameInArchive, binary()},{NameInArchive, Filename}] Filename = filename() NameInArchive = filename() - RetValue = ok|{error,{Name,Reason}} <V>Reason = term() + RetValue = ok|{error,{Name,Reason}} + Reason = term() -

The -create/2 function creates a tar file and +

The create/2 function + creates a tar file and archives the files whose names are given in FileList into it. The files may either be read from disk or given as binaries.

@@ -171,11 +171,11 @@ NameInArchive = filename() OptionList = [Option] Option = compressed|cooked|dereference|verbose - RetValue = ok|{error,{Name,Reason}} <V>Reason = term() + RetValue = ok|{error,{Name,Reason}} + Reason = term() -

The -create/3 function +

The create/3 function creates a tar file and archives the files whose names are given in FileList into it. The files may either be read from disk or given as binaries.

@@ -220,9 +220,8 @@ Reason = term() -

The -extract/1 function extracts - all files from a tar archive.

+

The extract/1 function + extracts all files from a tar archive.

If the Name argument is given as "{binary,Binary}", the contents of the binary is assumed to be a tar archive.

@@ -250,9 +249,8 @@ Reason = term() -

The -extract/2 function extracts - files from a tar archive.

+

The extract/2 function + extracts files from a tar archive.

If the Name argument is given as "{binary,Binary}", the contents of the binary is assumed to be a tar archive.

@@ -322,8 +320,8 @@ Reason = term() -

The -format_error/1 converts +

The format_error/1 + function converts an error reason term to a human-readable error message string.

@@ -339,8 +337,8 @@ Reason = term() -

The -open/2 function creates a tar file for writing. +

The open/2 function creates + a tar file for writing. (Any existing file with the same name will be truncated.)

By convention, the name of a tar file should end in ".tar". To abide to the convention, you'll need to add ".tar" yourself @@ -373,7 +371,6 @@ You should not rely on the specific contents of the TarDescriptor term, as it may change in future versions as more features are added to the erl_tar module.

-

@@ -386,9 +383,8 @@ Reason = term() -

The -table/1 function retrieves - the names of all files in the tar file Name.

+

The table/1 function + retrieves the names of all files in the tar file Name.

@@ -398,9 +394,8 @@ Name = filename() -

The -table/2 function retrieves - the names of all files in the tar file Name.

+

The table/2 function + retrieves the names of all files in the tar file Name.

@@ -410,8 +405,7 @@ Name = filename() -

The -t/1 function prints the names +

The t/1 function prints the names of all files in the tar file Name to the Erlang shell. (Similar to "tar t".)

@@ -423,8 +417,8 @@ Name = filename() -

The -tt/1 function prints names and +

The tt/1 function prints + names and information about all files in the tar file Name to the Erlang shell. (Similar to "tar tv".)

diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index f19f92be6f..efd9514db6 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -512,11 +512,10 @@ Error: fun containing local Erlang function calls of the reference counter, keeping track of how many times the table has been fixed by the process.

If the table never has been fixed, the call returns - false.

- Item=stats, Value=tuple()

+ false.

+

Item=stats, Value=tuple()

Returns internal statistics about set, bag and duplicate_bag tables on an internal format used by OTP test suites. - Not for production use. - + Not for production use.

@@ -661,9 +660,9 @@ ets:is_compiled_ms(Broken).
table. The difference being the same as between =:= and ==. As an example, one might insert an object with the - integer()1 as a key in an ordered_set + integer() 1 as a key in an ordered_set and get the object returned as a result of doing a - lookup/2 with the float()1.0 as the + lookup/2 with the float() 1.0 as the key to search for.

If the table is of type set or ordered_set, the function returns either the empty list or a list with one @@ -946,7 +945,7 @@ ets:select(Table,MatchSpec), table is named or not. If one or more options are left out, the default values are used. This means that not specifying any options ([]) is the same as specifying - [set,protected,{keypos,1},{heir,none},{write_concurrency,false},{read_concurrency,false}].

+ [set, protected, {keypos,1}, {heir,none}, {write_concurrency,false}, {read_concurrency,false}].

set @@ -963,7 +962,7 @@ ets:select(Table,MatchSpec), ordered_set tables regard keys as equal when they compare equal, not only when they match. This means that to an ordered_set, the - integer()1 and the float()1.0 are regarded as equal. This also means that the + integer() 1 and the float() 1.0 are regarded as equal. This also means that the key used to lookup an element not necessarily matches the key in the elements returned, if float()'s and integer()'s are mixed in diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml index 38de51322f..f91fac9c82 100644 --- a/lib/stdlib/doc/src/gb_sets.xml +++ b/lib/stdlib/doc/src/gb_sets.xml @@ -61,7 +61,6 @@ and do the same thing in the sets and ordsets modules. That is, by only changing the module name for each call, you can try out different set representations.

-

add_element/2

diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml index e35b5adace..421eeb4fd3 100644 --- a/lib/stdlib/doc/src/gen_fsm.xml +++ b/lib/stdlib/doc/src/gen_fsm.xml @@ -4,7 +4,7 @@
- 19962010 + 19962011 Ericsson AB. All Rights Reserved. @@ -430,7 +430,6 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4 denote a state of the state machine. state data is used to denote the internal state of the Erlang process which implements the state machine.

-

diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index 60c0b91212..36089f2603 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -2632,7 +2632,7 @@ that is, also when starting a gen_server, gen_fsm etc.

This limitation has now been properly documented and the behavior of the gen_fsm, gen_server, and - proc_libstart and start_link + proc_lib start and start_link functions when providing this option has been changed from hanging indefinitely to failing with reason badarg.

@@ -2749,7 +2749,6 @@ join option that can be used to force QLC to use a particular kind of join in some QLC expression.

Several other changes have also been included:

-

The new tmpdir option of cursor/2, diff --git a/lib/stdlib/doc/src/qlc.xml b/lib/stdlib/doc/src/qlc.xml index 6a45ade447..ce50631ca9 100644 --- a/lib/stdlib/doc/src/qlc.xml +++ b/lib/stdlib/doc/src/qlc.xml @@ -688,7 +688,6 @@ ets:match_spec_run(ets:lookup(86033, {2,2}), -

diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index edd119d37a..ec607d6e4c 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -59,7 +59,6 @@ processes are started in order from left to right according to this list. When the supervisor terminates, it first terminates its child processes in reversed start order, from right to left.

-

A supervisor can have one of the following restart strategies:

diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml index b741ab7db1..0c1e398dc4 100644 --- a/lib/stdlib/doc/src/timer.xml +++ b/lib/stdlib/doc/src/timer.xml @@ -84,7 +84,7 @@ Send Messageto Pidafter a specified Time. -

+

send_after/3 @@ -98,6 +98,7 @@

Same as send_after(Time, self(), Message).

+

@@ -107,7 +108,7 @@ Send an exit signal with Reasonafter a specified Time. -

+

exit_after/3 @@ -128,6 +129,7 @@

Same as exit_after(Time, self(), kill).

+

@@ -144,7 +146,7 @@ Send Messagerepeatedly at intervals of Time. -

+

send_interval/3 @@ -158,6 +160,7 @@

Same as send_interval(Time, self(), Message).

+

@@ -188,7 +191,7 @@ Function, Arguments) or apply(Fun, Arguments) In microseconds -

+

tc/3 @@ -209,6 +212,7 @@ +

@@ -254,7 +258,6 @@
Examples

This example illustrates how to print out "Hello World!" in 5 seconds:

-

       1> timer:apply_after(5000, io, format, ["~nHello World!~n", []]).
       {ok,TRef}
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index b03fc7f4e2..cf0d581352 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -243,12 +243,10 @@
       
       Extract files from a zip archive
       
-        

The -unzip/1 function extracts - all files from a zip archive. The - -unzip/2 function provides options - to extract some files, and more.

+

The unzip/1 function extracts + all files from a zip archive. + The unzip/2 function provides + options to extract some files, and more.

If the Archive argument is given as a binary, the contents of the binary is assumed to be a zip archive, otherwise it should be a filename.

@@ -413,8 +411,8 @@ Open an archive and return a handle to it -

The -zip_open function opens a +

The zip_open function + opens a zip archive, and reads and saves its directory. This means that subsequently reading files from the archive will be faster than unzipping files one at a time with unzip.

@@ -436,8 +434,7 @@ Extract files from an open archive -

The -zip_get function extracts +

The zip_get function extracts one or all files from an open archive.

The files will be unzipped to memory or to file, depending on the options given to the zip_open function when the @@ -448,9 +445,8 @@ Close an open archive -

The -zip_close/1 function closes - a zip archive, previously opened with zip_open. All +

The zip_close/1 function + closes a zip archive, previously opened with zip_open. All resources are closed, and the handle should not be used after closing.

diff --git a/lib/test_server/doc/src/ts.xml b/lib/test_server/doc/src/ts.xml index 496ad3667a..f9b48d8372 100644 --- a/lib/test_server/doc/src/ts.xml +++ b/lib/test_server/doc/src/ts.xml @@ -77,7 +77,7 @@

ts:install/0 is used if the target platform is the same as the controller host, i.e. if you run on "local target" - and no options are needed. Then running ts:install/0ts + and no options are needed. Then running ts:install/0 ts will run an autoconf script for your current environment and set up the necessary variables needed by the test suites. diff --git a/lib/wx/src/gen/wxRegion.erl b/lib/wx/src/gen/wxRegion.erl index 0ceba1d203..4e8d98a54f 100644 --- a/lib/wx/src/gen/wxRegion.erl +++ b/lib/wx/src/gen/wxRegion.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -48,7 +48,7 @@ new() -> %% new(Bmp::wxBitmap:wxBitmap()) -> wxRegion() %%

%%

-%% new(Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> wxRegion() +%% new(Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> wxRegion() %%

new(#wx_ref{type=BmpT,ref=BmpRef}) -> ?CLASS(BmpT,wxBitmap), diff --git a/lib/wx/src/gen/wxWindow.erl b/lib/wx/src/gen/wxWindow.erl index 33665a0ad6..031314bfe2 100644 --- a/lib/wx/src/gen/wxWindow.erl +++ b/lib/wx/src/gen/wxWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -1144,10 +1144,10 @@ setCaret(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=CaretT,ref=CaretRef}) -> %% @doc See external documentation. %%
Alternatives: %%

-%% setClientSize(This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok +%% setClientSize(This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok %%

%%

-%% setClientSize(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok +%% setClientSize(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok %%

setClientSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH}) when is_integer(SizeW),is_integer(SizeH) -> -- cgit v1.2.3 From 64b082b98d952cdb91ed5a899b0f8ab350a4981e Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Mon, 19 Sep 2011 15:20:31 +0200 Subject: Improve the generation of man pages Empty lines have been eliminated. Spurious spacing has been corrected. --- lib/erl_docgen/priv/xsl/db_man.xsl | 104 +++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 26 deletions(-) diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl index 8db4714249..c7efced3d2 100644 --- a/lib/erl_docgen/priv/xsl/db_man.xsl +++ b/lib/erl_docgen/priv/xsl/db_man.xsl @@ -25,12 +25,12 @@ xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> - + @@ -137,8 +137,8 @@ (there is no spec with more than one clause) --> .RS - .TP - Types + .TP 3 + Types: @@ -223,10 +223,13 @@ - - - .br - + + + + + .br + + @@ -319,8 +322,7 @@ - .nf - .B + .nf .br .fi @@ -345,6 +347,13 @@ .br + + + + \fB\fR\& + + + @@ -465,13 +474,13 @@ .TP 2 * - .LP + .LP .RS 2 - .RE + .RE @@ -494,7 +503,7 @@ .RS 2 - .LP .LP + .LP .RE @@ -529,7 +538,16 @@ - .br + + + + .B + + + .br + + @@ -547,17 +565,17 @@ .LP - .nf + .nf - .fi + .fi .LP - .nf + .nf - .fi + .fi @@ -715,8 +733,8 @@ .RS - .TP - Types + .TP 3 + Types: .RE @@ -788,7 +806,36 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -804,11 +851,16 @@ - - - - - + + + + + + + + + + -- cgit v1.2.3 From 5d9c9606bd3d239f52b6156d07000d1b5bbe0858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 26 Sep 2011 11:32:33 +0200 Subject: erl_prim_loader: Eliminate dialyzer warning The concat/1 function is now only used to append lists when constructing filenames. Thus it is too general and the first clause (that handles characters) will never be used. We could just remove the clause that is never used, but then the name 'concat' would be misleading and someone could use misuse it. Therefore, replace concat/1 with the join/2 function that can only be used for joining filename components. --- erts/preloaded/src/erl_prim_loader.erl | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 4a72bae105..0b4db3d9d0 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -470,7 +470,7 @@ efile_get_file_from_port2(#state{prim_state = PS} = State, File) -> end. efile_get_file_from_port3(State, File, [P | Paths]) -> - case efile_get_file_from_port2(State, concat([P,"/",File])) of + case efile_get_file_from_port2(State, join(P, File)) of {{error,Reason},State1} when Reason =/= emfile -> case Paths of [] -> % return last error @@ -644,7 +644,7 @@ inet_get_file_from_port(State, File, Paths) -> end. inet_get_file_from_port1(File, [P | Paths], State) -> - File1 = concat([P,"/",File]), + File1 = join(P, File), case inet_send_and_rcv({get,File1}, File1, State) of {{error,Reason},State1} -> case Paths of @@ -1152,14 +1152,8 @@ send_all(U, [IP | AL], Cmd) -> send_all(U, AL, Cmd); send_all(_U, [], _) -> ok. -%%concat([A|T]) when is_atom(A) -> %Atom -%% atom_to_list(A) ++ concat(T); -concat([C|T]) when C >= 0, C =< 255 -> - [C|concat(T)]; -concat([S|T]) -> %String - S ++ concat(T); -concat([]) -> - []. +join(P, F) -> + P ++ "/" ++ F. member(X, [X|_]) -> true; member(X, [_|Y]) -> member(X, Y); -- cgit v1.2.3 From e423e12e8ad87348ca6c583b0ebdbe5de2aefc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 26 Sep 2011 11:39:48 +0200 Subject: Update preloaded modules --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 50528 -> 50180 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index 20c82c52bb..a28c24ab0c 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ -- cgit v1.2.3 From d9ec7c91ca6ae019ad80b03fb184924bad8d6bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 26 Sep 2011 13:58:33 +0200 Subject: ic documentation: Support parallel make --- lib/ic/doc/src/Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile index 8eda436a24..acb6848fee 100644 --- a/lib/ic/doc/src/Makefile +++ b/lib/ic/doc/src/Makefile @@ -206,6 +206,8 @@ JAVADOCFLAGS = \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- +_create_dirs := $(shell mkdir -p $(JAVA_OUT_DIR)) + $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ @@ -256,10 +258,7 @@ clean clean_docs clean_tex: endif -$(JAVA_OUT_DIR): - mkdir $(JAVA_OUT_DIR) - -$(JAVADOC_GENERATED_FILES): $(JAVA_OUT_DIR) +$(JAVADOC_GENERATED_FILES): @(cd ../../java_src; $(JAVADOC) $(JAVADOCFLAGS) com.ericsson.otp.ic) man: $(MAN3_FILES) -- cgit v1.2.3 From ab017dce9a19f2fcd470c85f562122aac161b466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 26 Sep 2011 14:49:28 +0200 Subject: busy_port_SUITE: Avoid crash in register/2 Add an end_per_testcase/2 function to ensure that the process with the name 'busy_drv_server' has been killed before the next test case attempts to register a process with the same name. --- erts/emulator/test/busy_port_SUITE.erl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl index 8365e1c540..dac2a70f59 100644 --- a/erts/emulator/test/busy_port_SUITE.erl +++ b/erts/emulator/test/busy_port_SUITE.erl @@ -20,7 +20,7 @@ -module(busy_port_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, + init_per_group/2,end_per_group/2,end_per_testcase/2, io_to_busy/1, message_order/1, send_3/1, system_monitor/1, no_trap_exit/1, no_trap_exit_unlinked/1, trap_exit/1, multiple_writers/1, @@ -53,6 +53,20 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +end_per_testcase(_Case, Config) when is_list(Config) -> + case whereis(busy_drv_server) of + undefined -> + ok; + Pid when is_pid(Pid) -> + Ref = monitor(process, Pid), + unlink(Pid), + exit(Pid, kill), + receive + {'DOWN',Ref,process,Pid,_} -> + ok + end + end, + Config. %% Tests I/O operations to a busy port, to make sure a suspended send %% operation is correctly restarted. This used to crash Beam. -- cgit v1.2.3 From 101d00d11e4e2c24cc5d54739e348aa34527e315 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 22 Sep 2011 10:16:59 +0200 Subject: Temporary disable tests on MAC due to issus with the MAC ODBC drivers --- lib/odbc/test/odbc_test_lib.erl | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/odbc/test/odbc_test_lib.erl b/lib/odbc/test/odbc_test_lib.erl index 4d7d1ae2fa..a8439d5fb6 100644 --- a/lib/odbc/test/odbc_test_lib.erl +++ b/lib/odbc/test/odbc_test_lib.erl @@ -36,18 +36,25 @@ match_float(Float, Match, Delta) -> (Float < Match + Delta) and (Float > Match - Delta). odbc_check() -> - case erlang:system_info({wordsize, external}) of - 4 -> - ok; - Other -> - case os:type() of - {unix, linux} -> + case os:type() of + {unix,darwin} -> + lists:flatten( + io_lib:format("Currently we have no working drivers for MAC", + [])); + _ -> + case erlang:system_info({wordsize, external}) of + 4 -> ok; - Platform -> - lists:flatten( - io_lib:format("Word on platform ~w size" - " ~w not supported", [Other, - Platform])) + Other -> + case os:type() of + {unix, linux} -> + ok; + Platform -> + lists:flatten( + io_lib:format("Word on platform ~w size" + " ~w not supported", [Other, + Platform])) + end end end. -- cgit v1.2.3 From edb449fc7f7ea9861b322edb6c00da907cec8c9c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 26 Sep 2011 15:37:00 +0200 Subject: crypto: touch Makefile to provoke patch release --- lib/crypto/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile index 13eebea6a9..2a8fc6acfd 100644 --- a/lib/crypto/Makefile +++ b/lib/crypto/Makefile @@ -36,3 +36,4 @@ SPECIAL_TARGETS = include $(ERL_TOP)/make/otp_subdir.mk +# touched by patch 1176 -- cgit v1.2.3 From 951e8fecc4641a2ab62653c56adc74d54fafd83a Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 20 Sep 2011 09:48:00 +0200 Subject: Minor documentation fixes Connector/listener -> connecting/listening transport. --- lib/diameter/doc/src/diameter_sctp.xml | 10 ++++++---- lib/diameter/doc/src/diameter_tcp.xml | 13 +++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml index d0377f4b38..c1e839b8e1 100644 --- a/lib/diameter/doc/src/diameter_sctp.xml +++ b/lib/diameter/doc/src/diameter_sctp.xml @@ -74,11 +74,12 @@ marker="diameter_transport#start">diameter_transport(3).

The only diameter_sctp-specific argument is the options list. Options raddr and rport specify the remote address -and port for a connector and not valid for a listener. +and port for a connecting transport and not valid for a listening +transport. The former is required while latter defaults to 3868 if unspecified. More than one raddr option can be specified, in which case the -connector in question attempts each in sequence until an association -is established. +connecting transport in question attempts each in sequence until +an association is established. Remaining options are any accepted by gen_sctp:open/1, with the exception of options mode, binary, list, active and sctp_events. @@ -89,7 +90,8 @@ and port respectively.

Multiple ip options can be specified for a multihomed peer. If none are specified then the values of Host-IP-Address on the service are used. (In particular, one of these must be specified.) -Option port defaults to 3868 for a listener and 0 for a connector.

+Option port defaults to 3868 for a listening transport and 0 for a +connecting transport.

diameter_sctp uses the transport_data field of diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml index 5d6e07b1b8..a502e53972 100644 --- a/lib/diameter/doc/src/diameter_tcp.xml +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -74,13 +74,14 @@ marker="diameter_transport#start">diameter_transport(3).

The only diameter_tcp-specific argument is the options list. Options raddr and rport specify the remote address -and port for a connector and not valid for a listener. +and port for a connecting transport and not valid for a listening +transport. Remaining options are any accepted by gen_tcp:connect/3 for -a connector, or gen_tcp:listen/2 for a listener, with the exception -of binary, packet and active. -Also, option port can be specified for a listener to specify the -local listening port, the default being the standardized 3868 if -unspecified. +a connecting transport, or gen_tcp:listen/2 for a listening transport, +with the exception of binary, packet and active. +Also, option port can be specified for a listening transport +to specify the local listening port, the default being the standardized +3868 if unspecified. Note that option ip specifies the local address.

-- cgit v1.2.3 From 73f89318887d473536350b1531cad27f9ab94c7c Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 22 Sep 2011 19:52:47 +0200 Subject: Fix header folding bug A prepare_request callback from diameter can return a diameter_header record with in order to set values in the header of an outgoing request. The fault in diameter_lib:fold_tuple/3 caused encode of the outgoing request to fail. --- lib/diameter/src/app/diameter_lib.erl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/app/diameter_lib.erl index b5c0e1bf6a..46fd87c591 100644 --- a/lib/diameter/src/app/diameter_lib.erl +++ b/lib/diameter/src/app/diameter_lib.erl @@ -255,12 +255,13 @@ w(L) -> fold_tuple(_, T, undefined) -> T; -fold_tuple(N, T0, T) -> - element(2, lists:foldl(fun(X, {M,_} = A) -> {M+1, ft(X, A)} end, - {N, T0}, - lists:nthtail(N-1, tuple_to_list(T)))). +fold_tuple(N, T0, T1) -> + {_, T} = lists:foldl(fun(V, {I,_} = IT) -> {I+1, ft(V, IT)} end, + {N, T0}, + lists:nthtail(N-1, tuple_to_list(T1))), + T. -ft(undefined, T) -> +ft(undefined, {_, T}) -> T; -ft(X, {N, T}) -> - setelement(N, T, X). +ft(Value, {Idx, T}) -> + setelement(Idx, T, Value). -- cgit v1.2.3 From 48a715dec34a61208e82f91b49a3d3670a62d7ce Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 23 Sep 2011 17:01:39 +0200 Subject: Fix improper use of error_logger:info_report/2 Function doesn't take a format string and arguments as we called it. Instead use error_logger:info_report/1 and use the same report format as used for warning and error reports. --- lib/diameter/src/app/diameter_lib.erl | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/app/diameter_lib.erl index b5c0e1bf6a..36cc201dde 100644 --- a/lib/diameter/src/app/diameter_lib.erl +++ b/lib/diameter/src/app/diameter_lib.erl @@ -46,14 +46,9 @@ report(Reason, MFA) -> info_report(Reason, MFA). -info_report(Reason, {M,F,A}) -> - error_logger:info_report(" Reason: ~p~n" - " Pid: ~p~n" - " Node: ~p~n" - " Module: ~p~n" - " Function: ~p~n" - "Arguments: ~p~n", - [Reason, self(), node(), M, F, A]). +info_report(Reason, MFA) -> + report(fun error_logger:info_report/1, Reason, MFA), + true. %%% --------------------------------------------------------------------------- %%% # error_report(Reason, MFA) @@ -69,7 +64,7 @@ warning_report(Reason, MFA) -> report(fun error_logger:warning_report/1, Reason, MFA). report(Fun, Reason, MFA) -> - Fun([{reason, Reason}, {who, self()}, {where, node()}, {what, MFA}]), + Fun([{why, Reason}, {who, self()}, {what, MFA}]), false. %%% --------------------------------------------------------------------------- -- cgit v1.2.3 From 7d38b593e8b1624e1ce2cda8fa57a42cdf2d3068 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 23 Sep 2011 19:55:01 +0200 Subject: Fix and clarify semantics of peer filters An eval filter returning a non-true value caused the call process to fail and the doc was vague on how an exception was treated. Clarify that the non-tuple host/realm filters assume messages of a certain form. Various minor corrections to align code and doc. --- lib/diameter/doc/src/diameter.xml | 37 ++++++++++++---- lib/diameter/doc/src/diameter_app.xml | 7 ++- lib/diameter/src/app/diameter_service.erl | 71 ++++++++++++++++--------------- 3 files changed, 72 insertions(+), 43 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 36b6cbf0cf..2cad70e3bc 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -277,6 +277,10 @@ callback.

+

+An invalid option will cause call/4 +to fail.

+ @@ -405,6 +409,8 @@ sense.

eval([{M,F,A} | T]) -> apply(M, F, T ++ A); +eval([[F|A] | T]) -> + eval([F | T ++ A]); eval([F|A]) -> apply(F, A); eval(F) -> @@ -461,14 +467,14 @@ or any peer if the request does not contain a Destination-Realm AVP.

-{host, any|UTF8String()} +{host, any|DiameterIdentity()}

Matches only those peers whose Origin-Host has the specified value, or all peers if the atom any.

-{realm, any|UTF8String() +{realm, any|DiameterIdentity()

Matches only those peers whose Origin-Realm has the @@ -478,8 +484,9 @@ value, or all peers if the atom any.

{eval, evaluable()}

-Matches only those peers for which the specified evaluable() evaluates -to true on the peer's diameter_caps record.

+Matches only those peers for which the specified evaluable() returns +true on the connection's diameter_caps record. +Any other return value or exception is equivalent to false.

{neg, peer_filter()} @@ -503,6 +510,21 @@ specified list.

+

+Note that the host and realm filters examine the +outgoing request as passed to call/4, +assuming that this is a record- or list-valued message() as documented +in diameter_app(3), and that +the message contains at most one of each AVP. +If this is not the case then the {host|realm, DiameterIdentity()} +filters must be used to achieve the desired result. +Note also that an empty host/realm (which should not be typical) +is equivalent to an unspecified one for the purposes of filtering.

+ +

+An invalid filter is equivalent to {any, []}, a filter +that matches no peer.

+
@@ -787,7 +809,7 @@ transports.

SvcName = service_name() App = application_alias() -Request = diameter_app:message() +Request = diameter_app:message() | term() Answer = term() Options = [call_opt()] @@ -819,9 +841,8 @@ If there are no suitable peers, or if pick_peer/4 rejects them by returning 'false', then {error, no_connection} is returned. -If pick_peer/4 -selects a candidate peer then a request process is spawned for the -outgoing request, in which there is a +Otherwise pick_peer/4 +is followed by a prepare_request/3 callback, the message is encoded and sent.

diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml index fc359b9d1d..f2bada84ae 100644 --- a/lib/diameter/doc/src/diameter_app.xml +++ b/lib/diameter/doc/src/diameter_app.xml @@ -269,7 +269,12 @@ The candidate peers list will only include those which are selected by any filter option specified in the call to diameter:call/4, and only those which have indicated support for the Diameter application in -question.

+question. +The order of the elements is unspecified except that any +peers whose Origin-Host and Origin-Realm matches that of the +outgoing request (in the sense of a {filter, {all, [host, realm]}} +option to diameter:call/4) +will be placed at the head of the list.

The return values false and {false, State} are diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl index 63b0649dc4..a72453d431 100644 --- a/lib/diameter/src/app/diameter_service.erl +++ b/lib/diameter/src/app/diameter_service.erl @@ -1398,15 +1398,15 @@ recv_answer(Timeout, %% is, from the last peer to which we've transmitted. receive - {answer = A, Ref, Rq, Pkt} -> %% Answer from peer. + {answer = A, Ref, Rq, Pkt} -> %% Answer from peer {A, Rq, Pkt}; - {timeout = Reason, TRef, _} -> %% No timely reply + {timeout = Reason, TRef, _} -> %% No timely reply {error, Req, Reason}; - {failover = Reason, TRef, false} -> %% No alternative peer. + {failover = Reason, TRef, false} -> %% No alternate peer {error, Req, Reason}; - {failover, TRef, Transport} -> %% Resend to alternate peer. + {failover, TRef, Transport} -> %% Resend to alternate peer try_retransmit(Timeout, SvcName, Req, Transport); - {failover, TRef} -> %% May have missed failover notification. + {failover, TRef} -> %% May have missed failover notification Seqs = diameter_codec:sequence_numbers(RPkt), Pid = whois(SvcName), is_pid(Pid) andalso (Pid ! {failover, TRef, Seqs}), @@ -2482,6 +2482,7 @@ rpd(Pid, Alias, PDict) -> %%% %%% Output: {TransportPid, #diameter_caps{}, #diameter_app{}} %%% | false +%%% | {error, Reason} %%% --------------------------------------------------------------------------- %% Initial call, from an arbitrary process. @@ -2540,22 +2541,12 @@ get_destination(Msg, Dict) -> [str(get_avp_value(Dict, 'Destination-Realm', Msg)), str(get_avp_value(Dict, 'Destination-Host', Msg))]. -%% TODO: -%% -%% Should add some way of specifying destination directly so that the -%% only requirement is that the prepare_request callback returns -%% something specific. (eg. {host, DH}; that is, let the caller specify.) -%% -%% Also, there is no longer any need to call get_destination at all in -%% the default case. - -str(T) - when T == undefined; - T == [] -> +%% This is not entirely correct. The avp could have an arity 1, in +%% which case an empty list is a DiameterIdentity of length 0 rather +%% than the list of no values we treat it as by mapping to undefined. +%% This behaviour is documented. +str([]) -> undefined; -str([X]) - when is_list(X) -> - X; str(T) -> T. @@ -2690,7 +2681,8 @@ peers(Alias, RH, Filter, Peers) -> end. %% Place a peer whose Destination-Host/Realm matches those of the -%% request at the front of the result list. +%% request at the front of the result list. Could add some sort of +%% 'sort' option to allow more control. ps([], _, _, {Ys, Ns}) -> lists:reverse(Ys, Ns); @@ -2700,11 +2692,11 @@ ps([{_TPid, #diameter_caps{} = Caps} = TC | Rest], RH, Filter, Acc) -> TC, Acc)). -pacc(true, true, TC, {Ts, Fs}) -> - {[TC|Ts], Fs}; -pacc(true, false, TC, {Ts, Fs}) -> - {Ts, [TC|Fs]}; -pacc(false, _, _, Acc) -> +pacc(true, true, Peer, {Ts, Fs}) -> + {[Peer|Ts], Fs}; +pacc(true, false, Peer, {Ts, Fs}) -> + {Ts, [Peer|Fs]}; +pacc(_, _, _, Acc) -> Acc. %% caps_filter/3 @@ -2712,17 +2704,19 @@ pacc(false, _, _, Acc) -> caps_filter(C, RH, {neg, F}) -> not caps_filter(C, RH, F); -caps_filter(C, RH, {all, L}) -> +caps_filter(C, RH, {all, L}) + when is_list(L) -> lists:all(fun(F) -> caps_filter(C, RH, F) end, L); -caps_filter(C, RH, {any, L}) -> +caps_filter(C, RH, {any, L}) + when is_list(L) -> lists:any(fun(F) -> caps_filter(C, RH, F) end, L); -caps_filter(#diameter_caps{origin_host = {_,H}}, [_,DH], host) -> - eq(undefined, DH, H); +caps_filter(#diameter_caps{origin_host = {_,OH}}, [_,DH], host) -> + eq(undefined, DH, OH); -caps_filter(#diameter_caps{origin_realm = {_,R}}, [DR,_], realm) -> - eq(undefined, DR, R); +caps_filter(#diameter_caps{origin_realm = {_,OR}}, [DR,_], realm) -> + eq(undefined, DR, OR); caps_filter(C, _, Filter) -> caps_filter(C, Filter). @@ -2738,6 +2732,9 @@ caps_filter(#diameter_caps{origin_host = {_,OH}}, {host, H}) -> caps_filter(#diameter_caps{origin_realm = {_,OR}}, {realm, R}) -> eq(any, R, OR); +%% Anything else is expected to be an eval filter. Filter failure is +%% documented as being equivalent to a non-matching filter. + caps_filter(C, T) -> try {eval, F} = T, @@ -2746,8 +2743,14 @@ caps_filter(C, T) -> _:_ -> false end. -eq(X, A, B) -> - X == A orelse A == B. +eq(Any, Id, PeerId) -> + Any == Id orelse try + iolist_to_binary(Id) == iolist_to_binary(PeerId) + catch + _:_ -> false + end. +%% OctetString() can be specified as an iolist() so test for string +%% rather then term equality. %% transports/1 -- cgit v1.2.3 From 322885a2c501384bb5c83d391d0c3fa91d82d5da Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 25 Sep 2011 16:49:29 +0200 Subject: Fix sending of messages of arbitrary form diameter:call/4 can be passed anything, as long as the subsequent prepare_request callback returns a term that can be encoded. --- lib/diameter/src/app/diameter_service.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl index 63b0649dc4..a7fe733340 100644 --- a/lib/diameter/src/app/diameter_service.erl +++ b/lib/diameter/src/app/diameter_service.erl @@ -2561,7 +2561,7 @@ str(T) -> %% get_avp_value/3 %% -%% Support outgoing messages in one of three forms: +%% Find an AVP in a message of one of three forms: %% %% - a message record (as generated from a .dia spec) or %% - a list of an atom message name followed by 2-tuple, avp name/value pairs. @@ -2593,8 +2593,9 @@ get_avp_value(_, Name, [_MsgName | Avps]) -> undefined end; -get_avp_value(Dict, Name, Rec) - when is_tuple(Rec) -> +%% Message is typically a record but not necessarily: diameter:call/4 +%% can be passed an arbitrary term. +get_avp_value(Dict, Name, Rec) -> try Dict:'#get-'(Name, Rec) catch -- cgit v1.2.3 From 60bf2967f81dd51b5da10d8a9e8502b9026d543a Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 22 Jul 2011 12:12:25 +0200 Subject: Remove slask and beam --- lib/diameter/test/diameter_etcp_test.beam | Bin 1808 -> 0 bytes .../test/slask/diameter_persistent_table_test.erl | 495 --------------------- 2 files changed, 495 deletions(-) delete mode 100644 lib/diameter/test/diameter_etcp_test.beam delete mode 100644 lib/diameter/test/slask/diameter_persistent_table_test.erl diff --git a/lib/diameter/test/diameter_etcp_test.beam b/lib/diameter/test/diameter_etcp_test.beam deleted file mode 100644 index efaaec69d5..0000000000 Binary files a/lib/diameter/test/diameter_etcp_test.beam and /dev/null differ diff --git a/lib/diameter/test/slask/diameter_persistent_table_test.erl b/lib/diameter/test/slask/diameter_persistent_table_test.erl deleted file mode 100644 index bb907a5777..0000000000 --- a/lib/diameter/test/slask/diameter_persistent_table_test.erl +++ /dev/null @@ -1,495 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the persistent-table component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_persistent_table_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/1, - suite_init/1, suite_fin/1, - - simple_start_and_stop/1, - table_create_and_delete/1 - - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - --record(command, {id, desc, cmd, verify}). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all(suite) -> - Cases = - [ - simple_start_and_stop, - table_create_and_delete - ], - {req, [], {conf, suite_init, Cases, suite_fin}}. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(suite) -> []; -suite_init(doc) -> []; -suite_init(Config) when is_list(Config) -> - Config. - - -suite_fin(suite) -> []; -suite_fin(doc) -> []; -suite_fin(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case(s) -%% - -simple_start_and_stop(suite) -> - []; -simple_start_and_stop(doc) -> - []; -simple_start_and_stop(Config) when is_list(Config) -> - diameter:enable_trace(100, io), - case diameter_persistent_table:start_link() of - {ok, Pid} -> - unlink(Pid); - {error, Reason} -> - exit({failed_starting, Reason}) - end, - - ok = diameter_persistent_table:stop(), - ok. - - -table_create_and_delete(suite) -> - []; -table_create_and_delete(doc) -> - []; -table_create_and_delete(Config) when is_list(Config) -> - process_flag(trap_exit, true), - - %% Command range values - Initial = 100, - ClientCreation = 200, - Nice = 300, - Evil = 400, - End = 500, - - Verbosity = min, - %% Verbosity = max, - - Data01 = lists:sort([{a, 10}, {b, 20}, {c, 30}]), - Data02 = lists:sort([{x, 100}, {y, 200}, {z, 300}]), - - Commands = - [ - %% Initial commands - initial_command( Initial + 0, - "enable trace", - fun() -> diameter:enable_trace(Verbosity, io) end, - ok), - initial_command( Initial + 1, - "start persistent-table process", - fun() -> - case diameter_persistent_table:start_link() of - {ok, Pid} when is_pid(Pid) -> - ok; - Error -> - Error - end - end, - ok), - - client_create_command( ClientCreation + 1, - "1", - client01), - - client_create_command( ClientCreation + 2, - "2", - client02), - - nice_command( Nice + 1, - "client 1 create table 1", - fun() -> - create_table(client01, tab01, []), - diameter_persistent_table:which_tables() - end, - fun([tab01] = Tabs) -> - {ok, Tabs}; - (Unexpected) -> - {error, {bad_tables, Unexpected}} - end), - - nice_command( Nice + 2, - "client 1 create table 2", - fun() -> - create_table(client01, tab02, []), - diameter_persistent_table:which_tables() - end, - fun([tab01, tab02] = Tabs) -> - {ok, Tabs}; - ([tab02, tab01] = Tabs) -> - {ok, Tabs}; - (Unexpected) -> - {error, {bad_tables, Unexpected}} - end), - - nice_command( Nice + 3, - "client 2 create table 1", - fun() -> - create_table(client02, tab03, []), - diameter_persistent_table:which_tables(whereis(client02)) - end, - fun([tab03] = Tabs) -> - {ok, Tabs}; - (Unexpected) -> - {error, {bad_tables, Unexpected}} - end), - - nice_command( Nice + 4, - "client 1 delete table 1", - fun() -> - delete_table(client01, tab01), - diameter_persistent_table:which_tables(whereis(client01)) - end, - fun([tab02] = Tabs) -> - {ok, Tabs}; - (Unexpected) -> - {error, {bad_tables, Unexpected}} - end), - - nice_command( Nice + 5, - "client 1 fill in some data in tab02", - fun() -> - populate_table(client01, tab02, Data01), - lists:sort(ets:tab2list(tab02)) - end, - fun(Data) when Data =:= Data01 -> - {ok, Data}; - (Unexpected) -> - {error, {bad_data, Unexpected}} - end), - - nice_command( Nice + 6, - "client 2 fill in some data in tab03", - fun() -> - populate_table(client02, tab03, Data02), - lists:sort(ets:tab2list(tab03)) - end, - fun(Data) when Data =:= Data02 -> - {ok, Data}; - (Unexpected) -> - {error, {bad_data, Unexpected}} - end), - - nice_command( Nice + 7, - "simulate client 1 crash", - fun() -> - simulate_crash(client01) - end, - fun(ok) -> - {ok, crashed}; - (Unexpected) -> - {error, {bad_simulation_result, Unexpected}} - end), - - client_create_command( Nice + 8, - "1 restarted", - client01), - - nice_command( Nice + 9, - "client 1 create tab02 - verify data", - fun() -> - create_table(client01, tab02, []), - lists:sort(ets:tab2list(tab02)) - end, - fun(Data) when Data =:= Data01 -> - {ok, Data}; - (Unexpected) -> - {error, {bad_data, Unexpected}} - end), - - evil_command( Evil + 1, - "try (and fail) to delete the non-existing table tab04", - fun() -> - delete_table(client02, tab04) - end, - fun({error, {unknown_table, tab04}}) -> - {ok, tab04}; - (X) -> - {error, {bad_result, X}} - end), - - evil_command( Evil + 2, - "try (and fail) to delete a not owned table tab02", - fun() -> - delete_table(client02, tab02) - end, - fun({error, {not_owner, tab02}}) -> - {ok, tab02}; - (X) -> - {error, {bad_result, X}} - end), - - evil_command( Evil + 3, - "try (and fail) to create an already existing *and* owned table - tab03", - fun() -> - create_table(client02, tab03, []) - end, - fun({error, {already_owner, tab03}}) -> - {ok, tab03}; - (X) -> - {error, {bad_result, X}} - end), - - evil_command( Evil + 4, - "try (and fail) to create an already existing not owned table - tab02", - fun() -> - create_table(client02, tab02, []) - end, - fun({error, {not_owner, _Owner, tab02}}) -> - {ok, tab02}; - (X) -> - {error, {bad_result, X}} - end), - - end_command( End + 1, - "stop client01", - fun() -> stop_client(client01) end), - - end_command( End + 2, - "stop client02", - fun() -> stop_client(client02) end), - - end_command( End + 2, - "stop persistent-table", - fun() -> diameter_persistent_table:stop() end), - - evil_command( Evil + 5, - "try (and fail) to stop a not running persistent-table process", - fun() -> - diameter_persistent_table:stop() - end, - fun({'EXIT', {noproc, _}}) -> - {ok, not_running}; - (X) -> - {error, {bad_result, X}} - end) - - ], - - exec(Commands). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% -%% Command engine -%% - -exec([]) -> - ok; -exec([#command{id = No, - desc = Desc, - cmd = Cmd, - verify = Verify}|Commands]) -> - io:format("Executing command ~2w: ~s: ", [No, Desc]), - case (catch Verify((catch Cmd()))) of - {ok, OK} -> - io:format("ok => ~p~n", [OK]), - exec(Commands); - {error, Reason} -> - io:format("error => ~p~n", [Reason]), - {error, {bad_result, No, Reason}}; - Error -> - io:format("exit => ~p~n", [Error]), - {error, {unexpected_result, No, Error}} - end. - -initial_command(No, Desc0, Cmd, VerifyVal) when is_function(Cmd) -> - Desc = lists:flatten(io_lib:format("Initial - ~s", [Desc0])), - command(No, Desc, Cmd, VerifyVal). - -client_create_command(No, Desc0, Name) -> - Desc = lists:flatten(io_lib:format("Client create - ~s", [Desc0])), - Self = self(), - Cmd = fun() -> start_client(Self, Name) end, - command(No, Desc, Cmd, ok). - -nice_command(No, Desc0, Cmd, Verify) - when is_function(Cmd) andalso is_function(Verify) -> - Desc = lists:flatten(io_lib:format("Nice - ~s", [Desc0])), - command(No, Desc, Cmd, Verify). - -evil_command(No, Desc0, Cmd, Verify) - when is_function(Cmd) andalso is_function(Verify) -> - Desc = lists:flatten(io_lib:format("Evil - ~s", [Desc0])), - command(No, Desc, Cmd, Verify). - -end_command(No, Desc0, Cmd) when is_function(Cmd) -> - Desc = lists:flatten(io_lib:format("End - ~s", [Desc0])), - command(No, Desc, Cmd, ok). - -command(No, Desc, Cmd, Verify) - when (is_integer(No) andalso - is_list(Desc) andalso - is_function(Cmd) andalso - is_function(Verify)) -> - #command{id = No, - desc = Desc, - cmd = Cmd, - verify = Verify}; -command(No, Desc, Cmd, VerifyVal) - when (is_integer(No) andalso - is_list(Desc) andalso - is_function(Cmd)) -> - Verify = - fun(Val) -> - case Val of - VerifyVal -> - {ok, Val}; - _ -> - {error, Val} - end - end, - #command{id = No, - desc = Desc, - cmd = Cmd, - verify = Verify}. - - -start_client(Parent, Name) -> - ClientPid = spawn_link(fun() -> client_init(Parent, Name) end), - receive - {ClientPid, started} -> - ClientPid, - ok; - {'EXIT', ClientPid, Reason} -> - {error, {failed_starting_client, Reason}} - end. - -stop_client(Client) -> - Pid = whereis(Client), - Pid ! stop, - receive - {'EXIT', Pid, normal} -> - ok - end. - -create_table(Client, Tab, Opts) -> - Self = self(), - Pid = whereis(Client), - Pid ! {create_table, Tab, Opts, Self}, - receive - {Pid, created} -> - ok; - {Pid, {create_failed, Error}} -> - Error - end. - -delete_table(Client, Tab) -> - Self = self(), - Pid = whereis(Client), - Pid ! {delete_table, Tab, Self}, - receive - {Pid, deleted} -> - ok; - {Pid, {delete_failed, Error}} -> - Error - end. - -populate_table(Client, Tab, Data) -> - Self = self(), - Pid = whereis(Client), - Pid ! {populate_table, Tab, Data, Self}, - receive - {Pid, populated} -> - ok - end. - -simulate_crash(Client) -> - Pid = whereis(Client), - Pid ! simulate_crash, - receive - {'EXIT', Pid, simulated_crash} -> - ok - end. - -client_init(Parent, Name) -> - erlang:register(Name, self()), - process_flag(trap_exit, true), - Parent ! {self(), started}, - client_loop(). - -client_loop() -> - receive - stop -> - exit(normal); - - {create_table, T, Opts, From} when is_atom(T) andalso is_list(Opts) -> - case diameter_persistent_table:create(T, Opts) of - ok -> - From ! {self(), created}; - Error -> - From ! {self(), {create_failed, Error}} - end, - client_loop(); - - {delete_table, T, From} -> - case diameter_persistent_table:delete(T) of - ok -> - From ! {self(), deleted}; - Error -> - From ! {self(), {delete_failed, Error}} - end, - client_loop(); - - {populate_table, Tab, Data, From} -> - ets:insert(Tab, Data), - From ! {self(), populated}, - client_loop(); - - simulate_crash -> - exit(simulated_crash) - end. - -- cgit v1.2.3 From c75c5a530c10158d4a586a372a165835835bba1b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 22 Jul 2011 12:09:53 +0200 Subject: Add codec suite based on pure ct --- lib/diameter/test/.gitignore | 2 + lib/diameter/test/Makefile | 86 +---- lib/diameter/test/diameter_codec_SUITE.erl | 76 +++++ lib/diameter/test/diameter_codec_test.erl | 500 +++++++++++++++++++++++++++++ lib/diameter/test/diameter_ct.erl | 59 ++++ lib/diameter/test/diameter_enum.erl | 406 +++++++++++++++++++++++ lib/diameter/test/diameter_util.erl | 170 ++++++++++ 7 files changed, 1227 insertions(+), 72 deletions(-) create mode 100644 lib/diameter/test/.gitignore create mode 100644 lib/diameter/test/diameter_codec_SUITE.erl create mode 100644 lib/diameter/test/diameter_codec_test.erl create mode 100644 lib/diameter/test/diameter_ct.erl create mode 100644 lib/diameter/test/diameter_enum.erl create mode 100644 lib/diameter/test/diameter_util.erl diff --git a/lib/diameter/test/.gitignore b/lib/diameter/test/.gitignore new file mode 100644 index 0000000000..8a186ed5b5 --- /dev/null +++ b/lib/diameter/test/.gitignore @@ -0,0 +1,2 @@ + +log diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index b3648c7bb1..c8b405a541 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -302,83 +302,25 @@ test: make -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ $(MAYBE_ESTOP) -utest: make - $(MERL) $(ARGS) -sname diameter_utest $(ERL_PATH) \ - $(MAYBE_ETVIEW) \ - -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ - $(ESTOP) - -# ftest: make -# $(MERL) $(ARGS) -sname diameter_ftest $(ERL_PATH) \ -# -s diameter_filter \ -# -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ -# $(ESTOP) -# +log: + mkdir $@ ########################## -# tickets: make -# $(MERL) $(ARGS) -sname diameter_tickets $(ERL_PATH) \ -# -s $(DIAMETER_TEST_SERVER) tickets $(SUITE) \ -# $(ESTOP) -# - -app: make - $(MERL) $(ARGS) -sname diameter_app $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_app_test \ - $(ESTOP) - -appup: make - $(MERL) $(ARGS) -sname diameter_appup $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_appup_test \ - $(ESTOP) - -compiler: make - $(MERL) $(ARGS) -sname diameter_compiler $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_compiler_test \ - $(ESTOP) - -conf: make - $(MERL) $(ARGS) -sname diameter_config $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_config_test \ - $(ESTOP) - -sync: make - $(MERL) $(ARGS) -sname diameter_sync $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_sync_test \ +# This assumes GNU sed to exit 1 if the output looks to indicate failure. +# diameter_ct:run/1 itself can't tell (it seems). +codec: log make + $(MERL) $(ARGS) \ + -sname diameter_test_$@ \ + -s diameter_ct run $@ \ + -s init stop \ + | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' + +app appup compiler conf sync session stats reg peer tcp: make + $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ $(ESTOP) -session: make - $(MERL) $(ARGS) -sname diameter_session $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_session_test \ - $(ESTOP) - -stats: make - $(MERL) $(ARGS) -sname diameter_stats $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_stats_test \ - $(ESTOP) - -reg: make - $(MERL) $(ARGS) -sname diameter_reg $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_reg_test \ - $(ESTOP) - -peer: make - $(MERL) $(ARGS) -sname diameter_peer $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_peer_test \ - $(ESTOP) - -ptab: make - $(MERL) $(ARGS) -sname diameter_persistent_table $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_persistent_table_test \ - $(ESTOP) - -tcp: make - $(MERL) $(ARGS) -sname diameter_tcp $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_tcp_test \ - $(ESTOP) - - node: $(MERL) -sname diameter $(ERL_PATH) diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl new file mode 100644 index 0000000000..07e2a705c3 --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -0,0 +1,76 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Test encode/decode of dictionary-related modules. Each test case +%% runs multiple tests in parallel since many of the tests are just +%% the same code with different in-data: implementing each test as a +%% single testcase would make for much duplication with ct's +%% requirement of one function per testcase. (Instead of allowing a +%% testcase to be an MFA instead of function name, say.) +%% + +-module(diameter_codec_SUITE). + +-export([suite/0, + all/0, + init_per_testcase/2, + end_per_testcase/2]). + +%% testcases +-export([base/1, + gen/1, + lib/1]). + +-define(APP, diameter). +-define(L, atom_to_list). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [base, gen, lib]. + +init_per_testcase(gen, Config) -> + {ok, App} = diameter_util:appfile(?APP), + {modules, Ms} = lists:keyfind(modules, 1, App), + [_|_] = Gs = lists:filter(fun(M) -> + lists:prefix("diameter_gen_", ?L(M)) + end, + Ms), + [{dicts, Gs} | Config]; + +init_per_testcase(_Name, Config) -> + Config. + +end_per_testcase(_, _) -> + ok. + +%% =========================================================================== + +base(_Config) -> + diameter_codec_test:base(). + +gen([{dicts, Ms} | _]) -> + lists:foreach(fun diameter_codec_test:gen/1, Ms). + +lib(_Config) -> + diameter_codec_test:lib(). diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl new file mode 100644 index 0000000000..aab7ab35cc --- /dev/null +++ b/lib/diameter/test/diameter_codec_test.erl @@ -0,0 +1,500 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(diameter_codec_test). + +-compile(export_all). + +%% +%% Test encode/decode of dictionary-related modules. +%% + +-include_lib("diameter/include/diameter.hrl"). + +-define(BASE, diameter_gen_base_rfc3588). +-define(BOOL, [true, false]). + +%% =========================================================================== +%% Interface. + +base() -> + [] = run([{?MODULE, [base, T]} || T <- [zero, decode]]). + +gen(Mod) -> + Fs = [{Mod, F, []} || F <- [name, id, vendor_id, vendor_name]], + [] = run(Fs ++ [{?MODULE, [gen, Mod, T]} || T <- [messages, + command_codes, + avp_types, + grouped, + enums, + import_avps, + import_groups, + import_enums]]). + +lib() -> + Vs = {_,_} = values('Address'), + [] = run([[fun lib/2, N, Vs] || N <- [1,2]]). + +%% =========================================================================== +%% Internal functions. + +lib(N, {_,_} = T) -> + B = 1 == N rem 2, + [] = run([[fun lib/2, A, B] || A <- element(N,T)]); + +lib(IP, B) -> + LA = tuple_to_list(IP), + {SA,Fun} = ip(LA), + [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, LA, SA]]). + +lib(IP, B, Fun, A) -> + try Fun(A) of + IP when B -> + ok + catch + error:_ when not B -> + ok + end. + +ip([_,_,_,_] = A) -> + [$.|S] = lists:append(["." ++ integer_to_list(N) || N <- A]), + {S, fun diameter_lib:ip4address/1}; +ip([_,_,_,_,_,_,_,_] = A) -> + [$:|S] = lists:flatten([":" ++ io_lib:format("~.16B", [N]) || N <- A]), + {S, fun diameter_lib:ip6address/1}. + +%% ------------------------------------------------------------------------ +%% base/1 +%% +%% Test of diameter_types. +%% ------------------------------------------------------------------------ + +base(T) -> + [] = run([{?MODULE, [base, T, F]} || F <- types()]). + +%% Ensure that 'zero' values encode only zeros. +base(zero = T, F) -> + B = diameter_types:F(encode, T), + B = z(B); + +%% Ensure that we can decode what we encode and vice-versa, and that +%% we can't decode invalid values. +base(decode, F) -> + {Eq, Vs, Ns} = b(values(F)), + [] = run([{?MODULE, [base_decode, F, Eq, V]} || V <- Vs]), + [] = run([{?MODULE, [base_invalid, F, Eq, V]} || V <- Ns]). + +base_decode(F, Eq, Value) -> + d(fun(X,V) -> diameter_types:F(X,V) end, Eq, Value). + +base_invalid(F, Eq, Value) -> + try + base_decode(F, Eq, Value), + exit(nok) + catch + error: _ -> + ok + end. + +b({_,_,_} = T) -> + T; +b({B,Vs}) + when is_atom(B) -> + {B,Vs,[]}; +b({Vs,Ns}) -> + {true, Vs, Ns}; +b(Vs) -> + {true, Vs, []}. + +types() -> + [F || {F,2} <- diameter_types:module_info(exports)]. + +%% ------------------------------------------------------------------------ +%% gen/2 +%% +%% Test of generated encode/decode module. +%% ------------------------------------------------------------------------ + +gen(M, T) -> + [] = run(lists:map(fun(X) -> {?MODULE, [gen, M, T, X]} end, + fetch(T, M:dict()))). + +fetch(T, Spec) -> + case orddict:find(T, Spec) of + {ok, L} -> + L; + error -> + [] + end. + +gen(M, messages, {Name, Code, Flags, _, _}) -> + Rname = M:msg2rec(Name), + Name = M:rec2msg(Rname), + {Code, F, _} = M:msg_header(Name), + 0 = F band 2#00001111, + Name = case M:msg_name(Code, lists:member('REQ', Flags)) of + N when Name /= 'answer-message' -> + N; + '' when Name == 'answer-message', M == ?BASE -> + Name + end, + [] = arity(M, Name, Rname); + +gen(M, command_codes = T, {Code, {Req, Abbr}, Ans}) -> + Rname = M:msg2rec(Req), + Rname = M:msg2rec(Abbr), + gen(M, T, {Code, Req, Ans}); + +gen(M, command_codes = T, {Code, Req, {Ans, Abbr}}) -> + Rname = M:msg2rec(Ans), + Rname = M:msg2rec(Abbr), + gen(M, T, {Code, Req, Ans}); + +gen(M, command_codes, {Code, Req, Ans}) -> + Msgs = orddict:fetch(messages, M:dict()), + {_, Code, _, _, _} = lists:keyfind(Req, 1, Msgs), + {_, Code, _, _, _} = lists:keyfind(Ans, 1, Msgs); + +gen(M, avp_types, {Name, Code, Type, _Flags, _Encr}) -> + {Code, Flags, VendorId} = M:avp_header(Name), + 0 = Flags band 2#00011111, + V = undefined /= VendorId, + V = 0 /= Flags band 2#10000000, + {Name, Type} = M:avp_name(Code, VendorId), + B = M:empty_value(Name), + B = z(B), + [] = avp_decode(M, Type, Name); + +gen(M, grouped, {Name, _, _, _}) -> + Rname = M:name2rec(Name), + [] = arity(M, Name, Rname); + +gen(M, enums, {Name, ED}) -> + [] = run([{?MODULE, [enum, M, Name, T]} || T <- ED]); + +gen(M, Tag, {_Mod, L}) -> + T = retag(Tag), + [] = run([{?MODULE, [gen, M, T, I]} || I <- L]). + +%% avp_decode/3 + +avp_decode(Mod, Type, Name) -> + {Eq, Vs, _} = b(values(Type, Name, Mod)), + [] = run([{?MODULE, [avp_decode, Mod, Name, Type, Eq, V]} + || V <- v(Vs)]). + +avp_decode(Mod, Name, Type, Eq, Value) -> + d(fun(X,V) -> avp(Mod, X, V, Name, Type) end, Eq, Value). + +avp(Mod, decode = X, V, Name, 'Grouped') -> + {Rec, _} = Mod:avp(X, V, Name), + Rec; +avp(Mod, X, V, Name, _) -> + Mod:avp(X, V, Name). + +%% v/1 + +%% List of values ... +v(Vs) + when is_list(Vs) -> + Vs; + +%% .. or enumeration for grouped avps. This could be quite large +%% (millions of values) but since the avps are also tested +%% individually don't bother trying everything. Instead, choose a +%% reasonable number of values at random. +v(E) -> + v(2000, E(0), E). + +v(Max, Ord, E) + when Ord =< Max -> + diameter_enum:to_list(E); +v(Max, Ord, E) -> + {M,S,U} = now(), + random:seed(M,S,U), + v(Max, Ord, E, []). + +v(0, _, _, Acc) -> + Acc; +v(N, Ord, E, Acc) -> + v(N-1, Ord, E, [E(random:uniform(Ord)) | Acc]). + +%% arity/3 + +arity(M, Name, Rname) -> + Rec = M:'#new-'(Rname), + [] = run([{?MODULE, [arity, M, Name, F, Rec]} + || F <- M:'#info-'(Rname, fields)]). + +arity(M, Name, AvpName, Rec) -> + Def = M:'#get-'(AvpName, Rec), + Def = case M:avp_arity(Name, AvpName) of + 1 -> + undefined; + A when 0 /= A -> + [] + end. + +%% enum/3 + +enum(M, Name, {E,_}) -> + B = <>, + B = M:avp(encode, E, Name), + E = M:avp(decode, B, Name). + +retag(import_avps) -> avp_types; +retag(import_groups) -> grouped; +retag(import_enums) -> enums; + +retag(avp_types) -> import_avps; +retag(enums) -> import_enums. + +%% =========================================================================== + +d(F, Eq, V) -> + B = F(encode, V), + D = F(decode, B), + V = if Eq -> %% test for value equality ... + D; + true -> %% ... or that encode/decode is idempotent + D = F(decode, F(encode, D)), + V + end. + +z(B) -> + << <<0>> || <<_>> <= B >>. + +%% values/1 +%% +%% Return a list of base type values. Can also be wrapped in a tuple +%% with 'false' to indicate that encode followed by decode may not be +%% the identity map. (Although that this composition is idempotent is +%% tested.) + +values('OctetString' = T) -> + {["", atom_to_list(T)], [-1, 256]}; + +values('Integer32') -> + Mx = (1 bsl 31) - 1, + Mn = -1*Mx, + {[Mn, 0, random(Mn,Mx), Mx], [Mn - 1, Mx + 1]}; + +values('Integer64') -> + Mx = (1 bsl 63) - 1, + Mn = -1*Mx, + {[Mn, 0, random(Mn,Mx), Mx], [Mn - 1, Mx + 1]}; + +values('Unsigned32') -> + M = (1 bsl 32) - 1, + {[0, random(M), M], [-1, M + 1]}; + +values('Unsigned64') -> + M = (1 bsl 64) - 1, + {[0, random(M), M], [-1, M + 1]}; + +values('Float32') -> + E = (1 bsl 8) - 2, + F = (1 bsl 23) - 1, + <> = <<0:1/integer, E:8/integer, F:23/integer>>, + <> = <<1:1/integer, E:8/integer, F:23/integer>>, + {[0.0, infinity, '-infinity', Mx, Mn], [0]}; + +values('Float64') -> + E = (1 bsl 11) - 2, + F = (1 bsl 52) - 1, + <> = <<0:1/integer, E:11/integer, F:52/integer>>, + <> = <<1:1/integer, E:11/integer, F:52/integer>>, + {[0.0, infinity, '-infinity', Mx, Mn], [0]}; + +values('Address') -> + {[{255,0,random(16#FF),1}, {65535,0,0,random(16#FFFF),0,0,0,1}], + [{256,0,0,1}, {65536,0,0,0,0,0,0,1}]}; + +values('DiameterIdentity') -> + {["x", "diameter.com"], [""]}; + +values('DiameterURI') -> + {false, ["aaa" ++ S ++ "://diameter.se" ++ P ++ Tr ++ Pr + || S <- ["", "s"], + P <- ["", ":1234"], + Tr <- ["" | [";transport=" ++ X + || X <- ["tcp", "sctp", "udp"]]], + Pr <- ["" | [";protocol=" ++ X + || X <- ["diameter","radius","tacacs+"]]]]}; + +values(T) + when T == 'IPFilterRule'; + T == 'QoSFilterRule' -> + ["deny in 0 from 127.0.0.1 to 10.0.0.1"]; + +%% RFC 3629 defines the UTF-8 encoding of U+0000 through U+10FFFF with the +%% exception of U+D800 through U+DFFF. +values('UTF8String') -> + {[[], + lists:seq(0,16#1FF), + [0,16#D7FF,16#E000,16#10FFFF], + [random(16#D7FF), random(16#E000,16#10FFFF)]], + [[-1], + [16#D800], + [16#DFFF], + [16#110000]]}; + +values('Time') -> + {[{{1968,1,20},{3,14,8}}, %% 19000101T000000 + 1 bsl 31 + {date(), time()}, + {{2036,2,7},{6,28,15}}, + {{2036,2,7},{6,28,16}}, %% 19000101T000000 + 2 bsl 31 + {{2104,2,26},{9,42,23}}], + [{{1968,1,20},{3,14,7}}, + {{2104,2,26},{9,42,24}}]}. %% 19000101T000000 + 3 bsl 31 + +%% values/3 +%% +%% Return list or enumerations of values for a given AVP. Can be +%% wrapped as for values/1. + +values('Enumerated', Name, Mod) -> + {_Name, Vals} = lists:keyfind(Name, 1, types(enums, Mod)), + lists:map(fun({N,_}) -> N end, Vals); + +values('Grouped', Name, Mod) -> + Rname = Mod:name2rec(Name), + Rec = Mod:'#new-'(Rname), + Avps = Mod:'#info-'(Rname, fields), + Enum = diameter_enum:combine(lists:map(fun({_,Vs,_}) -> to_enum(Vs) end, + [values(F, Mod) || F <- Avps])), + {false, diameter_enum:append(group(Mod, Name, Rec, Avps, Enum))}; + +values(_, 'Framed-IP-Address', _) -> + [{127,0,0,1}]; + +values(Type, _, _) -> + values(Type). + +to_enum(Vs) + when is_list(Vs) -> + diameter_enum:new(Vs); +to_enum(E) -> + E. + +%% values/2 + +values('AVP', _) -> + {true, [#diameter_avp{code = 0, data = <<0>>}], []}; + +values(Name, Mod) -> + Avps = types(avp_types, Mod), + {Name, _Code, Type, _Flags, _Encr} = lists:keyfind(Name, 1, Avps), + b(values(Type, Name, Mod)). + +%% group/5 +%% +%% Pack four variants of group values: tagged list containing all +%% values, the corresponding record, a minimal tagged list and the +%% coresponding record. + +group(Mod, Name, Rec, Avps, Enum) -> + lists:map(fun(B) -> group(Mod, Name, Rec, Avps, Enum, B) end, + [{A,R} || A <- ?BOOL, R <- ?BOOL]). + +group(Mod, Name, Rec, Avps, Enum, B) -> + diameter_enum:map(fun(Vs) -> g(Mod, Name, Rec, Avps, Vs, B) end, Enum). + +g(Mod, Name, Rec, Avps, Values, {All, AsRec}) -> + {Tagged, []} + = lists:foldl(fun(N, {A, [V|Vs]}) -> + {pack(All, Mod:avp_arity(Name, N), N, V, A), Vs} + end, + {[], Values}, + Avps), + g(AsRec, Mod, Tagged, Rec). + +g(true, Mod, Vals, Rec) -> + Mod:'#set-'(Vals, Rec); +g(false, _, Vals, _) -> + Vals. + +pack(true, Arity, Avp, Value, Acc) -> + [all(Arity, Avp, Value) | Acc]; +pack(false, Arity, Avp, Value, Acc) -> + min(Arity, Avp, Value, Acc). + +all(Mod, Name, Avp, V) -> + all(Mod:avp_arity(Name, Avp), Avp, V). + +all(1, Avp, V) -> + {Avp, V}; +all({0,'*'}, Avp, V) -> + a(1, Avp, V); +all({N,'*'}, Avp, V) -> + a(N, Avp, V); +all({_,N}, Avp, V) -> + a(N, Avp, V). + +a(N, Avp, V) + when N /= 0 -> + {Avp, lists:duplicate(N,V)}. + +min(Mod, Name, Avp, V, Acc) -> + min(Mod:avp_arity(Name, Avp), Avp, V, Acc). + +min(1, Avp, V, Acc) -> + [{Avp, V} | Acc]; +min({0,_}, _, _, Acc) -> + Acc; +min({N,_}, Avp, V, Acc) -> + [{Avp, lists:duplicate(N,V)} | Acc]. + +%% types/2 + +types(T, Mod) -> + types(T, retag(T), Mod). + +types(T, IT, Mod) -> + Dict = Mod:dict(), + fetch(T, Dict) ++ lists:flatmap(fun({_,As}) -> As end, fetch(IT, Dict)). + +%% random/[12] + +random(M) -> + random(0,M). + +random(Mn,Mx) -> + seed(get({?MODULE, seed})), + Mn + random:uniform(Mx - Mn + 1) - 1. + +seed(undefined) -> + put({?MODULE, seed}, true), + random:seed(now()); + +seed(true) -> + ok. + +%% run/1 +%% +%% Unravel nested badmatches resulting from [] matches on calls to +%% run/1 to make for more readable failures. + +run(L) -> + lists:flatmap(fun flatten/1, diameter_util:run(L)). + +flatten({_, {{badmatch, [{_, {{badmatch, _}, _}} | _] = L}, _}}) -> + L; +flatten(T) -> + [T]. diff --git a/lib/diameter/test/diameter_ct.erl b/lib/diameter/test/diameter_ct.erl new file mode 100644 index 0000000000..6842ca03c5 --- /dev/null +++ b/lib/diameter/test/diameter_ct.erl @@ -0,0 +1,59 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(diameter_ct). + +%% +%% Module used to run suites from Makefile. +%% + +-export([run/1]). + +%% ct:run_test/1 is currently documented as returning a list of test +%% results ... but no. Instead it returns the phenomenally useful +%% value 'ok' regardless of whether or not the suite in question has +%% failed testcases. + +run([Name]) -> + Start = info(), + ok = ct:run_test([{suite, suite(Name)}, + {logdir, "./log"}, + {auto_compile, false}]), + info(Start , info()). + +suite(Name) -> + list_to_atom("diameter_" ++ atom_to_list(Name) ++ "_SUITE"). + +info() -> + [{time, now()}, + {process_count, erlang:system_info(process_count)} + | erlang:memory()]. + +info(L0, L1) -> + [T, C | M] + = lists:zipwith(fun({T,N0}, {T,N1}) -> {T, N1, diff(T, N0, N1)} end, + L0, + L1), + Diff = [T, C, {memory, M}], + ct:pal("INFO: ~p~n", [Diff]). + +diff(time, T0, T1) -> + timer:now_diff(T1, T0); +diff(_, N0, N1) -> + N1 - N0. diff --git a/lib/diameter/test/diameter_enum.erl b/lib/diameter/test/diameter_enum.erl new file mode 100644 index 0000000000..dfb6d04e3c --- /dev/null +++ b/lib/diameter/test/diameter_enum.erl @@ -0,0 +1,406 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(diameter_enum). + +%% +%% This module constructs finite enumerations. +%% +%% An enumeration is represented as a function on integers, 0 mapping +%% to the number of values enumerated and successive integers mapping +%% to enumerated values. The function will fail on anything but 0 and +%% positive integers less then or equal to the value of the function +%% at 0. +%% +%% The purpose of this is to provide a way of stepping through a large +%% number of values without explicitly constructing the list of all +%% possible values. For example, consider the following function that +%% given a list of lists constructs the list of all possible lists +%% constructed by choosing one element from each sublist. +%% +%% combine([H]) -> +%% [[X] || X <- H]; +%% combine([H|T]) -> +%% Ys = combine(T), +%% [[X|Y] || X <- H, Y <- Ys]. +%% +%% Eg. [[1,2],[3,4,5]] -> [[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]] +%% +%% If L is a list of three 1000 element lists then combine(L) would +%% construct a list of length 10^9 which will likely exhaust available +%% memory. (Which is how this module came into being. A tail-recursive +%% implementation doesn't fare much better.) By contrast, +%% +%% F = enum:combine([enum:new(L) || L <- Lists]) +%% +%% only maps existing lists. It may still be undesirable to step +%% through a very large number of values but it's possible, and easy +%% to step through a selection of values as an alternative. +%% + +%% Functions that return enumerations. +-export([new/1, + combine/1, + reverse/1, + map/2, + append/1, + duplicate/2, + nthtail/2, + seq/2, + seq/3, + zip/1, + zip/2, + slice/3, + split/2]). + +%% Functions that operate on existing enumerations. +-export([foreach/2, + foldl/3, + foldr/3, + all/2, + any/2, + member/2, + last/1, + nth/2, + to_list/1]). + +%% ------------------------------------------------------------------------ +%% new/1 +%% +%% Turn a list/tuple of values into an enumeration that steps through +%% each element. Turn anything else into an enumeration of that single +%% value. +%% ------------------------------------------------------------------------ + +new(L) + when is_list(L) -> + new(list_to_tuple(L)); + +new(T) + when is_tuple(T) -> + enum(size(T), fun(N) -> element(N,T) end); + +new(T) -> + fun(0) -> 1; (1) -> T end. + +enum(Ord, F) -> + fun(0) -> Ord; (N) when 0 < N, N =< Ord -> F(N) end. + +%% ------------------------------------------------------------------------ +%% combine/1 +%% +%% Map a list/tuple of enumerations to the enumeration of all +%% lists/tuples constructed by choosing one value from each +%% enumeration in the list/tuple. +%% ------------------------------------------------------------------------ + +combine(T) + when is_tuple(T) -> + F = combine(tuple_to_list(T)), + enum(F(0), fun(N) -> list_to_tuple(F(N)) end); + +combine([]) -> + fun(0) -> 0 end; + +%% Given positive integers n_1,...,n_k, construct a bijection from +%% {0,...,\prod_{i=1}^k} n_i - 1} to {0,...,n_1} x ... x {0,...,n_k} +%% that maps N to (N_1,...,N_k) where: +%% +%% N_1 = (N div 1) rem n_1 +%% ... +%% N_k = (N div n_1*...*n_{k-1}) rem n_k +%% +%% That is: +%% +%% N_i = (N div \prod_{j=1}^{i-1} n_j) rem n_i +%% +%% This corresponds to looping through N_1, incrementing N_2 as N_1 +%% loops, and so on up through N_k. The inverse map is as follows. +%% +%% (N_1,...,N_k) -> N = N_1 + N_2*n_1 + ... + N_k*n_{k-1}*...*n_1 +%% +%% = \sum_{i=1}^k N_i*\prod_{j=i}^{i-1} n_j +%% +%% [Proof: Induction on k. For k=1 we have the identity map. If +%% g_k : (N_1,...,N_k) |-> N above is bijective then consider +%% the bijection +%% +%% G : (t,n) |--> t + n*K, K = n_k*...*n_1 +%% +%% from {0,...,K-1} x {0,...,n_{k+1}-1} onto {0,...,n_{k+1}*K - 1} +%% with inverse F : n |--> (n rem K, n div K). Since +%% +%% g_{k+1}(N_1,...,N_{k+1}) = g_k(N_1,...,N_K) + N_{k+1}*K +%% = G(g_k(N_1,...,N_K), N_{k+1}) +%% +%% and G, g_k and ((N-1,...,N_k),N_{k+1}) -> (N_1,...,N_{k+1}) +%% are all bijections, so is g_{k+1}.] + +combine([_|_] = L) -> + [Ord | Divs] = lists:foldl(fun(F,[D|_] = A) -> [F(0)*D | A] end, [1], L), + RL = lists:reverse(L), + enum(Ord, fun(N) -> combine(N, Ord, Divs, RL) end). + +%% Since we use 0 to return the number of elements enumerated, use +%% bijections from {1,...,N} rather than {0,...,N-1}. + +combine(N, Ord, Divs, L) + when 0 < N, N =< Ord -> + {Vs, []} = lists:foldl(fun(F, {A, [D|Ds]}) -> + {[F(1 + (((N-1) div D) rem F(0))) | A], Ds} + end, + {[], Divs}, + L), + Vs. + +%% ------------------------------------------------------------------------ +%% reverse/1 +%% +%% Construct the enumeration that reverses the order in which values +%% are traversed. +%% ------------------------------------------------------------------------ + +reverse(E) -> + Ord = E(0), + enum(Ord, fun(N) -> E(Ord + 1 - N) end). + +%% ------------------------------------------------------------------------ +%% map/2 +%% +%% Construct an enumeration that maps enumerated values. +%% ------------------------------------------------------------------------ + +map(Fun, E) -> + enum(E(0), fun(N) -> Fun(E(N)) end). + +%% ------------------------------------------------------------------------ +%% append/2 +%% +%% Construct an enumeration that successively steps through each of a +%% list of enumerations. +%% ------------------------------------------------------------------------ + +append(Es) -> + [Ord | Os] = lists:foldl(fun(E, [N|_] = A) -> [N+E(0)|A] end, [0], Es), + Rev = lists:reverse(Es), + enum(Ord, fun(N) -> append(N, Os, Rev) end). + +append(N, [Ord | _], [E | _]) + when N > Ord -> + E(N - Ord); +append(N, [_|Os], [_|Es]) -> + append(N, Os, Es). + +%% ------------------------------------------------------------------------ +%% duplicate/2 +%% +%% Construct an enumeration that traverses an enumeration multiple +%% times. Equivalent to append(lists:duplicate(N, E)). +%% ------------------------------------------------------------------------ + +duplicate(N, E) -> + Ord = E(0), + enum(N*Ord, fun(M) -> E(1 + ((M-1) rem Ord)) end). + +%% ------------------------------------------------------------------------ +%% nthtail/2 +%% +%% Construct an enumeration that omits values at the head of an +%% existing enumeration. +%% ------------------------------------------------------------------------ + +nthtail(N, E) + when 0 =< N -> + nthtail(E(0) - N, N, E). + +nthtail(Ord, N, E) + when 0 =< Ord -> + enum(Ord, fun(M) -> E(M+N) end). + +%% ------------------------------------------------------------------------ +%% seq/[23] +%% +%% Construct an enumeration that steps through a sequence of integers. +%% ------------------------------------------------------------------------ + +seq(From, To) -> + seq(From, To, 1). + +seq(From, To, Incr) + when From =< To -> + enum((To - From + Incr) div Incr, fun(N) -> From + (N-1)*Incr end). + +%% ------------------------------------------------------------------------ +%% zip/[12] +%% +%% Construct an enumeration whose nth value is the list of nth values +%% of a list of enumerations. +%% ------------------------------------------------------------------------ + +zip(Es) -> + zip(fun(T) -> T end, Es). + +zip(_, []) -> + []; +zip(Fun, Es) -> + enum(lists:min([E(0) || E <- Es]), fun(N) -> Fun([E(N) || E <- Es]) end). + +%% ------------------------------------------------------------------------ +%% slice/3 +%% +%% Construct an enumeration of a given length from a given starting point. +%% ------------------------------------------------------------------------ + +slice(N, Len, E) + when is_integer(N), N > 0, is_integer(Len), Len >= 0 -> + slice(N, Len, E(0) - (N - 1), E). + +slice(_, _, Tail, _) + when Tail < 1 -> + fun(0) -> 0 end; + +slice(N, Len, Tail, E) -> + enum(lists:min([Len, Tail]), fun(M) -> E(N-1+M) end). + +%% ------------------------------------------------------------------------ +%% split/2 +%% +%% Split an enumeration into a list of enumerations of the specified +%% length. The last enumeration of the list may have order less than +%% this length. +%% ------------------------------------------------------------------------ + +split(Len, E) + when is_integer(Len), Len > 0 -> + split(1, E(0), Len, E, []). + +split(N, Ord, _, _, Acc) + when N > Ord -> + lists:reverse(Acc); + +split(N, Ord, Len, E, Acc) -> + split(N+Len, Ord, Len, E, [slice(N, Len, E) | Acc]). + +%% ------------------------------------------------------------------------ +%% foreach/2 +%% +%% Apply a fun to each value of an enumeration. +%% ------------------------------------------------------------------------ + +foreach(Fun, E) -> + foldl(fun(N,ok) -> Fun(N), ok end, ok, E). + +%% ------------------------------------------------------------------------ +%% foldl/3 +%% foldr/3 +%% +%% Fold through values in an enumeration. +%% ------------------------------------------------------------------------ + +foldl(Fun, Acc, E) -> + foldl(E(0), 1, Fun, Acc, E). + +foldl(M, N, _, Acc, _) + when N == M+1 -> + Acc; +foldl(M, N, Fun, Acc, E) -> + foldl(M, N+1, Fun, Fun(E(N), Acc), E). + +foldr(Fun, Acc, E) -> + foldl(Fun, Acc, reverse(E)). + +%% ------------------------------------------------------------------------ +%% all/2 +%% +%% Do all values of an enumeration satisfy a predicate? +%% ------------------------------------------------------------------------ + +all(Pred, E) -> + all(E(0), 1, Pred, E). + +all(M, N, _, _) + when N == M+1 -> + true; +all(M, N, Pred, E) -> + Pred(E(N)) andalso all(M, N+1, Pred, E). + +%% Note that andalso/orelse are tail-recusive as of R13A. + +%% ------------------------------------------------------------------------ +%% any/2 +%% +%% Does any value of an enumeration satisfy a predicate? +%% ------------------------------------------------------------------------ + +any(Pred, E) -> + any(E(0), 1, Pred, E). + +any(M, N, _, _) + when N == M+1 -> + false; +any(M, N, Pred, E) -> + Pred(E(N)) orelse any(M, N+1, Pred, E). + +%% ------------------------------------------------------------------------ +%% member/2 +%% +%% Does a value match any in an enumeration? +%% ------------------------------------------------------------------------ + +member(X, E) -> + member(E(0), 1, X, E). + +member(M, N, _, _) + when N == M+1 -> + false; +member(M, N, X, E) -> + match(E(N), X) orelse member(M, N+1, X, E). + +match(X, X) -> + true; +match(_, _) -> + false. + +%% ------------------------------------------------------------------------ +%% last/1 +%% +%% Return the last value of an enumeration. +%% ------------------------------------------------------------------------ + +last(E) -> + E(E(0)). + +%% ------------------------------------------------------------------------ +%% nth/2 +%% +%% Return a selected value of an enumeration. +%% ------------------------------------------------------------------------ + +nth(N, E) -> + E(N). + +%% ------------------------------------------------------------------------ +%% to_list/1 +%% +%% Turn an enumeration into a list. Not good if the very many values +%% are enumerated. +%% ------------------------------------------------------------------------ + +to_list(E) -> + foldr(fun(X,A) -> [X|A] end, [], E). diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl new file mode 100644 index 0000000000..93760a1c07 --- /dev/null +++ b/lib/diameter/test/diameter_util.erl @@ -0,0 +1,170 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(diameter_util). + +%% +%% Utility functions. +%% + +-export([appfile/1, + run/1, + fold/3, + foldl/3, + scramble/1, + ps/0]). + +%% appfile/1 +%% +%% Extract info from the app file of the named application. + +appfile(Name) -> + appfile(code:lib_dir(Name, ebin), Name). + +appfile({error = E, Reason}, _) -> + {E, {code, Reason}}; +appfile(Dir, Name) -> + case file:consult(filename:join([Dir, atom_to_list(Name) ++ ".app"])) of + {ok, [{application, Name, App}]} -> + {ok, App}; + {ok, Huh} -> + {error, {content, Huh}}; + {error, Reason} -> + {error, {file, Reason}} + end. + +%% run/1 +%% +%% Evaluate functions in parallel and return a list of those that +%% failed to return. The fun takes a boolean (did the function return +%% or not), the function that was evaluated, the return value or exit +%% reason and the prevailing accumulator. + +run(L) -> + fold(fun cons/4, [], L). + +cons(true, _, _, Acc) -> + Acc; +cons(false, F, RC, Acc) -> + [{F, RC} | Acc]. + +%% fold/3 +%% +%% Parallel fold. Results are folded in the order received. + +fold(Fun, Acc0, L) + when is_function(Fun, 4) -> + Ref = make_ref(), + %% Spawn a middleman to collect down messages from processes + %% spawned for each function so as not to assume that all DOWN + %% messages are ours. + MRef = run1([fun fold/4, Ref, Fun, Acc0, L], Ref), + {Ref, RC} = down(MRef), + RC. + +fold(Ref, Fun, Acc0, L) -> + recv(run(Ref, L), Ref, Fun, Acc0). + +run(Ref, L) -> + [{run1(F, Ref), F} || F <- L]. + +run1(F, Ref) -> + {_, MRef} = spawn_monitor(fun() -> exit({Ref, eval(F)}) end), + MRef. + +recv([], _, _, Acc) -> + Acc; +recv(L, Ref, Fun, Acc) -> + {MRef, R} = down(), + {MRef, F} = lists:keyfind(MRef, 1, L), + recv(lists:keydelete(MRef, 1, L), + Ref, + Fun, + acc(R, Ref, F, Fun, Acc)). + +acc({Ref, RC}, Ref, F, Fun, Acc) -> + Fun(true, F, RC, Acc); +acc(Reason, _, F, Fun, Acc) -> + Fun(false, F, Reason, Acc). + +down(MRef) -> + receive {'DOWN', MRef, process, _, Reason} -> Reason end. + +down() -> + receive {'DOWN', MRef, process, _, Reason} -> {MRef, Reason} end. + +%% foldl/3 +%% +%% Parallel fold. Results are folded in order of the function list. + +foldl(Fun, Acc0, L) + when is_function(Fun, 4) -> + Ref = make_ref(), + recvl(run(Ref, L), Ref, Fun, Acc0). + +recvl([], _, _, Acc) -> + Acc; +recvl([{MRef, F} | L], Ref, Fun, Acc) -> + R = down(MRef), + recvl(L, Ref, Fun, acc(R, Ref, F, Fun, Acc)). + +%% scramble/1 +%% +%% Sort a list into random order. + +scramble(L) -> + foldl(fun(true, _, S, false) -> S end, + false, + [[fun s/1, L]]). + +s(L) -> + random:seed(now()), + s([], L). + +s(Acc, []) -> + Acc; +s(Acc, L) -> + {H, [T|Rest]} = lists:split(random:uniform(length(L)) - 1, L), + s([T|Acc], H ++ Rest). + +%% ps/0 + +ps() -> + [{P, process_info(P)} || P <- erlang:processes()]. + +%% eval/1 + +eval({M,[F|A]}) + when is_atom(F) -> + apply(M,F,A); + +eval({M,F,A}) -> + apply(M,F,A); + +eval([F|A]) + when is_function(F) -> + apply(F,A); + +eval(L) + when is_list(L) -> + run(L); + +eval(F) + when is_function(F,0) -> + F(). -- cgit v1.2.3 From 85272930ebdf97ba8cf65962da17e980403ef06c Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 19 Sep 2011 11:05:23 +0200 Subject: Migrate app suite to pure ct and simplify --- lib/diameter/test/Makefile | 4 +- lib/diameter/test/diameter_app_SUITE.erl | 139 +++++++++++ lib/diameter/test/diameter_app_test.erl | 393 ------------------------------- lib/diameter/test/modules.mk | 16 +- 4 files changed, 148 insertions(+), 404 deletions(-) create mode 100644 lib/diameter/test/diameter_app_SUITE.erl delete mode 100644 lib/diameter/test/diameter_app_test.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index c8b405a541..d77099785f 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -309,14 +309,14 @@ log: # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -codec: log make +app codec: log make $(MERL) $(ARGS) \ -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' -app appup compiler conf sync session stats reg peer tcp: make +appup compiler conf sync session stats reg peer tcp: make $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ $(ESTOP) diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl new file mode 100644 index 0000000000..898f302457 --- /dev/null +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests based on the contents of the diameter app file. +%% + +-module(diameter_app_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([keys/1, + modules/1, + exports/1, + applications/1, + undefined_calls/1, undefined_calls/0]). + +-define(APP, diameter). +-define(A, list_to_atom). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [keys, + modules, + exports, + applications, + undefined_calls]. + +init_per_suite(Config) -> + {ok, App} = diameter_util:appfile(?APP), + [{app, App} | Config]. + +end_per_suite(_Config) -> + ok. + +%% =========================================================================== + +%% keys/1 +%% +%% Ensure that the app file contain required keys. + +keys(Config) -> + App = fetch(app, Config), + [] = lists:filter(fun(K) -> not lists:keymember(K, 1, App) end, + [vsn, description, modules, registered, applications]). + +%% modules/1 +%% +%% Ensure that the app file module list match the installed beams. + +modules(Config) -> + Mods = fetch(modules, fetch(app, Config)), + Installed = installed_mods(), + {[], []} = {Mods -- Installed, Installed -- Mods}. + +installed_mods() -> + Dir = code:lib_dir(?APP, ebin), + {ok, Files} = file:list_dir(Dir), + [?A(lists:reverse(R)) || N <- Files, "maeb." ++ R <- [lists:reverse(N)]]. + +%% exports/1 +%% +%% Ensure that no module does export_all. + +exports(Config) -> + Mods = fetch(modules, fetch(app, Config)), + [] = [M || M <- Mods, exports_all(M)]. + +exports_all(Mod) -> + Opts = fetch(options, Mod:module_info(compile)), + + is_list(Opts) andalso lists:member(export_all, Opts). + +%% applications/1 +%% +%% Ensure that each dependent application is on the code path. + +applications(Config) -> + As = fetch(applications, fetch(app, Config)), + [] = [A || A <- As, {error, _} <- [diameter_util:appfile(A)]]. + +%% undefined_calls/1 +%% +%% Ensure that no function on our application calls an undefined function. + +undefined_calls() -> + [{timetrap, {minutes, 2}}]. + +undefined_calls(Config) -> + Mods = fetch(modules, fetch(app, Config)), + + RootDir = code:root_dir(), + EbinDir = code:lib_dir(?APP, ebin), + + {ok, XRef} = xref:start(make_name(xref_test_name)), + ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]), + + XRefName = make_name(xref_name), + {ok, XRefName} = xref:add_release(XRef, RootDir, {name, XRefName}), + {ok, _} = xref:replace_application(XRef, ?APP, EbinDir), + + {ok, Undefs} = xref:analyze(XRef, undefined_function_calls), + + xref:stop(XRef), + + [] = lists:filter(fun({{M,_,_},_}) -> lists:member(M, Mods) end, Undefs). + +make_name(Suf) -> + list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)). + +%% =========================================================================== + +fetch(Key, List) -> + {Key, Val} = lists:keyfind(Key, 1, List), + Val. diff --git a/lib/diameter/test/diameter_app_test.erl b/lib/diameter/test/diameter_app_test.erl deleted file mode 100644 index 7173c39caf..0000000000 --- a/lib/diameter/test/diameter_app_test.erl +++ /dev/null @@ -1,393 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the application specifics of the Diameter application -%%---------------------------------------------------------------------- --module(diameter_app_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2, - - fields/1, - modules/1, - exportall/1, - app_depend/1, - undef_funcs/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(undef_funcs = Case, Config) -> - NewConfig = [{tc_timeout, ?MINUTES(10)} | Config], - diameter_test_server:init_per_testcase(Case, NewConfig); -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - [ - fields, - modules, - exportall, - app_depend, - undef_funcs - ]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - io:format("~w:init_per_suite -> entry with" - "~n Config: ~p" - "~n", [?MODULE, Config]), - case is_app(diameter) of - {ok, AppFile} -> - io:format("AppFile: ~n~p~n", [AppFile]), - %% diameter:print_version_info(), - [{app_file, AppFile}|Config]; - {error, Reason} -> - ?FAIL(Reason) - end. - -is_app(App) -> - LibDir = code:lib_dir(App), - File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]), - case file:consult(File) of - {ok, [{application, App, AppFile}]} -> - {ok, AppFile}; - Error -> - {error, {invalid_format, Error}} - end. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -fields(suite) -> - []; -fields(doc) -> - []; -fields(Config) when is_list(Config) -> - AppFile = ?KEY1SEARCH(app_file, Config), - Fields = [vsn, description, modules, registered, applications], - case check_fields(Fields, AppFile, []) of - [] -> - ok; - Missing -> - ?FAIL({missing_fields, Missing}) - end. - -check_fields([], _AppFile, Missing) -> - Missing; -check_fields([Field|Fields], AppFile, Missing) -> - check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)). - -check_field(Name, AppFile, Missing) -> - io:format("checking field: ~p~n", [Name]), - case lists:keymember(Name, 1, AppFile) of - true -> - Missing; - false -> - [Name|Missing] - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -modules(suite) -> - []; -modules(doc) -> - []; -modules(Config) when is_list(Config) -> - AppFile = ?KEY1SEARCH(app_file, Config), - Mods = ?KEY1SEARCH(modules, AppFile), - EbinList = get_ebin_mods(diameter), - case missing_modules(Mods, EbinList, []) of - [] -> - ok; - Missing -> - throw({error, {missing_modules, Missing}}) - end, - Allowed = [diameter_codegen, - diameter_make, - diameter_spec_scan, - diameter_spec_util], - case extra_modules(Mods, EbinList, Allowed, []) of - [] -> - ok; - Extra -> - throw({error, {extra_modules, Extra}}) - end, - {ok, Mods}. - -get_ebin_mods(App) -> - LibDir = code:lib_dir(App), - EbinDir = filename:join([LibDir,"ebin"]), - {ok, Files0} = file:list_dir(EbinDir), - Files1 = [lists:reverse(File) || File <- Files0], - [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1]. - - -missing_modules([], _Ebins, Missing) -> - Missing; -missing_modules([Mod|Mods], Ebins, Missing) -> - case lists:member(Mod, Ebins) of - true -> - missing_modules(Mods, Ebins, Missing); - false -> - io:format("missing module: ~p~n", [Mod]), - missing_modules(Mods, Ebins, [Mod|Missing]) - end. - - -extra_modules(_Mods, [], Allowed, Extra) -> - Extra--Allowed; -extra_modules(Mods, [Mod|Ebins], Allowed, Extra) -> - case lists:member(Mod, Mods) of - true -> - extra_modules(Mods, Ebins, Allowed, Extra); - false -> - io:format("supefluous module: ~p~n", [Mod]), - extra_modules(Mods, Ebins, Allowed, [Mod|Extra]) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -exportall(suite) -> - []; -exportall(doc) -> - []; -exportall(Config) when is_list(Config) -> - AppFile = ?KEY1SEARCH(app_file, Config), - Mods = ?KEY1SEARCH(modules, AppFile), - check_export_all(Mods). - - -check_export_all([]) -> - ok; -check_export_all([Mod|Mods]) -> - case (catch apply(Mod, module_info, [compile])) of - {'EXIT', {undef, _}} -> - check_export_all(Mods); - O -> - case lists:keysearch(options, 1, O) of - false -> - check_export_all(Mods); - {value, {options, List}} -> - case lists:member(export_all, List) of - true -> - throw({error, {export_all, Mod}}); - false -> - check_export_all(Mods) - end - end - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -app_depend(suite) -> - []; -app_depend(doc) -> - []; -app_depend(Config) when is_list(Config) -> - AppFile = ?KEY1SEARCH(app_file, Config), - Apps = ?KEY1SEARCH(applications, AppFile), - check_apps(Apps). - - -check_apps([]) -> - ok; -check_apps([App|Apps]) -> - case is_app(App) of - {ok, _} -> - check_apps(Apps); - Error -> - throw({error, {missing_app, {App, Error}}}) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -undef_funcs(suite) -> - []; -undef_funcs(doc) -> - []; -undef_funcs(Config) when is_list(Config) -> - ?SKIP(diameter_not_known_by_xref), - App = diameter, - AppFile = ?KEY1SEARCH(app_file, Config), - Mods = ?KEY1SEARCH(modules, AppFile), - Root = code:root_dir(), - LibDir = code:lib_dir(App), - EbinDir = filename:join([LibDir,"ebin"]), - XRefTestName = undef_funcs_make_name(App, xref_test_name), - try - begin - XRef = xref_start(XRefTestName), - xref_set_defaults(XRef, [{verbose,false},{warnings,false}]), - XRefName = undef_funcs_make_name(App, xref_name), - XRefName = xref_add_release(XRef, Root, XRefName), - xref_replace_application(XRef, App, EbinDir), - Undefs = xref_analyze(XRef), - xref_stop(XRef), - analyze_undefined_function_calls(Undefs, Mods, []) - end - catch - throw:{error, Reason} -> - ?FAIL(Reason) - end. - - -xref_start(XRefTestName) -> - case (catch xref:start(XRefTestName)) of - {ok, XRef} -> - XRef; - {error, Reason} -> - throw({error, {failed_starting_xref, Reason}}); - Error -> - throw({error, {failed_starting_xref, Error}}) - end. - -xref_set_defaults(XRef, Defs) -> - case (catch xref:set_default(XRef, Defs)) of - ok -> - ok; - Error -> - throw({error, {failed_setting_defaults, Defs, Error}}) - end. - -xref_add_release(XRef, Root, Name) -> - case (catch xref:add_release(XRef, Root, {name, Name})) of - {ok, XRefName} -> - XRefName; - {error, Reason} -> - throw({error, {failed_adding_release, Reason}}); - Error -> - throw({error, {failed_adding_release, Error}}) - end. - -xref_replace_application(XRef, App, EbinDir) -> - case (catch xref:replace_application(XRef, App, EbinDir)) of - {ok, App} -> - ok; - {error, XRefMod, Reason} -> - throw({error, {failed_replacing_app, XRefMod, Reason}}); - Error -> - throw({error, {failed_replacing_app, Error}}) - end. - -xref_analyze(XRef) -> - case (catch xref:analyze(XRef, undefined_function_calls)) of - {ok, Undefs} -> - Undefs; - {error, Reason} -> - throw({error, {failed_detecting_func_calls, Reason}}); - Error -> - throw({error, {failed_detecting_func_calls, Error}}) - end. - -xref_stop(XRef) -> - xref:stop(XRef). - -analyze_undefined_function_calls([], _, []) -> - ok; -analyze_undefined_function_calls([], _, AppUndefs) -> - exit({suite_failed, {undefined_function_calls, AppUndefs}}); -analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs], - AppModules, AppUndefs) -> - %% Check that this module is our's - case lists:member(Mod,AppModules) of - true -> - {Calling,Called} = AppUndef, - {Mod1,Func1,Ar1} = Calling, - {Mod2,Func2,Ar2} = Called, - io:format("undefined function call: " - "~n ~w:~w/~w calls ~w:~w/~w~n", - [Mod1,Func1,Ar1,Mod2,Func2,Ar2]), - analyze_undefined_function_calls(Undefs, AppModules, - [AppUndef|AppUndefs]); - false -> - io:format("dropping ~p~n", [Mod]), - analyze_undefined_function_calls(Undefs, AppModules, AppUndefs) - end. - -%% This function is used simply to avoid cut-and-paste errors later... -undef_funcs_make_name(App, PostFix) -> - list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%% fail(Reason) -> -%% exit({suite_failed, Reason}). - -%% ?KEY1SEARCH(Key, L) -> -%% case lists:keysearch(Key, 1, L) of -%% undefined -> -%% fail({not_found, Key, L}); -%% {value, {Key, Value}} -> -%% Value -%% end. diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index ddc720d0c1..d500537736 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -21,12 +21,14 @@ TEST_SPEC_FILE = diameter.spec COVER_SPEC_FILE = diameter.cover -BEHAVIOUR_MODULES = - MODULES = \ - $(BEHAVIOUR_MODULES) \ - diameter_SUITE \ - diameter_app_test \ + diameter_ct \ + diameter_util \ + diameter_enum \ + diameter_codec_SUITE \ + diameter_codec_test \ + diameter_app_SUITE \ + \ diameter_appup_test \ diameter_compiler_test \ diameter_config_test \ @@ -39,9 +41,5 @@ MODULES = \ diameter_test_lib \ diameter_test_server - INTERNAL_HRL_FILES = \ diameter_test_lib.hrl - - - -- cgit v1.2.3 From c70314ecb08697d0926c0e86e048cd22dab60068 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 27 Jul 2011 19:26:57 +0200 Subject: Move appup tests into app suite and use systools for both --- lib/diameter/test/diameter_app_SUITE.erl | 139 ++++++-- lib/diameter/test/diameter_appup_test.erl | 539 ----------------------------- lib/diameter/test/diameter_codec_SUITE.erl | 2 +- lib/diameter/test/diameter_util.erl | 39 ++- lib/diameter/test/modules.mk | 1 - 5 files changed, 141 insertions(+), 579 deletions(-) delete mode 100644 lib/diameter/test/diameter_appup_test.erl diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 898f302457..718f28d066 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -30,10 +30,12 @@ %% testcases -export([keys/1, + vsn/1, modules/1, exports/1, - applications/1, - undefined_calls/1, undefined_calls/0]). + release/1, + xref/1, xref/0, + relup/1]). -define(APP, diameter). -define(A, list_to_atom). @@ -45,46 +47,62 @@ suite() -> all() -> [keys, + vsn, modules, exports, - applications, - undefined_calls]. + release, + xref, + relup]. init_per_suite(Config) -> - {ok, App} = diameter_util:appfile(?APP), + [{application, ?APP, App}] = diameter_util:consult(?APP, app), [{app, App} | Config]. end_per_suite(_Config) -> ok. %% =========================================================================== - -%% keys/1 +%% # keys/1 %% -%% Ensure that the app file contain required keys. +%% Ensure that the app file contains selected keys. Some of these would +%% also be caught by other testcases. +%% =========================================================================== keys(Config) -> App = fetch(app, Config), [] = lists:filter(fun(K) -> not lists:keymember(K, 1, App) end, [vsn, description, modules, registered, applications]). -%% modules/1 +%% =========================================================================== +%% # vsn/1 +%% +%% Ensure that our app version sticks to convention. +%% =========================================================================== + +vsn(Config) -> + true = is_vsn(fetch(vsn, fetch(app, Config))). + +%% =========================================================================== +%% # modules/1 %% %% Ensure that the app file module list match the installed beams. +%% =========================================================================== modules(Config) -> Mods = fetch(modules, fetch(app, Config)), - Installed = installed_mods(), + Installed = code_mods(), {[], []} = {Mods -- Installed, Installed -- Mods}. -installed_mods() -> +code_mods() -> Dir = code:lib_dir(?APP, ebin), {ok, Files} = file:list_dir(Dir), [?A(lists:reverse(R)) || N <- Files, "maeb." ++ R <- [lists:reverse(N)]]. -%% exports/1 +%% =========================================================================== +%% # exports/1 %% %% Ensure that no module does export_all. +%% =========================================================================== exports(Config) -> Mods = fetch(modules, fetch(app, Config)), @@ -95,22 +113,38 @@ exports_all(Mod) -> is_list(Opts) andalso lists:member(export_all, Opts). -%% applications/1 +%% =========================================================================== +%% # release/1 %% -%% Ensure that each dependent application is on the code path. +%% Ensure that it's possible to build a minimal release with our app file. +%% =========================================================================== -applications(Config) -> - As = fetch(applications, fetch(app, Config)), - [] = [A || A <- As, {error, _} <- [diameter_util:appfile(A)]]. +release(Config) -> + App = fetch(app, Config), + Rel = {release, + {"diameter test release", fetch(vsn, App)}, + {erts, erlang:system_info(version)}, + [{A, appvsn(A)} || A <- fetch(applications, App)]}, + Dir = fetch(priv_dir, Config), + ok = write_file(filename:join([Dir, "diameter_test.rel"]), Rel), + {ok, _, []} = systools:make_script("diameter_test", [{path, [Dir]}, + {outdir, Dir}, + silent]). + +appvsn(Name) -> + [{application, Name, App}] = diameter_util:consult(Name, app), + fetch(vsn, App). -%% undefined_calls/1 +%% =========================================================================== +%% # xref/1 %% -%% Ensure that no function on our application calls an undefined function. +%% Ensure that no function in our application calls an undefined function. +%% =========================================================================== -undefined_calls() -> +xref() -> [{timetrap, {minutes, 2}}]. -undefined_calls(Config) -> +xref(Config) -> Mods = fetch(modules, fetch(app, Config)), RootDir = code:root_dir(), @@ -133,7 +167,68 @@ make_name(Suf) -> list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)). %% =========================================================================== +%% # relup/1 +%% +%% Ensure that we can generate release upgrade files using our appup file. +%% =========================================================================== + +relup(Config) -> + [{Vsn, Up, Down}] = diameter_util:consult(?APP, appup), + true = is_vsn(Vsn), + + App = fetch(app, Config), + Rel = [{erts, erlang:system_info(version)} + | [{A, appvsn(A)} || A <- fetch(applications, App)]], + + Dir = fetch(priv_dir, Config), + + Name = write_rel(Dir, Rel, Vsn), + UpFrom = acc_rel(Dir, Rel, Up), + DownTo = acc_rel(Dir, Rel, Down), + + {[Name], [Name], UpFrom, DownTo} %% no intersections + = {[Name] -- UpFrom, + [Name] -- DownTo, + UpFrom -- DownTo, + DownTo -- UpFrom}, + + {ok, _, _, []} = systools:make_relup(Name, UpFrom, DownTo, [{path, [Dir]}, + {outdir, Dir}, + silent]). + +acc_rel(Dir, Rel, List) -> + lists:foldl(fun(T,A) -> acc_rel(Dir, Rel, T, A) end, + [], + List). + +acc_rel(Dir, Rel, {Vsn, _}, Acc) -> + [write_rel(Dir, Rel, Vsn) | Acc]. + +%% Write a rel file and return its name. +write_rel(Dir, [Erts | Apps], Vsn) -> + true = is_vsn(Vsn), + Name = "diameter_test_" ++ Vsn, + ok = write_file(filename:join([Dir, Name ++ ".rel"]), + {release, + {"diameter " ++ Vsn ++ " test release", Vsn}, + Erts, + Apps}), + Name. + +%% =========================================================================== +%% =========================================================================== fetch(Key, List) -> - {Key, Val} = lists:keyfind(Key, 1, List), + {Key, {Key, Val}} = {Key, lists:keyfind(Key, 1, List)}, %% useful badmatch Val. + +write_file(Path, T) -> + file:write_file(Path, io_lib:format("~p.", [T])). + +%% Is a version string of the expected form? Return the argument +%% itself for 'false' for a useful badmatch. +is_vsn(V) -> + is_list(V) + andalso length(V) == string:span(V, "0123456789.") + andalso V == string:join(string:tokens(V, [$.]), ".") %% no ".." + orelse {error, V}. diff --git a/lib/diameter/test/diameter_appup_test.erl b/lib/diameter/test/diameter_appup_test.erl deleted file mode 100644 index 97a089e01a..0000000000 --- a/lib/diameter/test/diameter_appup_test.erl +++ /dev/null @@ -1,539 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the application specifics of the Diameter application -%%---------------------------------------------------------------------- --module(diameter_appup_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2, - - appup/1 - ]). - --export([t/0, t/1]). - --compile({no_auto_import,[error/1]}). - --include("diameter_test_lib.hrl"). - --define(APPLICATION, diameter). - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - [appup]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - AppFile = file_name(?APPLICATION, ".app"), - AppupFile = file_name(?APPLICATION, ".appup"), - [{app_file, AppFile}, {appup_file, AppupFile}|Config]. - - -file_name(App, Ext) -> - LibDir = code:lib_dir(App), - filename:join([LibDir, "ebin", atom_to_list(App) ++ Ext]). - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -appup(suite) -> - []; -appup(doc) -> - "perform a simple check of the appup file"; -appup(Config) when is_list(Config) -> - AppupFile = key1search(appup_file, Config), - AppFile = key1search(app_file, Config), - Modules = modules(AppFile), - check_appup(AppupFile, Modules). - -modules(File) -> - case file:consult(File) of - {ok, [{application,diameter,Info}]} -> - case lists:keysearch(modules,1,Info) of - {value, {modules, Modules}} -> - Modules; - false -> - fail({bad_appinfo, Info}) - end; - Error -> - fail({bad_appfile, Error}) - end. - - -check_appup(AppupFile, Modules) -> - case file:consult(AppupFile) of - {ok, [{V, UpFrom, DownTo}]} -> - check_appup(V, UpFrom, DownTo, Modules); - Else -> - fail({bad_appupfile, Else}) - end. - - -check_appup(V, UpFrom, DownTo, Modules) -> - check_version(V), - check_depends(up, UpFrom, Modules), - check_depends(down, DownTo, Modules), - check_module_subset(UpFrom), - check_module_subset(DownTo), - ok. - - -check_depends(_, [], _) -> - ok; -check_depends(UpDown, [Dep|Deps], Modules) -> - check_depend(UpDown, Dep, Modules), - check_depends(UpDown, Deps, Modules). - - -check_depend(up = UpDown, {add_application, ?APPLICATION} = Instr, Modules) -> - d("check_instructions(~w) -> entry with" - "~n Instruction: ~p" - "~n Modules: ~p", [UpDown, Instr, Modules]), - ok; -check_depend(down = UpDown, {remove_application, ?APPLICATION} = Instr, - Modules) -> - d("check_instructions(~w) -> entry with" - "~n Instruction: ~p" - "~n Modules: ~p", [UpDown, Instr, Modules]), - ok; -check_depend(UpDown, {V, Instructions}, Modules) -> - d("check_instructions(~w) -> entry with" - "~n V: ~p" - "~n Modules: ~p", [UpDown, V, Modules]), - check_version(V), - case check_instructions(UpDown, - Instructions, Instructions, [], [], Modules) of - {_Good, []} -> - ok; - {_, Bad} -> - fail({bad_instructions, Bad, UpDown}) - end. - - -check_instructions(_, [], _, Good, Bad, _) -> - {lists:reverse(Good), lists:reverse(Bad)}; -check_instructions(UpDown, [Instr|Instrs], AllInstr, Good, Bad, Modules) -> - d("check_instructions(~w) -> entry with" - "~n Instr: ~p", [UpDown,Instr]), - case (catch check_instruction(UpDown, Instr, AllInstr, Modules)) of - ok -> - check_instructions(UpDown, Instrs, AllInstr, - [Instr|Good], Bad, Modules); - {error, Reason} -> - d("check_instructions(~w) -> bad instruction: " - "~n Reason: ~p", [UpDown,Reason]), - check_instructions(UpDown, Instrs, AllInstr, Good, - [{Instr, Reason}|Bad], Modules) - end. - -%% A new module is added -check_instruction(up, {add_module, Module}, _, Modules) - when is_atom(Module) -> - d("check_instruction -> entry when up-add_module instruction with" - "~n Module: ~p", [Module]), - check_module(Module, Modules); - -%% An old module is re-added -check_instruction(down, {add_module, Module}, _, Modules) - when is_atom(Module) -> - d("check_instruction -> entry when down-add_module instruction with" - "~n Module: ~p", [Module]), - case (catch check_module(Module, Modules)) of - {error, {unknown_module, Module, Modules}} -> - ok; - ok -> - error({existing_readded_module, Module}) - end; - -%% Removing a module on upgrade: -%% - the module has been removed from the app-file. -%% - check that no module depends on this (removed) module -check_instruction(up, {remove, {Module, Pre, Post}}, _, Modules) - when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) -> - d("check_instruction -> entry when up-remove instruction with" - "~n Module: ~p" - "~n Pre: ~p" - "~n Post: ~p", [Module, Pre, Post]), - case (catch check_module(Module, Modules)) of - {error, {unknown_module, Module, Modules}} -> - check_purge(Pre), - check_purge(Post); - ok -> - error({existing_removed_module, Module}) - end; - -%% Removing a module on downgrade: the module exist -%% in the app-file. -check_instruction(down, {remove, {Module, Pre, Post}}, AllInstr, Modules) - when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) -> - d("check_instruction -> entry when down-remove instruction with" - "~n Module: ~p" - "~n Pre: ~p" - "~n Post: ~p", [Module, Pre, Post]), - case (catch check_module(Module, Modules)) of - ok -> - check_purge(Pre), - check_purge(Post), - check_no_remove_depends(Module, AllInstr); - {error, {unknown_module, Module, Modules}} -> - error({nonexisting_removed_module, Module}) - end; - -check_instruction(_, {load_module, Module, Pre, Post, Depend}, - AllInstr, Modules) - when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) -> - d("check_instruction -> entry when load_module instruction with" - "~n Module: ~p" - "~n Pre: ~p" - "~n Post: ~p" - "~n Depend: ~p", [Module, Pre, Post, Depend]), - check_module(Module, Modules), - check_module_depend(Module, Depend, Modules), - check_module_depend(Module, Depend, updated_modules(AllInstr, [])), - check_purge(Pre), - check_purge(Post); - -check_instruction(_, {update, Module, Change, Pre, Post, Depend}, - AllInstr, Modules) - when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) -> - d("check_instruction -> entry when update instruction with" - "~n Module: ~p" - "~n Change: ~p" - "~n Pre: ~p" - "~n Post: ~p" - "~n Depend: ~p", [Module, Change, Pre, Post, Depend]), - check_module(Module, Modules), - check_module_depend(Module, Depend, Modules), - check_module_depend(Module, Depend, updated_modules(AllInstr, [])), - check_change(Change), - check_purge(Pre), - check_purge(Post); - -check_instruction(_, {update, Module, supervisor}, _, Modules) - when is_atom(Module) -> - check_module(Module, Modules); - -check_instruction(_, {apply, {Module, Function, Args}}, _, Modules) - when is_atom(Module) andalso is_atom(Function) andalso is_list(Args) -> - d("check_instruction -> entry when down-apply instruction with" - "~n Module: ~p" - "~n Function: ~p" - "~n Args: ~p", [Module, Function, Args]), - check_module(Module, Modules), - check_apply(Module, Function, Args); - -check_instruction(_, {restart_application, ?APPLICATION}, _AllInstr, _Modules) -> - ok; - -check_instruction(_, Instr, _AllInstr, _Modules) -> - d("check_instruction -> entry when unknown instruction with" - "~n Instr: ~p", [Instr]), - error({error, {unknown_instruction, Instr}}). - - -%% If Module X depends on Module Y, then module Y must have an update -%% instruction of some sort (otherwise the depend is faulty). -updated_modules([], Modules) -> - d("update_modules -> entry when done with" - "~n Modules: ~p", [Modules]), - Modules; -updated_modules([Instr|Instrs], Modules) -> - d("update_modules -> entry with" - "~n Instr: ~p" - "~n Modules: ~p", [Instr,Modules]), - Module = instruction_module(Instr), - d("update_modules -> Module: ~p", [Module]), - updated_modules(Instrs, [Module|Modules]). - -instruction_module({add_module, Module}) -> - Module; -instruction_module({remove, {Module, _, _}}) -> - Module; -instruction_module({load_module, Module, _, _, _}) -> - Module; -instruction_module({update, Module, _, _, _, _}) -> - Module; -instruction_module({apply, {Module, _, _}}) -> - Module; -instruction_module(Instr) -> - d("instruction_module -> entry when unknown instruction with" - "~n Instr: ~p", [Instr]), - error({error, {unknown_instruction, Instr}}). - - -%% Check that the modules handled in an instruction set for version X -%% is a subset of the instruction set for version X-1. -check_module_subset(Instructions) -> - do_check_module_subset(modules_of(Instructions)). - -do_check_module_subset([]) -> - ok; -do_check_module_subset([_]) -> - ok; -do_check_module_subset([{_V1, Mods1}|T]) -> - {V2, Mods2} = hd(T), - %% Check that the modules in V1 is a subset of V2 - case do_check_module_subset2(Mods1, Mods2) of - ok -> - do_check_module_subset(T); - {error, Modules} -> - fail({subset_missing_instructions, V2, Modules}) - end. - -do_check_module_subset2(Mods1, Mods2) -> - do_check_module_subset2(Mods1, Mods2, []). - -do_check_module_subset2([], _, []) -> - ok; -do_check_module_subset2([], _, Acc) -> - {error, lists:reverse(Acc)}; -do_check_module_subset2([Mod|Mods], Mods2, Acc) -> - case lists:member(Mod, Mods2) of - true -> - do_check_module_subset2(Mods, Mods2, Acc); - false -> - do_check_module_subset2(Mods, Mods2, [Mod|Acc]) - end. - - -modules_of(Instructions) -> - modules_of(Instructions, []). - -modules_of([], Acc) -> - lists:reverse(Acc); -modules_of([{V,Instructions}|T], Acc) -> - Mods = modules_of2(Instructions, []), - modules_of(T, [{V, Mods}|Acc]). - -modules_of2([], Acc) -> - lists:reverse(Acc); -modules_of2([Instr|Instructions], Acc) -> - case module_of(Instr) of - {value, Mod} -> - modules_of2(Instructions, [Mod|Acc]); - false -> - modules_of2(Instructions, Acc) - end. - -module_of({add_module, Module}) -> - {value, Module}; -module_of({remove, {Module, _Pre, _Post}}) -> - {value, Module}; -module_of({load_module, Module, _Pre, _Post, _Depend}) -> - {value, Module}; -module_of({update, Module, _Change, _Pre, _Post, _Depend}) -> - {value, Module}; -module_of(_) -> - false. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% The version is a string consting of numbers separated by dots: "." -%% Example: "3.3.3" -%% -check_version(V) when is_list(V) -> - case do_check_version(string:tokens(V, [$.])) of - ok -> - ok; - {error, BadVersionPart} -> - throw({error, {bad_version, V, BadVersionPart}}) - end; -check_version(V) -> - error({bad_version, V}). - -do_check_version([]) -> - ok; -do_check_version([H|T]) -> - case (catch list_to_integer(H)) of - I when is_integer(I) -> - do_check_version(T); - _ -> - {error, H} - end. - -check_module(M, Modules) when is_atom(M) -> - case lists:member(M,Modules) of - true -> - ok; - false -> - error({unknown_module, M, Modules}) - end; -check_module(M, _) -> - error({bad_module, M}). - - -check_module_depend(M, [], _) when is_atom(M) -> - d("check_module_depend -> entry with" - "~n M: ~p", [M]), - ok; -check_module_depend(M, Deps, Modules) when is_atom(M) andalso is_list(Deps) -> - d("check_module_depend -> entry with" - "~n M: ~p" - "~n Deps: ~p" - "~n Modules: ~p", [M, Deps, Modules]), - case [Dep || Dep <- Deps, lists:member(Dep, Modules) == false] of - [] -> - ok; - Unknown -> - error({unknown_depend_modules, Unknown}) - end; -check_module_depend(_M, D, _Modules) -> - d("check_module_depend -> entry when bad depend with" - "~n D: ~p", [D]), - error({bad_depend, D}). - - -check_no_remove_depends(_Module, []) -> - ok; -check_no_remove_depends(Module, [Instr|Instrs]) -> - check_no_remove_depend(Module, Instr), - check_no_remove_depends(Module, Instrs). - -check_no_remove_depend(Module, {load_module, Mod, _Pre, _Post, Depend}) -> - case lists:member(Module, Depend) of - true -> - error({removed_module_in_depend, load_module, Mod, Module}); - false -> - ok - end; -check_no_remove_depend(Module, {update, Mod, _Change, _Pre, _Post, Depend}) -> - case lists:member(Module, Depend) of - true -> - error({removed_module_in_depend, update, Mod, Module}); - false -> - ok - end; -check_no_remove_depend(_, _) -> - ok. - - -check_change(soft) -> - ok; -check_change({advanced, _Something}) -> - ok; -check_change(Change) -> - error({bad_change, Change}). - - -check_purge(soft_purge) -> - ok; -check_purge(brutal_purge) -> - ok; -check_purge(Purge) -> - error({bad_purge, Purge}). - - -check_apply(Module, Function, Args) -> - case (catch Module:module_info()) of - Info when is_list(Info) -> - check_exported(Function, Args, Info); - {'EXIT', {undef, _}} -> - error({not_existing_module, Module}) - end. - -check_exported(Function, Args, Info) -> - case lists:keysearch(exports, 1, Info) of - {value, {exports, FuncList}} -> - Arity = length(Args), - Arities = [A || {F, A} <- FuncList, F == Function], - case lists:member(Arity, Arities) of - true -> - ok; - false -> - error({not_exported_function, Function, Arity}) - end; - _ -> - error({bad_export, Info}) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -error(Reason) -> - throw({error, Reason}). - -fail(Reason) -> - exit({suite_failed, Reason}). - -key1search(Key, L) -> - case lists:keysearch(Key, 1, L) of - undefined -> - fail({not_found, Key, L}); - {value, {Key, Value}} -> - Value - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -d(F, A) -> - d(false, F, A). - -d(true, F, A) -> - io:format(F ++ "~n", A); -d(_, _, _) -> - ok. - - diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index 07e2a705c3..c1b069f447 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -50,7 +50,7 @@ all() -> [base, gen, lib]. init_per_testcase(gen, Config) -> - {ok, App} = diameter_util:appfile(?APP), + [{application, ?APP, App}] = diameter_util:consult(?APP, app), {modules, Ms} = lists:keyfind(modules, 1, App), [_|_] = Gs = lists:filter(fun(M) -> lists:prefix("diameter_gen_", ?L(M)) diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 93760a1c07..99f4fa1977 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -23,31 +23,38 @@ %% Utility functions. %% --export([appfile/1, +-export([consult/2, run/1, fold/3, foldl/3, scramble/1, ps/0]). -%% appfile/1 +-define(L, atom_to_list). + +%% consult/2 %% -%% Extract info from the app file of the named application. - -appfile(Name) -> - appfile(code:lib_dir(Name, ebin), Name). - -appfile({error = E, Reason}, _) -> - {E, {code, Reason}}; -appfile(Dir, Name) -> - case file:consult(filename:join([Dir, atom_to_list(Name) ++ ".app"])) of - {ok, [{application, Name, App}]} -> - {ok, App}; - {ok, Huh} -> - {error, {content, Huh}}; +%% Extract info from the app/appup file (presumably) of the named +%% application. + +consult(Name, Suf) + when is_atom(Name), is_atom(Suf) -> + case code:lib_dir(Name, ebin) of + {error = E, Reason} -> + {E, {Name, Reason}}; + Dir -> + consult(filename:join([Dir, ?L(Name) ++ "." ++ ?L(Suf)])) + end. + +consult(Path) -> + case file:consult(Path) of + {ok, Terms} -> + Terms; {error, Reason} -> - {error, {file, Reason}} + {error, {Path, Reason}} end. +%% Name/Path in the return value distinguish the errors and allow for +%% a useful badmatch. %% run/1 %% diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index d500537736..65c5ea9333 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -29,7 +29,6 @@ MODULES = \ diameter_codec_test \ diameter_app_SUITE \ \ - diameter_appup_test \ diameter_compiler_test \ diameter_config_test \ diameter_peer_test \ -- cgit v1.2.3 From 34171e0c62d28fde23a690b5615a5d00ffac7045 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 19 Sep 2011 11:32:48 +0200 Subject: Add dict suite, remove session suite --- lib/diameter/test/Makefile | 12 +-- lib/diameter/test/diameter_dict_SUITE.erl | 143 ++++++++++++++++++++++++++++ lib/diameter/test/diameter_session_test.erl | 104 -------------------- lib/diameter/test/modules.mk | 2 +- 4 files changed, 147 insertions(+), 114 deletions(-) create mode 100644 lib/diameter/test/diameter_dict_SUITE.erl delete mode 100644 lib/diameter/test/diameter_session_test.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index d77099785f..c2619df204 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -67,7 +67,7 @@ SOURCE = $(HRL_FILES) $(ERL_FILES) TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) -APP_CASES = app appup +APP_CASES = app TRANSPORT_CASES = tcp @@ -229,9 +229,6 @@ help: @echo " app" @echo " Run the $(APPLICATION) application sub-test-suite. " @echo "" - @echo " appup" - @echo " Run the $(APPLICATION) application upgrade (appup) sub-test-suite. " - @echo "" @echo " compiler" @echo " Run the $(APPLICATION) compiler sub-test-suite(s). " @echo "" @@ -242,9 +239,6 @@ help: @echo " sync" @echo " Run the $(APPLICATION) sync sub-test-suite. " @echo "" - @echo " session" - @echo " Run the $(APPLICATION) session sub-test-suite. " - @echo "" @echo " stats" @echo " Run the $(APPLICATION) stats sub-test-suite. " @echo "" @@ -309,14 +303,14 @@ log: # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -app codec: log make +app codec dict: log make $(MERL) $(ARGS) \ -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' -appup compiler conf sync session stats reg peer tcp: make +compiler conf sync stats reg peer tcp: make $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ $(ESTOP) diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl new file mode 100644 index 0000000000..3b61edba58 --- /dev/null +++ b/lib/diameter/test/diameter_dict_SUITE.erl @@ -0,0 +1,143 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of the dict-like diameter_dict. +%% + +-module(diameter_dict_SUITE). + +-export([suite/0, + all/0]). + +%% testcases +-export([scramble/1, + append/1, + fetch/1, + fetch_keys/1, + filter/1, + find/1, + fold/1, + is_key/1, + map/1, + merge/1, + update/1, + update_counter/1]). + +-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). + +-define(dict, diameter_dict). +-define(util, diameter_util). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [scramble | tc()]. + +tc() -> + [append, + fetch, + fetch_keys, + filter, + find, + fold, + is_key, + map, + merge, + update, + update_counter]. + +%% =========================================================================== + +scramble(Config) -> + [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). + +-define(KV100, [{N,[N]} || N <- lists:seq(1,100)]). + +append(_) -> + D = ?dict:append(k, v, ?dict:new()), + [{k,[v,v]}] = ?dict:to_list(?dict:append(k, v, D)). + +fetch(_) -> + D = ?dict:from_list(?KV100), + [50] = ?dict:fetch(50, D), + Ref = make_ref(), + Ref = try ?dict:fetch(Ref, D) catch _:_ -> Ref end. + +fetch_keys(_) -> + L = ?KV100, + D = ?dict:from_list(L), + L = [{N,[N]} || N <- lists:sort(?dict:fetch_keys(D))]. + +filter(_) -> + L = ?KV100, + F = fun(K,[_]) -> 0 == K rem 2 end, + D = ?dict:filter(F, ?dict:from_list(L)), + true = [T || {K,V} = T <- L, F(K,V)] == lists:sort(?dict:to_list(D)). + +find(_) -> + D = ?dict:from_list(?KV100), + {ok, [50]} = ?dict:find(50, D), + error = ?dict:find(make_ref(), D). + +fold(_) -> + L = ?KV100, + S = lists:sum([N || {N,_} <- L]), + S = ?dict:fold(fun(K,[_],A) -> K + A end, 0, ?dict:from_list(L)). + +is_key(_) -> + L = ?KV100, + D = ?dict:from_list(L), + true = lists:all(fun({N,_}) -> ?dict:is_key(N,D) end, L), + false = ?dict:is_key(make_ref(), D). + +map(_) -> + L = ?KV100, + F = fun(_,V) -> [N] = V, N*2 end, + D = ?dict:map(F, ?dict:from_list(L)), + M = [{K, F(K,V)} || {K,V} <- L], + M = lists:sort(?dict:to_list(D)). + +merge(_) -> + L = ?KV100, + F = fun(_,V1,V2) -> V1 ++ V2 end, + D = ?dict:merge(F, ?dict:from_list(L), ?dict:from_list(L)), + M = [{K, F(K,V,V)} || {K,V} <- L], + M = lists:sort(?dict:to_list(D)). + +update(_) -> + L = ?KV100, + F = fun([V]) -> 2*V end, + D = ?dict:update(50, F, ?dict:from_list(L)), + 100 = ?dict:fetch(50, D), + Ref = make_ref(), + Ref = try ?dict:update(Ref, F, D) catch _:_ -> Ref end, + [Ref] = ?dict:fetch(Ref, ?dict:update(Ref, + fun(_,_) -> ?ERROR(i_think_not) end, + [Ref], + D)). + +update_counter(_) -> + L = [{N,2*N} || {N,_} <- ?KV100], + D = ?dict:update_counter(50, 20, ?dict:from_list(L)), + 120 = ?dict:fetch(50,D), + 2 = ?dict:fetch(1,D). diff --git a/lib/diameter/test/diameter_session_test.erl b/lib/diameter/test/diameter_session_test.erl deleted file mode 100644 index a32647d83d..0000000000 --- a/lib/diameter/test/diameter_session_test.erl +++ /dev/null @@ -1,104 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the session component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_session_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 65c5ea9333..06b2893246 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -28,12 +28,12 @@ MODULES = \ diameter_codec_SUITE \ diameter_codec_test \ diameter_app_SUITE \ + diameter_dict_SUITE \ \ diameter_compiler_test \ diameter_config_test \ diameter_peer_test \ diameter_reg_test \ - diameter_session_test \ diameter_stats_test \ diameter_sync_test \ diameter_tcp_test \ -- cgit v1.2.3 From c179382d36fd4c19a063cba04b34d4d19b05083d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 28 Jul 2011 12:00:26 +0200 Subject: Add reg suite --- lib/diameter/test/Makefile | 6 +- lib/diameter/test/diameter_reg_SUITE.erl | 111 +++++++++++++++++++++++++++++++ lib/diameter/test/diameter_reg_test.erl | 104 ----------------------------- lib/diameter/test/modules.mk | 2 +- 4 files changed, 115 insertions(+), 108 deletions(-) create mode 100644 lib/diameter/test/diameter_reg_SUITE.erl delete mode 100644 lib/diameter/test/diameter_reg_test.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index c2619df204..57b2daf8da 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -73,7 +73,7 @@ TRANSPORT_CASES = tcp ALL_CASES = \ $(APP_CASES) \ - compiler conf sync session stats reg peer \ + compiler conf sync stats reg peer \ $(TRANSPORT_CASES) @@ -303,14 +303,14 @@ log: # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -app codec dict: log make +app codec dict reg: log make $(MERL) $(ARGS) \ -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' -compiler conf sync stats reg peer tcp: make +compiler conf sync stats peer tcp: make $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ $(ESTOP) diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl new file mode 100644 index 0000000000..5ae6c494e3 --- /dev/null +++ b/lib/diameter/test/diameter_reg_SUITE.erl @@ -0,0 +1,111 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of the server implemented by diameter_reg.erl. +%% + +-module(diameter_reg_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([scramble/1, + add/1, + add_new/1, + del/1, + repl/1, + terms/1, + pids/1]). + +-define(reg, diameter_reg). +-define(util, diameter_util). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [scramble | tc()]. + +tc() -> + [add, + add_new, + del, + repl, + terms, + pids]. + +init_per_suite(Config) -> + ok = diameter:start(), + Config. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +%% =========================================================================== + +scramble(Config) -> + [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). + +add(_) -> + Ref = make_ref(), + true = ?reg:add(Ref), + true = ?reg:add(Ref), + [{Ref, Pid}] = ?reg:match(Ref), + Pid = self(). + +add_new(_) -> + Ref = make_ref(), + true = ?reg:add_new(Ref), + false = ?reg:add_new(Ref). + +del(_) -> + Ref = make_ref(), + true = ?reg:add_new(Ref), + true = ?reg:add_new({Ref}), + true = ?reg:del({Ref}), + [{Ref, Pid}] = ?reg:match(Ref), + Pid = self(). + +repl(_) -> + Ref = make_ref(), + true = ?reg:add_new({Ref}), + true = ?reg:repl({Ref}, Ref), + false = ?reg:add_new(Ref), + false = ?reg:repl({Ref}, Ref), + [{Ref, Pid}] = ?reg:match(Ref), + Pid = self(). + +terms(_) -> + Ref = make_ref(), + true = ?reg:add_new(Ref), + [[Pid]] = [L || {T,L} <- ?reg:terms(), T == Ref], + Pid = self(). + +pids(_) -> + Ref = make_ref(), + true = ?reg:add_new(Ref), + %% Don't match [[Ref]] since this will only necessarily be the + %% case when the test is run in its own process. + [_|_] = [L || {P,L} <- ?reg:pids(), P == self()]. diff --git a/lib/diameter/test/diameter_reg_test.erl b/lib/diameter/test/diameter_reg_test.erl deleted file mode 100644 index a2638d6712..0000000000 --- a/lib/diameter/test/diameter_reg_test.erl +++ /dev/null @@ -1,104 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011_2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the reg component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_reg_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 06b2893246..210d621e17 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -29,11 +29,11 @@ MODULES = \ diameter_codec_test \ diameter_app_SUITE \ diameter_dict_SUITE \ + diameter_reg_SUITE \ \ diameter_compiler_test \ diameter_config_test \ diameter_peer_test \ - diameter_reg_test \ diameter_stats_test \ diameter_sync_test \ diameter_tcp_test \ -- cgit v1.2.3 From 1148b00de74628e8b272b129c9a33df92046ddfc Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 28 Jul 2011 12:27:06 +0200 Subject: Add sync suite --- lib/diameter/test/Makefile | 4 +- lib/diameter/test/diameter_sync_SUITE.erl | 131 ++++++++++++++++++++++++++++++ lib/diameter/test/diameter_sync_test.erl | 104 ------------------------ lib/diameter/test/modules.mk | 2 +- 4 files changed, 134 insertions(+), 107 deletions(-) create mode 100644 lib/diameter/test/diameter_sync_SUITE.erl delete mode 100644 lib/diameter/test/diameter_sync_test.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 57b2daf8da..a1131afae2 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -303,14 +303,14 @@ log: # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -app codec dict reg: log make +app codec dict reg sync: log make $(MERL) $(ARGS) \ -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' -compiler conf sync stats peer tcp: make +compiler conf stats peer tcp: make $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ $(ESTOP) diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl new file mode 100644 index 0000000000..1b1fec8281 --- /dev/null +++ b/lib/diameter/test/diameter_sync_SUITE.erl @@ -0,0 +1,131 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of the server implemented by diameter_sync.erl. +%% + +-module(diameter_sync_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([scramble/1, + call/1, + cast/1, + timeout/1, + flush/1]). + +-define(sync, diameter_sync). +-define(util, diameter_util). + +-define(TIMEOUT, infinity). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [scramble | tc()]. + +tc() -> + [call, + cast, + timeout, + flush]. + +init_per_suite(Config) -> + ok = diameter:start(), + Config. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +%% =========================================================================== + +scramble(Config) -> + [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). + +call(_) -> + Ref = make_ref(), + Q = {q, Ref}, + F = fun() -> Ref end, + Ref = ?sync:call(Q, F, infinity, ?TIMEOUT), + Ref = ?sync:call(Q, F, 0, infinity), + Ref = call(Q, F), + Ref = call(Q, {fun(_) -> Ref end, x}), + timeout = call(Q, fun() -> exit(unexpected) end), + {_,_,_} = call(Q, {erlang, now, []}), + {_,_,_} = call(Q, [fun erlang:now/0]). + +cast(_) -> + Ref = make_ref(), + Q = {q, Ref}, + false = ?sync:carp(Q), + [] = ?sync:pids(Q), + %% Queue a request that blocks until we send it Ref and another + %% that exits with Ref. + ok = cast(Q, fun() -> receive Ref -> ok end end), + ok = cast(Q, fun() -> exit(Ref) end), + [_,Pid] = ?sync:pids(Q), + %% Ensure some expected truths ... + 2 = ?sync:pending(Q), + true = 2 =< ?sync:pending(), + true = lists:member(Q, ?sync:queues()), + %% ... and that the max number of requests is respected. + rejected = ?sync:call(Q, {erlang, now, []}, 1, ?TIMEOUT), + rejected = ?sync:cast(Q, {erlang, now, []}, 1, ?TIMEOUT), + %% Monitor on the identifiable request and see that exits when we + %% let the blocking request finish. + MRef = erlang:monitor(process, Pid), + {value, P} = ?sync:carp(Q), + P ! Ref, + Ref = receive + {'DOWN', MRef, process, _, Reason} -> + Reason + after ?TIMEOUT -> + false + end. + +timeout(_) -> + Q = make_ref(), + ok = ?sync:cast(Q, {timer, sleep, [2000]}, infinity, 2000), + timeout = ?sync:call(Q, fun() -> ok end, infinity, 1000). + +flush(_) -> + Q = make_ref(), + F = {timer, sleep, [2000]}, + ok = cast(Q, F), + ok = cast(Q, F), + 1 = ?sync:flush(Q). + +%% =========================================================================== + +call(Q, Req) -> + sync(call, Q, Req). + +cast(Q, Req) -> + sync(cast, Q, Req). + +sync(F, Q, Req) -> + ?sync:F(Q, Req, infinity, infinity). diff --git a/lib/diameter/test/diameter_sync_test.erl b/lib/diameter/test/diameter_sync_test.erl deleted file mode 100644 index 618fa5021b..0000000000 --- a/lib/diameter/test/diameter_sync_test.erl +++ /dev/null @@ -1,104 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the sync component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_sync_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 210d621e17..83f8b02e85 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -30,12 +30,12 @@ MODULES = \ diameter_app_SUITE \ diameter_dict_SUITE \ diameter_reg_SUITE \ + diameter_sync_SUITE \ \ diameter_compiler_test \ diameter_config_test \ diameter_peer_test \ diameter_stats_test \ - diameter_sync_test \ diameter_tcp_test \ diameter_test_lib \ diameter_test_server -- cgit v1.2.3 From 7213a44a036a9b1a2e744ea6059fbc5095d967fc Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 28 Jul 2011 15:43:06 +0200 Subject: Add stats suite --- lib/diameter/test/Makefile | 4 +- lib/diameter/test/diameter_stats_SUITE.erl | 84 +++++++++++++++++++++++ lib/diameter/test/diameter_stats_test.erl | 104 ----------------------------- lib/diameter/test/modules.mk | 2 +- 4 files changed, 87 insertions(+), 107 deletions(-) create mode 100644 lib/diameter/test/diameter_stats_SUITE.erl delete mode 100644 lib/diameter/test/diameter_stats_test.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index a1131afae2..1004055839 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -303,14 +303,14 @@ log: # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -app codec dict reg sync: log make +app codec dict reg stats sync: log make $(MERL) $(ARGS) \ -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' -compiler conf stats peer tcp: make +compiler conf peer tcp: make $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ $(ESTOP) diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl new file mode 100644 index 0000000000..e0bf6b8c4a --- /dev/null +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -0,0 +1,84 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of the server implemented by diameter_stats.erl. +%% + +-module(diameter_stats_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([scramble/1, + an/1, + twa/1]). + +-define(stat, diameter_stats). +-define(util, diameter_util). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [scramble | tc()]. + +tc() -> + [an, + twa]. + +init_per_suite(Config) -> + ok = diameter:start(), + Config. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +%% =========================================================================== + +scramble(Config) -> + [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). + +an(_) -> + Ref = {'_', make_ref()}, + true = ?stat:reg(Ref), + true = ?stat:reg(Ref), %% duplicate + ok = ?stat:incr(x), + ok = ?stat:incr(x, Ref), + ok = ?stat:incr(y, 2), + ok = ?stat:incr(y, Ref), + %% Flushing a pid flushes even stats on the registered reference. + [{x,2},{y,3}] = lists:sort(?stat:flush()), + [] = ?stat:flush(Ref), + [] = ?stat:flush(). + +twa(_) -> + Ref = make_ref(), + ok = ?stat:incr(x, 8), + ok = ?stat:incr(x, Ref, 7), + %% Flushing a reference doesn't affect registered pids. + [{x,7}] = ?stat:flush(Ref), + [] = ?stat:flush(Ref), + [{x,8}] = ?stat:flush(), + [] = ?stat:flush(). diff --git a/lib/diameter/test/diameter_stats_test.erl b/lib/diameter/test/diameter_stats_test.erl deleted file mode 100644 index 8b666edf50..0000000000 --- a/lib/diameter/test/diameter_stats_test.erl +++ /dev/null @@ -1,104 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the stats component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_stats_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 83f8b02e85..d27d64bb98 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -31,11 +31,11 @@ MODULES = \ diameter_dict_SUITE \ diameter_reg_SUITE \ diameter_sync_SUITE \ + diameter_stats_SUITE \ \ diameter_compiler_test \ diameter_config_test \ diameter_peer_test \ - diameter_stats_test \ diameter_tcp_test \ diameter_test_lib \ diameter_test_server -- cgit v1.2.3 From 8da27b50145cd7d481d67a1244715d898c7d2aaf Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 2 Aug 2011 18:29:06 +0200 Subject: Add watchdog suite --- lib/diameter/test/Makefile | 243 +++--------- lib/diameter/test/diameter_ct.hrl | 21 + lib/diameter/test/diameter_peer_test.erl | 104 ----- lib/diameter/test/diameter_watchdog_SUITE.erl | 540 ++++++++++++++++++++++++++ lib/diameter/test/modules.mk | 13 +- 5 files changed, 621 insertions(+), 300 deletions(-) create mode 100644 lib/diameter/test/diameter_ct.hrl delete mode 100644 lib/diameter/test/diameter_peer_test.erl create mode 100644 lib/diameter/test/diameter_watchdog_SUITE.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 1004055839..0bd3c0493c 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -17,40 +17,39 @@ # %CopyrightEnd% ifneq ($(ERL_TOP),) -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk +TOP = $(ERL_TOP) +DIAMETER_TOP = $(TOP)/lib/diameter else -include $(DIAMETER_TOP)/make/target.mk -include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +TOP = $(DIAMETER_TOP) endif +include $(TOP)/make/target.mk +include $(TOP)/make/$(TARGET)/otp.mk + # ---------------------------------------------------- # Application version # ---------------------------------------------------- + include ../vsn.mk -VSN=$(DIAMETER_VSN) +VSN = $(DIAMETER_VSN) # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- + RELSYSDIR = $(RELEASE_PATH)/diameter_test ifeq ($(findstring win32,$(TARGET)),win32) - MAKEFILE_SRC = Makefile.win32.src - else - MAKEFILE_SRC = Makefile.src - endif ifeq ($(TT_DIR),) TT_DIR = /tmp endif - # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- @@ -59,30 +58,17 @@ include modules.mk EBIN = . -HRL_FILES = diameter_test_lib.hrl - +HRL_FILES = $(INTERNAL_HRL_FILES) ERL_FILES = $(MODULES:%=%.erl) SOURCE = $(HRL_FILES) $(ERL_FILES) - TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) -APP_CASES = app - -TRANSPORT_CASES = tcp - -ALL_CASES = \ - $(APP_CASES) \ - compiler conf sync stats reg peer \ - $(TRANSPORT_CASES) - +SUITE_MODULES = $(filter diameter_%_SUITE, $(MODULES)) +SUITES = $(SUITE_MODULES:diameter_%_SUITE=%) EMAKEFILE = Emakefile -ifneq ($(ERL_TOP),) -MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) -else -MAKE_EMAKE = $(wildcard $(DIAMETER_TOP)/make/make_emakefile) -endif +MAKE_EMAKE = $(wildcard $(TOP)/make/make_emakefile) ifeq ($(MAKE_EMAKE),) BUILDTARGET = $(TARGET_FILES) @@ -92,7 +78,6 @@ BUILDTARGET = emakebuild RELTEST_FILES = $(EMAKEFILE) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) endif - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -107,59 +92,14 @@ ifeq ($(USE_DIAMETER_HIPE),true) ERL_COMPILE_FLAGS += +native -DDIAMETER_hipe_special=true endif -ifneq ($(ERL_TOP),) -ERL_COMPILE_FLAGS += \ - $(DIAMETER_ERL_COMPILE_FLAGS) \ - -pa $(ERL_TOP)/lib/test_server/ebin \ - -I$(ERL_TOP)/lib/test_server/include -else -ERL_COMPILE_FLAGS += \ - $(DIAMETER_ERL_COMPILE_FLAGS) \ - -pa $(TEST_SERVER_DIR)/ebin \ - -I$(TEST_SERVER_DIR)/include -endif - -ERL_PATH = \ - -pa ../../$(APPLICATION)/ebin \ - -pa ../../et/ebin - -ifndef SUITE -SUITE = diameter_SUITE -endif - -ESTOP = -s init stop - -ifeq ($(DONT_STOP),true) -MAYBE_ESTOP = -else -MAYBE_ESTOP = $(ESTOP) -endif - -ETVIEW = -s et_viewer -ifeq ($(USE_ET_VIEWER),true) -MAYBE_ETVIEW = -else -MAYBE_ETVIEW = $(ETVIEW) -endif - -ifeq ($(MERL),) -MERL = $(ERL) -endif - -ARGS += -noshell - -ifeq ($(DISABLE_TC_TIMEOUT),true) -ARGS += -diameter_test_timeout -endif - - -DIAMETER_TEST_SERVER = diameter_test_server - +ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) # ---------------------------------------------------- # Targets # ---------------------------------------------------- +test: $(SUITES) + tests debug opt: $(BUILDTARGET) targets: $(TARGET_FILES) @@ -169,8 +109,9 @@ targets: $(TARGET_FILES) emakebuild: $(EMAKEFILE) $(EMAKEFILE): - $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' | grep -v Warning > $(EMAKEFILE) - $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) | grep -v Warning >> $(EMAKEFILE) + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o $(EBIN) '*_SUITE_make' $(MODULES) \ + | grep -v Warning \ + > $(EMAKEFILE) clean: rm -f $(EMAKEFILE) @@ -180,121 +121,64 @@ clean: docs: info: - @echo "MAKE_EMAKE = $(MAKE_EMAKE)" - @echo "EMAKEFILE = $(EMAKEFILE)" - @echo "BUILDTARGET = $(BUILDTARGET)" - @echo "" + @echo "MAKE_EMAKE = $(MAKE_EMAKE)" + @echo "EMAKEFILE = $(EMAKEFILE)" + @echo "BUILDTARGET = $(BUILDTARGET)" + @echo @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" @echo "ERL = $(ERL)" @echo "ERLC = $(ERLC)" - @echo "MERL = $(MERL)" - @echo "" - @echo "ARGS = $(ARGS)" - @echo "" + @echo @echo "HRL_FILES = $(HRL_FILES)" @echo "ERL_FILES = $(ERL_FILES)" @echo "TARGET_FILES = $(TARGET_FILES)" - @echo "" + @echo + @echo "SUITE_MODULES = $(SUITE_MODULES)" + @echo "SUITES = $(SUITES)" + @echo help: - @echo "" - @echo "This Makefile controls the test of the $(APPLICATION) application. " - @echo "" + @echo + @echo "This Makefile controls the test of the $(APPLICATION) application." + @echo @echo "There are two separate ways to perform the test of $(APPLICATION)." - @echo "" + @echo @echo " a) Run the official OTP test-server (which we do not describe here)" - @echo "" - @echo " b) Run the test-server provided with this application. " + @echo + @echo " b) Run the test-server provided with this application." @echo " There are a number of targets to run the entire or parts" @echo " of this applications ($(APPLICATION)) test-suite" - @echo "" + @echo @echo "Targets:" - @echo "" + @echo @echo " help" @echo " Print this info" - @echo "" + @echo @echo " info" - @echo " Prints various environment variables. " - @echo " May be useful when debugging the Makefile. " - @echo "" + @echo " Prints various environment variables." + @echo " May be useful when debugging the Makefile." + @echo @echo " tests | debug | opt " - @echo " Compile all test-code. " - @echo "" + @echo " Compile all test-code." + @echo @echo " clean " - @echo " Remove all targets. " - @echo "" + @echo " Remove all targets." + @echo @echo " test" - @echo " Run the entire $(APPLICATION) test-suite. " - @echo "" - @echo " app" - @echo " Run the $(APPLICATION) application sub-test-suite. " - @echo "" - @echo " compiler" - @echo " Run the $(APPLICATION) compiler sub-test-suite(s). " - @echo "" - @echo " conf" - @echo " Run the $(APPLICATION) config sub-test-suite. " - @echo " Checks various aspects of the $(APPLICATION) configuration. " - @echo "" - @echo " sync" - @echo " Run the $(APPLICATION) sync sub-test-suite. " - @echo "" - @echo " stats" - @echo " Run the $(APPLICATION) stats sub-test-suite. " - @echo "" - @echo " reg" - @echo " Run the $(APPLICATION) reg sub-test-suite. " - @echo "" - @echo " peer" - @echo " Run the $(APPLICATION) peer sub-test-suite" - @echo "" - @echo " ptab" - @echo " Run the $(APPLICATION) persistent-table sub-test-suite" - @echo "" - @echo " tcp" - @echo " Run the $(APPLICATION) tcp sub-test-suite" - @echo "" - @echo "" + @echo " Run all test suites." + @echo + @echo " $(SUITES)" + @echo " Run a specific test suite." + @echo # ---------------------------------------------------- # Special Targets # ---------------------------------------------------- -all: make - @echo "make sure epmd is new" - @epmd -kill > /dev/null - @echo "Running all sub-suites separatelly" - @for i in $(ALL_CASES); do \ - echo "SUITE: $$i"; \ - clearmake -V $$i > $$i.log; \ - done - -aall: make - @echo "make sure epmd is new" - @epmd -kill > /dev/null - @echo "Running all app sub-suites separatelly" - @for i in $(APP_CASES); do \ - echo "SUITE: $$i"; \ - clearmake -V $$i > $$i.log; \ - done - echo "done" - -tall: make - @echo "make sure epmd is new" - @epmd -kill > /dev/null - @echo "Running all transport sub-suites separatelly" - @for i in $(TRANSPORT_CASES); do \ - echo "SUITE: $$i"; \ - clearmake -V $$i > $$i.log; \ - done - -make: targets - -test: make - $(MERL) $(ARGS) -sname diameter_test $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ - $(MAYBE_ESTOP) +all: $(SUITES) + +beam: targets log: mkdir $@ @@ -303,31 +187,19 @@ log: # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -app codec dict reg stats sync: log make - $(MERL) $(ARGS) \ +$(SUITES): log beam + $(ERL) -noshell \ + -pa ../ebin \ -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' -compiler conf peer tcp: make - $(MERL) $(ARGS) -sname diameter_$@ $(ERL_PATH) \ - -s $(DIAMETER_TEST_SERVER) t diameter_$@_test \ - $(ESTOP) - -node: - $(MERL) -sname diameter $(ERL_PATH) - - # ---------------------------------------------------- # Release Targets # ---------------------------------------------------- -ifneq ($(ERL_TOP),) -include $(ERL_TOP)/make/otp_release_targets.mk -else -include $(DIAMETER_TOP)/make/release_targets.mk -endif +include $(TOP)/make/otp_release_targets.mk release_spec: @@ -340,5 +212,4 @@ release_tests_spec: tests # $(HRL_FILES) $(ERL_FILES) \ # $(RELSYSDIR) # - chmod -R u+w $(RELSYSDIR) - + chmod -f -R u+w $(RELSYSDIR) diff --git a/lib/diameter/test/diameter_ct.hrl b/lib/diameter/test/diameter_ct.hrl new file mode 100644 index 0000000000..b6bd2ca9da --- /dev/null +++ b/lib/diameter/test/diameter_ct.hrl @@ -0,0 +1,21 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +-define(APP, diameter). +-define(ERROR(T), erlang:error({?MODULE, ?LINE, T})). diff --git a/lib/diameter/test/diameter_peer_test.erl b/lib/diameter/test/diameter_peer_test.erl deleted file mode 100644 index 27e75e26ef..0000000000 --- a/lib/diameter/test/diameter_peer_test.erl +++ /dev/null @@ -1,104 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the peer component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_peer_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl new file mode 100644 index 0000000000..dec307529a --- /dev/null +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -0,0 +1,540 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of the RFC3539 watchdog state machine as implemented by +%% module diameter_watchdog. +%% + +-module(diameter_watchdog_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([reopen/1, reopen/4]). + +-export([start/3, %% diameter_transport callback + id/1, %% jitter callback + run/1]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_ct.hrl"). + +%% =========================================================================== + +-define(util, diameter_util). + +-define(BASE, diameter_gen_base_rfc3588). +-define(APPL_ID, diameter_gen_base_rfc3588:id()). +-define(SUCCESS, 2001). %% DIAMETER_SUCCESS + +%% Addresses for the local and remote diameter nodes. The values don't +%% matter since we're faking transport. +-define(LOCALHOST, {127,0,0,1}). +-define(REMOTEHOST, {10,0,0,1}). + +-define(CAPS, #diameter_caps{origin_host = "node.innan.com", + origin_realm = "innan.com", + host_ip_address = [?LOCALHOST], + vendor_id = 1022, + product_name = "remote", + auth_application_id = [?APPL_ID]}). + +-define(APPL, #diameter_app{alias = ?MODULE, + dictionary = ?BASE, + module = [?MODULE], + init_state = now(), + id = ?APPL_ID, + mutable = false}). + +%% Service record maintained by our faked service process. +-define(SERVICE, #diameter_service{pid = self(), + capabilities = ?CAPS, + applications = [?APPL]}). + +%% Watchdog timer as a callback. +-define(WD(T), {?MODULE, id, [T]}). + +%% Watchdog timers used by the testcases. Note that the short timeout +%% with random jitter is excluded since the reopen/1 isn't smart +%% enough to deal with it: see ONE_WD below. +-define(WD_TIMERS, [?WD(6000) + | [F_(T_) || T_ <- [10000, 20000, 30000], + F_ <- [fun(T__) -> T__ end, + fun(T__) -> ?WD(T__) end]]]). + +%% Transport types. +-define(TRANSPORTS, [connect, accept]). + +%% Message over the transport interface. +-define(TMSG(T), {diameter, T}). + +%% Receive a message within a specified time. +-define(RECV(T, Timeout), + receive T -> now() + after Timeout -> ?ERROR({timeout, Timeout}) + end). + +%% Receive a message in a given number of watchdogs, plus or minus +%% half. Note that the call to now_diff assumes left to right +%% evaluation order. +-define(RECV(T, N, WdL, WdH), + [?ERROR({received, _Elapsed_, _LowerBound_, N, WdL}) + || _UpperBound_ <- [(N)*(WdH) + (WdH) div 2], + _Elapsed_ <- [now_diff(now(), ?RECV(T, _UpperBound_))], + _LowerBound_ <- [(N)*(WdL) - (WdL) div 2], + _Elapsed_ =< _LowerBound_*1000]). + +%% A timeout that ensures one watchdog. The ensure only one watchdog +%% requires (Wd + 2000) + 1000 < 2*(Wd - 2000) ==> 7000 < Wd for the +%% case with random jitter. +-define(ONE_WD(Wd), jitter(Wd,2000) + 1000). + +%% =========================================================================== + +suite() -> + [{timetrap, {minutes, 6}}].%% enough for 11 watchdogs @ 30 sec plus jitter + +all() -> + [reopen]. + +init_per_suite(Config) -> + ok = diameter:start(), + Config. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +%% =========================================================================== +%% # reopen/1 +%% =========================================================================== + +%% Test the watchdog state machine for the required failover, failback +%% and reopen behaviour. Do this by having the testcase replace +%% diameter_service and start watchdogs, and having this module +%% implement a transport process that plays the role of the peer +%% Diameter node. + +reopen(_) -> + [] = ?util:run([{?MODULE, [run, [reopen, Wd, T, N, M]]} + || Wd <- ?WD_TIMERS, + T <- ?TRANSPORTS, + N <- [0,1,2], + M <- ['DWR', 'DWA', other]]). + +reopen(Wd, Type, N, What) -> + Ref = make_ref(), + + %% The maker of transport processes. + TPid = start({N, Wd, What, Ref}), + + %% Act like diameter_service and start the watchdog process, which + %% in turn starts a peer_fsm process, which in turn starts a + %% transport process by way of start/3. Messages received by the + %% testcase are those sent by diameter_watchdog to the service + %% process (= process starting the watchdog). + WPid1 = watchdog(Type, Ref, TPid, Wd), + + %% Low/high watchdog timeouts. + WdL = jitter(Wd, -2000), + WdH = jitter(Wd, 2000), + + %% Connection should come up immediately as a consequence of + %% starting the watchdog process. In the accepting case this + %% results in a new watchdog on a transport waiting for a new + %% connection. + ?RECV({connection_up, WPid1, _}, 1000), + + WPid2 = case Type of + connect -> + WPid1; + accept -> + watchdog(Type, Ref, TPid, Wd) + end, + + %% OKAY Timer expires & Failover() + %% Pending SetWatchdog() SUSPECT + %% + %% Since our transport is replying to N DWR's before becoming + %% silent, we should go down after N+2 watchdog_timer expirations: + %% that is, after the first unanswered DWR. Knowing the min/max + %% watchdog timeout values gives the time interval in which the + %% down message is expected. + ?RECV({connection_down, WPid1}, N+2, WdL, WdH), + + %% SUSPECT Receive DWA Pending = FALSE + %% Failback() + %% SetWatchdog() OKAY + %% + %% SUSPECT Receive non-DWA Failback() + %% SetWatchdog() OKAY + %% + %% The transport receives a message before the expiry of another + %% watchdog to induce failback. + ?RECV({connection_up, WPid1}, WdH), + + %% OKAY Timer expires & SendWatchdog() + %% !Pending SetWatchdog() + %% Pending = TRUE OKAY + %% + %% OKAY Timer expires & Failover() + %% Pending SetWatchdog() SUSPECT + %% + %% The transport is still not responding to watchdogs so the + %% connection should go back down after either one or two watchdog + %% expiries, depending on whether or not DWA restored the connection. + F = choose(What == 'DWA', 2, 1), + ?RECV({connection_down, WPid1}, F, WdL, WdH), + + %% SUSPECT Timer expires CloseConnection() + %% SetWatchdog() DOWN + %% + %% DOWN Timer expires AttemptOpen() + %% SetWatchdog() DOWN + %% + %% Our transport tells us when the fake connection is + %% reestablished, which should happen after another couple of + %% watchdog expiries, the first bringing the watchdog to state + %% DOWN, the second triggering an attempt to reopen the + %% connection. + ?RECV({reopen, Ref}, 2, WdL, WdH), + + %% DOWN Connection up NumDWA = 0 + %% SendWatchdog() + %% SetWatchdog() + %% Pending = TRUE REOPEN + %% + %% REOPEN Receive DWA & Pending = FALSE + %% NumDWA < 2 NumDWA++ REOPEN + %% + %% REOPEN Receive DWA & Pending = FALSE + %% NumDWA == 2 NumDWA++ + %% Failback() OKAY + %% + %% Now the watchdog should require three received DWA's before + %% taking the connection back up. The first DWR is sent directly + %% after capabilities exchange so it should take no more than two + %% watchdog expiries. + ?RECV({connection_up, WPid2, _}, 2, WdL, WdH). + +%% =========================================================================== + +%% Start the fake transport process. From diameter's point of view +%% it's started when diameter calls start/3. We start it before this +%% happens since we use the same fake transport each time diameter +%% calls start/3. The process lives and dies with the test case. +start(Config) -> + Pid = self(), + spawn(fun() -> loop(init(Pid, Config)) end). + +%% Transport start from diameter. This may be called multiple times +%% depending on the testcase. +start({Type, _Ref}, #diameter_service{}, Pid) -> + Ref = make_ref(), + MRef = erlang:monitor(process, Pid), + Pid ! {start, self(), Type, Ref}, + {Ref, TPid} = receive + {Ref, _} = T -> + T; + {'DOWN', MRef, process, _, _} = T -> + T + end, + erlang:demonitor(MRef, [flush]), + {ok, TPid}. + +%% id/1 + +id(T) -> + T. + +%% =========================================================================== + +choose(true, X, _) -> X; +choose(false, _, X) -> X. + +%% run/1 +%% +%% A more useful badmatch in case of failure. + +run([F|A]) -> + ok = try + apply(?MODULE, F, A), + ok + catch + E:R -> + {A, E, R, erlang:get_stacktrace()} + end. + +%% now_diff/2 + +now_diff(T1, T2) -> + timer:now_diff(T2, T1). + +%% jitter/2 + +jitter(?WD(T), _) -> + T; +jitter(T,D) -> + T+D. + +%% watchdog/4 +%% +%% Fake the call from diameter_service. The watchdog process will send +%% messages to the calling "service" process so our tests are that the +%% watchdog responds as expected. + +watchdog(Type, Ref, TPid, Wd) -> + Opts = [{transport_module, ?MODULE}, + {transport_config, TPid}, + {watchdog_timer, Wd}], + monitor(diameter_watchdog:start({Type, Ref}, + {false, Opts, false, ?SERVICE})). + +monitor(Pid) -> + erlang:monitor(process, Pid), + Pid. + +%% =========================================================================== + +%% Transport process implmentation. Fakes reception of messages by +%% sending fakes to the parent (peer fsm) process that called start/3. + +-record(transport, + {type, %% connect | accept | manager + parent, %% pid() of peer_fsm/ervice process + open = false, %% done with capabilities exchange? + config}).%% testcase-specific config + +%% init/2 + +%% Testcase starting the manager. +init(SvcPid, {_,_,_,_} = Config) -> + putr(peer, [{'Origin-Host', hostname() ++ ".utan.com"}, + {'Origin-Realm', "utan.com"}]), + #transport{type = manager, + parent = monitor(SvcPid), + config = Config}; + +%% Manager starting a transport. +init(_, {Type, ParentPid, SvcPid, TwinPid, Peer, {N,_,_,_} = Config}) -> + putr(peer, Peer), + putr(service, SvcPid), + putr(count, init(Type, ParentPid, TwinPid, N)),%% number of DWR's to answer + #transport{type = Type, + parent = monitor(ParentPid), + config = Config}. + +init(Type, ParentPid, undefined, N) -> + connected(ParentPid, Type), + N; +init(_, _, TPid, _) -> + monitor(TPid), + 3. + +%% Generate a unique hostname for the faked peer. +hostname() -> + lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))). + +%% loop/1 + +loop(S) -> + loop(msg(receive T -> T end, S)). + +msg(T,S) -> + case transition(T,S) of + ok -> + S; + #transport{} = NS -> + NS; + {stop, Reason} -> + x(Reason) + end. + +x(Reason) -> + exit(Reason). + +%% transition/2 + +%% Manager is being asked for a new transport process. +transition({start, Pid, Type, Ref}, #transport{type = manager, + parent = SvcPid, + config = Config}) -> + TPid = start({Type, Pid, SvcPid, getr(transport), getr(peer), Config}), + Pid ! {Ref, TPid}, + putr(transport, TPid), + ok; + +%% Peer fsm or testcase process has died. +transition({'DOWN', _, process, Pid, _} = T, #transport{parent = Pid}) -> + {stop, T}; + +%% Twin transport process has gone down. In the connect case, the +%% transport isn't started until this happens in the first place so +%% connect immediately. In the accept case, fake the peer reconnecting +%% only after another watchdog expiry. +transition({'DOWN', _, process, _, _}, #transport{type = Type, + config = {_, Wd, _, _}}) -> + Tmo = case Type of + connect -> + 0; + accept -> + ?ONE_WD(Wd) + end, + erlang:send_after(Tmo, self(), reconnect), + ok; + +transition(reconnect, #transport{type = Type, + parent = Pid, + config = {_,_,_,Ref}}) -> + getr(service) ! {reopen, Ref}, + connected(Pid, Type), + ok; + +%% Peer fsm process is sending CER: fake the peer's CEA. +transition(?TMSG({send, Bin}), #transport{type = connect, + open = false, + parent = Pid} + = S) -> + {Code, Flags, _} = ?BASE:msg_header('CER'), + <<_:32, Flags:8, Code:24, _:96, _/binary>> = Bin, + Hdr = make_header(Bin), + recv(Pid, {Hdr, make_cea()}), + S#transport{open = true}; + +%% Peer fsm process is sending CEA. +transition(?TMSG({send, Bin}), #transport{type = accept, + open = false} + = S) -> + {Code, Flags, _} = ?BASE:msg_header('CEA'), + <<_:32, Flags:8, Code:24, _:96, _/binary>> = Bin, + S#transport{open = true}; + +%% Watchdog is sending DWR or DWA. +transition(?TMSG({send, Bin}), #transport{open = true} = S) -> + {Code, _, _} = ?BASE:msg_header('DWR'), + {Code, _, _} = ?BASE:msg_header('DWA'), + <<_:32, R:1, 0:7, Code:24, _:96, _/binary>> = Bin, + Hdr = make_header(Bin), + dwa(1 == R, S, Hdr), + ok; + +%% We're telling ourselves to fake a received message. +transition({recv, Msg}, #transport{parent = Pid}) -> + recv(Pid, Msg), + ok; + +%% We're telling ourselves to receive a message to induce failback. +transition(failback = T, #transport{parent = Pid}) -> + recv(Pid, eraser(T)), + ok. + +make_header(Bin) -> + #diameter_header{end_to_end_id = E, + hop_by_hop_id = H} + = diameter_codec:decode_header(Bin), + #diameter_header{end_to_end_id = E, + hop_by_hop_id = H}. + +recv(Pid, Msg) -> + Pid ! ?TMSG({recv, encode(Msg)}). + +%% Replace the end-to-end/hop-by-hop identifiers with those from an +%% incoming request to which we're constructing a reply. +encode({Hdr, [_|_] = Msg}) -> + #diameter_header{hop_by_hop_id = HBH, + end_to_end_id = E2E} + = Hdr, + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg), + <> = Bin, + <>; + +encode([_|_] = Msg) -> + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg), + Bin. + +connected(Pid, connect) -> + Pid ! ?TMSG({self(), connected, make_ref()}); +connected(Pid, accept) -> + Pid ! ?TMSG({self(), connected}), + recv(Pid, make_cer()). + +make_cer() -> + ['CER' | getr(peer)] ++ [{'Host-IP-Address', [?REMOTEHOST]}, + {'Vendor-Id', 1028}, + {'Product-Name', "Utan"}, + {'Auth-Application-Id', [?APPL_ID]}]. + +make_cea() -> + ['CER' | Rest] = make_cer(), + ['CEA', {'Result-Code', ?SUCCESS} | Rest]. + +make_dwr() -> + ['DWR' | getr(peer)]. + +make_dwa() -> + ['DWR' | Rest] = make_dwr(), + ['DWA', {'Result-Code', ?SUCCESS} | Rest]. + +dwa(false, _, _) -> %% outgoing was DWA ... + ok; +dwa(true, S, Hdr) -> %% ... or DWR + dwa(getr(count), Hdr, S); + +%% React to the DWR only after another watchdog expiry. We shouldn't +%% get another DWR while the answer is pending. +dwa(0, Hdr, #transport{config = {_, Wd, What, _}}) -> + erlang:send_after(?ONE_WD(Wd), self(), failback), + putr(failback, make_msg(What, Hdr)), + eraser(count); + +dwa(undefined, _, _) -> + undefined = getr(failback), %% ensure this is after failback + ok; + +%% Reply with DWA. +dwa(N, Hdr, #transport{parent = Pid}) -> + putr(count, N-1), + recv(Pid, {Hdr, make_dwa()}). + +%% Answer to received DWR. +make_msg('DWA', Hdr) -> + {Hdr, make_dwa()}; + +%% DWR from peer. +make_msg('DWR', _) -> + make_dwr(); + +%% An unexpected answer is discarded after passing through the +%% watchdog state machine. +make_msg(other, _) -> + ['RAA', {'Session-Id', diameter:session_id("abc")}, + {'Result-Code', 2001} + | getr(peer)]. + +putr(Key, Val) -> + put({?MODULE, Key}, Val). + +getr(Key) -> + get({?MODULE, Key}). + +eraser(Key) -> + erase({?MODULE, Key}). diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index d27d64bb98..daf6ef64ec 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -17,8 +17,7 @@ # # %CopyrightEnd% -TEST_SPEC_FILE = diameter.spec - +TEST_SPEC_FILE = diameter.spec COVER_SPEC_FILE = diameter.cover MODULES = \ @@ -32,13 +31,7 @@ MODULES = \ diameter_reg_SUITE \ diameter_sync_SUITE \ diameter_stats_SUITE \ - \ - diameter_compiler_test \ - diameter_config_test \ - diameter_peer_test \ - diameter_tcp_test \ - diameter_test_lib \ - diameter_test_server + diameter_watchdog_SUITE INTERNAL_HRL_FILES = \ - diameter_test_lib.hrl + diameter_ct.hrl -- cgit v1.2.3 From e05868f49b442c10cedbded390c110473cda6f00 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 8 Aug 2011 18:24:36 +0200 Subject: Add transport and gen_sctp suites --- lib/diameter/test/diameter_gen_sctp_SUITE.erl | 354 ++++++++++++++++++ lib/diameter/test/diameter_tcp_test.erl | 482 ------------------------- lib/diameter/test/diameter_transport_SUITE.erl | 454 +++++++++++++++++++++++ lib/diameter/test/modules.mk | 4 +- 4 files changed, 811 insertions(+), 483 deletions(-) create mode 100644 lib/diameter/test/diameter_gen_sctp_SUITE.erl delete mode 100644 lib/diameter/test/diameter_tcp_test.erl create mode 100644 lib/diameter/test/diameter_transport_SUITE.erl diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl new file mode 100644 index 0000000000..be6d28beb2 --- /dev/null +++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl @@ -0,0 +1,354 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Some gen_sctp-specific tests demonstrating problems that were +%% encountered during diameter development but have nothing +%% specifically to do with diameter. At least one of them can cause +%% diameter_transport_SUITE testcases to fail. +%% + +-module(diameter_gen_sctp_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([send_not_from_controlling_process/1, + send_from_multiple_clients/1, + receive_what_was_sent/1]). + +-include_lib("kernel/include/inet_sctp.hrl"). + +%% Message from gen_sctp are of this form. +-define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}). + +%% Open sockets on the loopback address. +-define(ADDR, {127,0,0,1}). + +%% Snooze, nap, siesta. +-define(SLEEP(T), receive after T -> ok end). + +%% An indescribably long number of milliseconds after which everthing +%% that should have happened has. +-define(FOREVER, 2000). + +%% The first byte in each message we send as a simple guard against +%% not receiving what was sent. +-define(MAGIC, 42). + +%% =========================================================================== + +suite() -> + [{timetrap, {minutes, 2}}]. + +all() -> + [send_not_from_controlling_process, + send_from_multiple_clients, + receive_what_was_sent]. + +init_per_suite(Config) -> + try gen_sctp:open() of + {ok, Sock} -> + gen_sctp:close(Sock), + Config + catch + error: badarg -> + {skip, no_sctp} + end. + +end_per_suite(_Config) -> + ok. + +%% =========================================================================== + +%% send_not_from_controlling_process/1 +%% +%% This testcase failing shows gen_sctp:send/4 hanging when called +%% outside the controlling process of the socket in question. + +send_not_from_controlling_process(_) -> + Pids = send_not_from_controlling_process(), + ?SLEEP(?FOREVER), + try + [] = [{P,I} || P <- Pids, I <- [process_info(P)], I /= undefined] + after + lists:foreach(fun(P) -> exit(P, kill) end, Pids) + end. + +%% send_not_from_controlling_process/0 +%% +%% Returns the pids of three spawned processes: a listening process, a +%% connecting process and a sending process. +%% +%% The expected behaviour is that all three processes exit: +%% +%% - The listening process exits upon receiving an SCTP message +%% sent by the sending process. +%% - The connecting process exits upon listening process exit. +%% - The sending process exits upon gen_sctp:send/4 return. +%% +%% The observed behaviour is that all three processes remain alive +%% indefinitely: +%% +%% - The listening process never receives the SCTP message sent +%% by the sending process. +%% - The connecting process has an inet_reply message in its mailbox +%% as a consequence of the call to gen_sctp:send/4 call from the +%% sending process. +%% - The call to gen_sctp:send/4 in the sending process doesn't return, +%% hanging in prim_inet:getopts/2. + +send_not_from_controlling_process() -> + FPid = self(), + {L, MRef} = spawn_monitor(fun() -> listen(FPid) end),%% listening process + receive + {?MODULE, C, S} -> + erlang:demonitor(MRef, [flush]), + [L,C,S]; + {'DOWN', MRef, process, _, _} = T -> + error(T) + end. + +%% listen/1 + +listen(FPid) -> + {ok, Sock} = open(), + ok = gen_sctp:listen(Sock, true), + {ok, PortNr} = inet:port(Sock), + LPid = self(), + spawn(fun() -> connect1(PortNr, FPid, LPid) end), %% connecting process + Id = assoc(Sock), + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], _Bin}) + = recv(). %% Waits with this as current_function. + +%% recv/0 + +recv() -> + receive T -> T end. + +%% connect1/3 + +connect1(PortNr, FPid, LPid) -> + {ok, Sock} = open(), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Id = assoc(Sock), + FPid ! {?MODULE, + self(), + spawn(fun() -> send(Sock, Id) end)}, %% sending process + MRef = erlang:monitor(process, LPid), + down(MRef). %% Waits with this as current_function. + +%% down/1 + +down(MRef) -> + receive {'DOWN', MRef, process, _, Reason} -> Reason end. + +%% send/2 + +send(Sock, Id) -> + ok = gen_sctp:send(Sock, Id, 0, <<0:32>>). + +%% =========================================================================== + +%% send_from_multiple_clients/0 +%% +%% Demonstrates sluggish delivery of messages. + +send_from_multiple_clients(_) -> + {S, Rs} = T = send_from_multiple_clients(8, 1024), + {false, [], _} = {?FOREVER < S, + Rs -- [OI || {O,_} = OI <- Rs, is_integer(O)], + T}. + +%% send_from_multiple_clients/2 +%% +%% Opens a listening socket and then spawns a specified number of +%% processes, each of which connects to the listening socket. Each +%% connecting process then sends a message, whose size in bytes is +%% passed as an argument, the listening process sends a reply +%% containing the time at which the message was received, and the +%% connecting process then exits upon reception of this reply. +%% +%% Returns the elapsed time for all connecting process to exit +%% together with a list of exit reasons for the connecting processes. +%% In the successful case a connecting process exits with the +%% outbound/inbound transit times for the sent/received message as +%% reason. +%% +%% The observed behaviour is that some outbound messages (that is, +%% from a connecting process to the listening process) can take an +%% unexpectedly long time to complete their journey. The more +%% connecting processes, the longer the possible delay it seems. +%% +%% eg. (With F = fun send_from_multiple_clients/2.) +%% +%% 5> F(2, 1024). +%% {875,[{128,116},{113,139}]} +%% 6> F(4, 1024). +%% {2995290,[{2994022,250},{2994071,80},{200,130},{211,113}]} +%% 7> F(8, 1024). +%% {8997461,[{8996161,116}, +%% {2996471,86}, +%% {2996278,116}, +%% {2996360,95}, +%% {246,112}, +%% {213,159}, +%% {373,173}, +%% {376,118}]} +%% 8> F(8, 1024). +%% {21001891,[{20999968,128}, +%% {8997891,172}, +%% {8997927,91}, +%% {2995716,164}, +%% {2995860,87}, +%% {134,100}, +%% {117,98}, +%% {149,125}]} + +send_from_multiple_clients(N, Sz) + when is_integer(N), 0 < N, is_integer(Sz), 0 < Sz -> + timer:tc(fun listen/2, [N, <>]). + +%% listen/2 + +listen(N, Bin) -> + {ok, Sock} = open(), + ok = gen_sctp:listen(Sock, true), + {ok, PortNr} = inet:port(Sock), + + %% Spawn a middleman that in turn spawns N connecting processes, + %% collects a list of exit reasons and then exits with the list as + %% reason. loop/3 returns when we receive this list from the + %% middleman's 'DOWN'. + + Self = self(), + Fun = fun() -> exit(connect2(Self, PortNr, Bin)) end, + {_, MRef} = spawn_monitor(fun() -> exit(fold(N, Fun)) end), + loop(Sock, MRef, Bin). + +%% fold/2 +%% +%% Spawn N processes and collect their exit reasons in a list. + +fold(N, Fun) -> + start(N, Fun), + acc(N, []). + +start(0, _) -> + ok; +start(N, Fun) -> + spawn_monitor(Fun), + start(N-1, Fun). + +acc(0, Acc) -> + Acc; +acc(N, Acc) -> + receive + {'DOWN', _MRef, process, _, RC} -> + acc(N-1, [RC | Acc]) + end. + +%% loop/3 + +loop(Sock, MRef, Bin) -> + receive + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], B}) -> + Sz = size(Bin), + {Sz, Bin} = {size(B), B}, %% assert + ok = send(Sock, Id, mark(Bin)), + loop(Sock, MRef, Bin); + ?SCTP(Sock, _) -> + loop(Sock, MRef, Bin); + {'DOWN', MRef, process, _, Reason} -> + Reason + end. + +%% connect2/3 + +connect2(Pid, PortNr, Bin) -> + erlang:monitor(process, Pid), + + {ok, Sock} = open(), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Id = assoc(Sock), + + %% T1 = time before send + %% T2 = time after listening process received our message + %% T3 = time after reply is received + + T1 = now(), + ok = send(Sock, Id, Bin), + T2 = unmark(recv(Sock, Id)), + T3 = now(), + {timer:now_diff(T2, T1), timer:now_diff(T3, T2)}. %% {Outbound, Inbound} + +%% recv/2 + +recv(Sock, Id) -> + receive + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin}) -> + Bin; + T -> %% eg. 'DOWN' + exit(T) + end. + +%% send/3 + +send(Sock, Id, Bin) -> + gen_sctp:send(Sock, Id, 0, Bin). + +%% mark/1 + +mark(Bin) -> + Info = term_to_binary(now()), + <>. + +%% unmark/1 + +unmark(Bin) -> + {_,_,_} = binary_to_term(Bin). + +%% =========================================================================== + +%% receive_what_was_sent/1 +%% +%% Demonstrates reception of a message that differs from that sent. + +receive_what_was_sent(_Config) -> + send_from_multiple_clients(1, 1024*32). %% fails + +%% =========================================================================== + +%% open/0 + +open() -> + gen_sctp:open([{ip, ?ADDR}, {port, 0}, {active, true}, binary]). + +%% assoc/1 + +assoc(Sock) -> + receive + ?SCTP(Sock, {[], #sctp_assoc_change{state = S, + assoc_id = Id}}) -> + comm_up = S, %% assert + Id + end. diff --git a/lib/diameter/test/diameter_tcp_test.erl b/lib/diameter/test/diameter_tcp_test.erl deleted file mode 100644 index b002a3d289..0000000000 --- a/lib/diameter/test/diameter_tcp_test.erl +++ /dev/null @@ -1,482 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the tcp transport component of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_tcp_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2, - - start_and_stop_transport_plain/1, - start_and_listen/1, - simple_connect/1, - simple_send_and_recv/1 - - ]). - --export([t/0, t/1]). - -%% diameter_peer (internal) callback API --export([up/1, up/3, recv/2]). - --include("diameter_test_lib.hrl"). --include_lib("diameter/include/diameter.hrl"). -%% -include_lib("diameter/src/tcp/diameter_tcp.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - [ - {group, start}, - {group, simple} - ]. - -groups() -> - [ - {start, [], [start_and_stop_transport_plain, start_and_listen]}, - {simple, [], [simple_connect, simple_send_and_recv]} - ]. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case(s) -%% - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Plain start and stop of TCP transport -%% - -start_and_stop_transport_plain(suite) -> - []; -start_and_stop_transport_plain(doc) -> - []; -start_and_stop_transport_plain(Config) when is_list(Config) -> - - ?SKIP(not_yet_implemented), - - %% This has been changed *a lot* since it was written... - - process_flag(trap_exit, true), - Transport = ensure_transport_started(), - TcpTransport = ensure_tcp_transport_started(), - ensure_tcp_transport_stopped(TcpTransport), - ensure_transport_stopped(Transport), - i("done"), - ok. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Start TCP transport and then create a listen socket -%% - -start_and_listen(suite) -> - []; -start_and_listen(doc) -> - []; -start_and_listen(Config) when is_list(Config) -> - - ?SKIP(not_yet_implemented), - - %% This has been changed *a lot* since it was written... - - process_flag(trap_exit, true), - Transport = ensure_transport_started(), - TcpTransport = ensure_tcp_transport_started(), - - case listen([{port, 0}]) of - {ok, Acceptor} when is_pid(Acceptor) -> - Ref = erlang:monitor(process, Acceptor), - [{Acceptor, Info}] = diameter_tcp:which_listeners(), - case lists:keysearch(socket, 1, Info) of - {value, {_, Listen}} -> - i("Listen socket: ~p" - "~n Opts: ~p" - "~n Stats: ~p" - "~n Name: ~p", - [Listen, - ok(inet:getopts(Listen, [keepalive, delay_send])), - ok(inet:getstat(Listen)), - ok(inet:sockname(Listen)) - ]), - ok; - _ -> - ?FAIL({bad_listener_info, Acceptor, Info}) - end, - Crash = simulate_crash, - exit(Acceptor, Crash), - receive - {'DOWN', Ref, process, Acceptor, Crash} -> - ?SLEEP(1000), - case diameter_tcp:which_listeners() of - [{NewAcceptor, _NewInfo}] -> - diameter_tcp_accept:stop(NewAcceptor), - ?SLEEP(1000), - case diameter_tcp:which_listeners() of - [] -> - ok; - UnexpectedListeners -> - ?FAIL({unexpected_listeners, empty, UnexpectedListeners}) - end; - UnexpectedListeners -> - ?FAIL({unexpected_listeners, non_empty, UnexpectedListeners}) - end - after 5000 -> - ?FAIL({failed_killing, Acceptor}) - end; - Error -> - ?FAIL({failed_creating_acceptor, Error}) - end, - ensure_tcp_transport_stopped(TcpTransport), - ensure_transport_stopped(Transport), - i("done"), - ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% TCP transport connecting -%% - -simple_connect(suite) -> - []; -simple_connect(doc) -> - []; -simple_connect(Config) when is_list(Config) -> - - ?SKIP(not_yet_implemented), - - %% This has been changed *a lot* since it was written... - - process_flag(trap_exit, true), - Transport = ensure_transport_started(), - TcpTransport = ensure_tcp_transport_started(), - {_Acceptor, Port} = ensure_tcp_listener(), - - {ok, Hostname} = inet:gethostname(), - - i("try connect"), - Opts = [{host, Hostname}, {port, Port}, {module, ?MODULE}], - Conn = case connect(Opts) of - {ok, C} -> - C; - Error -> - ?FAIL({failed_connecting, Error}) - end, - i("connected: ~p", [Conn]), - - %% Up for connect - receive - {diameter, {up, Host, Port}} -> - i("Received expected connect up (~p:~p)", [Host, Port]), - ok - after 5000 -> - ?FAIL(connect_up_confirmation_timeout) - end, - - %% Up for accept - receive - {diameter, {up, _ConnPid}} -> - i("Received expected accept up"), - ok - after 5000 -> - ?FAIL(acceptor_up_confirmation_timeout) - end, - - i("try disconnect"), - diameter_tcp:disconnect(Conn), - ensure_tcp_transport_stopped(TcpTransport), - ensure_transport_stopped(Transport), - i("done"), - ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Plain start and stop of TCP transport -%% - -simple_send_and_recv(suite) -> - []; -simple_send_and_recv(doc) -> - []; -simple_send_and_recv(Config) when is_list(Config) -> - - ?SKIP(not_yet_implemented), - - %% This has been changed *a lot* since it was written... - - process_flag(trap_exit, true), - %% -------------------------------------------------- - %% Start the TCP transport sub-system - %% - - Transport = ensure_transport_started(), - TcpTransport = ensure_tcp_transport_started(), - - {_Acceptor, Port} = ensure_tcp_listener(), - - {ok, Hostname} = inet:gethostname(), - - i("try connect"), - Opts = [{host, Hostname}, {port, Port}, {module, ?MODULE}], - Conn = case connect(Opts) of - {ok, C1} -> - C1; - Error -> - ?FAIL({failed_connecting, Error}) - end, - i("connected: ~p", [Conn]), - - %% Up for connect - receive - {diameter, {up, Host, Port}} -> - i("Received expected connect up (~p:~p)", [Host, Port]), - ok - after 5000 -> - ?FAIL(connect_up_confirmation_timeout) - end, - - %% Up for accept - APid = - receive - {diameter, {up, C2}} -> - i("Received expected accept up"), - C2 - after 5000 -> - ?FAIL(acceptor_up_confirmation_timeout) - end, - - %% -------------------------------------------------- - %% Start some stuff needed for the codec to run - %% - - i("start persistent table"), - {ok, _Pers} = diameter_persistent_table:start_link(), - - i("start session"), - {ok, _Session} = diameter_session:start_link(), - - i("try decode a (DWR) message"), - Base = diameter_gen_base_rfc3588, - DWR = ['DWR', - {'Origin-Host', Hostname}, - {'Origin-Realm', "whatever-realm"}, - {'Origin-State-Id', [10]}], - - #diameter_packet{msg = Msg} = diameter_codec:encode(Base, DWR), - - - %% -------------------------------------------------- - %% Now try to send the message - %% - %% This is not the codec-test suite, so we dont really care what we - %% send, as long as it encoded/decodes correctly in the transport - %% - - i("try send from connect side"), - ok = diameter_tcp:send_message(Conn, Msg), - - %% Wait for data on Accept side - APkt = - receive - {diameter, {recv, A}} -> - i("[accept] Received expected data message: ~p", [A]), - A - after 5000 -> - ?FAIL(acceptor_up_confirmation_timeout) - end, - - %% Send the same message back, just to have something to send... - i("try send (\"reply\") from accept side"), - ok = diameter_tcp:send_message(APid, APkt), - - %% Wait for data on Connect side - receive - {diameter, {recv, B}} -> - i("[connect] Received expected data message: ~p", [B]), - ok - after 5000 -> - ?FAIL(acceptor_up_confirmation_timeout) - end, - - i("we are done - now close shop"), - diameter_session:stop(), - diameter_persistent_table:stop(), - - ensure_tcp_transport_stopped(TcpTransport), - ensure_transport_stopped(Transport), - i("done"), - ok. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -ensure_transport_started() -> -%% i("start diameter transport (top) supervisor"), - case diameter_transport_sup:start_link() of - {ok, TransportSup} -> - TransportSup; - Error -> - ?FAIL({failed_starting_transport_sup, Error}) - end. - -ensure_transport_stopped(Pid) when is_pid(Pid) -> -%% i("stop diameter transport (top) supervisor"), - Stop = fun(P) -> exit(P, kill) end, - ensure_stopped(Pid, Stop, failed_stopping_transport_sup). - -ensure_tcp_transport_started() -> -%% i("start diameter TCP transport"), - case diameter_tcp:start_transport() of - {ok, TcpTransport} when is_pid(TcpTransport) -> - TcpTransport; - Error -> - ?FAIL({failed_starting_transport, Error}) - end. - -ensure_tcp_transport_stopped(Pid) when is_pid(Pid) -> -%% i("stop diameter TCP transport supervisor"), - Stop = fun(P) -> diameter_tcp:stop_transport(P) end, - ensure_stopped(Pid, Stop, failed_stopping_tcp_transport). - - -ensure_tcp_listener() -> -%% i("create diameter TCP transport listen socket"), - case listen([{port, 0}]) of - {ok, Acceptor} -> - [{Acceptor, Info}] = diameter_tcp:which_listeners(), - case lists:keysearch(socket, 1, Info) of - {value, {_, Listen}} -> - {ok, Port} = inet:port(Listen), - {Acceptor, Port}; - _ -> - ?FAIL({failed_retrieving_listen_socket, Info}) - end; - Error -> - ?FAIL({failed_creating_listen_socket, Error}) - end. - - -ensure_stopped(Pid, Stop, ReasonTag) when is_pid(Pid) -> -%% i("ensure_stopped -> create monitor to ~p", [Pid]), - Ref = erlang:monitor(process, Pid), -%% i("ensure_stopped -> try stop"), - Stop(Pid), -%% i("ensure_stopped -> await DOWN message"), - receive - {'DOWN', Ref, process, Pid, _} -> -%% i("ensure_stopped -> received DOWN message"), - ok - after 5000 -> -%% i("ensure_stopped -> timeout"), - ?FAIL({ReasonTag, Pid}) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -listen(Opts) -> - diameter_tcp:listen([{module, ?MODULE} | Opts]). - -connect(Opts) -> - diameter_tcp:connect([{module, ?MODULE} | Opts]). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -up(Pid, Host, Port) -> - Pid ! {diameter, {up, Host, Port}}, - ok. - -up(Pid) -> - Pid ! {diameter, {up, self()}}, - ok. - -recv(Pid, Pkt) -> - Pid ! {diameter, {recv, Pkt}}. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -i(F) -> - i(F, []). - -i(F, A) -> - io:format(F ++ "~n", A). - - -ok({ok, Whatever}) -> - Whatever; -ok(Crap) -> - Crap. - - diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl new file mode 100644 index 0000000000..6de6d6bad3 --- /dev/null +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -0,0 +1,454 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of diameter_tcp/sctp as implementations of the diameter +%% transport interface. See also the sctp suite for some gen_sctp +%% related issues. +%% + +-module(diameter_transport_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([scramble/1, + tcp_accept/1, + tcp_connect/1, + sctp_accept/1, + sctp_connect/1]). + +-export([accept/1, + connect/1, + init/2]). + +-include_lib("kernel/include/inet_sctp.hrl"). +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_ct.hrl"). + +-define(util, diameter_util). + +%% Corresponding to diameter_* transport modules. +-define(TRANSPORTS, [tcp, sctp]). + +%% Receive a message. +-define(RECV(Pat, Ret), receive Pat -> Ret end). +-define(RECV(Pat), ?RECV(Pat, now())). + +%% Or not. +-define(WAIT(Ms), receive after Ms -> now() end). + +%% Sockets are opened on the loopback address. +-define(ADDR, {127,0,0,1}). + +%% diameter_tcp doesn't use anything but host_ip_address, and that +%% only is a local address isn't configured as at transport start. +-define(SVC(Addrs), #diameter_service{capabilities + = #diameter_caps{host_ip_address + = Addrs}}). + +%% The term diameter_tcp/sctp registers after opening a listening +%% socket. This is an implementation detail that should probably be +%% replaced by some documented way of getting at the port number of +%% the listening socket, which is what we're after since we specify +%% port 0 to get something unused. +-define(TCP_LISTENER(Ref, Addr, LSock), + {diameter_tcp, listener, {Ref, {Addr, LSock}}}). +-define(SCTP_LISTENER(Ref, Addr, LSock), + {diameter_sctp, listener, {Ref, {[Addr], LSock}}}). + +%% The term we register after open a listening port with gen_tcp. +-define(TEST_LISTENER(Ref, PortNr), + {?MODULE, listen, Ref, PortNr}). + +%% Message over the transport interface. +-define(TMSG(T), {diameter, T}). + +%% Options for gen_tcp/gen_sctp. +-define(TCP_OPTS, [binary, {active, true}, {packet, 0}]). +-define(SCTP_OPTS, [binary, {active, true}, {sctp_initmsg, ?SCTP_INIT}]). + +%% Request a specific number of streams just because we can. +-define(SCTP_INIT, #sctp_initmsg{num_ostreams = 5, + max_instreams = 5}). + +%% Messages from gen_sctp. +-define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}). + +%% =========================================================================== + +suite() -> + [{timetrap, {minutes, 2}}]. + +all() -> + [scramble | tc()]. + +tc() -> + [tcp_accept, + tcp_connect, + sctp_accept, + sctp_connect]. + +init_per_suite(Config) -> + ok = diameter:start(), + [{sctp, have_sctp()} | Config]. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +%% =========================================================================== +%% scramble/1 + +scramble(Config) -> + [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). + +%% =========================================================================== +%% tcp_accept/1 +%% sctp_accept/1 +%% +%% diameter transport accepting, test code connecting. + +tcp_accept(_) -> + accept(tcp). + +sctp_accept(Config) -> + if_sctp(fun accept/1, Config). + +%% Start multiple accepting transport processes that are connected to +%% with an equal number of connecting processes using gen_tcp/sctp +%% directly. + +-define(PEER_COUNT, 8). + +accept(Prot) -> + T = {Prot, make_ref()}, + [] = ?util:run(?util:scramble(acc(2*?PEER_COUNT, T, []))). + +acc(0, _, Acc) -> + Acc; +acc(N, T, Acc) -> + acc(N-1, T, [{?MODULE, [init, + element(1 + N rem 2, {accept, gen_connect}), + T]} + | Acc]). + +%% =========================================================================== +%% tcp_connect/1 +%% sctp_connect/1 +%% +%% Test code accepting, diameter transport connecting. + +tcp_connect(_) -> + connect(tcp). + +sctp_connect(Config) -> + if_sctp(fun connect/1, Config). + +connect(Prot) -> + T = {Prot, make_ref()}, + [] = ?util:run([{?MODULE, [init, X, T]} || X <- [gen_accept, connect]]). + +%% =========================================================================== +%% =========================================================================== + +%% have_sctp/0 + +have_sctp() -> + try gen_sctp:open() of + {ok, Sock} -> + gen_sctp:close(Sock), + true + catch + error: badarg -> + false + end. + +%% if_sctp/2 + +if_sctp(F, Config) -> + case proplists:get_value(sctp, Config) of + true -> + F(sctp); + false -> + {skip, no_sctp} + end. + +%% init/2 + +init(accept, {Prot, Ref}) -> + %% Start an accepting transport and receive notification of a + %% connection. + TPid = start_accept(Prot, Ref), + + %% Receive a message and send it back. + <<_:8, Len:24, _/binary>> = Bin = bin(Prot, ?RECV(?TMSG({recv, P}), P)), + + Len = size(Bin), + TPid ! ?TMSG({send, Bin}), + + %% Expect the transport process to die as a result of the peer + %% closing the connection. + MRef = erlang:monitor(process, TPid), + ?RECV({'DOWN', MRef, process, _, _}); + +init(gen_connect, {Prot, Ref}) -> + %% Lookup the peer's listening socket. + {ok, PortNr} = inet:port(lsock(Prot, Ref)), + + %% Connect, send a message and receive it back. + {ok, Sock} = gen_connect(Prot, PortNr, Ref), + Bin = make_msg(), + ok = gen_send(Prot, Sock, Bin), + Bin = gen_recv(Prot, Sock); + +init(gen_accept, {Prot, Ref}) -> + %% Open a listening socket and publish the port number. + {ok, LSock} = gen_listen(Prot), + {ok, PortNr} = inet:port(LSock), + true = diameter_reg:add_new(?TEST_LISTENER(Ref, PortNr)), + + %% Accept a connection, receive a message and send it back. + {ok, Sock} = gen_accept(Prot, LSock), + Bin = gen_recv(Prot, Sock), + ok = gen_send(Prot, Sock, Bin); + +init(connect, {Prot, Ref}) -> + %% Lookup the peer's listening socket. + [{?TEST_LISTENER(_, PortNr), _}] = match(?TEST_LISTENER(Ref, '_')), + + %% Start a connecting transport and receive notification of + %% the connection. + TPid = start_connect(Prot, PortNr, Ref), + + %% Send a message and receive it back. + Bin = make_msg(), + TPid ! ?TMSG({send, Bin}), + Bin = bin(Prot, ?RECV(?TMSG({recv, P}), P)), + + %% Expect the transport process to die as a result of the peer + %% closing the connection. + MRef = erlang:monitor(process, TPid), + ?RECV({'DOWN', MRef, process, _, _}). + +lsock(sctp, Ref) -> + [{?SCTP_LISTENER(_ , _, LSock), _}] + = match(?SCTP_LISTENER(Ref, ?ADDR, '_')), + LSock; +lsock(tcp, Ref) -> + [{?TCP_LISTENER(_ , _, LSock), _}] + = match(?TCP_LISTENER(Ref, ?ADDR, '_')), + LSock. + +match(Pat) -> + case diameter_reg:match(Pat) of + [] -> + ?WAIT(50), + match(Pat); + L -> + L + end. + +bin(sctp, #diameter_packet{bin = Bin}) -> + Bin; +bin(tcp, Bin) -> + Bin. + +%% make_msg/0 +%% +%% A valid Diameter message in as far as diameter_tcp examines it, +%% the module examining the length in the Diameter header to locate +%% message boundaries. + +make_msg() -> + N = 1024, + Bin = rand_bytes(4*N), + Len = 4*(N+1), + <<1:8, Len:24, Bin/binary>>. + +%% crypto:rand_bytes/1 isn't available on all platforms (since openssl +%% isn't) so roll our own. +rand_bytes(N) -> + random:seed(now()), + rand_bytes(N, <<>>). + +rand_bytes(0, Bin) -> + Bin; +rand_bytes(N, Bin) -> + Oct = random:uniform(256) - 1, + rand_bytes(N-1, <>). + +%% =========================================================================== + +%% start_connect/3 + +start_connect(Prot, PortNr, Ref) -> + {ok, TPid, [?ADDR]} = start_connect(Prot, + {connect, Ref}, + ?SVC([]), + [{raddr, ?ADDR}, + {rport, PortNr}, + {ip, ?ADDR}, + {port, 0}]), + ?RECV(?TMSG({TPid, connected, _})), + TPid. + +start_connect(sctp, T, Svc, Opts) -> + diameter_sctp:start(T, Svc, [{sctp_initmsg, ?SCTP_INIT} | Opts]); +start_connect(tcp, T, Svc, Opts) -> + diameter_tcp:start(T, Svc, Opts). + +%% start_accept/2 +%% +%% Start transports sequentially by having each wait for a message +%% from a job in a queue before commencing. Only one transport with +%% a pending accept is started at a time since diameter_sctp currently +%% assumes (and diameter currently implements) this. + +start_accept(Prot, Ref) -> + Pid = sync(accept, Ref), + + %% Configure the same port number for transports on the same + %% reference. + PortNr = portnr(Prot, Ref), + {Mod, Opts} = tmod(Prot), + + try + {ok, TPid, [?ADDR]} = Mod:start({accept, Ref}, + ?SVC([?ADDR]), + [{port, PortNr} | Opts]), + ?RECV(?TMSG({TPid, connected})), + TPid + after + Pid ! Ref + end. + +sync(What, Ref) -> + ok = diameter_sync:cast({?MODULE, What, Ref}, + [fun lock/2, Ref, self()], + infinity, + infinity), + receive {start, Ref, Pid} -> Pid end. + +lock(Ref, Pid) -> + Pid ! {start, Ref, self()}, + erlang:monitor(process, Pid), + Ref = receive T -> T end. + +tmod(sctp) -> + {diameter_sctp, [{sctp_initmsg, ?SCTP_INIT}]}; +tmod(tcp) -> + {diameter_tcp, []}. + +portnr(sctp, Ref) -> + case diameter_reg:match(?SCTP_LISTENER(Ref, ?ADDR, '_')) of + [{?SCTP_LISTENER(_, _, LSock), _}] -> + {ok, N} = inet:port(LSock), + N; + [] -> + 0 + end; +portnr(tcp, Ref) -> + case diameter_reg:match(?TCP_LISTENER(Ref, ?ADDR, '_')) of + [{?TCP_LISTENER(_, _, LSock), _}] -> + {ok, N} = inet:port(LSock), + N; + [] -> + 0 + end. + +%% =========================================================================== + +%% gen_connect/3 + +gen_connect(Prot, PortNr, Ref) -> + Pid = sync(connect, Ref), + + %% Stagger connect attempts to avoid the situation that no + %% transport process is accepting yet. + receive after 250 -> ok end, + + try + gen_connect(Prot, PortNr) + after + Pid ! Ref + end. + +gen_connect(sctp = P, PortNr) -> + {ok, Sock} = Ok = gen_sctp:open([{ip, ?ADDR}, {port, 0} | ?SCTP_OPTS]), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Ok = gen_accept(P, Sock); +gen_connect(tcp, PortNr) -> + gen_tcp:connect(?ADDR, PortNr, ?TCP_OPTS). + +%% gen_listen/1 + +gen_listen(sctp) -> + {ok, Sock} = gen_sctp:open([{ip, ?ADDR}, {port, 0} | ?SCTP_OPTS]), + {gen_sctp:listen(Sock, true), Sock}; +gen_listen(tcp) -> + gen_tcp:listen(0, [{ip, ?ADDR} | ?TCP_OPTS]). + +%% gen_accept/2 + +gen_accept(sctp, Sock) -> + Assoc = ?RECV(?SCTP(Sock, {_, #sctp_assoc_change{state = comm_up, + outbound_streams = O, + inbound_streams = I, + assoc_id = A}}), + {O, I, A}), + putr(assoc, Assoc), + {ok, Sock}; +gen_accept(tcp, LSock) -> + gen_tcp:accept(LSock). + +%% gen_send/3 + +gen_send(sctp, Sock, Bin) -> + {OS, _IS, Id} = getr(assoc), + {_, _, Us} = now(), + gen_sctp:send(Sock, Id, Us rem OS, Bin); +gen_send(tcp, Sock, Bin) -> + gen_tcp:send(Sock, Bin). + +%% gen_recv/2 + +gen_recv(sctp, Sock) -> + {_OS, _IS, Id} = getr(assoc), + ?RECV(?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin}), Bin); +gen_recv(tcp, Sock) -> + tcp_recv(Sock, <<>>). + +tcp_recv(_, <<_:8, Len:24, _/binary>> = Bin) + when Len =< size(Bin) -> + Bin; +tcp_recv(Sock, B) -> + receive {tcp, Sock, Bin} -> tcp_recv(Sock, <>) end. + +%% putr/2 + +putr(Key, Val) -> + put({?MODULE, Key}, Val). + +%% getr/1 + +getr(Key) -> + get({?MODULE, Key}). diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index daf6ef64ec..218a70017a 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -31,7 +31,9 @@ MODULES = \ diameter_reg_SUITE \ diameter_sync_SUITE \ diameter_stats_SUITE \ - diameter_watchdog_SUITE + diameter_watchdog_SUITE \ + diameter_transport_SUITE \ + diameter_gen_sctp_SUITE INTERNAL_HRL_FILES = \ diameter_ct.hrl -- cgit v1.2.3 From f34f4fbe9a37028cdb02c789ca89fa0647c9b8cc Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 15 Aug 2011 10:24:04 +0200 Subject: Remove old test framework --- lib/diameter/test/diameter_SUITE.erl | 108 ------ lib/diameter/test/diameter_compiler_test.erl | 104 ----- lib/diameter/test/diameter_config_test.erl | 105 ----- lib/diameter/test/diameter_test_lib.erl | 478 ----------------------- lib/diameter/test/diameter_test_lib.hrl | 106 ------ lib/diameter/test/diameter_test_server.erl | 551 --------------------------- 6 files changed, 1452 deletions(-) delete mode 100644 lib/diameter/test/diameter_SUITE.erl delete mode 100644 lib/diameter/test/diameter_compiler_test.erl delete mode 100644 lib/diameter/test/diameter_config_test.erl delete mode 100644 lib/diameter/test/diameter_test_lib.erl delete mode 100644 lib/diameter/test/diameter_test_lib.hrl delete mode 100644 lib/diameter/test/diameter_test_server.erl diff --git a/lib/diameter/test/diameter_SUITE.erl b/lib/diameter/test/diameter_SUITE.erl deleted file mode 100644 index 443cf90e92..0000000000 --- a/lib/diameter/test/diameter_SUITE.erl +++ /dev/null @@ -1,108 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Test application config -%%---------------------------------------------------------------------- - --module(diameter_SUITE). - --export([ - suite/0, - all/0, - groups/0, - - init_per_testcase/2, - fin_per_testcase/2, - - init_per_suite/1, - end_per_suite/1, - - init_per_group/2, - end_per_group/2, - - init/0 - ]). - --export([t/0, t/1]). - - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - -init() -> - process_flag(trap_exit, true), - ?FLUSH(). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Top test case - -suite() -> - [{ct_hooks, [{ts_install_cth, [{nodenames,1}]}]}]. - -all() -> - [ - {group, app}, - {group, appup}, - {group, compiler}, - {group, config}, - {group, sync}, - {group, session}, - {group, stats}, - {group, reg}, - {group, peer}, - {group, tcp} - ]. - -groups() -> - [{app, [], [{diameter_app_test, all}]}, - {appup, [], [{diameter_appup_test, all}]}, - {compiler, [], [{diameter_compiler_test, all}]}, - {config, [], [{diameter_config_test, all}]}, - {sync, [], [{diameter_sync_test, all}]}, - {session, [], [{diameter_session_test, all}]}, - {stats, [], [{diameter_stats_test, all}]}, - {reg, [], [{diameter_reg_test, all}]}, - {peer, [], [{diameter_peer_test, all}]}, - {tcp, [], [{diameter_tcp_test, all}]}]. - - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. diff --git a/lib/diameter/test/diameter_compiler_test.erl b/lib/diameter/test/diameter_compiler_test.erl deleted file mode 100644 index ae4c9c668d..0000000000 --- a/lib/diameter/test/diameter_compiler_test.erl +++ /dev/null @@ -1,104 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the dia compiler of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_compiler_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/diameter_config_test.erl b/lib/diameter/test/diameter_config_test.erl deleted file mode 100644 index c44fb654ab..0000000000 --- a/lib/diameter/test/diameter_config_test.erl +++ /dev/null @@ -1,105 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Verify the config server of the Diameter application -%%---------------------------------------------------------------------- -%% --module(diameter_config_test). - --export([ - init_per_testcase/2, fin_per_testcase/2, - - all/0, - groups/0, - init_per_suite/1, end_per_suite/1, - suite_init/1, suite_fin/1, - init_per_group/2, end_per_group/2 - - %% foo/1 - ]). - --export([t/0, t/1]). - --include("diameter_test_lib.hrl"). - - -t() -> diameter_test_server:t(?MODULE). -t(Case) -> diameter_test_server:t({?MODULE, Case}). - - -%% Test server callbacks -init_per_testcase(Case, Config) -> - diameter_test_server:init_per_testcase(Case, Config). - -fin_per_testcase(Case, Config) -> - diameter_test_server:fin_per_testcase(Case, Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -all() -> - []. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite_init(X) -> init_per_suite(X). - -init_per_suite(suite) -> []; -init_per_suite(doc) -> []; -init_per_suite(Config) when is_list(Config) -> - Config. - - -suite_fin(X) -> end_per_suite(X). - -end_per_suite(suite) -> []; -end_per_suite(doc) -> []; -end_per_suite(Config) when is_list(Config) -> - - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% Test case example -%% - -%% foo(suite) -> -%% []; -%% foo(doc) -> -%% []; -%% foo(Config) when is_list(Config) -> -%% ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/lib/diameter/test/diameter_test_lib.erl b/lib/diameter/test/diameter_test_lib.erl deleted file mode 100644 index 3d46236526..0000000000 --- a/lib/diameter/test/diameter_test_lib.erl +++ /dev/null @@ -1,478 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Lightweight test server -%%---------------------------------------------------------------------- -%% - --module(diameter_test_lib). - --export([ - sleep/1, - - hours/1, - minutes/1, - seconds/1, - - key1search/2, - - non_pc_tc_maybe_skip/4, - os_based_skip/1, - - fail/3, - skip/3, - fatal_skip/3, - - log/4, - error/3, - - flush/0, - - proxy_start/1, proxy_start/2, - proxy_init/2, - - still_alive/1, - - prepare_test_case/5, - lookup_config/2, - - mk_nodes/2, start_nodes/3, - - display_system_info/1, display_system_info/2, display_system_info/3, - display_alloc_info/0, - alloc_info/0, - - report_event/3 - - ]). - --include("diameter_test_lib.hrl"). - --record('REASON', {mod, line, desc}). - - -%% ---------------------------------------------------------------- -%% Time related function -%% - -sleep(infinity) -> - receive - after infinity -> - ok - end; -sleep(MSecs) -> - receive - after trunc(MSecs) -> - ok - end, - ok. - - -hours(N) -> trunc(N * 1000 * 60 * 60). -minutes(N) -> trunc(N * 1000 * 60). -seconds(N) -> trunc(N * 1000). - - -%% ---------------------------------------------------------------- - -key1search(Key, L) -> - case lists:keysearch(Key, 1, L) of - undefined -> - fail({not_found, Key, L}, ?MODULE, ?LINE); - {value, {Key, Value}} -> - Value - end. - - -%% ---------------------------------------------------------------- -%% Conditional skip of testcases -%% - -non_pc_tc_maybe_skip(Config, Condition, File, Line) - when is_list(Config) andalso is_function(Condition) -> - %% Check if we shall skip the skip - case os:getenv("TS_OS_BASED_SKIP") of - "false" -> - ok; - _ -> - case lists:keysearch(ts, 1, Config) of - {value, {ts, megaco}} -> - %% Always run the testcase if we are using our own - %% test-server... - ok; - _ -> - case (catch Condition()) of - true -> - skip(non_pc_testcase, File, Line); - _ -> - ok - end - end - end. - - -os_based_skip(any) -> - true; -os_based_skip(Skippable) when is_list(Skippable) -> - {OsFam, OsName} = - case os:type() of - {_Fam, _Name} = FamAndName -> - FamAndName; - Fam -> - {Fam, undefined} - end, - case lists:member(OsFam, Skippable) of - true -> - true; - false -> - case lists:keysearch(OsFam, 1, Skippable) of - {value, {OsFam, OsName}} -> - true; - {value, {OsFam, OsNames}} when is_list(OsNames) -> - lists:member(OsName, OsNames); - _ -> - false - end - end; -os_based_skip(_) -> - false. - - -%%---------------------------------------------------------------------- - -error(Actual, Mod, Line) -> - global:send(megaco_global_logger, {failed, Mod, Line}), - log(" Bad result: ~p~n", [Actual], Mod, Line), - Label = lists:concat([Mod, "(", Line, ") unexpected result"]), - report_event(60, Label, [{line, Mod, Line}, {error, Actual}]), - case global:whereis_name(megaco_test_case_sup) of - undefined -> - ignore; - Pid -> - Fail = #'REASON'{mod = Mod, line = Line, desc = Actual}, - Pid ! {fail, self(), Fail} - end, - Actual. - -log(Format, Args, Mod, Line) -> - case global:whereis_name(megaco_global_logger) of - undefined -> - io:format(user, "~p~p(~p): " ++ Format, - [self(), Mod, Line] ++ Args); - Pid -> - io:format(Pid, "~p~p(~p): " ++ Format, - [self(), Mod, Line] ++ Args) - end. - -skip(Actual, File, Line) -> - log("Skipping test case~n", [], File, Line), - String = lists:flatten(io_lib:format("Skipping test case ~p(~p): ~p~n", - [File, Line, Actual])), - exit({skipped, String}). - -fatal_skip(Actual, File, Line) -> - error(Actual, File, Line), - exit(shutdown). - - -fail(Actual, File, Line) -> - log("Test case failing~n", [], File, Line), - String = lists:flatten(io_lib:format("Test case failing ~p (~p): ~p~n", - [File, Line, Actual])), - exit({suite_failed, String}). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Flush the message queue and return its messages - -flush() -> - receive - Msg -> - [Msg | flush()] - after 1000 -> - [] - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% The proxy process - -proxy_start(ProxyId) -> - spawn_link(?MODULE, proxy_init, [ProxyId, self()]). - -proxy_start(Node, ProxyId) -> - spawn_link(Node, ?MODULE, proxy_init, [ProxyId, self()]). - -proxy_init(ProxyId, Controller) -> - process_flag(trap_exit, true), - ?LOG("[~p] proxy started by ~p~n",[ProxyId, Controller]), - proxy_loop(ProxyId, Controller). - -proxy_loop(OwnId, Controller) -> - receive - {'EXIT', Controller, Reason} -> - p("proxy_loop -> received exit from controller" - "~n Reason: ~p" - "~n", [Reason]), - exit(Reason); - {apply, Fun} -> - p("proxy_loop -> received apply request~n", []), - Res = Fun(), - p("proxy_loop -> apply result: " - "~n ~p" - "~n", [Res]), - Controller ! {res, OwnId, Res}, - proxy_loop(OwnId, Controller); - OtherMsg -> - p("proxy_loop -> received unknown message: " - "~n OtherMsg: ~p" - "~n", [OtherMsg]), - Controller ! {msg, OwnId, OtherMsg}, - proxy_loop(OwnId, Controller) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Check if process is alive and kicking -still_alive(Pid) -> - case catch erlang:is_process_alive(Pid) of % New BIF in Erlang/OTP R5 - true -> - true; - false -> - false; - {'EXIT', _} -> % Pre R5 backward compatibility - case process_info(Pid, message_queue_len) of - undefined -> false; - _ -> true - end - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -mk_nodes(0, Nodes) -> - Nodes; -mk_nodes(N, []) -> - mk_nodes(N - 1, [node()]); -mk_nodes(N, Nodes) when N > 0 -> - Head = hd(Nodes), - [Name, Host] = node_to_name_and_host(Head), - Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)]. - -mk_node(N, Name, Host) -> - list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). - -%% Returns [Name, Host] -node_to_name_and_host(Node) -> - string:tokens(atom_to_list(Node), [$@]). - -start_nodes([Node | Nodes], File, Line) -> - case net_adm:ping(Node) of - pong -> - start_nodes(Nodes, File, Line); - pang -> - [Name, Host] = node_to_name_and_host(Node), - case slave:start_link(Host, Name) of - {ok, NewNode} when NewNode =:= Node -> - Path = code:get_path(), - {ok, Cwd} = file:get_cwd(), - true = rpc:call(Node, code, set_path, [Path]), - ok = rpc:call(Node, file, set_cwd, [Cwd]), - true = rpc:call(Node, code, set_path, [Path]), - {_, []} = rpc:multicall(global, sync, []), - start_nodes(Nodes, File, Line); - Other -> - fatal_skip({cannot_start_node, Node, Other}, File, Line) - end - end; -start_nodes([], _File, _Line) -> - ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -display_alloc_info() -> - io:format("Allocator memory information:~n", []), - AllocInfo = alloc_info(), - display_alloc_info(AllocInfo). - -display_alloc_info([]) -> - ok; -display_alloc_info([{Alloc, Mem}|AllocInfo]) -> - io:format(" ~15w: ~10w~n", [Alloc, Mem]), - display_alloc_info(AllocInfo). - -alloc_info() -> - case erlang:system_info(allocator) of - {_Allocator, _Version, Features, _Settings} -> - alloc_info(Features); - _ -> - [] - end. - -alloc_info(Allocators) -> - Allocs = [temp_alloc, sl_alloc, std_alloc, ll_alloc, eheap_alloc, - ets_alloc, binary_alloc, driver_alloc], - alloc_info(Allocators, Allocs, []). - -alloc_info([], _, Acc) -> - lists:reverse(Acc); -alloc_info([Allocator | Allocators], Allocs, Acc) -> - case lists:member(Allocator, Allocs) of - true -> - Instances0 = erlang:system_info({allocator, Allocator}), - Instances = - if - is_list(Instances0) -> - [Instance || Instance <- Instances0, - element(1, Instance) =:= instance]; - true -> - [] - end, - AllocatorMem = alloc_mem_info(Instances), - alloc_info(Allocators, Allocs, [{Allocator, AllocatorMem} | Acc]); - - false -> - alloc_info(Allocators, Allocs, Acc) - end. - -alloc_mem_info(Instances) -> - alloc_mem_info(Instances, []). - -alloc_mem_info([], Acc) -> - lists:sum([Mem || {instance, _, Mem} <- Acc]); -alloc_mem_info([{instance, N, Info}|Instances], Acc) -> - InstanceMemInfo = alloc_instance_mem_info(Info), - alloc_mem_info(Instances, [{instance, N, InstanceMemInfo} | Acc]). - -alloc_instance_mem_info(InstanceInfo) -> - MBCS = alloc_instance_mem_info(mbcs, InstanceInfo), - SBCS = alloc_instance_mem_info(sbcs, InstanceInfo), - MBCS + SBCS. - -alloc_instance_mem_info(Key, InstanceInfo) -> - case lists:keysearch(Key, 1, InstanceInfo) of - {value, {Key, Info}} -> - case lists:keysearch(blocks_size, 1, Info) of - {value, {blocks_size, Mem, _, _}} -> - Mem; - _ -> - 0 - end; - _ -> - 0 - end. - - -display_system_info(WhenStr) -> - display_system_info(WhenStr, undefined, undefined). - -display_system_info(WhenStr, undefined, undefined) -> - display_system_info(WhenStr, ""); -display_system_info(WhenStr, Mod, Func) -> - ModFuncStr = lists:flatten(io_lib:format(" ~w:~w", [Mod, Func])), - display_system_info(WhenStr, ModFuncStr). - -display_system_info(WhenStr, ModFuncStr) -> - Fun = fun(F) -> case (catch F()) of - {'EXIT', _} -> - undefined; - Res -> - Res - end - end, - ProcCount = Fun(fun() -> erlang:system_info(process_count) end), - ProcLimit = Fun(fun() -> erlang:system_info(process_limit) end), - ProcMemAlloc = Fun(fun() -> erlang:memory(processes) end), - ProcMemUsed = Fun(fun() -> erlang:memory(processes_used) end), - ProcMemBin = Fun(fun() -> erlang:memory(binary) end), - ProcMemTot = Fun(fun() -> erlang:memory(total) end), - %% error_logger:info_msg( - io:format("~n" - "~n*********************************************" - "~n" - "System info ~s~s => " - "~n Process count: ~w" - "~n Process limit: ~w" - "~n Process memory alloc: ~w" - "~n Process memory used: ~w" - "~n Memory for binaries: ~w" - "~n Memory total: ~w" - "~n" - "~n*********************************************" - "~n" - "~n", [WhenStr, ModFuncStr, - ProcCount, ProcLimit, ProcMemAlloc, ProcMemUsed, - ProcMemBin, ProcMemTot]), - ok. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -prepare_test_case(Actions, N, Config, File, Line) -> - OrigNodes = lookup_config(nodes, Config), - TestNodes = lookup_config(nodenames, Config), %% For testserver - This = node(), - SomeNodes = OrigNodes ++ (TestNodes -- OrigNodes), - AllNodes = [This | (SomeNodes -- [This])], - Nodes = pick_n_nodes(N, AllNodes, File, Line), - start_nodes(Nodes, File, Line), - do_prepare_test_case(Actions, Nodes, Config, File, Line). - -do_prepare_test_case([init | Actions], Nodes, Config, File, Line) -> - process_flag(trap_exit, true), - megaco_test_lib:flush(), - do_prepare_test_case(Actions, Nodes, Config, File, Line); -do_prepare_test_case([{stop_app, App} | Actions], Nodes, Config, File, Line) -> - _Res = rpc:multicall(Nodes, application, stop, [App]), - do_prepare_test_case(Actions, Nodes, Config, File, Line); -do_prepare_test_case([], Nodes, _Config, _File, _Line) -> - Nodes. - -pick_n_nodes(all, AllNodes, _File, _Line) -> - AllNodes; -pick_n_nodes(N, AllNodes, _File, _Line) - when is_integer(N) andalso (length(AllNodes) >= N) -> - AllNodes -- lists:nthtail(N, AllNodes); -pick_n_nodes(N, AllNodes, File, Line) -> - fatal_skip({too_few_nodes, N, AllNodes}, File, Line). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -lookup_config(Key, Config) -> - case lists:keysearch(Key, 1, Config) of - {value, {Key, Val}} -> - Val; - _ -> - [] - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -report_event(_Severity, _Label, _Content) -> - %% diameter:report_event(Severity, Label, Content). - hopefully_traced. - - -p(F,A) -> - io:format("~p" ++ F ++ "~n", [self()|A]). diff --git a/lib/diameter/test/diameter_test_lib.hrl b/lib/diameter/test/diameter_test_lib.hrl deleted file mode 100644 index 0b86f38de7..0000000000 --- a/lib/diameter/test/diameter_test_lib.hrl +++ /dev/null @@ -1,106 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Define common macros for testing -%%---------------------------------------------------------------------- -%% - --define(FLUSH(), diameter_test_lib:flush()). - --define(SLEEP(MSEC), diameter_test_lib:sleep(MSEC)). --define(M(), diameter_test_lib:millis()). --define(MDIFF(A,B), diameter_test_lib:millis_diff(A,B)). - --define(HOURS(T), diameter_test_lib:hours(T)). --define(MINUTES(T), diameter_test_lib:minutes(T)). --define(SECONDS(T), diameter_test_lib:seconds(T)). - --define(KEY1SEARCH(Key, L), diameter_test_lib:key1search(Key, L)). - - --define(APPLY(Proxy, Fun), - Proxy ! {apply, Fun}). - --define(LOG(Format, Args), - diameter_test_lib:log(Format, Args, ?MODULE, ?LINE)). - --define(ERROR(Reason), - diameter_test_lib:error(Reason, ?MODULE, ?LINE)). - --define(OS_BASED_SKIP(Skippable), - diameter_test_lib:os_based_skip(Skippable)). - --define(NON_PC_TC_MAYBE_SKIP(Config, Condition), - diameter_test_lib:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)). - --define(FAIL(Reason), - diameter_test_lib:fail(Reason, ?MODULE, ?LINE)). - --define(SKIP(Reason), - diameter_test_lib:skip(Reason, ?MODULE, ?LINE)). - --define(VERIFYL(Expected, Expr), - fun(A,B) when list(A), list(B) -> - A1 = lists:sort(A), - B1 = lists:sort(B), - case A1 of - B1 -> ?LOG("Ok, ~p~n", [B]); - _ -> ?ERROR(B) - end, - B; - (A,A) -> - ?LOG("Ok, ~p~n", [A]), - A; - (A,B) -> - ?ERROR(B), - B - end(Expected, (catch Expr))). - --define(VERIFY(Expected, Expr), - fun() -> - AcTuAlReS = (catch (Expr)), - case AcTuAlReS of - Expected -> ?LOG("Ok, ~p~n", [AcTuAlReS]); - _ -> ?ERROR(AcTuAlReS) - end, - AcTuAlReS - end()). - --define(RECEIVE(Expected), - ?VERIFY(Expected, ?FLUSH())). - --define(MULTI_RECEIVE(Expected), - ?VERIFY(lists:sort(Expected), lists:sort(?FLUSH()))). - --define(ACQUIRE_NODES(N, Config), - diameter_test_lib:prepare_test_case([init, {stop_app, diameter}], - N, Config, ?FILE, ?LINE)). - - --define(REPORT_IMPORTANT(Label, Content), ?REPORT_EVENT(20, Label, Content)). --define(REPORT_VERBOSE(Label, Content), ?REPORT_EVENT(40, Label, Content)). --define(REPORT_DEBUG(Label, Content), ?REPORT_EVENT(60, Label, Content)). --define(REPORT_TRACE(Label, Content), ?REPORT_EVENT(80, Label, Content)). - --define(REPORT_EVENT(Severity, Label, Content), - diameter_test_lib:report_event(Severity, Label, - [{line, ?MODULE, ?LINE} | Content])). - diff --git a/lib/diameter/test/diameter_test_server.erl b/lib/diameter/test/diameter_test_server.erl deleted file mode 100644 index e2ff73fb8e..0000000000 --- a/lib/diameter/test/diameter_test_server.erl +++ /dev/null @@ -1,551 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Lightweight test server -%%---------------------------------------------------------------------- - --module(diameter_test_server). - --export([ - t/1, t/2, - - init_per_testcase/2, - fin_per_testcase/2 - ]). - --include("diameter_test_lib.hrl"). - - --define(GLOGGER, diameter_global_logger). - - -%% ---------------------------------------------------------------- -%% - -t([Case]) when is_atom(Case) -> - t(Case); -t(Case) -> - process_flag(trap_exit, true), - MEM = fun() -> case (catch erlang:memory()) of - {'EXIT', _} -> - []; - Res -> - Res - end - end, - Alloc1 = diameter_test_lib:alloc_info(), - Mem1 = MEM(), - Res = lists:flatten(t(Case, default_config())), - Alloc2 = diameter_test_lib:alloc_info(), - Mem2 = MEM(), - %% io:format("Res: ~p~n", [Res]), - display_result(Res, Alloc1, Mem1, Alloc2, Mem2), - Res. - - -groups(Mod) when is_atom(Mod) -> - try Mod:groups() of - Groups when is_list(Groups) -> - Groups; - BadGroups -> - exit({bad_groups, Mod, BadGroups}) - catch - _:_ -> - [] - end. - -init_suite(Mod, Config) -> - io:format("~w:init_suite -> entry with" - "~n Mod: ~p" - "~n Config: ~p" - "~n", [?MODULE, Mod, Config]), - Mod:init_per_suite(Config). - -end_suite(Mod, Config) -> - Mod:end_per_suite(Config). - -init_group(Mod, Group, Config) -> - Mod:init_per_group(Group, Config). - -end_group(Mod, Group, Config) -> - Mod:init_per_group(Group, Config). - -%% This is for sub-SUITEs -t({_Mod, {NewMod, all}, _Groups}, _Config) when is_atom(NewMod) -> - io:format("~w:t(all) -> entry with" - "~n NewMod: ~p" - "~n", [?MODULE, NewMod]), - t(NewMod); -t({Mod, {group, Name} = Group, Groups}, Config) - when is_atom(Mod) andalso is_atom(Name) andalso is_list(Groups) -> - io:format("~w:t(group) -> entry with" - "~n Mod: ~p" - "~n Name: ~p" - "~n Groups: ~p" - "~n Config: ~p" - "~n", [?MODULE, Mod, Name, Groups, Config]), - case lists:keysearch(Name, 1, Groups) of - {value, {Name, _Props, GroupsAndCases}} -> - try init_group(Mod, Name, Config) of - Config2 when is_list(Config2) -> - Res = [t({Mod, Case, Groups}, Config2) || - Case <- GroupsAndCases], - (catch end_group(Mod, Name, Config2)), - Res; - Error -> - io:format(" => group (~w) init failed: ~p~n", - [Name, Error]), - [{failed, {Mod, Group}, Error}] - catch - exit:{skipped, SkipReason} -> - io:format(" => skipping group: ~p~n", [SkipReason]), - [{skipped, {Mod, Group}, SkipReason, 0}]; - exit:{undef, _} -> - [t({Mod, Case, Groups}, Config) || - Case <- GroupsAndCases]; - T:E -> - [{failed, {Mod, Group}, {T,E}, 0}] - end; - false -> - exit({unknown_group, Mod, Name, Groups}) - end; -t({Mod, Fun, _}, Config) - when is_atom(Mod) andalso is_atom(Fun) -> - io:format("~w:t -> entry with" - "~n Mod: ~p" - "~n Fun: ~p" - "~n Config: ~p" - "~n", [?MODULE, Mod, Fun, Config]), - case catch apply(Mod, Fun, [suite]) of - [] -> - io:format("Eval: ~p:", [{Mod, Fun}]), - Res = eval(Mod, Fun, Config), - {R, _, _, _} = Res, - io:format(" ~p~n", [R]), - Res; - - Cases when is_list(Cases) -> - io:format("Expand: ~p ...~n", [{Mod, Fun}]), - Map = fun(Case) when is_atom(Case) -> {Mod, Case}; - (Case) -> Case - end, - t(lists:map(Map, Cases), Config); - - {'EXIT', {undef, _}} -> - io:format("Undefined: ~p~n", [{Mod, Fun}]), - [{nyi, {Mod, Fun}, ok, 0}]; - - Error -> - io:format("Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]), - [{failed, {Mod, Fun}, Error, 0}] - end; -t(Mod, Config) when is_atom(Mod) -> - io:format("~w:t -> entry with" - "~n Mod: ~p" - "~n Config: ~p" - "~n", [?MODULE, Mod, Config]), - %% This is assumed to be a test suite, so we start by calling - %% the top test suite function(s) (all/0 and groups/0). - case (catch Mod:all()) of - Cases when is_list(Cases) -> - %% The list may contain atoms (actual test cases) and - %% group-tuples (a tuple naming a group of test cases). - %% A group is defined by the (optional) groups/0 function. - io:format("~w:t -> suite all ok" - "~n Cases: ~p" - "~n", [?MODULE, Cases]), - Groups = groups(Mod), - io:format("~w:t -> " - "~n Groups: ~p" - "~n", [?MODULE, Groups]), - try init_suite(Mod, Config) of - Config2 when is_list(Config2) -> - io:format("~w:t -> suite init ok" - "~n Config2: ~p" - "~n", [?MODULE, Config2]), - Res = [t({Mod, Case, Groups}, Config2) || Case <- Cases], - (catch end_suite(Mod, Config2)), - Res; - Error -> - io:format(" => suite init failed: ~p~n", [Error]), - [{failed, {Mod, init_per_suite}, Error}] - catch - exit:{skipped, SkipReason} -> - io:format(" => skipping suite: ~p~n", [SkipReason]), - [{skipped, {Mod, init_per_suite}, SkipReason, 0}]; - exit:{undef, _} -> - io:format("~w:t -> suite init failed. exit undef(1)~n", [?MODULE]), - [t({Mod, Case, Groups}, Config) || Case <- Cases]; - exit:undef -> - io:format("~w:t -> suite init failed. exit undef(2)~n", [?MODULE]), - [t({Mod, Case, Groups}, Config) || Case <- Cases]; - T:E -> - io:format("~w:t -> suite init failed. " - "~n T: ~p" - "~n E: ~p" - "~n", [?MODULE, T,E]), - [{failed, {Mod, init_per_suite}, {T,E}, 0}] - end; - {'EXIT', {undef, _}} -> - io:format("Undefined: ~p~n", [{Mod, all}]), - [{nyi, {Mod, all}, ok, 0}]; - - Crap -> - io:format("~w:t -> suite all failed: " - "~n Crap: ~p" - "~n", [?MODULE, Crap]), - Crap - end; -t(Bad, _Config) -> - io:format("~w:t -> entry with" - "~n Bad: ~p" - "~n", [?MODULE, Bad]), - [{badarg, Bad, ok, 0}]. - -eval(Mod, Fun, Config) -> - TestCase = {?MODULE, Mod, Fun}, - Label = lists:concat(["TEST CASE: ", Fun]), - ?REPORT_VERBOSE(Label ++ " started", [TestCase, Config]), - global:register_name(diameter_test_case_sup, self()), - Flag = process_flag(trap_exit, true), - put(diameter_test_server, true), - Config2 = Mod:init_per_testcase(Fun, Config), - Self = self(), - Pid = spawn_link(fun() -> do_eval(Self, Mod, Fun, Config2) end), - R = wait_for_evaluator(Pid, Mod, Fun, Config2, []), - Mod:fin_per_testcase(Fun, Config2), - erase(diameter_test_server), - global:unregister_name(diameter_test_case_sup), - process_flag(trap_exit, Flag), - R. - -wait_for_evaluator(Pid, Mod, Fun, Config, Errors) -> - wait_for_evaluator(Pid, Mod, Fun, Config, Errors, 0). -wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) -> - TestCase = {?MODULE, Mod, Fun}, - Label = lists:concat(["TEST CASE: ", Fun]), - receive - {done, Pid, ok, Time} when Errors =:= [] -> - ?REPORT_VERBOSE(Label ++ " ok", - [{test_case, TestCase}, {config, Config}]), - {ok, {Mod, Fun}, Errors, Time}; - {done, Pid, ok, Time} -> - ?REPORT_VERBOSE(Label ++ " failed", - [{test_case, TestCase}, {config, Config}]), - {failed, {Mod, Fun}, Errors, Time}; - {done, Pid, {ok, _}, Time} when Errors =:= [] -> - ?REPORT_VERBOSE(Label ++ " ok", - [{test_case, TestCase}, {config, Config}]), - {ok, {Mod, Fun}, Errors, Time}; - {done, Pid, {ok, _}, Time} -> - ?REPORT_VERBOSE(Label ++ " failed", - [{test_case, TestCase}, {config, Config}]), - {failed, {Mod, Fun}, Errors, Time}; - {done, Pid, Fail, Time} -> - ?REPORT_IMPORTANT(Label ++ " failed", - [{test_case, TestCase}, - {config, Config}, - {return, Fail}, - {errors, Errors}]), - {failed, {Mod, Fun}, Fail, Time}; - {'EXIT', Pid, {skipped, Reason}, Time} -> - ?REPORT_IMPORTANT(Label ++ " skipped", - [{test_case, TestCase}, - {config, Config}, - {skipped, Reason}]), - {skipped, {Mod, Fun}, Errors, Time}; - {'EXIT', Pid, Reason, Time} -> - ?REPORT_IMPORTANT(Label ++ " crashed", - [{test_case, TestCase}, - {config, Config}, - {'EXIT', Reason}]), - {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors], Time}; - {fail, Pid, Reason, Time} -> - wait_for_evaluator(Pid, Mod, Fun, Config, - Errors ++ [Reason], AccTime + Time) - end. - -do_eval(ReplyTo, Mod, Fun, Config) -> - diameter_test_lib:display_system_info("before", Mod, Fun), - case timer:tc(Mod, Fun, [Config]) of - {Time, {'EXIT', {skipped, Reason}}} -> - display_tc_time(Time), - diameter_test_lib:display_system_info("after (skipped)", Mod, Fun), - ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time}; - {Time, {'EXIT', Reason}} -> - display_tc_time(Time), - diameter_test_lib:display_system_info("after (crashed)", Mod, Fun), - ReplyTo ! {'EXIT', self(), Reason, Time}; - {Time, Other} -> - display_tc_time(Time), - diameter_test_lib:display_system_info("after", Mod, Fun), - ReplyTo ! {done, self(), Other, Time} - end, - unlink(ReplyTo), - exit(shutdown). - - -display_tc_time(Time) -> - io:format("~n" - "~n*********************************************" - "~n" - "~nTest case completion time: ~.3f sec (~w)" - "~n", [(Time / 1000000), Time]), - ok. - - -display_result(Res, Alloc1, Mem1, Alloc2, Mem2) -> - io:format("~nAllocator info: ~n", []), - display_alloc(Alloc1, Alloc2), - io:format("~nMemory info: ~n", []), - display_memory(Mem1, Mem2), - display_result(Res). - -display_alloc([], []) -> - io:format("-~n", []), - ok; -display_alloc(A1, A2) -> - do_display_alloc(A1, A2). - -do_display_alloc([], _) -> - ok; -do_display_alloc([{Alloc, Mem1}|AllocInfo1], AllocInfo2) -> - Mem2 = - case lists:keysearch(Alloc, 1, AllocInfo2) of - {value, {_, Val}} -> - Val; - false -> - undefined - end, - io:format("~15w: ~10w -> ~w~n", [Alloc, Mem1, Mem2]), - do_display_alloc(AllocInfo1, AllocInfo2). - -display_memory([], []) -> - io:format("-~n", []), - ok; -display_memory(Mem1, Mem2) -> - do_display_memory(Mem1, Mem2). - - -do_display_memory([], _) -> - ok; -do_display_memory([{Key, Mem1}|MemInfo1], MemInfo2) -> - Mem2 = - case lists:keysearch(Key, 1, MemInfo2) of - {value, {_, Val}} -> - Val; - false -> - undefined - end, - io:format("~15w: ~10w -> ~w~n", [Key, Mem1, Mem2]), - do_display_memory(MemInfo1, MemInfo2). - -display_result([]) -> - io:format("OK~n", []); -display_result(Res) when is_list(Res) -> - Ok = [{MF, Time} || {ok, MF, _, Time} <- Res], - Nyi = [MF || {nyi, MF, _, _Time} <- Res], - Skipped = [{MF, Reason} || {skipped, MF, Reason, _Time} <- Res], - Failed = [{MF, Reason} || {failed, MF, Reason, _Time} <- Res], - Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res], - display_summery(Ok, Nyi, Skipped, Failed, Crashed), - display_ok(Ok), - display_skipped(Skipped), - display_failed(Failed), - display_crashed(Crashed). - -display_summery(Ok, Nyi, Skipped, Failed, Crashed) -> - io:format("~nTest case summery:~n", []), - display_summery(Ok, "successfull"), - display_summery(Nyi, "not yet implemented"), - display_summery(Skipped, "skipped"), - display_summery(Failed, "failed"), - display_summery(Crashed, "crashed"), - io:format("~n", []). - -display_summery(Res, Info) -> - io:format(" ~w test cases ~s~n", [length(Res), Info]). - -display_ok([]) -> - ok; -display_ok(Ok) -> - io:format("Ok test cases:~n", []), - F = fun({{M, F}, Time}) -> - io:format(" ~w : ~w => ~.2f sec~n", [M, F, Time / 1000000]) - end, - lists:foreach(F, Ok), - io:format("~n", []). - -display_skipped([]) -> - ok; -display_skipped(Skipped) -> - io:format("Skipped test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, - lists:foreach(F, Skipped), - io:format("~n", []). - - -display_failed([]) -> - ok; -display_failed(Failed) -> - io:format("Failed test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, - lists:foreach(F, Failed), - io:format("~n", []). - -display_crashed([]) -> - ok; -display_crashed(Crashed) -> - io:format("Crashed test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, - lists:foreach(F, Crashed), - io:format("~n", []). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Test server callbacks -init_per_testcase(_Case, Config) -> - Pid = group_leader(), - Name = ?GLOGGER, - case global:whereis_name(Name) of - undefined -> - global:register_name(?GLOGGER, Pid); - Pid -> - io:format("~w:init_per_testcase -> " - "already registered to ~p~n", [?MODULE, Pid]), - ok; - OtherPid when is_pid(OtherPid) -> - io:format("~w:init_per_testcase -> " - "already registered to other ~p (~p)~n", - [?MODULE, OtherPid, Pid]), - exit({already_registered, {?GLOGGER, OtherPid, Pid}}) - end, - set_kill_timer(Config). - -fin_per_testcase(_Case, Config) -> - Name = ?GLOGGER, - case global:whereis_name(Name) of - undefined -> - io:format("~w:fin_per_testcase -> already un-registered~n", - [?MODULE]), - ok; - Pid when is_pid(Pid) -> - global:unregister_name(?GLOGGER), - ok - end, - reset_kill_timer(Config). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Set kill timer - -set_kill_timer(Config) -> - case init:get_argument(diameter_test_timeout) of - {ok, _} -> - Config; - _ -> - Time = - case lookup_config(tc_timeout, Config) of - [] -> - timer:minutes(5); - ConfigTime when is_integer(ConfigTime) -> - ConfigTime - end, - Dog = - case get(diameter_test_server) of - true -> - Self = self(), - spawn_link(fun() -> watchdog(Self, Time) end); - _ -> - test_server:timetrap(Time) - end, - [{kill_timer, Dog}|Config] - - - end. - -reset_kill_timer(Config) -> - DogKiller = - case get(diameter_test_server) of - true -> - fun(P) when is_pid(P) -> P ! stop; - (_) -> ok - end; - _ -> - fun(Ref) -> test_server:timetrap_cancel(Ref) end - end, - case lists:keysearch(kill_timer, 1, Config) of - {value, {kill_timer, Dog}} -> - DogKiller(Dog), - lists:keydelete(kill_timer, 1, Config); - _ -> - Config - end. - -watchdog(Pid, Time) -> - erlang:now(), - receive - stop -> - ok - after Time -> - case (catch process_info(Pid)) of - undefined -> - ok; - Info -> - ?LOG(" Watchdog in test case timed out " - "for ~p after ~p min" - "~n~p" - "~n", - [Pid, Time div (1000*60), Info]), - exit(Pid, kill) - end - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -lookup_config(Key, Config) -> - diameter_test_lib:lookup_config(Key, Config). - -default_config() -> - [{nodes, default_nodes()}, {ts, diameter}]. - -default_nodes() -> - mk_nodes(2, []). - -mk_nodes(0, Nodes) -> - Nodes; -mk_nodes(N, []) -> - mk_nodes(N - 1, [node()]); -mk_nodes(N, Nodes) when N > 0 -> - Head = hd(Nodes), - [Name, Host] = node_to_name_and_host(Head), - Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)]. - -mk_node(N, Name, Host) -> - list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). - -%% Returns [Name, Host] -node_to_name_and_host(Node) -> - string:tokens(atom_to_list(Node), [$@]). - - - - -- cgit v1.2.3 From d3edee5b2dd743fb348066328df3b3a00da36896 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 15 Aug 2011 16:16:03 +0200 Subject: Makefile/spec cleanup --- lib/diameter/test/Makefile | 62 +++++++++++++++++------------------------ lib/diameter/test/diameter.spec | 8 ------ 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 0bd3c0493c..a69af8ef2f 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -16,11 +16,11 @@ # # %CopyrightEnd% -ifneq ($(ERL_TOP),) +ifeq ($(ERL_TOP),) +TOP = $(DIAMETER_TOP) +else TOP = $(ERL_TOP) DIAMETER_TOP = $(TOP)/lib/diameter -else -TOP = $(DIAMETER_TOP) endif include $(TOP)/make/target.mk @@ -98,7 +98,7 @@ ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) # Targets # ---------------------------------------------------- -test: $(SUITES) +all test: $(SUITES) tests debug opt: $(BUILDTARGET) @@ -116,6 +116,8 @@ $(EMAKEFILE): clean: rm -f $(EMAKEFILE) rm -f $(TARGET_FILES) + +realclean: clean rm -f errs core *~ docs: @@ -145,49 +147,39 @@ help: @echo @echo " a) Run the official OTP test-server (which we do not describe here)" @echo - @echo " b) Run the test-server provided with this application." - @echo " There are a number of targets to run the entire or parts" - @echo " of this applications ($(APPLICATION)) test-suite" + @echo " b) Run individual suites using targets in this makefile, target" + @echo " xxx running the testcases contained in $(APPLICATION)_xxx_SUITE." + @echo " Note that this requires GNU sed." @echo @echo "Targets:" @echo - @echo " help" - @echo " Print this info" + @echo " all" + @echo " Run all test suites." @echo - @echo " info" - @echo " Prints various environment variables." - @echo " May be useful when debugging the Makefile." + @echo " $(SUITES)" + @echo " Run a specific test suite." @echo - @echo " tests | debug | opt " - @echo " Compile all test-code." + @echo " targets" + @echo " Compile all test-code." @echo - @echo " clean " - @echo " Remove all targets." + @echo " clean" + @echo " Remove generated files." @echo - @echo " test" - @echo " Run all test suites." + @echo " info" + @echo " Prints various environment variables." + @echo " May be useful when debugging this Makefile." @echo - @echo " $(SUITES)" - @echo " Run a specific test suite." + @echo " help" + @echo " Print this info." @echo - # ---------------------------------------------------- # Special Targets # ---------------------------------------------------- -all: $(SUITES) - -beam: targets - -log: - mkdir $@ - -########################## - # This assumes GNU sed to exit 1 if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -$(SUITES): log beam +$(SUITES): log targets $(ERL) -noshell \ -pa ../ebin \ -sname diameter_test_$@ \ @@ -195,6 +187,9 @@ $(SUITES): log beam -s init stop \ | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' +log: + mkdir $@ + # ---------------------------------------------------- # Release Targets # ---------------------------------------------------- @@ -208,8 +203,3 @@ release_docs_spec: release_tests_spec: tests $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(RELTEST_FILES) $(RELSYSDIR) -# $(INSTALL_DATA) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) \ -# $(HRL_FILES) $(ERL_FILES) \ -# $(RELSYSDIR) -# - chmod -f -R u+w $(RELSYSDIR) diff --git a/lib/diameter/test/diameter.spec b/lib/diameter/test/diameter.spec index a6e71762eb..fae7863bec 100644 --- a/lib/diameter/test/diameter.spec +++ b/lib/diameter/test/diameter.spec @@ -1,9 +1 @@ {suites, "../diameter_test", all}. -%%{skip, {diameter_compiler_test, all, "Not yet implemented"}}. -%%{skip, {diameter_config_test, all, "Not yet implemented"}}. -%%{skip, {diameter_peer_test, all, "Not yet implemented"}}. -%%{skip, {diameter_reg_test, all, "Not yet implemented"}}. -%%{skip, {diameter_session_test, all, "Not yet implemented"}}. -%%{skip, {diameter_stats_test, all, "Not yet implemented"}}. -%%{skip, {diameter_sync_test, all, "Not yet implemented"}}. -%%{skip, {diameter_tcp_test, all, "Not yet implemented"}}. -- cgit v1.2.3 From 2a6b5dd6abbb94607b5c59ec5a1e0d292880d78d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 15 Aug 2011 18:01:07 +0200 Subject: Generate dependencies makefile --- lib/diameter/test/.gitignore | 3 ++- lib/diameter/test/Makefile | 30 ++++++++++++++++++++++++++---- lib/diameter/test/depend.sed | 30 ++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 lib/diameter/test/depend.sed diff --git a/lib/diameter/test/.gitignore b/lib/diameter/test/.gitignore index 8a186ed5b5..df38dfc5e3 100644 --- a/lib/diameter/test/.gitignore +++ b/lib/diameter/test/.gitignore @@ -1,2 +1,3 @@ -log +/log +/depend.mk diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index a69af8ef2f..fb892f1d75 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -102,9 +102,7 @@ all test: $(SUITES) tests debug opt: $(BUILDTARGET) -targets: $(TARGET_FILES) - -.PHONY: emakebuild +beam targets: $(TARGET_FILES) emakebuild: $(EMAKEFILE) @@ -116,10 +114,13 @@ $(EMAKEFILE): clean: rm -f $(EMAKEFILE) rm -f $(TARGET_FILES) + rm -f depend.mk realclean: clean rm -f errs core *~ +.PHONY: all emakebuild test tests debug opt beam targets clean realclean + docs: info: @@ -159,7 +160,7 @@ help: @echo " $(SUITES)" @echo " Run a specific test suite." @echo - @echo " targets" + @echo " beam" @echo " Compile all test-code." @echo @echo " clean" @@ -173,6 +174,8 @@ help: @echo " Print this info." @echo +.PHONY: docs info help + # ---------------------------------------------------- # Special Targets # ---------------------------------------------------- @@ -190,6 +193,8 @@ $(SUITES): log targets log: mkdir $@ +.PHONY: $(SUITES) + # ---------------------------------------------------- # Release Targets # ---------------------------------------------------- @@ -203,3 +208,20 @@ release_docs_spec: release_tests_spec: tests $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(RELTEST_FILES) $(RELSYSDIR) + +.PHONY: release_spec release_docs_spec release_test_specs + +# ---------------------------------------------------- + +depend: depend.mk + +# Generate dependencies makefile. +depend.mk: depend.sed $(MODULES:%=%.erl) Makefile + (for f in $(MODULES); do \ + sed -f $< $$f.erl | sed "s@/@/$$f@"; \ + done) \ + > $@ + +-include depend.mk + +.PHONY: depend diff --git a/lib/diameter/test/depend.sed b/lib/diameter/test/depend.sed new file mode 100644 index 0000000000..effb668e38 --- /dev/null +++ b/lib/diameter/test/depend.sed @@ -0,0 +1,30 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. 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% +# + +# +# Extract local include dependencies from .erl files. The output is massaged +# further in Makefile. +# + +/^-include/!d +/^-include_lib/d + +s@^-include("@@ +s@".*@@ +s@^@$(EBIN)/.$(EMULATOR): @ -- cgit v1.2.3 From 56701b99f5c7a9a361657151c4378e9151112a7d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 18 Aug 2011 15:38:24 +0200 Subject: Don't require GNU sed to fail testsuite targets --- lib/diameter/test/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index fb892f1d75..08a4067cf9 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -150,7 +150,6 @@ help: @echo @echo " b) Run individual suites using targets in this makefile, target" @echo " xxx running the testcases contained in $(APPLICATION)_xxx_SUITE." - @echo " Note that this requires GNU sed." @echo @echo "Targets:" @echo @@ -180,7 +179,7 @@ help: # Special Targets # ---------------------------------------------------- -# This assumes GNU sed to exit 1 if the output looks to indicate failure. +# Exit with a non-zero status if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). $(SUITES): log targets $(ERL) -noshell \ @@ -188,7 +187,8 @@ $(SUITES): log targets -sname diameter_test_$@ \ -s diameter_ct run $@ \ -s init stop \ - | sed '/ FAILED /h; p; $$!d; x; /./!d; Q 1' + | awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}' +# Shorter in sed but requires a GNU extension (ie. Q). log: mkdir $@ -- cgit v1.2.3 From e3902570caa368c759fdf3b19981991bf43b57ec Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 16 Aug 2011 11:34:18 +0200 Subject: Improve xref testcase --- lib/diameter/test/diameter_app_SUITE.erl | 36 ++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 718f28d066..170166d1e6 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -34,7 +34,7 @@ modules/1, exports/1, release/1, - xref/1, xref/0, + xref/1, relup/1]). -define(APP, diameter). @@ -141,28 +141,42 @@ appvsn(Name) -> %% Ensure that no function in our application calls an undefined function. %% =========================================================================== -xref() -> - [{timetrap, {minutes, 2}}]. - xref(Config) -> - Mods = fetch(modules, fetch(app, Config)), - - RootDir = code:root_dir(), - EbinDir = code:lib_dir(?APP, ebin), + App = fetch(app, Config), + Mods = fetch(modules, App) -- [diameter_codegen, diameter_dbg], + %% Skip modules that aren't required at runtime and that have + %% dependencies beyond those applications listed in the app file. {ok, XRef} = xref:start(make_name(xref_test_name)), ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]), - XRefName = make_name(xref_name), - {ok, XRefName} = xref:add_release(XRef, RootDir, {name, XRefName}), - {ok, _} = xref:replace_application(XRef, ?APP, EbinDir), + %% Only add our application and those it's dependent on according + %% to the app file. Well, almost. erts beams are also required to + %% stop xref from complaining about calls to module erlang, which + %% was previously in kernel. Erts isn't an application however, in + %% the sense that there's no .app file, and isn't listed in + %% applications. Seems less than ideal. + ok = lists:foreach(fun(A) -> add_application(XRef, A) end, + [?APP, erts | fetch(applications, App)]), {ok, Undefs} = xref:analyze(XRef, undefined_function_calls), xref:stop(XRef), + %% Only care about calls from our own application. [] = lists:filter(fun({{M,_,_},_}) -> lists:member(M, Mods) end, Undefs). +add_application(XRef, App) -> + add_application(XRef, App, code:lib_dir(App)). + +%% erts will not be in the lib directory before installation. +add_application(XRef, erts, {error, _}) -> + Dir = filename:join([code:root_dir(), "erts", "preloaded", "ebin"]), + {ok, _} = xref:add_directory(XRef, Dir, []); +add_application(XRef, App, Dir) + when is_list(Dir) -> + {ok, App} = xref:add_application(XRef, Dir, []). + make_name(Suf) -> list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)). -- cgit v1.2.3 From 6708f4e2ee7e05eacd72780bd6ae38cd0944e81b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 12 Sep 2011 17:09:27 +0200 Subject: Minor diameter_ct simplification --- lib/diameter/test/Makefile | 2 +- lib/diameter/test/diameter_ct.erl | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 08a4067cf9..ddf49b4573 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -185,7 +185,7 @@ $(SUITES): log targets $(ERL) -noshell \ -pa ../ebin \ -sname diameter_test_$@ \ - -s diameter_ct run $@ \ + -s diameter_ct run diameter_$@_SUITE \ -s init stop \ | awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}' # Shorter in sed but requires a GNU extension (ie. Q). diff --git a/lib/diameter/test/diameter_ct.erl b/lib/diameter/test/diameter_ct.erl index 6842ca03c5..f8ee3dc1d7 100644 --- a/lib/diameter/test/diameter_ct.erl +++ b/lib/diameter/test/diameter_ct.erl @@ -26,20 +26,16 @@ -export([run/1]). %% ct:run_test/1 is currently documented as returning a list of test -%% results ... but no. Instead it returns the phenomenally useful -%% value 'ok' regardless of whether or not the suite in question has -%% failed testcases. +%% results ... but no. Instead it returns 'ok' regardless of whether +%% or not the suite in question has failed testcases. -run([Name]) -> +run([Suite]) -> Start = info(), - ok = ct:run_test([{suite, suite(Name)}, + ok = ct:run_test([{suite, Suite}, {logdir, "./log"}, {auto_compile, false}]), info(Start , info()). -suite(Name) -> - list_to_atom("diameter_" ++ atom_to_list(Name) ++ "_SUITE"). - info() -> [{time, now()}, {process_count, erlang:system_info(process_count)} -- cgit v1.2.3 From 81f0eeffd5116b7529619b3f4cba1c2ff2144566 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 14 Sep 2011 17:53:23 +0200 Subject: Minor macro cleanup --- lib/diameter/test/diameter_app_SUITE.erl | 3 ++- lib/diameter/test/diameter_codec_SUITE.erl | 3 ++- lib/diameter/test/diameter_dict_SUITE.erl | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 170166d1e6..d710fa155d 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -37,7 +37,8 @@ xref/1, relup/1]). --define(APP, diameter). +-include("diameter_ct.hrl"). + -define(A, list_to_atom). %% =========================================================================== diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index c1b069f447..0c004b3edb 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -38,7 +38,8 @@ gen/1, lib/1]). --define(APP, diameter). +-include("diameter_ct.hrl"). + -define(L, atom_to_list). %% =========================================================================== diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl index 3b61edba58..3db9907074 100644 --- a/lib/diameter/test/diameter_dict_SUITE.erl +++ b/lib/diameter/test/diameter_dict_SUITE.erl @@ -40,7 +40,7 @@ update/1, update_counter/1]). --define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). +-include("diameter_ct.hrl"). -define(dict, diameter_dict). -define(util, diameter_util). -- cgit v1.2.3 From 2c21849168b76b2cece7f14474ed30d9f734d6e4 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 15 Sep 2011 09:56:03 +0200 Subject: Remove gen_sctp suite since it's not diameter-specific --- lib/diameter/test/diameter_gen_sctp_SUITE.erl | 354 ------------------------- lib/diameter/test/diameter_transport_SUITE.erl | 3 +- lib/diameter/test/modules.mk | 3 +- 3 files changed, 2 insertions(+), 358 deletions(-) delete mode 100644 lib/diameter/test/diameter_gen_sctp_SUITE.erl diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl deleted file mode 100644 index be6d28beb2..0000000000 --- a/lib/diameter/test/diameter_gen_sctp_SUITE.erl +++ /dev/null @@ -1,354 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2011. 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% -%% - -%% -%% Some gen_sctp-specific tests demonstrating problems that were -%% encountered during diameter development but have nothing -%% specifically to do with diameter. At least one of them can cause -%% diameter_transport_SUITE testcases to fail. -%% - --module(diameter_gen_sctp_SUITE). - --export([suite/0, - all/0, - init_per_suite/1, - end_per_suite/1]). - -%% testcases --export([send_not_from_controlling_process/1, - send_from_multiple_clients/1, - receive_what_was_sent/1]). - --include_lib("kernel/include/inet_sctp.hrl"). - -%% Message from gen_sctp are of this form. --define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}). - -%% Open sockets on the loopback address. --define(ADDR, {127,0,0,1}). - -%% Snooze, nap, siesta. --define(SLEEP(T), receive after T -> ok end). - -%% An indescribably long number of milliseconds after which everthing -%% that should have happened has. --define(FOREVER, 2000). - -%% The first byte in each message we send as a simple guard against -%% not receiving what was sent. --define(MAGIC, 42). - -%% =========================================================================== - -suite() -> - [{timetrap, {minutes, 2}}]. - -all() -> - [send_not_from_controlling_process, - send_from_multiple_clients, - receive_what_was_sent]. - -init_per_suite(Config) -> - try gen_sctp:open() of - {ok, Sock} -> - gen_sctp:close(Sock), - Config - catch - error: badarg -> - {skip, no_sctp} - end. - -end_per_suite(_Config) -> - ok. - -%% =========================================================================== - -%% send_not_from_controlling_process/1 -%% -%% This testcase failing shows gen_sctp:send/4 hanging when called -%% outside the controlling process of the socket in question. - -send_not_from_controlling_process(_) -> - Pids = send_not_from_controlling_process(), - ?SLEEP(?FOREVER), - try - [] = [{P,I} || P <- Pids, I <- [process_info(P)], I /= undefined] - after - lists:foreach(fun(P) -> exit(P, kill) end, Pids) - end. - -%% send_not_from_controlling_process/0 -%% -%% Returns the pids of three spawned processes: a listening process, a -%% connecting process and a sending process. -%% -%% The expected behaviour is that all three processes exit: -%% -%% - The listening process exits upon receiving an SCTP message -%% sent by the sending process. -%% - The connecting process exits upon listening process exit. -%% - The sending process exits upon gen_sctp:send/4 return. -%% -%% The observed behaviour is that all three processes remain alive -%% indefinitely: -%% -%% - The listening process never receives the SCTP message sent -%% by the sending process. -%% - The connecting process has an inet_reply message in its mailbox -%% as a consequence of the call to gen_sctp:send/4 call from the -%% sending process. -%% - The call to gen_sctp:send/4 in the sending process doesn't return, -%% hanging in prim_inet:getopts/2. - -send_not_from_controlling_process() -> - FPid = self(), - {L, MRef} = spawn_monitor(fun() -> listen(FPid) end),%% listening process - receive - {?MODULE, C, S} -> - erlang:demonitor(MRef, [flush]), - [L,C,S]; - {'DOWN', MRef, process, _, _} = T -> - error(T) - end. - -%% listen/1 - -listen(FPid) -> - {ok, Sock} = open(), - ok = gen_sctp:listen(Sock, true), - {ok, PortNr} = inet:port(Sock), - LPid = self(), - spawn(fun() -> connect1(PortNr, FPid, LPid) end), %% connecting process - Id = assoc(Sock), - ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], _Bin}) - = recv(). %% Waits with this as current_function. - -%% recv/0 - -recv() -> - receive T -> T end. - -%% connect1/3 - -connect1(PortNr, FPid, LPid) -> - {ok, Sock} = open(), - ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), - Id = assoc(Sock), - FPid ! {?MODULE, - self(), - spawn(fun() -> send(Sock, Id) end)}, %% sending process - MRef = erlang:monitor(process, LPid), - down(MRef). %% Waits with this as current_function. - -%% down/1 - -down(MRef) -> - receive {'DOWN', MRef, process, _, Reason} -> Reason end. - -%% send/2 - -send(Sock, Id) -> - ok = gen_sctp:send(Sock, Id, 0, <<0:32>>). - -%% =========================================================================== - -%% send_from_multiple_clients/0 -%% -%% Demonstrates sluggish delivery of messages. - -send_from_multiple_clients(_) -> - {S, Rs} = T = send_from_multiple_clients(8, 1024), - {false, [], _} = {?FOREVER < S, - Rs -- [OI || {O,_} = OI <- Rs, is_integer(O)], - T}. - -%% send_from_multiple_clients/2 -%% -%% Opens a listening socket and then spawns a specified number of -%% processes, each of which connects to the listening socket. Each -%% connecting process then sends a message, whose size in bytes is -%% passed as an argument, the listening process sends a reply -%% containing the time at which the message was received, and the -%% connecting process then exits upon reception of this reply. -%% -%% Returns the elapsed time for all connecting process to exit -%% together with a list of exit reasons for the connecting processes. -%% In the successful case a connecting process exits with the -%% outbound/inbound transit times for the sent/received message as -%% reason. -%% -%% The observed behaviour is that some outbound messages (that is, -%% from a connecting process to the listening process) can take an -%% unexpectedly long time to complete their journey. The more -%% connecting processes, the longer the possible delay it seems. -%% -%% eg. (With F = fun send_from_multiple_clients/2.) -%% -%% 5> F(2, 1024). -%% {875,[{128,116},{113,139}]} -%% 6> F(4, 1024). -%% {2995290,[{2994022,250},{2994071,80},{200,130},{211,113}]} -%% 7> F(8, 1024). -%% {8997461,[{8996161,116}, -%% {2996471,86}, -%% {2996278,116}, -%% {2996360,95}, -%% {246,112}, -%% {213,159}, -%% {373,173}, -%% {376,118}]} -%% 8> F(8, 1024). -%% {21001891,[{20999968,128}, -%% {8997891,172}, -%% {8997927,91}, -%% {2995716,164}, -%% {2995860,87}, -%% {134,100}, -%% {117,98}, -%% {149,125}]} - -send_from_multiple_clients(N, Sz) - when is_integer(N), 0 < N, is_integer(Sz), 0 < Sz -> - timer:tc(fun listen/2, [N, <>]). - -%% listen/2 - -listen(N, Bin) -> - {ok, Sock} = open(), - ok = gen_sctp:listen(Sock, true), - {ok, PortNr} = inet:port(Sock), - - %% Spawn a middleman that in turn spawns N connecting processes, - %% collects a list of exit reasons and then exits with the list as - %% reason. loop/3 returns when we receive this list from the - %% middleman's 'DOWN'. - - Self = self(), - Fun = fun() -> exit(connect2(Self, PortNr, Bin)) end, - {_, MRef} = spawn_monitor(fun() -> exit(fold(N, Fun)) end), - loop(Sock, MRef, Bin). - -%% fold/2 -%% -%% Spawn N processes and collect their exit reasons in a list. - -fold(N, Fun) -> - start(N, Fun), - acc(N, []). - -start(0, _) -> - ok; -start(N, Fun) -> - spawn_monitor(Fun), - start(N-1, Fun). - -acc(0, Acc) -> - Acc; -acc(N, Acc) -> - receive - {'DOWN', _MRef, process, _, RC} -> - acc(N-1, [RC | Acc]) - end. - -%% loop/3 - -loop(Sock, MRef, Bin) -> - receive - ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], B}) -> - Sz = size(Bin), - {Sz, Bin} = {size(B), B}, %% assert - ok = send(Sock, Id, mark(Bin)), - loop(Sock, MRef, Bin); - ?SCTP(Sock, _) -> - loop(Sock, MRef, Bin); - {'DOWN', MRef, process, _, Reason} -> - Reason - end. - -%% connect2/3 - -connect2(Pid, PortNr, Bin) -> - erlang:monitor(process, Pid), - - {ok, Sock} = open(), - ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), - Id = assoc(Sock), - - %% T1 = time before send - %% T2 = time after listening process received our message - %% T3 = time after reply is received - - T1 = now(), - ok = send(Sock, Id, Bin), - T2 = unmark(recv(Sock, Id)), - T3 = now(), - {timer:now_diff(T2, T1), timer:now_diff(T3, T2)}. %% {Outbound, Inbound} - -%% recv/2 - -recv(Sock, Id) -> - receive - ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin}) -> - Bin; - T -> %% eg. 'DOWN' - exit(T) - end. - -%% send/3 - -send(Sock, Id, Bin) -> - gen_sctp:send(Sock, Id, 0, Bin). - -%% mark/1 - -mark(Bin) -> - Info = term_to_binary(now()), - <>. - -%% unmark/1 - -unmark(Bin) -> - {_,_,_} = binary_to_term(Bin). - -%% =========================================================================== - -%% receive_what_was_sent/1 -%% -%% Demonstrates reception of a message that differs from that sent. - -receive_what_was_sent(_Config) -> - send_from_multiple_clients(1, 1024*32). %% fails - -%% =========================================================================== - -%% open/0 - -open() -> - gen_sctp:open([{ip, ?ADDR}, {port, 0}, {active, true}, binary]). - -%% assoc/1 - -assoc(Sock) -> - receive - ?SCTP(Sock, {[], #sctp_assoc_change{state = S, - assoc_id = Id}}) -> - comm_up = S, %% assert - Id - end. diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index 6de6d6bad3..7543a62cad 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -19,8 +19,7 @@ %% %% Tests of diameter_tcp/sctp as implementations of the diameter -%% transport interface. See also the sctp suite for some gen_sctp -%% related issues. +%% transport interface. %% -module(diameter_transport_SUITE). diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 218a70017a..b7177d55d3 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -32,8 +32,7 @@ MODULES = \ diameter_sync_SUITE \ diameter_stats_SUITE \ diameter_watchdog_SUITE \ - diameter_transport_SUITE \ - diameter_gen_sctp_SUITE + diameter_transport_SUITE INTERNAL_HRL_FILES = \ diameter_ct.hrl -- cgit v1.2.3 From cfda2e2834bcb766d8f85777ac61e7cc25e25f4d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 19 Sep 2011 12:30:41 +0200 Subject: Use groups for parallel testcase execution --- lib/diameter/test/diameter_dict_SUITE.erl | 14 +++++++------- lib/diameter/test/diameter_reg_SUITE.erl | 12 ++++++------ lib/diameter/test/diameter_stats_SUITE.erl | 12 ++++++------ lib/diameter/test/diameter_sync_SUITE.erl | 12 ++++++------ lib/diameter/test/diameter_transport_SUITE.erl | 15 ++++++--------- 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl index 3db9907074..170b3c1695 100644 --- a/lib/diameter/test/diameter_dict_SUITE.erl +++ b/lib/diameter/test/diameter_dict_SUITE.erl @@ -24,11 +24,11 @@ -module(diameter_dict_SUITE). -export([suite/0, - all/0]). + all/0, + groups/0]). %% testcases --export([scramble/1, - append/1, +-export([append/1, fetch/1, fetch_keys/1, filter/1, @@ -51,7 +51,10 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [scramble | tc()]. + [{group, all} | tc()]. + +groups() -> + [{all, [parallel], tc()}]. tc() -> [append, @@ -68,9 +71,6 @@ tc() -> %% =========================================================================== -scramble(Config) -> - [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). - -define(KV100, [{N,[N]} || N <- lists:seq(1,100)]). append(_) -> diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl index 5ae6c494e3..83661d48de 100644 --- a/lib/diameter/test/diameter_reg_SUITE.erl +++ b/lib/diameter/test/diameter_reg_SUITE.erl @@ -25,12 +25,12 @@ -export([suite/0, all/0, + groups/0, init_per_suite/1, end_per_suite/1]). %% testcases --export([scramble/1, - add/1, +-export([add/1, add_new/1, del/1, repl/1, @@ -46,7 +46,10 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [scramble | tc()]. + [{group, all} | tc()]. + +groups() -> + [{all, [parallel], tc()}]. tc() -> [add, @@ -65,9 +68,6 @@ end_per_suite(_Config) -> %% =========================================================================== -scramble(Config) -> - [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). - add(_) -> Ref = make_ref(), true = ?reg:add(Ref), diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl index e0bf6b8c4a..85300b0d76 100644 --- a/lib/diameter/test/diameter_stats_SUITE.erl +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -25,12 +25,12 @@ -export([suite/0, all/0, + groups/0, init_per_suite/1, end_per_suite/1]). %% testcases --export([scramble/1, - an/1, +-export([an/1, twa/1]). -define(stat, diameter_stats). @@ -42,7 +42,10 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [scramble | tc()]. + [{group, all} | tc()]. + +groups() -> + [{all, [parallel], tc()}]. tc() -> [an, @@ -57,9 +60,6 @@ end_per_suite(_Config) -> %% =========================================================================== -scramble(Config) -> - [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). - an(_) -> Ref = {'_', make_ref()}, true = ?stat:reg(Ref), diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl index 1b1fec8281..ecd935bd98 100644 --- a/lib/diameter/test/diameter_sync_SUITE.erl +++ b/lib/diameter/test/diameter_sync_SUITE.erl @@ -25,12 +25,12 @@ -export([suite/0, all/0, + groups/0, init_per_suite/1, end_per_suite/1]). %% testcases --export([scramble/1, - call/1, +-export([call/1, cast/1, timeout/1, flush/1]). @@ -46,7 +46,10 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [scramble | tc()]. + [{group, all} | tc()]. + +groups() -> + [{all, [parallel], tc()}]. tc() -> [call, @@ -63,9 +66,6 @@ end_per_suite(_Config) -> %% =========================================================================== -scramble(Config) -> - [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). - call(_) -> Ref = make_ref(), Q = {q, Ref}, diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index 7543a62cad..7c2c1f187e 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -26,12 +26,12 @@ -export([suite/0, all/0, + groups/0, init_per_suite/1, end_per_suite/1]). %% testcases --export([scramble/1, - tcp_accept/1, +-export([tcp_accept/1, tcp_connect/1, sctp_accept/1, sctp_connect/1]). @@ -99,7 +99,10 @@ suite() -> [{timetrap, {minutes, 2}}]. all() -> - [scramble | tc()]. + [{group, all} | tc()]. + +groups() -> + [{all, [parallel], tc()}]. tc() -> [tcp_accept, @@ -114,12 +117,6 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok = diameter:stop(). -%% =========================================================================== -%% scramble/1 - -scramble(Config) -> - [] = ?util:run(?util:scramble([{?MODULE, [F, Config]} || F <- tc()])). - %% =========================================================================== %% tcp_accept/1 %% sctp_accept/1 -- cgit v1.2.3 From f1cfc008d1c10e778fa974521754c59b6dcd8d19 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 22 Sep 2011 19:49:47 +0200 Subject: Add traffic suite --- lib/diameter/test/Makefile | 6 +- lib/diameter/test/depend.sed | 1 + lib/diameter/test/diameter_traffic_SUITE.erl | 607 +++++++++++++++++++++++++++ lib/diameter/test/modules.mk | 3 +- 4 files changed, 614 insertions(+), 3 deletions(-) create mode 100644 lib/diameter/test/diameter_traffic_SUITE.erl diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index ddf49b4573..64e200584f 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -92,7 +92,9 @@ ifeq ($(USE_DIAMETER_HIPE),true) ERL_COMPILE_FLAGS += +native -DDIAMETER_hipe_special=true endif -ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) +ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) \ + -DDIAMETER_CT=true \ + -I $(DIAMETER_TOP)/src/app # ---------------------------------------------------- # Targets @@ -183,7 +185,7 @@ help: # diameter_ct:run/1 itself can't tell (it seems). $(SUITES): log targets $(ERL) -noshell \ - -pa ../ebin \ + -pa $(DIAMETER_TOP)/ebin \ -sname diameter_test_$@ \ -s diameter_ct run diameter_$@_SUITE \ -s init stop \ diff --git a/lib/diameter/test/depend.sed b/lib/diameter/test/depend.sed index effb668e38..a399eb45f0 100644 --- a/lib/diameter/test/depend.sed +++ b/lib/diameter/test/depend.sed @@ -24,6 +24,7 @@ /^-include/!d /^-include_lib/d +/diameter_gen/d s@^-include("@@ s@".*@@ diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl new file mode 100644 index 0000000000..00b2c2c90e --- /dev/null +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -0,0 +1,607 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of traffic between two Diameter nodes, one client, one server. +%% + +-module(diameter_traffic_SUITE). + +-export([suite/0, + all/0, + groups/0, + init_per_suite/1, + end_per_suite/1, + init_per_group/2, + end_per_group/2, + init_per_testcase/2, + end_per_testcase/2]). + +%% testcases +-export([result_codes/1, + send_ok/1, + send_arbitrary/1, + send_unknown/1, + send_unknown_mandatory/1, + send_noreply/1, + send_unsupported/1, + send_unsupported_app/1, + send_error_bit/1, + send_unsupported_version/1, + send_long/1, + send_nopeer/1, + send_noapp/1, + send_discard/1, + send_any/1, + send_all/1, + send_timeout/1, + send_error/1, + send_detach/1, + send_encode_error/1, + remove_transports/1, + stop_services/1]). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/5, pick_peer/6, + prepare_request/4, prepare_request/5, + prepare_retransmit/4, + handle_answer/5, handle_answer/6, + handle_error/5, + handle_request/3]). + +-ifdef(DIAMETER_CT). +-include("diameter_gen_base_rfc3588.hrl"). +-else. +-include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). +-endif. + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_ct.hrl"). + +%% =========================================================================== + +-define(ADDR, {127,0,0,1}). +-define(LISTEN_PORT, 3868). + +-define(CLIENT, "CLIENT"). +-define(SERVER, "SERVER"). + +-define(APP_ALIAS, base). +-define(EXTRA, an_extra_argument). +-define(ENCODINGS, [list, record]). + +-define(DICT, ?DIAMETER_DICT_COMMON). +-define(APP_ID, ?DIAMETER_APP_ID_COMMON). + +%% Config for diameter:start_service/2. +-define(SERVICE(Name), + [{'Origin-Host', Name ++ ".erlang.org"}, + {'Origin-Realm', "erlang.org"}, + {'Host-IP-Address', [?ADDR]}, + {'Vendor-Id', 12345}, + {'Product-Name', "OTP/diameter"}, + {'Acct-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_COMMON}, + {module, ?MODULE}, + {answer_errors, callback}]}]). + +%% Config for diameter:add_transport/2. In the listening case, listen +%% on a free port that we then lookup using the implementation detail +%% that diameter_tcp registers the port with diameter_reg. +-define(CONNECT(PortNr), + {connect, [{transport_module, diameter_tcp}, + {transport_config, [{raddr, ?ADDR}, + {rport, PortNr}, + {ip, ?ADDR}, + {port, 0}]}, + {watchdog_timer, 6000}, + {reconnect_timer, 1000}]}). +-define(LISTEN, + {listen, [{transport_module, diameter_tcp}, + {transport_config, [{ip, ?ADDR}, {port, 0}]}, + {watchdog_timer, 6000}, + {reconnect_timer, 1000}]}). + +-define(SUCCESS, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS'). +-define(COMMAND_UNSUPPORTED, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_COMMAND_UNSUPPORTED'). +-define(TOO_BUSY, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_TOO_BUSY'). +-define(APPLICATION_UNSUPPORTED, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_APPLICATION_UNSUPPORTED'). +-define(INVALID_HDR_BITS, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_INVALID_HDR_BITS'). +-define(AVP_UNSUPPORTED, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_AVP_UNSUPPORTED'). +-define(UNSUPPORTED_VERSION, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_UNSUPPORTED_VERSION'). + +-define(EVENT_RECORD, + ?'DIAMETER_BASE_ACCOUNTING-RECORD-TYPE_EVENT_RECORD'). +-define(AUTHORIZE_ONLY, + ?'DIAMETER_BASE_RE-AUTH-REQUEST-TYPE_AUTHORIZE_ONLY'). +-define(AUTHORIZE_AUTHENTICATE, + ?'DIAMETER_BASE_RE-AUTH-REQUEST-TYPE_AUTHORIZE_AUTHENTICATE'). + +-define(LOGOUT, + ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). +-define(BAD_ANSWER, + ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_BAD_ANSWER'). + +-define(A, list_to_atom). +-define(L, atom_to_list). +-define(P(N), ?A("p_" ++ ?L(N))). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [result_codes | [{group, N} || {N, _, _} <- groups()]] + ++ [remove_transports, stop_services]. + +groups() -> + Ts = tc(), + [{E, [], Ts} || E <- ?ENCODINGS] + ++ [{?P(E), [parallel], Ts} || E <- ?ENCODINGS]. + +init_per_suite(Config) -> + ok = diameter:start(), + ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)), + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)), + {ok, LRef} = diameter:add_transport(?SERVER, ?LISTEN), + true = diameter:subscribe(?CLIENT), + {ok, CRef} = diameter:add_transport(?CLIENT, ?CONNECT(portnr())), + #diameter_event{service = ?CLIENT, + info = {up, CRef, _Peer, _Config, #diameter_packet{}}} + = receive #diameter_event{service = ?CLIENT} = E -> E + after 2000 -> false + end, + true = diameter:unsubscribe(?CLIENT), + [{transports, {LRef, CRef}} | Config]. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +init_per_group(Name, Config) -> + E = case ?L(Name) of + "p_" ++ Rest -> + ?A(Rest); + _ -> + Name + end, + [{encode, E} | Config]. + +end_per_group(_, _) -> + ok. + +init_per_testcase(Name, Config) -> + [{testcase, Name} | Config]. + +end_per_testcase(_, _) -> + ok. + +%% Testcases to run when services are started and connections +%% established. +tc() -> + [send_ok, + send_arbitrary, + send_unknown, + send_unknown_mandatory, + send_noreply, + send_unsupported, + send_unsupported_app, + send_error_bit, + send_unsupported_version, + send_long, + send_nopeer, + send_noapp, + send_discard, + send_any, + send_all, + send_timeout, + send_error, + send_detach, + send_encode_error]. + +portnr() -> + portnr(10). + +portnr(N) + when 0 < N -> + case diameter_reg:match({diameter_tcp, listener, '_'}) of + [{T, _Pid}] -> + {_, _, {_LRef, {_Addr, LSock}}} = T, + {ok, PortNr} = inet:port(LSock), + PortNr; + [] -> + receive after 50 -> ok end, + portnr(N-1) + end. + +%% =========================================================================== + +%% Ensure that result codes have the expected values. +result_codes(_Config) -> + {2001, 3001, 3004, 3007, 3008, 5001, 5011} + = {?SUCCESS, + ?COMMAND_UNSUPPORTED, + ?TOO_BUSY, + ?APPLICATION_UNSUPPORTED, + ?INVALID_HDR_BITS, + ?AVP_UNSUPPORTED, + ?UNSUPPORTED_VERSION}. + +%% Send an ACR and expect success. +send_ok(Config) -> + Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD}, + {'Accounting-Record-Number', 1}], + #diameter_base_ACA{'Result-Code' = ?SUCCESS} + = call(Config, Req). + +%% Send an ASR with an arbitrary AVP and expect success and the same +%% AVP in the reply. +send_arbitrary(Config) -> + Req = ['ASR', {'AVP', [#diameter_avp{name = 'Class', value = "XXX"}]}], + #diameter_base_ASA{'Result-Code' = ?SUCCESS, + 'AVP' = Avps} + = call(Config, Req), + [#diameter_avp{name = 'Class', + value = "XXX"}] + = Avps. + +%% Send an unknown AVP (to some client) and check that it comes back. +send_unknown(Config) -> + Req = ['ASR', {'AVP', [#diameter_avp{code = 999, + is_mandatory = false, + data = <<17>>}]}], + #diameter_base_ASA{'Result-Code' = ?SUCCESS, + 'AVP' = Avps} + = call(Config, Req), + [#diameter_avp{code = 999, + is_mandatory = false, + data = <<17>>}] + = Avps. + +%% Ditto but set the M flag. +send_unknown_mandatory(Config) -> + Req = ['ASR', {'AVP', [#diameter_avp{code = 999, + is_mandatory = true, + data = <<17>>}]}], + #diameter_base_ASA{'Result-Code' = ?AVP_UNSUPPORTED, + 'Failed-AVP' = Failed} + = call(Config, Req), + [#'diameter_base_Failed-AVP'{'AVP' = Avps}] = Failed, + [#diameter_avp{code = 999, + is_mandatory = true, + data = <<17>>}] + = Avps. + +%% Send an STR that the server ignores. +send_noreply(Config) -> + Req = ['STR', {'Termination-Cause', ?BAD_ANSWER}], + {error, timeout} = call(Config, Req). + +%% Send an unsupported command and expect 3001. +send_unsupported(Config) -> + Req = ['STR', {'Termination-Cause', ?BAD_ANSWER}], + #'diameter_base_answer-message'{'Result-Code' = ?COMMAND_UNSUPPORTED} + = call(Config, Req). + +%% Send an unsupported command and expect 3007. +send_unsupported_app(Config) -> + Req = ['STR', {'Termination-Cause', ?BAD_ANSWER}], + #'diameter_base_answer-message'{'Result-Code' = ?APPLICATION_UNSUPPORTED} + = call(Config, Req). + +%% Send a request with the E bit set and expect 3008. +send_error_bit(Config) -> + Req = ['STR', {'Termination-Cause', ?BAD_ANSWER}], + #'diameter_base_answer-message'{'Result-Code' = ?INVALID_HDR_BITS} + = call(Config, Req). + +%% Send a bad version and check that we get 5011. +send_unsupported_version(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + #diameter_base_STA{'Result-Code' = ?UNSUPPORTED_VERSION} + = call(Config, Req). + +%% Send something long that will be fragmented by TCP. +send_long(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'User-Name', [lists:duplicate(1 bsl 20, $X)]}], + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = call(Config, Req). + +%% Send something for which pick_peer finds no suitable peer. +send_nopeer(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + {error, no_connection} = call(Config, Req, [{extra, [?EXTRA]}]). + +%% Send something on an unconfigured application. +send_noapp(_Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + {error, no_connection} = diameter:call(?CLIENT, unknown_alias, Req). + +%% Send something that's discarded by prepare_request. +send_discard(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + {error, unprepared} = call(Config, Req). + +%% Send something using a filter that doesn't match any peer. +send_any(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + {error, no_connection} = call(Config, Req, [{filter, {any, []}}]). + +%% Success with a non-trivial filter. +send_all(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = call(Config, Req, [{filter, {all, []}}]). + +%% Timeout before the server manages an answer. +send_timeout(Config) -> + Req = ['RAR', {'Re-Auth-Request-Type', ?AUTHORIZE_ONLY}], + {error, timeout} = call(Config, Req, [{timeout, 1000}]). + +%% Explicitly answer with an answer-message and ensure that we +%% received the Session-Id. +send_error(Config) -> + Req = ['RAR', {'Re-Auth-Request-Type', ?AUTHORIZE_AUTHENTICATE}], + #'diameter_base_answer-message'{'Result-Code' = ?TOO_BUSY, + 'Session-Id' = SId} + = call(Config, Req), + undefined /= SId. + +%% Send a request with the detached option and receive it as a message +%% from handle_answer instead. +send_detach(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + Ref = make_ref(), + ok = call(Config, Req, [{extra, [{self(), Ref}]}, detach]), + #diameter_packet{msg = Rec, errors = []} + = receive {Ref, T} -> T after 2000 -> false end, + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = Rec. + +%% Send a request which can't be encoded and expect {error, encode}. +send_encode_error(Config) -> + {error, encode} = call(Config, ['STR']). %% No Termination-Cause + +remove_transports(Config) -> + {LRef, CRef} = proplists:get_value(transports, Config), + true = diameter:subscribe(?SERVER), + ok = diameter:remove_transport(?CLIENT, CRef), + {down, LRef, _, _} + = receive #diameter_event{service = ?SERVER, info = I} -> I + after 5000 -> false + end. + +stop_services(_Config) -> + {ok, ok} = {diameter:stop_service(?CLIENT), diameter:stop_service(?SERVER)}. + +%% =========================================================================== + +call(Config, Req) -> + call(Config, Req, []). + +call(Config, Req, Opts) -> + Name = proplists:get_value(testcase, Config), + Enc = proplists:get_value(encode, Config), + diameter:call(?CLIENT, + ?APP_ALIAS, + msg(Req, Enc), + [{extra, [Name]} | Opts]). + +msg(L, list) -> + L; +msg([H|T], record) -> + ?DICT:'#new-'(?DICT:msg2rec(H), T). + +set(L, Vs) + when is_list(L) -> + L ++ Vs; +set(Rec, Vs) -> + ?DICT:'#set-'(Vs, Rec). + +%% =========================================================================== +%% diameter callbacks + +%% peer_up/3 + +peer_up(_SvcName, _Peer, State) -> + State. + +%% peer_down/3 + +peer_down(_SvcName, _Peer, State) -> + State. + +%% pick_peer/5/6 + +pick_peer([Peer], _, ?CLIENT, _State, Name) + when Name /= send_detach -> + {ok, Peer}. + +pick_peer([_Peer], _, ?CLIENT, _State, send_nopeer, ?EXTRA) -> + false; + +pick_peer([Peer], _, ?CLIENT, _State, send_detach, {_,_}) -> + {ok, Peer}. + +%% prepare_request/4/5 + +prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name) -> + prepare(Pkt, Caps, Name). + +prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, _) -> + {send, prepare(Pkt, Caps)}. + +prepare(Pkt, Caps, send_unsupported) -> + Req = prepare(Pkt, Caps), + #diameter_packet{bin = <>} + = E + = diameter_codec:encode(?DICT, Pkt#diameter_packet{msg = Req}), + {send, E#diameter_packet{bin = <>}}; + +prepare(Pkt, Caps, send_unsupported_app) -> + Req = prepare(Pkt, Caps), + #diameter_packet{bin = <>} + = E + = diameter_codec:encode(?DICT, Pkt#diameter_packet{msg = Req}), + {send, E#diameter_packet{bin = <>}}; + +prepare(Pkg, Caps, send_error_bit) -> + #diameter_packet{header = Hdr} = Pkg, + {send, Pkg#diameter_packet{header = Hdr#diameter_header{is_error = true}, + msg = prepare(Pkg, Caps)}}; + +prepare(Pkg, Caps, send_unsupported_version) -> + #diameter_packet{header = Hdr} = Pkg, + {send, Pkg#diameter_packet{header = Hdr#diameter_header{version = 42}, + msg = prepare(Pkg, Caps)}}; + +prepare(_Pkg, _Caps, send_discard) -> + {discard, unprepared}; + +prepare(Pkg, Caps, _Name) -> + {send, prepare(Pkg, Caps)}. + +prepare(#diameter_packet{msg = Req}, Caps) + when is_record(Req, diameter_base_ACR); + 'ACR' == hd(Req) -> + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, DR}} + = Caps, + + set(Req, [{'Session-Id', diameter:session_id(OH)}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Realm', DR}]); + +prepare(#diameter_packet{msg = Req}, Caps) + when is_record(Req, diameter_base_ASR); + 'ASR' == hd(Req) -> + #diameter_caps{origin_host = {OH, DH}, + origin_realm = {OR, DR}} + = Caps, + set(Req, [{'Session-Id', diameter:session_id(OH)}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Host', DH}, + {'Destination-Realm', DR}, + {'Auth-Application-Id', ?APP_ID}]); + +prepare(#diameter_packet{msg = Req}, Caps) + when is_record(Req, diameter_base_STR); + 'STR' == hd(Req) -> + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, DR}} + = Caps, + set(Req, [{'Session-Id', diameter:session_id(OH)}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Realm', DR}, + {'Auth-Application-Id', ?APP_ID}]); + +prepare(#diameter_packet{msg = Req}, Caps) + when is_record(Req, diameter_base_RAR); + 'RAR' == hd(Req) -> + #diameter_caps{origin_host = {OH, DH}, + origin_realm = {OR, DR}} + = Caps, + set(Req, [{'Session-Id', diameter:session_id(OH)}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Host', DH}, + {'Destination-Realm', DR}, + {'Auth-Application-Id', ?APP_ID}]). + +%% prepare_retransmit/4 + +prepare_retransmit(_Pkt, false, _Peer, _Name) -> + discard. + +%% handle_answer/5/6 + +handle_answer(Pkt, Req, ?CLIENT, Peer, Name) -> + answer(Pkt, Req, Peer, Name). + +handle_answer(Pkt, _Req, ?CLIENT, _Peer, send_detach, {Pid, Ref}) -> + Pid ! {Ref, Pkt}. + +answer(#diameter_packet{msg = Rec, errors = []}, _Req, _Peer, _) -> + Rec. + +%% handle_error/5 + +handle_error(Reason, _Req, ?CLIENT, _Peer, _Name) -> + {error, Reason}. + +%% handle_request/3 + +%% Note that diameter will set Result-Code and Failed-AVPs if +%% #diameter_packet.errors is non-null. + +handle_request(Pkt, ?SERVER, {_Ref, Caps}) -> + request(Pkt, Caps). + +request(#diameter_packet{msg + = #diameter_base_ACR{'Session-Id' = SId, + 'Accounting-Record-Type' = RT, + 'Accounting-Record-Number' = RN}}, + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, _}}) -> + {reply, ['ACA', {'Result-Code', ?SUCCESS}, + {'Session-Id', SId}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Accounting-Record-Type', RT}, + {'Accounting-Record-Number', RN}]}; + +request(#diameter_packet{msg = #diameter_base_ASR{'Session-Id' = SId, + 'AVP' = Avps}}, + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, _}}) -> + {reply, #diameter_base_ASA{'Result-Code' = ?SUCCESS, + 'Session-Id' = SId, + 'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'AVP' = Avps}}; + +request(#diameter_packet{msg = #diameter_base_STR{'Termination-Cause' = ?LOGOUT, + 'Session-Id' = SId}}, + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, _}}) -> + {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS, + 'Session-Id' = SId, + 'Origin-Host' = OH, + 'Origin-Realm' = OR}}; + +request(#diameter_packet{msg = #diameter_base_STR{}}, _Caps) -> + discard; + +request(#diameter_packet{msg = #diameter_base_RAR{}}, _Caps) -> + receive after 2000 -> ok end, + {protocol_error, ?TOO_BUSY}. diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index b7177d55d3..f84ec45d52 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -32,7 +32,8 @@ MODULES = \ diameter_sync_SUITE \ diameter_stats_SUITE \ diameter_watchdog_SUITE \ - diameter_transport_SUITE + diameter_transport_SUITE \ + diameter_traffic_SUITE INTERNAL_HRL_FILES = \ diameter_ct.hrl -- cgit v1.2.3 From a271b2dacdcaf56d903c6fbaeeffe1aea5cf1522 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sat, 24 Sep 2011 21:54:18 +0200 Subject: More traffic cases --- lib/diameter/test/diameter_traffic_SUITE.erl | 294 +++++++++++++++++++++------ 1 file changed, 233 insertions(+), 61 deletions(-) diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 00b2c2c90e..8c85323222 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -48,12 +48,30 @@ send_nopeer/1, send_noapp/1, send_discard/1, - send_any/1, - send_all/1, + send_any_1/1, + send_any_2/1, + send_all_1/1, + send_all_2/1, send_timeout/1, send_error/1, send_detach/1, send_encode_error/1, + send_destination_1/1, + send_destination_2/1, + send_destination_3/1, + send_destination_4/1, + send_destination_5/1, + send_destination_6/1, + send_bad_option_1/1, + send_bad_option_2/1, + send_bad_filter_1/1, + send_bad_filter_2/1, + send_bad_filter_3/1, + send_bad_filter_4/1, + send_multiple_filters_1/1, + send_multiple_filters_2/1, + send_multiple_filters_3/1, + send_anything/1, remove_transports/1, stop_services/1]). @@ -79,10 +97,11 @@ %% =========================================================================== -define(ADDR, {127,0,0,1}). --define(LISTEN_PORT, 3868). -define(CLIENT, "CLIENT"). -define(SERVER, "SERVER"). +-define(REALM, "erlang.org"). +-define(HOST(Host, Realm), Host ++ [$.|Realm]). -define(APP_ALIAS, base). -define(EXTRA, an_extra_argument). @@ -93,8 +112,8 @@ %% Config for diameter:start_service/2. -define(SERVICE(Name), - [{'Origin-Host', Name ++ ".erlang.org"}, - {'Origin-Realm', "erlang.org"}, + [{'Origin-Host', Name ++ "." ++ ?REALM}, + {'Origin-Realm', ?REALM}, {'Host-IP-Address', [?ADDR]}, {'Vendor-Id', 12345}, {'Product-Name', "OTP/diameter"}, @@ -112,14 +131,10 @@ {transport_config, [{raddr, ?ADDR}, {rport, PortNr}, {ip, ?ADDR}, - {port, 0}]}, - {watchdog_timer, 6000}, - {reconnect_timer, 1000}]}). + {port, 0}]}]}). -define(LISTEN, {listen, [{transport_module, diameter_tcp}, - {transport_config, [{ip, ?ADDR}, {port, 0}]}, - {watchdog_timer, 6000}, - {reconnect_timer, 1000}]}). + {transport_config, [{ip, ?ADDR}, {port, 0}]}]}). -define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS'). @@ -135,6 +150,10 @@ ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_AVP_UNSUPPORTED'). -define(UNSUPPORTED_VERSION, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_UNSUPPORTED_VERSION'). +-define(REALM_NOT_SERVED, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_REALM_NOT_SERVED'). +-define(UNABLE_TO_DELIVER, + ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_UNABLE_TO_DELIVER'). -define(EVENT_RECORD, ?'DIAMETER_BASE_ACCOUNTING-RECORD-TYPE_EVENT_RECORD'). @@ -173,9 +192,8 @@ init_per_suite(Config) -> {ok, LRef} = diameter:add_transport(?SERVER, ?LISTEN), true = diameter:subscribe(?CLIENT), {ok, CRef} = diameter:add_transport(?CLIENT, ?CONNECT(portnr())), - #diameter_event{service = ?CLIENT, - info = {up, CRef, _Peer, _Config, #diameter_packet{}}} - = receive #diameter_event{service = ?CLIENT} = E -> E + {up, CRef, _Peer, _Config, #diameter_packet{}} + = receive #diameter_event{service = ?CLIENT, info = I} -> I after 2000 -> false end, true = diameter:unsubscribe(?CLIENT), @@ -218,15 +236,33 @@ tc() -> send_nopeer, send_noapp, send_discard, - send_any, - send_all, + send_any_1, + send_any_2, + send_all_1, + send_all_2, send_timeout, send_error, send_detach, - send_encode_error]. + send_encode_error, + send_destination_1, + send_destination_2, + send_destination_3, + send_destination_4, + send_destination_5, + send_destination_6, + send_bad_option_1, + send_bad_option_2, + send_bad_filter_1, + send_bad_filter_2, + send_bad_filter_3, + send_bad_filter_4, + send_multiple_filters_1, + send_multiple_filters_2, + send_multiple_filters_3, + send_anything]. portnr() -> - portnr(10). + portnr(20). portnr(N) when 0 < N -> @@ -244,9 +280,11 @@ portnr(N) %% Ensure that result codes have the expected values. result_codes(_Config) -> - {2001, 3001, 3004, 3007, 3008, 5001, 5011} + {2001, 3001, 3002, 3003, 3004, 3007, 3008, 5001, 5011} = {?SUCCESS, ?COMMAND_UNSUPPORTED, + ?UNABLE_TO_DELIVER, + ?REALM_NOT_SERVED, ?TOO_BUSY, ?APPLICATION_UNSUPPORTED, ?INVALID_HDR_BITS, @@ -349,16 +387,28 @@ send_discard(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], {error, unprepared} = call(Config, Req). -%% Send something using a filter that doesn't match any peer. -send_any(Config) -> +%% Send with a disjunctive filter. +send_any_1(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], {error, no_connection} = call(Config, Req, [{filter, {any, []}}]). +send_any_2(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Host', [?HOST(?SERVER, "unknown.org")]}], + #'diameter_base_answer-message'{'Result-Code' = ?UNABLE_TO_DELIVER} + = call(Config, Req, [{filter, {any, [host, realm]}}]). -%% Success with a non-trivial filter. -send_all(Config) -> +%% Send with a conjunctive filter. +send_all_1(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}], + Realm = lists:foldr(fun(C,A) -> [C,A] end, [], ?REALM), #diameter_base_STA{'Result-Code' = ?SUCCESS} - = call(Config, Req, [{filter, {all, []}}]). + = call(Config, Req, [{filter, {all, [{host, any}, + {realm, Realm}]}}]). +send_all_2(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Host', [?HOST(?SERVER, "unknown.org")]}], + {error, no_connection} + = call(Config, Req, [{filter, {all, [host, realm]}}]). %% Timeout before the server manages an answer. send_timeout(Config) -> @@ -389,17 +439,113 @@ send_detach(Config) -> send_encode_error(Config) -> {error, encode} = call(Config, ['STR']). %% No Termination-Cause +%% Send with filtering and expect success. +send_destination_1(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Host', [?HOST(?SERVER, ?REALM)]}], + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = call(Config, Req, [{filter, {all, [host, realm]}}]). +send_destination_2(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = call(Config, Req, [{filter, {all, [host, realm]}}]). + +%% Send with filtering on and expect failure when specifying an +%% unknown host or realm. +send_destination_3(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Realm', "unknown.org"}], + {error, no_connection} + = call(Config, Req, [{filter, {all, [host, realm]}}]). +send_destination_4(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Host', [?HOST(?SERVER, "unknown.org")]}], + {error, no_connection} + = call(Config, Req, [{filter, {all, [host, realm]}}]). + +%% Send without filtering and expect an error answer when specifying +%% an unknown host or realm. +send_destination_5(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Realm', "unknown.org"}], + #'diameter_base_answer-message'{'Result-Code' = ?REALM_NOT_SERVED} + = call(Config, Req). +send_destination_6(Config) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}, + {'Destination-Host', [?HOST(?SERVER, "unknown.org")]}], + #'diameter_base_answer-message'{'Result-Code' = ?UNABLE_TO_DELIVER} + = call(Config, Req). + +%% Specify an invalid option and expect failure. +send_bad_option_1(Config) -> + send_bad_option(Config, x). +send_bad_option_2(Config) -> + send_bad_option(Config, {extra, false}). + +send_bad_option(Config, Opt) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + try call(Config, Req, [Opt]) of + T -> erlang:error({?MODULE, ?LINE, T}) + catch + error: _ -> ok + end. + +%% Specify an invalid filter and expect no matching peers. +send_bad_filter_1(Config) -> + send_bad_filter(Config, {all, none}). +send_bad_filter_2(Config) -> + send_bad_filter(Config, {host, x}). +send_bad_filter_3(Config) -> + send_bad_filter(Config, {eval, fun() -> true end}). +send_bad_filter_4(Config) -> + send_bad_filter(Config, {eval, {?MODULE, not_exported, []}}). + +send_bad_filter(Config, F) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + {error, no_connection} = call(Config, Req, [{filter, F}]). + +%% Specify multiple filter options and expect them be conjunctive. +send_multiple_filters_1(Config) -> + Fun = fun(#diameter_caps{}) -> true end, + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = send_multiple_filters(Config, [host, {eval, Fun}]). +send_multiple_filters_2(Config) -> + E = {erlang, is_tuple, []}, + {error, no_connection} + = send_multiple_filters(Config, [realm, {neg, {eval, E}}]). +send_multiple_filters_3(Config) -> + E1 = [fun(#diameter_caps{}, ok) -> true end, ok], + E2 = {erlang, is_tuple, []}, + E3 = {erlang, is_record, [diameter_caps]}, + E4 = [{erlang, is_record, []}, diameter_caps], + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = send_multiple_filters(Config, [{eval, E} || E <- [E1,E2,E3,E4]]). + +send_multiple_filters(Config, Fs) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + call(Config, Req, [{filter, F} || F <- Fs]). + +%% Ensure that we can pass a request in any form to diameter:call/4, +%% only the return value from the prepare_request callback being +%% significant. +send_anything(Config) -> + #diameter_base_STA{'Result-Code' = ?SUCCESS} + = call(Config, anything). + +%% Remove the client transport and expect the server transport to +%% go down. remove_transports(Config) -> {LRef, CRef} = proplists:get_value(transports, Config), true = diameter:subscribe(?SERVER), ok = diameter:remove_transport(?CLIENT, CRef), {down, LRef, _, _} = receive #diameter_event{service = ?SERVER, info = I} -> I - after 5000 -> false + after 2000 -> false end. stop_services(_Config) -> - {ok, ok} = {diameter:stop_service(?CLIENT), diameter:stop_service(?SERVER)}. + {ok, ok} = {diameter:stop_service(?CLIENT), + diameter:stop_service(?SERVER)}. %% =========================================================================== @@ -414,16 +560,27 @@ call(Config, Req, Opts) -> msg(Req, Enc), [{extra, [Name]} | Opts]). -msg(L, list) -> +msg([_|_] = L, list) -> L; msg([H|T], record) -> - ?DICT:'#new-'(?DICT:msg2rec(H), T). + ?DICT:'#new-'(?DICT:msg2rec(H), T); +msg(T, _) -> + T. -set(L, Vs) - when is_list(L) -> - L ++ Vs; +%% Set only values that aren't already. +set([H|T], Vs) -> + [H | Vs ++ T]; set(Rec, Vs) -> - ?DICT:'#set-'(Vs, Rec). + lists:foldl(fun({F,_} = FV, A) -> set(?DICT:'#get-'(F, A), FV, A) end, + Rec, + Vs). + +set(E, FV, Rec) + when E == undefined; + E == [] -> + ?DICT:'#set-'(FV, Rec); +set(_, _, Rec) -> + Rec. %% =========================================================================== %% diameter callbacks @@ -452,8 +609,11 @@ pick_peer([Peer], _, ?CLIENT, _State, send_detach, {_,_}) -> %% prepare_request/4/5 +prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, send_discard) -> + {discard, unprepared}; + prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name) -> - prepare(Pkt, Caps, Name). + {send, prepare(Pkt, Caps, Name)}. prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, _) -> {send, prepare(Pkt, Caps)}. @@ -463,64 +623,65 @@ prepare(Pkt, Caps, send_unsupported) -> #diameter_packet{bin = <>} = E = diameter_codec:encode(?DICT, Pkt#diameter_packet{msg = Req}), - {send, E#diameter_packet{bin = <>}}; + E#diameter_packet{bin = <>}; prepare(Pkt, Caps, send_unsupported_app) -> Req = prepare(Pkt, Caps), #diameter_packet{bin = <>} = E = diameter_codec:encode(?DICT, Pkt#diameter_packet{msg = Req}), - {send, E#diameter_packet{bin = <>}}; + E#diameter_packet{bin = <>}; -prepare(Pkg, Caps, send_error_bit) -> - #diameter_packet{header = Hdr} = Pkg, - {send, Pkg#diameter_packet{header = Hdr#diameter_header{is_error = true}, - msg = prepare(Pkg, Caps)}}; +prepare(Pkt, Caps, send_error_bit) -> + #diameter_packet{header = Hdr} = Pkt, + Pkt#diameter_packet{header = Hdr#diameter_header{is_error = true}, + msg = prepare(Pkt, Caps)}; -prepare(Pkg, Caps, send_unsupported_version) -> - #diameter_packet{header = Hdr} = Pkg, - {send, Pkg#diameter_packet{header = Hdr#diameter_header{version = 42}, - msg = prepare(Pkg, Caps)}}; +prepare(Pkt, Caps, send_unsupported_version) -> + #diameter_packet{header = Hdr} = Pkt, + Pkt#diameter_packet{header = Hdr#diameter_header{version = 42}, + msg = prepare(Pkt, Caps)}; -prepare(_Pkg, _Caps, send_discard) -> - {discard, unprepared}; +prepare(Pkt, Caps, send_anything) -> + Req = ['STR', {'Termination-Cause', ?LOGOUT}], + prepare(Pkt#diameter_packet{msg = Req}, Caps); -prepare(Pkg, Caps, _Name) -> - {send, prepare(Pkg, Caps)}. +prepare(Pkt, Caps, _Name) -> + prepare(Pkt, Caps). prepare(#diameter_packet{msg = Req}, Caps) when is_record(Req, diameter_base_ACR); 'ACR' == hd(Req) -> - #diameter_caps{origin_host = {OH, _}, + #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, DR}} = Caps, set(Req, [{'Session-Id', diameter:session_id(OH)}, - {'Origin-Host', OH}, + {'Origin-Host', OH}, {'Origin-Realm', OR}, {'Destination-Realm', DR}]); prepare(#diameter_packet{msg = Req}, Caps) when is_record(Req, diameter_base_ASR); 'ASR' == hd(Req) -> - #diameter_caps{origin_host = {OH, DH}, + #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, set(Req, [{'Session-Id', diameter:session_id(OH)}, - {'Origin-Host', OH}, + {'Origin-Host', OH}, {'Origin-Realm', OR}, - {'Destination-Host', DH}, + {'Destination-Host', DH}, {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]); prepare(#diameter_packet{msg = Req}, Caps) when is_record(Req, diameter_base_STR); 'STR' == hd(Req) -> - #diameter_caps{origin_host = {OH, _}, + #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, DR}} = Caps, set(Req, [{'Session-Id', diameter:session_id(OH)}, - {'Origin-Host', OH}, + {'Origin-Host', OH}, {'Origin-Realm', OR}, {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]); @@ -532,9 +693,9 @@ prepare(#diameter_packet{msg = Req}, Caps) origin_realm = {OR, DR}} = Caps, set(Req, [{'Session-Id', diameter:session_id(OH)}, - {'Origin-Host', OH}, + {'Origin-Host', OH}, {'Origin-Realm', OR}, - {'Destination-Host', DH}, + {'Destination-Host', DH}, {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]). @@ -590,8 +751,22 @@ request(#diameter_packet{msg = #diameter_base_ASR{'Session-Id' = SId, 'Origin-Realm' = OR, 'AVP' = Avps}}; -request(#diameter_packet{msg = #diameter_base_STR{'Termination-Cause' = ?LOGOUT, - 'Session-Id' = SId}}, +request(#diameter_packet{msg = #diameter_base_STR{'Termination-Cause' = T}}, + _Caps) + when T /= ?LOGOUT -> + discard; + +request(#diameter_packet{msg = #diameter_base_STR{'Destination-Realm'= R}}, + #diameter_caps{origin_realm = {OR, _}}) + when R /= undefined, R /= OR -> + {protocol_error, ?REALM_NOT_SERVED}; + +request(#diameter_packet{msg = #diameter_base_STR{'Destination-Host'= [H]}}, + #diameter_caps{origin_host = {OH, _}}) + when H /= OH -> + {protocol_error, ?UNABLE_TO_DELIVER}; + +request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId}}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS, @@ -599,9 +774,6 @@ request(#diameter_packet{msg = #diameter_base_STR{'Termination-Cause' = ?LOGOUT, 'Origin-Host' = OH, 'Origin-Realm' = OR}}; -request(#diameter_packet{msg = #diameter_base_STR{}}, _Caps) -> - discard; - request(#diameter_packet{msg = #diameter_base_RAR{}}, _Caps) -> receive after 2000 -> ok end, {protocol_error, ?TOO_BUSY}. -- cgit v1.2.3 From e46c9a0c949b9961f3d6942537c800e486e101e9 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Mon, 26 Sep 2011 17:22:56 +0200 Subject: Prepare release --- lib/crypto/doc/src/notes.xml | 15 +++++++++++++++ lib/crypto/vsn.mk | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index a5434ebd68..55f8cc90ca 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -30,6 +30,21 @@

This document describes the changes made to the Crypto application.

+
Crypto 2.0.3.1 + +
Improvements and New Features + + +

+ crypto changed to be dynamically linked against OpenSSL

+

+ Own Id: OTP-9566 Aux Id: seq11912

+
+
+
+ +
+
Crypto 2.0.3
Fixed Bugs and Malfunctions diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index e754aabc44..547c33c07f 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.3 +CRYPTO_VSN = 2.0.3.1 -- cgit v1.2.3 From 2ba082f42a77d901b5306d15f05e1717ad137e00 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 23 Sep 2011 17:25:08 +0200 Subject: Use single format for error_logger reports --- lib/diameter/src/app/diameter_config.erl | 11 +++----- lib/diameter/src/app/diameter_internal.hrl | 23 +++-------------- lib/diameter/src/app/diameter_peer.erl | 11 +++----- lib/diameter/src/app/diameter_reg.erl | 12 +++------ lib/diameter/src/app/diameter_service.erl | 11 +++++--- lib/diameter/src/app/diameter_stats.erl | 11 +++----- lib/diameter/src/app/diameter_sync.erl | 35 +++++++++++--------------- lib/diameter/src/compiler/diameter_codegen.erl | 1 - 8 files changed, 39 insertions(+), 76 deletions(-) diff --git a/lib/diameter/src/app/diameter_config.erl b/lib/diameter/src/app/diameter_config.erl index 42c70890b3..a6b48fe65b 100644 --- a/lib/diameter/src/app/diameter_config.erl +++ b/lib/diameter/src/app/diameter_config.erl @@ -267,7 +267,7 @@ handle_call(uptime, _, #state{id = Time} = State) -> {reply, diameter_lib:now_diff(Time), State}; handle_call(Req, From, State) -> - warning_msg("received unexpected request from ~p:~n~w", [From, Req]), + ?UNEXPECTED([Req, From]), Reply = {error, {bad_request, Req}}, {reply, Reply, State}. @@ -276,7 +276,7 @@ handle_call(Req, From, State) -> %%% ---------------------------------------------------------- handle_cast(Msg, State) -> - warning_msg("received unexpected message:~n~w", [Msg]), + ?UNEXPECTED([Msg]), {noreply, State}. %%% ---------------------------------------------------------- @@ -309,7 +309,7 @@ handle_info(restart, State) -> {noreply, State}; handle_info(Info, State) -> - warning_msg("received unknown info:~n~w", [Info]), + ?UNEXPECTED([Info]), {noreply, State}. %%-------------------------------------------------------------------- @@ -674,8 +674,3 @@ cb(M,F) -> call(Request) -> gen_server:call(?SERVER, Request, infinity). - -%% warning_msg/2 - -warning_msg(F, A) -> - ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_internal.hrl b/lib/diameter/src/app/diameter_internal.hrl index 9de3914830..78645b1912 100644 --- a/lib/diameter/src/app/diameter_internal.hrl +++ b/lib/diameter/src/app/diameter_internal.hrl @@ -37,9 +37,10 @@ %% Failure reports always get a stack trace. -define(STACK, erlang:get_stacktrace()). -%% Info report for anything unexpected. --define(REPORT(Reason, Func, Args), - diameter_lib:report(Reason, {?MODULE, Func, Args})). +%% Warning report for unexpected messages in various processes. +-define(UNEXPECTED(F,A), + diameter_lib:warning_report(unexpected, {?MODULE, F, A})). +-define(UNEXPECTED(A), ?UNEXPECTED(?FUNC, A)). %% Something to trace on. -define(LOG(Slogan, Details), @@ -77,19 +78,3 @@ server_id, is_dynamic, expiration}). - -%%%---------------------------------------------------------------------- -%%% Error/warning/info message macro(s) -%%%---------------------------------------------------------------------- - --define(diameter_info(F, A), - (catch error_logger:info_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n", - [?APPLICATION, ?MODULE, self()|A]))). - --define(diameter_warning(F, A), - (catch error_logger:warning_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n", - [?APPLICATION, ?MODULE, self()|A]))). - --define(diameter_error(F, A), - (catch error_logger:error_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n", - [?APPLICATION, ?MODULE, self()|A]))). diff --git a/lib/diameter/src/app/diameter_peer.erl b/lib/diameter/src/app/diameter_peer.erl index 6b8971b8ea..3e78c4caef 100644 --- a/lib/diameter/src/app/diameter_peer.erl +++ b/lib/diameter/src/app/diameter_peer.erl @@ -148,7 +148,7 @@ handle_call(uptime, _, #state{id = Time} = State) -> {reply, diameter_lib:now_diff(Time), State}; handle_call(Req, From, State) -> - warning_msg("received unexpected request from ~p:~n~w", [From, Req]), + ?UNEXPECTED([Req, From]), {reply, nok, State}. %%% ---------------------------------------------------------- @@ -156,7 +156,7 @@ handle_call(Req, From, State) -> %%% ---------------------------------------------------------- handle_cast(Msg, State) -> - warning_msg("received unexpected message:~n~w", [Msg]), + ?UNEXPECTED([Msg]), {noreply, State}. %%% ---------------------------------------------------------- @@ -169,7 +169,7 @@ handle_info({notify, SvcName, T}, S) -> {noreply, S}; handle_info(Info, State) -> - warning_msg("received unexpected info:~n~w", [Info]), + ?UNEXPECTED([Info]), {noreply, State}. %% ---------------------------------------------------------- @@ -223,8 +223,3 @@ value([], V) -> call(Request) -> gen_server:call(?SERVER, Request, infinity). - -%% warning_msg/2 - -warning_msg(F, A) -> - ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_reg.erl b/lib/diameter/src/app/diameter_reg.erl index 8e5f34c2c3..882b9da238 100644 --- a/lib/diameter/src/app/diameter_reg.erl +++ b/lib/diameter/src/app/diameter_reg.erl @@ -243,7 +243,8 @@ handle_call(state, _, State) -> handle_call(uptime, _, #state{id = Time} = State) -> {reply, diameter_lib:now_diff(Time), State}; -handle_call(_Req, _From, State) -> +handle_call(Req, From, State) -> + ?UNEXPECTED([Req, From]), {reply, nok, State}. %%% ---------------------------------------------------------- @@ -251,7 +252,7 @@ handle_call(_Req, _From, State) -> %%% ---------------------------------------------------------- handle_cast(Msg, State)-> - warning_msg("received unexpected message:~n~w", [Msg]), + ?UNEXPECTED([Msg]), {noreply, State}. %%% ---------------------------------------------------------- @@ -264,7 +265,7 @@ handle_info({'DOWN', MRef, process, Pid, _}, State) -> {noreply, State}; handle_info(Info, State) -> - warning_msg("received unknown info:~n~w", [Info]), + ?UNEXPECTED([Info]), {noreply, State}. %%% ---------------------------------------------------------- @@ -324,8 +325,3 @@ repl([], _, _) -> call(Request) -> gen_server:call(?SERVER, Request, infinity). - -%% warning_msg/2 - -warning_msg(F, A) -> - ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl index 63b0649dc4..45e6b90d14 100644 --- a/lib/diameter/src/app/diameter_service.erl +++ b/lib/diameter/src/app/diameter_service.erl @@ -463,7 +463,7 @@ handle_call(stop, _From, S) -> %% stating a monitor that waits for DOWN before returning. handle_call(Req, From, S) -> - ?REPORT(unknown_request, ?FUNC, [Req, From]), + unexpected(handle_call, [Req, From], S), {reply, nok, S}. %%% --------------------------------------------------------------------------- @@ -471,7 +471,7 @@ handle_call(Req, From, S) -> %%% --------------------------------------------------------------------------- handle_cast(Req, S) -> - ?REPORT(unknown_request, ?FUNC, [Req]), + unexpected(handle_cast, [Req], S), {noreply, S}. %%% --------------------------------------------------------------------------- @@ -553,8 +553,8 @@ transition({failover, TRef, Seqs}, S) -> failover(TRef, Seqs, S), ok; -transition(Req, _) -> - ?REPORT(unknown_request, ?FUNC, [Req]), +transition(Req, S) -> + unexpected(handle_info, [Req], S), ok. %%% --------------------------------------------------------------------------- @@ -591,6 +591,9 @@ code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) -> %% =========================================================================== %% =========================================================================== +unexpected(F, A, #state{service_name = Name}) -> + ?UNEXPECTED(F, A ++ [Name]). + cb([_|_] = M, F, A) -> eval(M, F, A); cb(Rec, F, A) -> diff --git a/lib/diameter/src/app/diameter_stats.erl b/lib/diameter/src/app/diameter_stats.erl index b52d4cdcfb..71479afa95 100644 --- a/lib/diameter/src/app/diameter_stats.erl +++ b/lib/diameter/src/app/diameter_stats.erl @@ -207,7 +207,7 @@ handle_call({flush, Contrib}, _From, State) -> {reply, fetch(Contrib), State}; handle_call(Req, From, State) -> - warning_msg("received unexpected request from ~p:~n~w", [From, Req]), + ?UNEXPECTED([Req, From]), {reply, nok, State}. %% ---------------------------------------------------------- @@ -219,7 +219,7 @@ handle_cast({incr, Rec}, State) -> {noreply, State}; handle_cast(Msg, State) -> - warning_msg("received unexpected message:~n~w", [Msg]), + ?UNEXPECTED([Msg]), {noreply, State}. %% ---------------------------------------------------------- @@ -231,7 +231,7 @@ handle_info({'DOWN', _MRef, process, Pid, _}, State) -> {noreply, State}; handle_info(Info, State) -> - warning_msg("received unknown info:~n~w", [Info]), + ?UNEXPECTED([Info]), {noreply, State}. %% ---------------------------------------------------------- @@ -340,8 +340,3 @@ cast(Msg) -> call(Request) -> gen_server:call(?SERVER, Request, infinity). - -%% warning_msg/2 - -warning_msg(F, A) -> - ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_sync.erl b/lib/diameter/src/app/diameter_sync.erl index f7777ae809..ce2db4b3a2 100644 --- a/lib/diameter/src/app/diameter_sync.erl +++ b/lib/diameter/src/app/diameter_sync.erl @@ -204,37 +204,37 @@ handle_call(?REQUEST(Type, Name, Req, Max, Timeout), T = find(Name, QD), nq(queued(T) =< Max, T, {Type, From}, Name, Req, Timeout, State); -handle_call(Request, _From, State) -> - {reply, call(Request, State), State}. +handle_call(Request, From, State) -> + {reply, call(Request, From, State), State}. -%% call/2 +%% call/3 -call(?CARP(Name), #state{queue = QD}) -> +call(?CARP(Name), _, #state{queue = QD}) -> pcar(find(Name, QD)); -call(state, State) -> +call(state, _, State) -> State; -call(uptime, #state{time = T}) -> +call(uptime, _, #state{time = T}) -> diameter_lib:now_diff(T); -call({flush, Name}, #state{queue = QD}) -> +call({flush, Name}, _, #state{queue = QD}) -> cancel(find(Name, QD)); -call(pending, #state{pending = N}) -> +call(pending, _, #state{pending = N}) -> N; -call({pending, Name}, #state{queue = QD}) -> +call({pending, Name}, _, #state{queue = QD}) -> queued(find(Name, QD)); -call(queues, #state{queue = QD}) -> +call(queues, _, #state{queue = QD}) -> fetch_keys(QD); -call({pids, Name}, #state{queue = QD}) -> +call({pids, Name}, _, #state{queue = QD}) -> plist(find(Name, QD)); -call(Req, _State) -> %% ignore - warning_msg("received unexpected request:~n~w", [Req]), +call(Req, From, _State) -> %% ignore + ?UNEXPECTED(handle_call, [Req, From]), nok. %%% ---------------------------------------------------------- @@ -242,7 +242,7 @@ call(Req, _State) -> %% ignore %%% ---------------------------------------------------------- handle_cast(Msg, State) -> - warning_msg("received unexpected message:~n~w", [Msg]), + ?UNEXPECTED([Msg]), {noreply, State}. %%% ---------------------------------------------------------- @@ -267,7 +267,7 @@ info({'DOWN', MRef, process, Pid, Info}, queue = dq(fetch(Name, QD), Pid, Info, Name, QD)}; info(Info, State) -> - warning_msg("received unknown info:~n~w", [Info]), + ?UNEXPECTED(handle_info, [Info]), State. reply({call, From}, T) -> @@ -548,8 +548,3 @@ gen_call(Server, Req, Timeout) -> exit: _ -> timeout end. - -%% warning_msg/2 - -warning_msg(F, A) -> - ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index 30caebc544..a33b07a3d3 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -37,7 +37,6 @@ file/2, file/3]). --include_lib("diameter/src/app/diameter_internal.hrl"). -include("diameter_forms.hrl"). %% Generated functions that could have no generated clauses will have -- cgit v1.2.3 From 657c9991dd4b87234cddcc389a527ef99e76dfd4 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 23 Sep 2011 18:27:51 +0200 Subject: Remove duplicate info from error report at encode failure The message being encoded and dictionary module are included by diameter_codec.erl so diameter_gen.hrl doing so was overkill. --- lib/diameter/include/diameter_gen.hrl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl index 4c91954a21..d037e1044a 100644 --- a/lib/diameter/include/diameter_gen.hrl +++ b/lib/diameter/include/diameter_gen.hrl @@ -44,14 +44,14 @@ encode_avps(Name, Rec) -> ?MODULE, ?LINE, {Reason, Name, Rec}), - erlang:error(list_to_tuple(Reason ++ [Name, Rec, ?MODULE])); + erlang:error(list_to_tuple(Reason ++ [Name])); error: Reason -> Stack = erlang:get_stacktrace(), diameter_dbg:log({encode, failure}, ?MODULE, ?LINE, {Reason, Name, Rec, Stack}), - erlang:error({encode_failure, Reason, Name, Rec, ?MODULE, Stack}) + erlang:error({encode_failure, Reason, Name, Stack}) end. %% encode/2 -- cgit v1.2.3 From 06a771d3d8915baeaad3908d8056eba45609d32d Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 23 Sep 2011 18:52:14 +0200 Subject: Makefile dependency fix Dependency of generated dictionary modules on diameter.hrl and diameter_gen.hrl was missed. --- lib/diameter/src/app/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile index 6de220d282..229466e264 100644 --- a/lib/diameter/src/app/Makefile +++ b/lib/diameter/src/app/Makefile @@ -181,6 +181,10 @@ release_docs_spec: # Dependencies # ---------------------------------------------------- +$(SPEC_FILES:%.dia=$(EBIN)/%.$(EMULATOR)): \ + $(DIAMETER_TOP)/include/diameter.hrl \ + $(DIAMETER_TOP)/include/diameter_gen.hrl + depend: depend.mk # Generate dependencies makefile. It's assumed that the compile target -- cgit v1.2.3 From fbb8586af3dd74b52ecdfa74d758f14cb82683fd Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 26 Sep 2011 00:21:08 +0200 Subject: Fix and clarify relay behaviour Leave it up to a handle_request callback to decide whether or not to filter the peer from which the incoming request was sent. Reply with 3002 (DIAMETER_UNABLE_TO_DELIVER) on anything but an answer from the peer. --- lib/diameter/doc/src/diameter_app.xml | 40 ++++++++------- lib/diameter/src/app/diameter_service.erl | 83 +++++++++++++------------------ 2 files changed, 55 insertions(+), 68 deletions(-) diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml index fc359b9d1d..a3d9a8eeac 100644 --- a/lib/diameter/doc/src/diameter_app.xml +++ b/lib/diameter/doc/src/diameter_app.xml @@ -467,11 +467,11 @@ callback returned false.

Packet = packet() SvcName = term() Peer = peer() -Action = Reply | {relay, Opts} | discard | {eval, Action, ContF} +Action = Reply | {relay, Opts} | discard | {eval, Action, PostF} Reply = {reply, message()} | {protocol_error, 3000..3999} Opts = diameter:call_opts() -ContF = diameter:evaluable() +PostF = diameter:evaluable()

@@ -559,26 +559,28 @@ will cause the request process in question to fail.

{relay, Opts}

-Relay a request to another peer. -The appropriate Route-Record AVP will be added to the relayed request -by diameter and pick_peer/4 -and prepare_request/3 -callback will take place just as if pick_peer/4 +and subsequent callbacks take place just as if diameter:call/4 had been called explicitly. -However, returning a relay tuple also causes the End-to-End -Identifier to be preserved in the header of the relayed request as -required by RFC 3588.

+The End-to-End Identifier of the incoming request is preserved in the +header of the relayed request.

-The returned Opts should not specify detach and -the handle_answer/4 -callback following from a relayed request must return its first +The returned Opts should not specify detach. +A subsequent handle_answer/4 +callback for the relayed request must return its first argument, the diameter_packet record containing the answer message. Note that the extra option can be specified to supply arguments -that can distinguish the relay case from others if so desired, -although the form of the request message may be sufficient.

+that can distinguish the relay case from others if so desired. +Any other return value (for example, from a +handle_error/4 callback) +causes the request to be answered with 3002 (DIAMETER_UNABLE_TO_DELIVER).

discard @@ -587,18 +589,18 @@ although the form of the request message may be sufficient.

Discard the request.

-{eval, Action, ContF} +{eval, Action, PostF}

Handle the request as if Action has been returned and then -evaluate ContF in the request process.

+evaluate PostF in the request process.

-Note that diameter will respond to protocol errors in an incoming -request without invoking handle_request/3.

+Note that protocol errors detected by diameter will result in an +answer message without handle_request/3 being invoked.

diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl index 63b0649dc4..b7b9ac1ef4 100644 --- a/lib/diameter/src/app/diameter_service.erl +++ b/lib/diameter/src/app/diameter_service.erl @@ -1685,9 +1685,9 @@ recv_request({Id, Alias}, T, TPid, Apps, Caps, Pkt) -> %% DIAMETER_APPLICATION_UNSUPPORTED 3007 %% A request was sent for an application that is not supported. -recv_request(false, {_, OH, OR}, TPid, _, _, Pkt) -> - ?LOG({error, application}, Pkt), - reply(answer_message({OH, OR, 3007}, collect_avps(Pkt)), ?BASE, TPid, Pkt). +recv_request(false, T, TPid, _, _, Pkt) -> + As = collect_avps(Pkt), + protocol_error(3007, T, TPid, Pkt#diameter_packet{avps = As}). collect_avps(Pkt) -> case diameter_codec:collect_avps(Pkt) of @@ -1706,13 +1706,9 @@ collect_avps(Pkt) -> %% set to an unrecognized value, or that is inconsistent with the %% AVP's definition. %% -recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _], - bin = Bin, - avps = Avps} - = Pkt) +recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt) when is_bitstring(Bs) -> - ?LOG({error, invalid_avp_bits}, Bin), - reply(answer_message({OH, OR, 3009}, Avps), ?BASE, TPid, Pkt); + protocol_error(3009, T, TPid, Pkt); %% Either we support this application but don't recognize the command %% or we're a relay and the command isn't proxiable. @@ -1722,18 +1718,15 @@ recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _], %% recognize or support. This MUST be used when a Diameter node %% receives an experimental command that it does not understand. %% -recv_request({_, OH, OR}, +recv_request(T, {TPid, _}, #diameter_app{id = Id}, #diameter_packet{header = #diameter_header{is_proxiable = P}, - msg = M, - avps = Avps, - bin = Bin} + msg = M} = Pkt) when ?APP_ID_RELAY /= Id, undefined == M; ?APP_ID_RELAY == Id, not P -> - ?LOG({error, command_unsupported}, Bin), - reply(answer_message({OH, OR, 3001}, Avps), ?BASE, TPid, Pkt); + protocol_error(3001, T, TPid, Pkt); %% Error bit was set on a request. %% @@ -1742,15 +1735,12 @@ recv_request({_, OH, OR}, %% either set to an invalid combination, or to a value that is %% inconsistent with the command code's definition. %% -recv_request({_, OH, OR}, +recv_request(T, {TPid, _}, _, - #diameter_packet{header = #diameter_header{is_error = true}, - avps = Avps, - bin = Bin} + #diameter_packet{header = #diameter_header{is_error = true}} = Pkt) -> - ?LOG({error, error_bit}, Bin), - reply(answer_message({OH, OR, 3008}, Avps), ?BASE, TPid, Pkt); + protocol_error(3008, T, TPid, Pkt); %% A message in a locally supported application or a proxiable message %% in the relay application. Don't distinguish between the two since @@ -1878,7 +1868,7 @@ resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop resend(false, Opts, App, - {SvcName, _, _}, + {SvcName, _, _} = T, {TPid, #diameter_caps{origin_host = {_, OH}}}, #diameter_packet{header = Hdr0, avps = Avps} @@ -1887,46 +1877,41 @@ resend(false, Seq = diameter_session:sequence(), Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq}, Msg = [Hdr, Route | Avps], - %% Filter sender as ineligible receiver. - reply(call(SvcName, App, Msg, [{filter, {neg, {host, OH}}} | Opts]), - TPid, - Pkt). + resend(call(SvcName, App, Msg, Opts), T, TPid, Pkt). %% The incoming request is relayed with the addition of a -%% Route-Record. Note the requirement on the return from call/4. -%% This places a requirement on the values returned by the -%% handle_answer and handle_error callbacks of the application module -%% in question. +%% Route-Record. Note the requirement on the return from call/4 below, +%% which places a requirement on the value returned by the +%% handle_answer callback of the application module in question. +%% +%% Note that there's nothing stopping the request from being relayed +%% back to the sender. A pick_peer callback may want to avoid this but +%% a smart peer might recognize the potential loop and choose another +%% route. A less smart one will probably just relay the request back +%% again and force us to detect the loop. A pick_peer that wants to +%% avoid this can specify filter to avoid the possibility. +%% Eg. {neg, {host, OH} where #diameter_caps{origin_host = {OH, _}}. %% %% RFC 6.3 says that a relay agent does not modify Origin-Host but %% says nothing about a proxy. Assume it should behave the same way. -%% reply/3 +%% resend/4 %% %% Relay a reply to a relayed request. %% Answer from the peer: reset the hop by hop identifier and send. -reply(#diameter_packet{bin = B} - = Pkt, - TPid, - #diameter_packet{header = #diameter_header{hop_by_hop_id = Id}, - transport_data = TD}) -> +resend(#diameter_packet{bin = B} + = Pkt, + _, + TPid, + #diameter_packet{header = #diameter_header{hop_by_hop_id = Id}, + transport_data = TD}) -> send(TPid, Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B), transport_data = TD}); %% TODO: counters -%% Not. Ignoring the error feels harsh but there is no appropriate -%% Result-Code for a protocol error (which this isn't really anyway) -%% and the RFC doesn't provide any guidance how to act. A weakness -%% here is that we don't deal well with a decode error: the request -%% will simply timeout on the peer's end. Better would be to just send -%% the answer (with modified hop by hop identifier) on regardless, at -%% least in the relay case in which there's no examination of the -%% answer. In the proxy case it's not clear that the callback won't -%% examine the answer. Just be quiet here since a decode error causes -%% the request process to crash (or not depending on the error and -%% config and/or handle_answer callback). -reply(_, _, _) -> - ok. +%% Or not: DIAMETER_UNABLE_TO_DELIVER. +resend(_, T, TPid, Pkt) -> + protocol_error(3002, T, TPid, Pkt). %% is_loop/4 %% -- cgit v1.2.3 From 4a64f3a7d64e3aae364508054c0c1a9273db2301 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 22 Sep 2011 19:59:03 +0200 Subject: Fix bugs in sending of answer-message replies 3001 (DIAMETER_COMMAND_UNSUPPORTED) was not sent since the decode placed the AVP list in the errors field rather than the avps field of the diameter_packet, causing the subsequent encode to fail. Session-Id was also set improperly, causing encode to fail even in this case. --- lib/diameter/src/app/diameter_codec.erl | 22 +++++++--------------- lib/diameter/src/app/diameter_service.erl | 28 +++++++--------------------- 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/lib/diameter/src/app/diameter_codec.erl b/lib/diameter/src/app/diameter_codec.erl index f6cbde5446..d88f42fb7c 100644 --- a/lib/diameter/src/app/diameter_codec.erl +++ b/lib/diameter/src/app/diameter_codec.erl @@ -140,10 +140,10 @@ make_flags(Flags0, #diameter_header{is_request = R, mf(undefined, F, _) -> F; mf(B, F, N) -> %% reset the affected bit - (F bxor (F band (1 bsl N))) bor (bit(B) bsl N). + (F bxor (F band (1 bsl N))) bor bit(B, N). -bit(true) -> 1; -bit(false) -> 0. +bit(true, N) -> 1 bsl N; +bit(false, _) -> 0. %% values/1 @@ -199,25 +199,16 @@ msg_header(Mod, MsgName, Header) -> p(Flags, #diameter_header{is_request = true, is_proxiable = P}) -> - Flags bor choose(P, 2#01000000, 0); + Flags band (2#10110000 bor choose(P, 2#01000000, 0)); p(Flags, _) -> Flags. -%% The header below is that of the incoming request being answered, -%% not of the answer (which hasn't been encoded yet). - h(Mod, 'answer-message' = MsgName, Header) -> ?BASE = Mod, - #diameter_header{is_request = true, - cmd_code = Code} - = Header, + #diameter_header{cmd_code = Code} = Header, {_, Flags, ApplId} = ?BASE:msg_header(MsgName), {Code, Flags, ApplId}; -h(Mod, MsgName, #diameter_header{is_request = true, - cmd_code = Code}) -> - {Code, _, _} = Mod:msg_header(MsgName); %% ensure Code - h(Mod, MsgName, _) -> Mod:msg_header(MsgName). @@ -290,7 +281,8 @@ decode_avps(MsgName, Mod, Pkt, {Bs, Avps}) -> %% invalid avp bits ... decode_avps('', Mod, Pkt, Avps) -> %% unknown message ... ?LOG(unknown, {Mod, Pkt#diameter_packet.header}), - Pkt#diameter_packet{errors = lists:reverse(Avps)}; + Pkt#diameter_packet{avps = lists:reverse(Avps), + errors = [3001]}; %% DIAMETER_COMMAND_UNSUPPORTED %% msg = undefined identifies this case. decode_avps(MsgName, Mod, Pkt, Avps) -> %% ... or not diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl index 63b0649dc4..01a125fdc7 100644 --- a/lib/diameter/src/app/diameter_service.erl +++ b/lib/diameter/src/app/diameter_service.erl @@ -1971,24 +1971,20 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) -> %% make_reply_packet/2 +%% Binaries and header/avp lists are sent as-is. make_reply_packet(Bin, _) when is_binary(Bin) -> #diameter_packet{bin = Bin}; - make_reply_packet([#diameter_header{} | _] = Msg, _) -> #diameter_packet{msg = Msg}; +%% Otherwise a reply message clears the R and T flags and retains the +%% P flag. The E flag will be set at encode. make_reply_packet(Msg, #diameter_packet{header = ReqHdr}) -> - #diameter_header{end_to_end_id = EId, - hop_by_hop_id = Hid, - is_proxiable = P} - = ReqHdr, - - Hdr = #diameter_header{version = ?DIAMETER_VERSION, - end_to_end_id = EId, - hop_by_hop_id = Hid, - is_proxiable = P, - is_retransmitted = false}, + Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION, + is_request = false, + is_error = undefined, + is_retransmitted = false}, #diameter_packet{header = Hdr, msg = Msg}. @@ -2123,16 +2119,6 @@ answer_message({OH, OR, RC}, Avps) -> {'Result-Code', RC} | session_id(Code, Vid, Avps)]. -session_id(Code, Vid, Avps) - when is_list(Avps) -> - try - {value, #diameter_avp{} = Avp} = find_avp(Code, Vid, Avps), - Avp - catch - error: _ -> - [] - end; - session_id(Code, Vid, Avps) when is_list(Avps) -> try -- cgit v1.2.3 From 5f7725dc581c7891cb41e725db50076d654511ba Mon Sep 17 00:00:00 2001 From: Ben Murphy Date: Mon, 26 Sep 2011 08:39:18 +0100 Subject: fix unknown ssl extension parsing by changing length from bits to bytes --- lib/ssl/src/ssl_handshake.erl | 6 +++- lib/ssl/test/Makefile | 5 +-- lib/ssl/test/ssl_handshake_SUITE.erl | 67 ++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 lib/ssl/test/ssl_handshake_SUITE.erl diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 453ea20f99..0ac1ba9d66 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -39,6 +39,8 @@ encode_handshake/2, init_hashes/0, update_hashes/2, decrypt_premaster_secret/2]). +-export([dec_hello_extensions/2]). + -type tls_handshake() :: #client_hello{} | #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} | #client_key_exchange{} | #finished{} | #certificate_verify{} | @@ -912,9 +914,11 @@ dec_hello_extensions(<>, Acc) -> +dec_hello_extensions(<>, Acc) -> dec_hello_extensions(Rest, Acc); %% Need this clause? +%% I don't think we need this clause anymore. It was previously catching parsing errors caused by the missing /binary. +%% Maybe we should be logging an error somewhere because we really should not be entering this clause. dec_hello_extensions(_, Acc) -> Acc. diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 5be07cad2c..922abea41b 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -35,8 +35,9 @@ VSN=$(GS_VSN) # ---------------------------------------------------- MODULES = \ - ssl_test_lib \ + ssl_test_lib \ ssl_basic_SUITE \ + ssl_handshake_SUITE \ ssl_packet_SUITE \ ssl_payload_SUITE \ ssl_to_openssl_SUITE \ @@ -45,7 +46,7 @@ MODULES = \ old_ssl_active_SUITE \ old_ssl_active_once_SUITE \ old_ssl_passive_SUITE \ - old_ssl_verify_SUITE \ + old_ssl_verify_SUITE \ old_ssl_peer_cert_SUITE \ old_ssl_misc_SUITE \ old_ssl_protocol_SUITE \ diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl new file mode 100644 index 0000000000..08c23b2d47 --- /dev/null +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -0,0 +1,67 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2011. 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(ssl_handshake_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include("ssl_internal.hrl"). +-include("ssl_handshake.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> [ + decode_hello_handshake, + decode_single_hello_extension_correctly, + decode_unknown_hello_extension_correctly]. + +decode_hello_handshake(_Config) -> + HelloPacket = <<16#02, 16#00, 16#00, + 16#44, 16#03, 16#03, 16#4e, 16#7f, 16#c1, 16#03, 16#35, + 16#c2, 16#07, 16#b9, 16#4a, 16#58, 16#af, 16#34, 16#07, + 16#a6, 16#7e, 16#ef, 16#52, 16#cb, 16#e0, 16#ea, 16#b7, + 16#aa, 16#47, 16#c8, 16#c2, 16#2c, 16#66, 16#fa, 16#f8, + 16#09, 16#42, 16#cf, 16#00, 16#c0, 16#30, 16#00, 16#00, + 16#1c, + 16#00, 16#0b, 16#00, 16#04, 16#03, 16#00, 16#01, 16#02, % ec_point_formats + 16#ff, 16#01, 16#00, 16#01, 16#00, %% renegotiate + 16#00, 16#23, + 16#00, 16#00, 16#33, 16#74, 16#00, 16#07, 16#06, 16#73, + 16#70, 16#64, 16#79, 16#2f, 16#32>>, + + {Records, _Buffer} = ssl_handshake:get_tls_handshake(HelloPacket, <<>>), + + {Hello, _Data} = hd(Records), + #renegotiation_info{renegotiated_connection = <<0>>} = Hello#server_hello.renegotiation_info. + +decode_single_hello_extension_correctly(_Config) -> + Renegotiation = <>, + Extensions = ssl_handshake:dec_hello_extensions(Renegotiation, []), + [{renegotiation_info,#renegotiation_info{renegotiated_connection = <<0>>}}] = Extensions. + + +decode_unknown_hello_extension_correctly(_Config) -> + FourByteUnknown = <<16#CA,16#FE, ?UINT16(4), 3, 0, 1, 2>>, + Renegotiation = <>, + Extensions = ssl_handshake:dec_hello_extensions(<>, []), + [{renegotiation_info,#renegotiation_info{renegotiated_connection = <<0>>}}] = Extensions. + -- cgit v1.2.3 From bc4362edacedb40c6edb9e855aa234c066b8292f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 27 Sep 2011 08:51:51 +0200 Subject: beam_lib: Handle rare race in the crypto key server functionality In rare circumstances, there can be a race when the crypto key server is started by beam_lib:crypto_key_fun/1 shortly after stopping it using beam_lib:clear_crypto_key_fun/0. The race occurs because the crypto key server first sends back the reply to the calling process, then terminates. (The race is probably more likely to happen on CPUs with hyper threading.) --- lib/stdlib/src/beam_lib.erl | 14 +++++++++----- lib/stdlib/test/beam_lib_SUITE.erl | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl index d9c645d787..fdfbb2e998 100644 --- a/lib/stdlib/src/beam_lib.erl +++ b/lib/stdlib/src/beam_lib.erl @@ -893,13 +893,17 @@ call_crypto_server(Req) -> gen_server:call(?CRYPTO_KEY_SERVER, Req, infinity) catch exit:{noproc,_} -> - start_crypto_server(), - erlang:yield(), - call_crypto_server(Req) + %% Not started. + call_crypto_server_1(Req); + exit:{normal,_} -> + %% The process finished just as we called it. + call_crypto_server_1(Req) end. -start_crypto_server() -> - gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []). +call_crypto_server_1(Req) -> + gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []), + erlang:yield(), + call_crypto_server(Req). -spec init([]) -> {'ok', #state{}}. diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl index 91fff3cee4..27520a5c88 100644 --- a/lib/stdlib/test/beam_lib_SUITE.erl +++ b/lib/stdlib/test/beam_lib_SUITE.erl @@ -571,8 +571,18 @@ do_encrypted_abstr(Beam, Key) -> ?line {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]), ?line {ok,cleared} = beam_lib:clear_crypto_key_fun(), + + %% Try to force a stop/start race. + ?line start_stop_race(10000), + ok. +start_stop_race(0) -> + ok; +start_stop_race(N) -> + {error,_} = beam_lib:crypto_key_fun(bad_fun), + undefined = beam_lib:clear_crypto_key_fun(), + start_stop_race(N-1). bad_fun(F) -> {error,E} = beam_lib:crypto_key_fun(F), -- cgit v1.2.3 From 9a80440b68ca6ad37c962ecc333ff37fb7903ae6 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 25 Sep 2011 03:57:21 +0200 Subject: Add relay suite --- lib/diameter/test/diameter_relay_SUITE.erl | 414 +++++++++++++++++++++++++++++ lib/diameter/test/modules.mk | 3 +- 2 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 lib/diameter/test/diameter_relay_SUITE.erl diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl new file mode 100644 index 0000000000..cd53fbfd90 --- /dev/null +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -0,0 +1,414 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of traffic between seven Diameter nodes connected as follows. +%% +%% --- SERVER1.REALM2 +%% / +%% ---- RELAY.REALM2 ---- SERVER2.REALM2 +%% / | +%% CLIENT.REALM1 | +%% \ | +%% ---- RELAY.REALM3 ---- SERVER2.REALM3 +%% \ +%% --- SERVER2.REALM3 +%% + +-module(diameter_relay_SUITE). + +-export([suite/0, + all/0, + groups/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([send1/1, + send2/1, + send3/1, + send4/1, + send_loop/1, + send_timeout_1/1, + send_timeout_2/1, + remove_transports/1, + stop_services/1]). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-ifdef(DIAMETER_CT). +-include("diameter_gen_base_rfc3588.hrl"). +-else. +-include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). +-endif. + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_ct.hrl"). + +%% =========================================================================== + +-define(ADDR, {127,0,0,1}). + +-define(CLIENT, "CLIENT.REALM1"). +-define(RELAY1, "RELAY.REALM2"). +-define(SERVER1, "SERVER1.REALM2"). +-define(SERVER2, "SERVER2.REALM2"). +-define(RELAY2, "RELAY.REALM3"). +-define(SERVER3, "SERVER1.REALM3"). +-define(SERVER4, "SERVER2.REALM3"). + +-define(DICT_COMMON, ?DIAMETER_DICT_COMMON). +-define(DICT_RELAY, ?DIAMETER_DICT_RELAY). + +-define(APP_ALIAS, the_app). +-define(APP_ID, ?DICT_COMMON:id()). + +%% Config for diameter:start_service/2. +-define(SERVICE(Host, Dict), + [{'Origin-Host', Host}, + {'Origin-Realm', realm(Host)}, + {'Host-IP-Address', [?ADDR]}, + {'Vendor-Id', 12345}, + {'Product-Name', "OTP/diameter"}, + {'Acct-Application-Id', [Dict:id()]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, Dict}, + {module, ?MODULE}, + {answer_errors, callback}]}]). + +%% Config for diameter:add_transport/2. In the listening case, listen +%% on a free port that we then lookup using the implementation detail +%% that diameter_tcp registers the port with diameter_reg. +-define(CONNECT(PortNr), + {connect, [{transport_module, diameter_tcp}, + {transport_config, [{raddr, ?ADDR}, + {rport, PortNr}, + {ip, ?ADDR}, + {port, 0}]}]}). +-define(LISTEN, + {listen, [{transport_module, diameter_tcp}, + {transport_config, [{ip, ?ADDR}, {port, 0}]}]}). + +-define(SUCCESS, 2001). +-define(LOOP_DETECTED, 3005). +-define(UNABLE_TO_DELIVER, 3002). + +-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). +-define(AUTHORIZE_ONLY, ?'DIAMETER_BASE_RE-AUTH-REQUEST-TYPE_AUTHORIZE_ONLY'). + +-define(A, list_to_atom). +-define(L, atom_to_list). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [{group, N} || {N, _, _} <- groups()] + ++ [remove_transports, stop_services]. + +groups() -> + Ts = tc(), + [{all, [], Ts}, + {p, [parallel], Ts}]. + +init_per_suite(Config) -> + ok = diameter:start(), + + dbg:tracer(port, dbg:trace_port(file, "relay.dbg")), + dbg:p(all,c), + dbg:tpl(diameter_service, x), + dbg:tp(?MODULE, x), + + + [S1,S2,S3,S4] = S = [server(N, ?DICT_COMMON) || N <- [?SERVER1, + ?SERVER2, + ?SERVER3, + ?SERVER4]], + [R1,R2] = R = [server(N, ?DICT_RELAY) || N <- [?RELAY1, ?RELAY2]], + + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)), + + true = diameter:subscribe(?RELAY1), + true = diameter:subscribe(?RELAY2), + true = diameter:subscribe(?CLIENT), + + [C1,C2] = connect(?RELAY1, [S1,S2]), + [C3,C4] = connect(?RELAY2, [S3,S4]), + [C5,C6] = connect(?CLIENT, [R1,R2]), + + C7 = connect(?RELAY1, R2), + + [{transports, {S, R, [C1,C2,C3,C4,C5,C6,C7]}} | Config]. + +end_per_suite(_Config) -> + ok = diameter:stop(). + +%% Testcases to run when services are started and connections +%% established. +tc() -> + [send1, + send2, + send3, + send4, + send_loop, + send_timeout_1, + send_timeout_2]. + +server(Host, Dict) -> + ok = diameter:start_service(Host, ?SERVICE(Host, Dict)), + {ok, LRef} = diameter:add_transport(Host, ?LISTEN), + {LRef, portnr(LRef)}. + +connect(Host, {_LRef, PortNr}) -> + {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr)), + ok = receive + #diameter_event{service = Host, + info = {up, Ref, _, _, #diameter_packet{}}} -> + ok + after 2000 -> + false + end, + Ref; +connect(Host, Ports) -> + [connect(Host, P) || P <- Ports]. + +portnr(LRef) -> + portnr(LRef, 20). + +portnr(LRef, N) + when 0 < N -> + case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of + [{T, _Pid}] -> + {_, _, {LRef, {_Addr, LSock}}} = T, + {ok, PortNr} = inet:port(LSock), + PortNr; + [] -> + receive after 50 -> ok end, + portnr(LRef, N-1) + end. + +realm(Host) -> + tl(lists:dropwhile(fun(C) -> C /= $. end, Host)). + +%% =========================================================================== + +%% Send an STR intended for a specific server and expect success. +send1(_Config) -> + call(?SERVER1). +send2(_Config) -> + call(?SERVER2). +send3(_Config) -> + call(?SERVER3). +send4(_Config) -> + call(?SERVER4). + +%% Send an ASR that loops between the relays and expect the loop to +%% be detected. +send_loop(_Config) -> + Req = ['ASR', {'Destination-Realm', realm(?SERVER1)}, + {'Destination-Host', ?SERVER1}, + {'Auth-Application-Id', ?APP_ID}], + #'diameter_base_answer-message'{'Result-Code' = ?LOOP_DETECTED} + = call(Req, [{filter, realm}]). + +%% Send a RAR that is incorrectly routed and then discarded and expect +%% different results depending on whether or not we or the relay +%% timeout first. +send_timeout_1(_Config) -> + #'diameter_base_answer-message'{'Result-Code' = ?UNABLE_TO_DELIVER} + = send_timeout(7000). +send_timeout_2(_Config) -> + {error, timeout} = send_timeout(3000). + +send_timeout(Tmo) -> + Req = ['RAR', {'Destination-Realm', realm(?SERVER1)}, + {'Destination-Host', ?SERVER1}, + {'Auth-Application-Id', ?APP_ID}, + {'Re-Auth-Request-Type', ?AUTHORIZE_ONLY}], + call(Req, [{filter, realm}, {timeout, Tmo}]). + +%% Remove the client transports and expect the corresponding server +%% transport to go down. +remove_transports(Config) -> + {[S1,S2,S3,S4], [R1,R2], [C1,C2,C3,C4,C5,C6,C7]} + = proplists:get_value(transports, Config), + + true = diameter:subscribe(?SERVER1), + true = diameter:subscribe(?SERVER2), + true = diameter:subscribe(?SERVER3), + true = diameter:subscribe(?SERVER4), + true = diameter:subscribe(?RELAY1), + true = diameter:subscribe(?RELAY2), + + disconnect(S1, ?RELAY1, C1), + disconnect(S2, ?RELAY1, C2), + disconnect(S3, ?RELAY2, C3), + disconnect(S4, ?RELAY2, C4), + disconnect(R1, ?CLIENT, C5), + disconnect(R2, ?CLIENT, C6), + disconnect(R2, ?RELAY1, C7). + +disconnect({LRef, _PortNr}, Client, CRef) -> + ok = diameter:remove_transport(Client, CRef), + ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok + after 2000 -> false + end. + +stop_services(_Config) -> + S = [?CLIENT, ?RELAY1, ?RELAY2, ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4], + Ok = [ok || _ <- S], + Ok = [diameter:stop_service(H) || H <- S]. + +%% =========================================================================== + +call(Server) -> + Realm = realm(Server), + Req = ['STR', {'Destination-Realm', Realm}, + {'Destination-Host', [Server]}, + {'Termination-Cause', ?LOGOUT}, + {'Auth-Application-Id', ?APP_ID}], + #diameter_base_STA{'Result-Code' = ?SUCCESS, + 'Origin-Host' = Server, + 'Origin-Realm' = Realm} + = call(Req, [{filter, realm}]). + +call(Req, Opts) -> + diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). + +set([H|T], Vs) -> + [H | Vs ++ T]. + +%% =========================================================================== +%% diameter callbacks + +%% peer_up/3 + +peer_up(_SvcName, _Peer, State) -> + State. + +%% peer_down/3 + +peer_down(_SvcName, _Peer, State) -> + State. + +%% pick_peer/4 + +pick_peer([Peer | _], _, Svc, _State) + when Svc == ?RELAY1; + Svc == ?RELAY2; + Svc == ?CLIENT-> + {ok, Peer}. + +%% prepare_request/3 + +prepare_request(Pkt, Svc, _Peer) + when Svc == ?RELAY1; + Svc == ?RELAY2 -> + {send, Pkt}; + +prepare_request(Pkt, ?CLIENT, {_Ref, Caps}) -> + {send, prepare(Pkt, Caps)}. + +prepare(#diameter_packet{msg = Req}, Caps) -> + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, _}} + = Caps, + set(Req, [{'Session-Id', diameter:session_id(OH)}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}]). + +%% prepare_retransmit/3 + +prepare_retransmit(_Pkt, false, _Peer) -> + discard. + +%% handle_answer/4 + +%% A relay must return Pkt. +handle_answer(Pkt, _Req, Svc, _Peer) + when Svc == ?RELAY1; + Svc == ?RELAY2 -> + Pkt; + +handle_answer(Pkt, _Req, ?CLIENT, _Peer) -> + #diameter_packet{msg = Rec, errors = []} = Pkt, + Rec. + +%% handle_error/4 + +handle_error(Reason, _Req, _Svc, _Peer) -> + {error, Reason}. + +%% handle_request/3 + +handle_request(Pkt, OH, {_Ref, #diameter_caps{origin_host = {OH,_}} = Caps}) + when OH /= ?CLIENT -> + request(Pkt, Caps). + +%% RELAY1 routes any ASR or RAR to RELAY2 ... +request(#diameter_packet{header = #diameter_header{cmd_code = C}}, + #diameter_caps{origin_host = {?RELAY1, _}}) + when C == 274; %% ASR + C == 258 -> %% RAR + {relay, [{filter, {realm, realm(?RELAY2)}}]}; + +%% ... which in turn routes it back. Expect diameter to either answer +%% either with DIAMETER_LOOP_DETECTED/DIAMETER_UNABLE_TO_COMPLY. +request(#diameter_packet{header = #diameter_header{cmd_code = 274}}, + #diameter_caps{origin_host = {?RELAY2, _}}) -> + {relay, [{filter, {host, ?RELAY1}}]}; +request(#diameter_packet{header = #diameter_header{cmd_code = 258}}, + #diameter_caps{origin_host = {?RELAY2, _}}) -> + discard; + +%% Other request to a relay: send on to one of the servers in the +%% same realm. +request(_Pkt, #diameter_caps{origin_host = {OH, _}}) + when OH == ?RELAY1; + OH == ?RELAY2 -> + {relay, [{filter, {all, [host, realm]}}]}; + +%% Request received by a server: answer. +request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId, + 'Origin-Host' = Host, + 'Origin-Realm' = Realm, + 'Route-Record' = Route}}, + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, _}}) -> + %% The request should have the Origin-Host/Realm of the original + %% sender. + R = realm(?CLIENT), + {?CLIENT, R} = {Host, Realm}, + %% A relay appends the identity of the peer that a request was + %% received from to the Route-Record avp. + [?CLIENT] = Route, + {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS, + 'Session-Id' = SId, + 'Origin-Host' = OH, + 'Origin-Realm' = OR}}. diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index f84ec45d52..c6f709dc36 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -33,7 +33,8 @@ MODULES = \ diameter_stats_SUITE \ diameter_watchdog_SUITE \ diameter_transport_SUITE \ - diameter_traffic_SUITE + diameter_traffic_SUITE \ + diameter_relay_SUITE INTERNAL_HRL_FILES = \ diameter_ct.hrl -- cgit v1.2.3 From 162c0d3ee30790ec5a75e20b0e2e8bc61ed92375 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 26 Sep 2011 18:05:38 +0200 Subject: Explicit {init,end}_per_group/2 to work around ct bug Without these functions the result pages are currently mangled. The overview page shows that no suites have run, even though all in fact are, and diameter-specific page is truncated after the dict suite, which is the first suite that relied on an implicit {init,end}_per_group/2. This is apparently the result of a recent common_test commit. --- lib/diameter/test/diameter_dict_SUITE.erl | 10 +++++++++- lib/diameter/test/diameter_reg_SUITE.erl | 8 ++++++++ lib/diameter/test/diameter_relay_SUITE.erl | 8 ++++++++ lib/diameter/test/diameter_stats_SUITE.erl | 8 ++++++++ lib/diameter/test/diameter_sync_SUITE.erl | 8 ++++++++ lib/diameter/test/diameter_transport_SUITE.erl | 8 ++++++++ 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl index 170b3c1695..87bb9727fe 100644 --- a/lib/diameter/test/diameter_dict_SUITE.erl +++ b/lib/diameter/test/diameter_dict_SUITE.erl @@ -25,7 +25,9 @@ -export([suite/0, all/0, - groups/0]). + groups/0, + init_per_group/2, + end_per_group/2]). %% testcases -export([append/1, @@ -69,6 +71,12 @@ tc() -> update, update_counter]. +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + %% =========================================================================== -define(KV100, [{N,[N]} || N <- lists:seq(1,100)]). diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl index 83661d48de..ade824c9dd 100644 --- a/lib/diameter/test/diameter_reg_SUITE.erl +++ b/lib/diameter/test/diameter_reg_SUITE.erl @@ -26,6 +26,8 @@ -export([suite/0, all/0, groups/0, + init_per_group/2, + end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -59,6 +61,12 @@ tc() -> terms, pids]. +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index cd53fbfd90..0cda2df8ca 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -36,6 +36,8 @@ -export([suite/0, all/0, groups/0, + init_per_group/2, + end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -137,6 +139,12 @@ groups() -> [{all, [], Ts}, {p, [parallel], Ts}]. +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + init_per_suite(Config) -> ok = diameter:start(), diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl index 85300b0d76..e50a0050a6 100644 --- a/lib/diameter/test/diameter_stats_SUITE.erl +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -26,6 +26,8 @@ -export([suite/0, all/0, groups/0, + init_per_group/2, + end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -51,6 +53,12 @@ tc() -> [an, twa]. +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl index ecd935bd98..84f77b6066 100644 --- a/lib/diameter/test/diameter_sync_SUITE.erl +++ b/lib/diameter/test/diameter_sync_SUITE.erl @@ -26,6 +26,8 @@ -export([suite/0, all/0, groups/0, + init_per_group/2, + end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -57,6 +59,12 @@ tc() -> timeout, flush]. +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index 7c2c1f187e..d545859fe8 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -27,6 +27,8 @@ -export([suite/0, all/0, groups/0, + init_per_group/2, + end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -110,6 +112,12 @@ tc() -> sctp_accept, sctp_connect]. +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + init_per_suite(Config) -> ok = diameter:start(), [{sctp, have_sctp()} | Config]. -- cgit v1.2.3 From 028750246b040fa9e517aafe8f7bfe4da49c75b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 27 Sep 2011 10:43:07 +0200 Subject: distribution_SUITE: Use unique slave node names bad_dist_ext_connection_id/1 used the same names for the slave nodes as bad_dist_ext_receive/1, which would cause it to fail if bad_dist_ext_receive/1 failed. --- erts/emulator/test/distribution_SUITE.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index e4af5c00a6..3719593bd3 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -1597,8 +1597,8 @@ bad_dist_ext_control(Config) when is_list(Config) -> ?line stop_node(Victim). bad_dist_ext_connection_id(Config) when is_list(Config) -> - ?line {ok, Offender} = start_node(bad_dist_ext_receive_offender), - ?line {ok, Victim} = start_node(bad_dist_ext_receive_victim), + ?line {ok, Offender} = start_node(bad_dist_ext_connection_id_offender), + ?line {ok, Victim} = start_node(bad_dist_ext_connection_id_victim), ?line start_node_monitors([Offender,Victim]), ?line Parent = self(), -- cgit v1.2.3 From e2fb86d483ffcb5654a0e2c482f7c04442a83d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 27 Sep 2011 11:07:17 +0200 Subject: distribution_SUITE:bulk_send_bigbig/1: Fail with more information --- erts/emulator/test/distribution_SUITE.erl | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index 3719593bd3..3eaacdb044 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -173,15 +173,20 @@ bulk_sendsend(Terms, BinSize) -> Ratio = if MonitorCount2 == 0 -> MonitorCount1 / 1.0; true -> MonitorCount1 / MonitorCount2 end, - %% A somewhat arbitrary ratio, but hopefully one that will accommodate - %% a wide range of CPU speeds. - true = (Ratio > 8.0), - {comment, - integer_to_list(Rate1) ++ " K/s, " ++ - integer_to_list(Rate2) ++ " K/s, " ++ - integer_to_list(MonitorCount1) ++ " monitor msgs, " ++ - integer_to_list(MonitorCount2) ++ " monitor msgs, " ++ - float_to_list(Ratio) ++ " monitor ratio"}. + Comment = integer_to_list(Rate1) ++ " K/s, " ++ + integer_to_list(Rate2) ++ " K/s, " ++ + integer_to_list(MonitorCount1) ++ " monitor msgs, " ++ + integer_to_list(MonitorCount2) ++ " monitor msgs, " ++ + float_to_list(Ratio) ++ " monitor ratio", + if + %% A somewhat arbitrary ratio, but hopefully one that will + %% accommodate a wide range of CPU speeds. + Ratio > 8.0 -> + {comment,Comment}; + true -> + io:put_chars(Comment), + ?line ?t:fail(ratio_too_low) + end. bulk_sendsend2(Terms, BinSize, BusyBufSize) -> ?line Dog = test_server:timetrap(test_server:seconds(30)), -- cgit v1.2.3 From e36b171c318ba8c475fe0727fe2d0d35f86a4a73 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 27 Sep 2011 13:07:47 +0200 Subject: Fix bug in dataflow --- lib/dialyzer/src/dialyzer_dataflow.erl | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 659297f993..d74c04385b 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -1399,10 +1399,14 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, true -> Any = t_any(), [Any || _ <- Pats]; false -> t_to_tlist(OrigArgType) end, - case bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1) of - {error, bind, _, _, _} -> {{pattern_match, PatTypes}, false}; - {_, _} -> {{pattern_match_cov, PatTypes}, false} - end; + Tag = + case bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1) of + {error, bind, _, _, _} -> pattern_match; + {error, record, _, _, _} -> record_match; + {error, opaque, _, _, _} -> opaque_match; + {_, _} -> pattern_match_cov + end, + {{Tag, PatTypes}, false}; false -> %% Try to find out if this is a default clause in a list %% comprehension and supress this. A real Hack(tm) @@ -1442,12 +1446,12 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, opaque -> [PatString, format_type(Type, State1), format_type(OpaqueTerm, State1)] end, - FailedMsg = case ErrorType of - bind -> {pattern_match, PatTypes}; - record -> {record_match, PatTypes}; - opaque -> {opaque_match, PatTypes} + FailedTag = case ErrorType of + bind -> pattern_match; + record -> record_match; + opaque -> opaque_match end, - {FailedMsg, Force0} + {{FailedTag, PatTypes}, Force0} end, WarnType = case Msg of {opaque_match, _} -> ?WARN_OPAQUE; -- cgit v1.2.3 From 5891e32d8fe1b7ad05e9bca4f37bad746ee64c21 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Mon, 26 Sep 2011 12:00:26 +0200 Subject: Improve info in CT framework log --- lib/common_test/src/ct_framework.erl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 63a7c37fa6..02a5d60445 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1031,6 +1031,10 @@ make_conf(Mod, Name, Props, TestSpec) -> true -> {{Mod,init_per_group},{Mod,end_per_group}}; false -> + ct_logs:log("TEST INFO", "init_per_group/2 and " + "end_per_group/2 missing for group " + "~p in ~p, using default.", + [Name,Mod]), {{?MODULE,ct_init_per_group}, {?MODULE,ct_end_per_group}} end, @@ -1208,14 +1212,14 @@ error_in_suite(Config) -> %% use these instead ct_init_per_group(GroupName, Config) -> ct:comment(io_lib:format("start of ~p", [GroupName])), - ct_logs:log("WARNING", "init_per_group/2 for ~w missing " + ct_logs:log("TEST INFO", "init_per_group/2 for ~w missing " "in suite, using default.", [GroupName]), Config. ct_end_per_group(GroupName, _) -> ct:comment(io_lib:format("end of ~p", [GroupName])), - ct_logs:log("WARNING", "end_per_group/2 for ~w missing " + ct_logs:log("TEST INFO", "end_per_group/2 for ~w missing " "in suite, using default.", [GroupName]), ok. -- cgit v1.2.3 From 26550631bf825d738bd8c20c9fdb600e9867d81f Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 27 Sep 2011 01:24:12 +0200 Subject: Fix problem with test_server_ctrl creating invalid conf test OTP-9584 --- lib/common_test/src/ct_framework.erl | 10 +++++----- lib/test_server/src/test_server_ctrl.erl | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 02a5d60445..fb89685b7b 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -478,7 +478,6 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> _ -> ok end, - ct_util:delete_testdata(comment), ct_util:delete_suite_data(last_saved_config), FuncSpec = @@ -1026,19 +1025,20 @@ make_conf(Mod, Name, Props, TestSpec) -> _ -> ok end, - {InitConf,EndConf} = + {InitConf,EndConf,ExtraProps} = case erlang:function_exported(Mod,init_per_group,2) of true -> - {{Mod,init_per_group},{Mod,end_per_group}}; + {{Mod,init_per_group},{Mod,end_per_group},[]}; false -> ct_logs:log("TEST INFO", "init_per_group/2 and " "end_per_group/2 missing for group " "~p in ~p, using default.", [Name,Mod]), {{?MODULE,ct_init_per_group}, - {?MODULE,ct_end_per_group}} + {?MODULE,ct_end_per_group}, + [{suite,Mod}]} end, - {conf,[{name,Name}|Props],InitConf,TestSpec,EndConf}. + {conf,[{name,Name}|Props++ExtraProps],InitConf,TestSpec,EndConf}. %%%----------------------------------------------------------------- diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 7554a31530..4fad86d16d 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -2039,6 +2039,21 @@ add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_}}=Case|Cases], LastMod, PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; add_init_and_end_per_suite([{skip_case,_}=Case|Cases], LastMod, LastRef, FwMod) -> [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; +add_init_and_end_per_suite([{conf,Ref,Props,{FwMod,Func}}=Case|Cases], LastMod, + LastRef, FwMod) -> + %% if Mod == FwMod, this conf test is (probably) a test case group where + %% the init- and end-functions are missing in the suite, and if so, + %% the suite name should be stored as {suite,Suite} in Props + case proplists:get_value(suite, Props) of + Suite when Suite =/= undefined, Suite =/= LastMod -> + {PreCases, NextMod, NextRef} = + do_add_init_and_end_per_suite(LastMod, LastRef, Suite), + Case1 = {conf,Ref,proplists:delete(suite,Props),{FwMod,Func}}, + PreCases ++ [Case1|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; + _ -> + [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)] + end; add_init_and_end_per_suite([{conf,_,_,{Mod,_}}=Case|Cases], LastMod, LastRef, FwMod) when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = -- cgit v1.2.3 From 3c6e2ebefc49b08532e532ef33b6ae0db4b4a981 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 27 Sep 2011 01:47:41 +0200 Subject: Fix invalid call to undefined function OTP-9585 --- lib/common_test/src/ct_run.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 4ec3ac589d..26ca4f3cb4 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -509,7 +509,7 @@ script_start4(#opts{label = Label, profile = Profile, case install(InstallOpts) of ok -> ct_util:start(interactive, LogDir), - ct_util:set_testdata(logopts, LogOpts), + ct_util:set_testdata({logopts, LogOpts}), log_ts_names(Specs), io:nl(), ok; -- cgit v1.2.3 From 021b96da72cb7be9c65296016cd8a1eb8c6fc604 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 27 Sep 2011 01:55:58 +0200 Subject: Fix errors in test suites --- lib/common_test/test/ct_groups_test_2_SUITE.erl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/common_test/test/ct_groups_test_2_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE.erl index f33be8a9d4..940d791b15 100644 --- a/lib/common_test/test/ct_groups_test_2_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_2_SUITE.erl @@ -173,16 +173,14 @@ test_events(missing_conf) -> {?eh,start_info,{1,1,2}}, {?eh,tc_start,{ct_framework,ct_init_per_group}}, {?eh,tc_done,{ct_framework,ct_init_per_group,ok}}, - {?eh,test_stats,{1,0,{0,0}}}, {?eh,tc_start,{missing_conf_SUITE,tc1}}, {?eh,tc_done,{missing_conf_SUITE,tc1,ok}}, - {?eh,test_stats,{2,0,{0,0}}}, + {?eh,test_stats,{1,0,{0,0}}}, {?eh,tc_start,{missing_conf_SUITE,tc2}}, {?eh,tc_done,{missing_conf_SUITE,tc2,ok}}, - {?eh,test_stats,{3,0,{0,0}}}, + {?eh,test_stats,{2,0,{0,0}}}, {?eh,tc_start,{ct_framework,ct_end_per_group}}, {?eh,tc_done,{ct_framework,ct_end_per_group,ok}}, - {?eh,test_stats,{4,0,{0,0}}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]} ]; -- cgit v1.2.3 From 001f0a4baa95ccc6eb553cad9e4551b4e520dc8b Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 27 Sep 2011 13:24:23 +0200 Subject: Solve problem with ct_init/end_per_group being counted as test cases --- lib/common_test/src/ct_framework.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index fb89685b7b..37ecf4f928 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1296,6 +1296,10 @@ report(What,Data) -> ok; {end_per_group,_} -> ok; + {ct_init_per_group,_} -> + ok; + {ct_end_per_group,_} -> + ok; {_,ok} -> add_to_stats(ok); {_,{skipped,{failed,{_,init_per_testcase,_}}}} -> -- cgit v1.2.3 From 72ef6722850a627acbbdc520d24029593c52f003 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 27 Sep 2011 01:41:01 +0200 Subject: Set version to 0.10 and update appup --- lib/diameter/src/app/diameter.appup.src | 22 +++++++++++++++++++++- lib/diameter/vsn.mk | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/diameter/src/app/diameter.appup.src b/lib/diameter/src/app/diameter.appup.src index 2b96153575..3f77034a12 100644 --- a/lib/diameter/src/app/diameter.appup.src +++ b/lib/diameter/src/app/diameter.appup.src @@ -20,8 +20,28 @@ {"%VSN%", [ + {"0.9", + [ + {load_module, diameter, soft_purge, soft_purge, []}, + {load_module, diameter_capx, soft_purge, soft_purge, []}, + {load_module, diameter_codec, soft_purge, soft_purge, []}, + {load_module, diameter_lib, soft_purge, soft_purge, []}, + {load_module, diameter_types, soft_purge, soft_purge, []}, + {load_module, diameter_gen_base_accounting, soft_purge, soft_purge, []}, + {load_module, diameter_gen_base_rfc3588, soft_purge, soft_purge, []}, + {load_module, diameter_gen_relay, soft_purge, soft_purge, []}, + {update, diameter_service, soft, soft_purge, soft_purge, []}, + {update, diameter_config, soft, soft_purge, soft_purge, []}, + {update, diameter_peer, soft, soft_purge, soft_purge, []}, + {update, diameter_peer_fsm, soft, soft_purge, soft_purge, []}, + {update, diameter_reg, soft, soft_purge, soft_purge, []}, + {update, diameter_sctp, soft, soft_purge, soft_purge, []}, + {update, diameter_stats, soft, soft_purge, soft_purge, []}, + {update, diameter_sync, soft, soft_purge, soft_purge, []}, + {update, diameter_watchdog, soft, soft_purge, soft_purge, []} + ] + } ], [ ] }. - diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk index 9f822e4e85..c783450c9f 100644 --- a/lib/diameter/vsn.mk +++ b/lib/diameter/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = diameter -DIAMETER_VSN = 0.9 +DIAMETER_VSN = 0.10 PRE_VSN = APP_VSN = "$(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 9b7b4db9d7e5734f6c5c2193786c44cf1e273efb Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 27 Sep 2011 16:45:05 +0200 Subject: Both the SSLv3 and TLS 1.0/TLS 1.1 specifications require implementations to ignore data following the ClientHello (i.e., extensions) if they do not understand them. Data not following the protocol format for extensions will be ignored by the last dec_hello_extensions-clause. OTP-8596 --- lib/ssl/src/ssl_handshake.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 0ac1ba9d66..f873a6a913 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -914,11 +914,12 @@ dec_hello_extensions(<>, Acc) -> dec_hello_extensions(Rest, Acc); -%% Need this clause? -%% I don't think we need this clause anymore. It was previously catching parsing errors caused by the missing /binary. -%% Maybe we should be logging an error somewhere because we really should not be entering this clause. +%% This theoretically should not happen if the protocol is followed, but if it does it is ignored. dec_hello_extensions(_, Acc) -> Acc. -- cgit v1.2.3 From 7fc2604feb7d3887eb9271d1b9ef38e99db5176b Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 27 Sep 2011 20:04:29 +0300 Subject: Decrease tuple arity limit This fixes a memory related crash. --- lib/hipe/cerl/erl_types.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 1748c1cc16..0a76938799 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -242,7 +242,7 @@ -define(REC_TYPE_LIMIT, 2). -define(TUPLE_TAG_LIMIT, 5). --define(TUPLE_ARITY_LIMIT, 10). +-define(TUPLE_ARITY_LIMIT, 8). -define(SET_LIMIT, 13). -define(MAX_BYTE, 255). -define(MAX_CHAR, 16#10ffff). -- cgit v1.2.3 From 39a3e0aa40eb75f5780c4c0964343c046955adec Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 27 Sep 2011 20:10:22 +0300 Subject: Remove unused macro --- lib/hipe/cerl/erl_types.erl | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 0a76938799..15c923e3c7 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -247,7 +247,6 @@ -define(MAX_BYTE, 255). -define(MAX_CHAR, 16#10ffff). --define(WIDENING_LIMIT, 7). -define(UNIT_MULTIPLIER, 8). -define(TAG_IMMED1_SIZE, 4). -- cgit v1.2.3 From 5af64c7d57d83ce35bfd7b15ac3ce6ec7459fd73 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 27 Sep 2011 12:07:31 +0200 Subject: Don't include compiler/help modules in app --- lib/diameter/src/app/Makefile | 17 +++++++++++------ lib/diameter/src/app/diameter.app.src | 2 +- lib/diameter/src/app/diameter.appup.src | 8 ++++---- lib/diameter/src/app/diameter_internal.hrl | 2 +- lib/diameter/src/app/diameter_lib.erl | 12 +++++++++++- lib/diameter/src/app/modules.mk | 12 +++++++----- lib/diameter/src/compiler/Makefile | 10 ---------- lib/diameter/test/diameter_app_SUITE.erl | 12 ++++++++++-- 8 files changed, 45 insertions(+), 30 deletions(-) diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile index 229466e264..ab5754f74f 100644 --- a/lib/diameter/src/app/Makefile +++ b/lib/diameter/src/app/Makefile @@ -58,12 +58,20 @@ SPEC_ERL_FILES = \ SPEC_HRL_FILES = \ $(SPEC_FILES:%.dia=%.hrl) +MODULES = \ + $(RUNTIME_MODULES) \ + $(HELP_MODULES) + APP_MODULES = \ - $(MODULES) \ + $(RUNTIME_MODULES) \ $(SPEC_FILES:%.dia=%) +TARGET_MODULES = \ + $(APP_MODULES) \ + $(HELP_MODULES) + TARGET_FILES = \ - $(APP_MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(TARGET_MODULES:%=$(EBIN)/%.$(EMULATOR)) \ $(APP_TARGET) \ $(APPUP_TARGET) @@ -125,17 +133,15 @@ info: # ---------------------------------------------------- # Generate the app file and then modules into in. This shouldn't know -# about ../{compiler,transport} but good enough for now. +# about ../transport but good enough for now. $(APP_TARGET): $(APP_SRC) \ ../../vsn.mk \ modules.mk \ - ../compiler/modules.mk \ ../transport/modules.mk sed -e 's;%VSN%;$(VSN);' $< > $@ M=`echo $(APP_MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \ echo "/%APP_MODULES%/s//$$M/;w;q" | tr ';' '\n' \ | ed -s $@ - $(MAKE) -C ../compiler $(APP_TARGET) APP_TARGET=$(APP_TARGET) $(MAKE) -C ../transport $(APP_TARGET) APP_TARGET=$(APP_TARGET) $(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk @@ -150,7 +156,6 @@ app: $(APP_TARGET) $(APPUP_TARGET) diameter_gen_%.erl diameter_gen_%.hrl: diameter_gen_%.dia ../../bin/diameterc -i $(EBIN) -o $(@D) $< - # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/lib/diameter/src/app/diameter.app.src b/lib/diameter/src/app/diameter.app.src index 119997953e..a806b5c78a 100644 --- a/lib/diameter/src/app/diameter.app.src +++ b/lib/diameter/src/app/diameter.app.src @@ -20,7 +20,7 @@ {application, diameter, [{description, "Diameter protocol"}, {vsn, "%VSN%"}, - {modules, [%APP_MODULES%,%COMPILER_MODULES%,%TRANSPORT_MODULES%]}, + {modules, [%APP_MODULES%,%TRANSPORT_MODULES%]}, {registered, []}, {applications, [stdlib, kernel]}, {env, []}, diff --git a/lib/diameter/src/app/diameter.appup.src b/lib/diameter/src/app/diameter.appup.src index 3f77034a12..6d8ceadb92 100644 --- a/lib/diameter/src/app/diameter.appup.src +++ b/lib/diameter/src/app/diameter.appup.src @@ -24,21 +24,21 @@ [ {load_module, diameter, soft_purge, soft_purge, []}, {load_module, diameter_capx, soft_purge, soft_purge, []}, - {load_module, diameter_codec, soft_purge, soft_purge, []}, + {load_module, diameter_codec, soft_purge, soft_purge, [diameter_lib]}, {load_module, diameter_lib, soft_purge, soft_purge, []}, {load_module, diameter_types, soft_purge, soft_purge, []}, {load_module, diameter_gen_base_accounting, soft_purge, soft_purge, []}, {load_module, diameter_gen_base_rfc3588, soft_purge, soft_purge, []}, {load_module, diameter_gen_relay, soft_purge, soft_purge, []}, - {update, diameter_service, soft, soft_purge, soft_purge, []}, + {update, diameter_service, soft, soft_purge, soft_purge, [diameter_lib]}, {update, diameter_config, soft, soft_purge, soft_purge, []}, {update, diameter_peer, soft, soft_purge, soft_purge, []}, - {update, diameter_peer_fsm, soft, soft_purge, soft_purge, []}, + {update, diameter_peer_fsm, soft, soft_purge, soft_purge, [diameter_lib]}, {update, diameter_reg, soft, soft_purge, soft_purge, []}, {update, diameter_sctp, soft, soft_purge, soft_purge, []}, {update, diameter_stats, soft, soft_purge, soft_purge, []}, {update, diameter_sync, soft, soft_purge, soft_purge, []}, - {update, diameter_watchdog, soft, soft_purge, soft_purge, []} + {update, diameter_watchdog, soft, soft_purge, soft_purge, [diameter_lib]} ] } ], diff --git a/lib/diameter/src/app/diameter_internal.hrl b/lib/diameter/src/app/diameter_internal.hrl index 78645b1912..63b35550a8 100644 --- a/lib/diameter/src/app/diameter_internal.hrl +++ b/lib/diameter/src/app/diameter_internal.hrl @@ -44,7 +44,7 @@ %% Something to trace on. -define(LOG(Slogan, Details), - diameter_dbg:log(Slogan, ?MODULE, ?LINE, Details)). + diameter_lib:log(Slogan, ?MODULE, ?LINE, Details)). -define(LOGC(Bool, Slogan, Details), ((Bool) andalso ?LOG(Slogan, Details))). %% Compensate for no builtin ?FUNC for use in log reports. diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/app/diameter_lib.erl index f65e356444..362d593b24 100644 --- a/lib/diameter/src/app/diameter_lib.erl +++ b/lib/diameter/src/app/diameter_lib.erl @@ -30,7 +30,8 @@ ipaddr/1, spawn_opts/2, wait/1, - fold_tuple/3]). + fold_tuple/3, + log/4]). -include("diameter_internal.hrl"). @@ -260,3 +261,12 @@ ft(undefined, {_, T}) -> T; ft(Value, {Idx, T}) -> setelement(Idx, T, Value). + +%%% ---------------------------------------------------------- +%%% # log(Slogan, Mod, Line, Details) +%%% +%%% Called to have something to trace on for happenings of interest. +%%% ---------------------------------------------------------- + +log(_, _, _, _) -> + ok. diff --git a/lib/diameter/src/app/modules.mk b/lib/diameter/src/app/modules.mk index a7a78b1a9d..c133e6f64e 100644 --- a/lib/diameter/src/app/modules.mk +++ b/lib/diameter/src/app/modules.mk @@ -22,17 +22,13 @@ SPEC_FILES = \ diameter_gen_base_accounting.dia \ diameter_gen_relay.dia -MODULES = \ +RUNTIME_MODULES = \ diameter \ diameter_app \ - diameter_callback \ diameter_capx \ diameter_config \ - diameter_dbg \ diameter_codec \ diameter_dict \ - diameter_exprecs \ - diameter_info \ diameter_lib \ diameter_misc_sup \ diameter_peer \ @@ -49,6 +45,12 @@ MODULES = \ diameter_watchdog \ diameter_watchdog_sup +HELP_MODULES = \ + diameter_callback \ + diameter_exprecs \ + diameter_dbg \ + diameter_info + INTERNAL_HRL_FILES = \ diameter_internal.hrl \ diameter_types.hrl diff --git a/lib/diameter/src/compiler/Makefile b/lib/diameter/src/compiler/Makefile index 3ab76064ac..779013bfbc 100644 --- a/lib/diameter/src/compiler/Makefile +++ b/lib/diameter/src/compiler/Makefile @@ -93,16 +93,6 @@ info: @echo "TARGET_FILES = $(TARGET_FILES)" @echo "" -# ---------------------------------------------------- -# Special Build Targets -# ---------------------------------------------------- - -# Invoked from ../app to add modules to the app file. -$(APP_TARGET): force - M=`echo $(MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \ - echo "/%COMPILER_MODULES%/s//$$M/;w;q" | tr ';' '\n' \ - | ed -s $@ - # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index d710fa155d..104785b4e6 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -86,13 +86,21 @@ vsn(Config) -> %% =========================================================================== %% # modules/1 %% -%% Ensure that the app file module list match the installed beams. +%% Ensure that the app file modules and installed modules differ by +%% compiler/help modules. %% =========================================================================== modules(Config) -> Mods = fetch(modules, fetch(app, Config)), Installed = code_mods(), - {[], []} = {Mods -- Installed, Installed -- Mods}. + Help = [diameter_callback, + diameter_codegen, + diameter_dbg, + diameter_exprecs, + diameter_info, + diameter_spec_scan, + diameter_spec_util], + {[], Help} = {Mods -- Installed, lists:sort(Installed -- Mods)}. code_mods() -> Dir = code:lib_dir(?APP, ebin), -- cgit v1.2.3 From 0296dbb27b20c75edc6a2dd75369dc17dc98aa5a Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 27 Sep 2011 15:56:55 +0200 Subject: Example/dbg/comment fixes --- lib/diameter/src/app/diameter_callback.erl | 8 +- lib/diameter/src/app/diameter_dbg.erl | 147 ++++++++++------------------- lib/diameter/test/diameter_codec_SUITE.erl | 5 +- lib/diameter/test/diameter_relay_SUITE.erl | 2 +- 4 files changed, 56 insertions(+), 106 deletions(-) diff --git a/lib/diameter/src/app/diameter_callback.erl b/lib/diameter/src/app/diameter_callback.erl index fcf9a8fc1e..6d5c8cdca1 100644 --- a/lib/diameter/src/app/diameter_callback.erl +++ b/lib/diameter/src/app/diameter_callback.erl @@ -60,28 +60,28 @@ pick_peer([Peer|_], _, _SvcName, _State) -> %%% ---------------------------------------------------------- prepare_request(Pkt, _SvcName, _Peer) -> - Pkt. + {send, Pkt}. %%% ---------------------------------------------------------- %%% # prepare_retransmit/3 %%% ---------------------------------------------------------- prepare_retransmit(Pkt, _SvcName, _Peer) -> - Pkt. + {send, Pkt}. %%% ---------------------------------------------------------- %%% # handle_request/3 %%% ---------------------------------------------------------- handle_request(_Pkt, _SvcName, _Peer) -> - discard. + {protocol_error, 3001}. %% DIAMETER_COMMAND_UNSUPPORTED %%% ---------------------------------------------------------- %%% # handle_answer/4 %%% ---------------------------------------------------------- handle_answer(#diameter_packet{msg = Ans}, _Req, _SvcName, _Peer) -> - {ok, Ans}. + Ans. %%% --------------------------------------------------------------------------- %%% # handle_error/4 diff --git a/lib/diameter/src/app/diameter_dbg.erl b/lib/diameter/src/app/diameter_dbg.erl index b18f34e13d..5b0ac3a3b6 100644 --- a/lib/diameter/src/app/diameter_dbg.erl +++ b/lib/diameter/src/app/diameter_dbg.erl @@ -68,12 +68,6 @@ -define(VALUES(Rec), tl(tuple_to_list(Rec))). -%%% ---------------------------------------------------------- -%%% # log/4 -%%% -%%% Called to have something to trace on for happenings of interest. -%%% ---------------------------------------------------------- - log(_Slogan, _Mod, _Line, _Details) -> ok. @@ -82,9 +76,6 @@ log(_Slogan, _Mod, _Line, _Details) -> %%% ---------------------------------------------------------- help() -> - ?INFO:usage(usage()). - -usage() -> not_yet_implemented. %%% ---------------------------------------------------------- @@ -99,30 +90,23 @@ table(T) when (T == diameter_peer) orelse (T == diameter_reg) -> ?INFO:format(collect(T), fields(T), fun ?INFO:split/2); -table(diameter_service = T) -> - Fs = [name, started] ++ fields(T) ++ [peerT, - connT, - share_peers, - use_shared_peers, - shared_peers, - local_peers, - monitor], - ?INFO:format(T, - fun(R) -> - [I,N,S|Vs] = ?VALUES(R), - {Fs, [N,I] ++ ?VALUES(S) ++ Vs} - end, - fun ?INFO:split/2); - table(Table) when is_atom(Table) -> case fields(Table) of undefined = No -> No; Fields -> - ?INFO:format(Table, Fields, fun ?INFO:split/2) + ?INFO:format(Table, Fields, fun split/2) end. +split([started, name | Fs], [S, N | Vs]) -> + {name, [started | Fs], N, [S | Vs]}; +split([[F|FT]|Fs], [Rec|Vs]) -> + [_, V | VT] = tuple_to_list(Rec), + {F, FT ++ Fs, V, VT ++ Vs}; +split([F|Fs], [V|Vs]) -> + {F, Fs, V, Vs}. + %%% ---------------------------------------------------------- %%% # TableName() %%% ---------------------------------------------------------- @@ -146,14 +130,14 @@ table(Table) %%% ---------------------------------------------------------- tables() -> - format_all(fun ?INFO:split/3). - -format_all(SplitFun) -> - ?INFO:format(field(?LOCAL), SplitFun, fun collect/1). + ?INFO:format(field(?LOCAL), fun split/3, fun collect/1). field(Tables) -> lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)). +split(_, Fs, Vs) -> + split(Fs, Vs). + %%% ---------------------------------------------------------- %%% # modules() %%% ---------------------------------------------------------- @@ -396,76 +380,24 @@ stop() -> %% tp/1 tpl(T) -> - dbg(tpl, dbg(T)). + dbg(tpl, T). tp(T) -> - dbg(tp, dbg(T)). - -%% dbg/1 - -dbg(x) -> - [{M, x, []} || M <- [diameter_tcp, - diameter_etcp, - diameter_sctp, - diameter_peer_fsm, - diameter_watchdog]]; - -dbg(log) -> - {?MODULE, log, 4}; - -dbg({log = F, Mods}) - when is_list(Mods) -> - {?MODULE, F, [{['_','$1','_','_'], - [?ORCOND([{'==', '$1', M} || M <- Mods])], - []}]}; - -dbg({log = F, Mod}) -> - dbg({F, [Mod]}); - -dbg(send) -> - {diameter_peer, send, 2}; - -dbg(recv) -> - {diameter_peer, recv, 2}; - -dbg(sendrecv) -> - [{diameter_peer, send, 2}, - {diameter_peer, recv, 2}]; - -dbg(decode) -> - [{diameter_codec,decode,2}]; - -dbg(encode) -> - [{diameter_codec,encode,2,[]}, - {diameter_codec,encode,3,[]}, - {diameter_codec,encode,4}]; - -dbg(transition = T) -> - [{?MODULE, log, [{[T,M,'_','_'],[],[]}]} - || M <- [diameter_watchdog, diameter_peer_fsm]]; - -dbg(T) -> - T. + dbg(tp, T). %% dbg/2 -dbg(TF, L) +dbg(F, L) when is_list(L) -> - {ok, lists:foldl(fun(T,A) -> {ok, X} = dbg(TF, T), [X|A] end, [], L)}; + [dbg(F, X) || X <- L]; dbg(F, M) when is_atom(M) -> - dbg(F, {M}); + apply(dbg, F, [M, x]); dbg(F, T) when is_tuple(T) -> - [_|_] = A = tuple_to_list(T), - {ok,_} = apply(dbg, F, case is_list(lists:last(A)) of - false -> - A ++ [[{'_',[],[{exception_trace}]}]]; - true -> - A - end). + apply(dbg, F, tuple_to_list(T)). %% =========================================================================== %% =========================================================================== @@ -493,15 +425,19 @@ peers(Name) -> peers(_, undefined) -> []; -peers(Name, {Cs,As}) -> - mk_peer(Name, connector, Cs) ++ mk_peer(Name, acceptor, As). - -mk_peer(Name, T, Ts) -> - [[Name | mk_peer(T,Vs)] || Vs <- Ts]. - -mk_peer(Type, Vs) -> - [Ref, State, Opts, WPid, TPid, SApps, Caps] - = get_values(Vs, [ref, state, options, watchdog, peer, apps, caps]), +peers(Name, Ts) -> + lists:flatmap(fun(T) -> mk_peers(Name, T) end, Ts). + +mk_peers(Name, [_, {type, connect} | _] = Ts) -> + [[Name | mk_peer(Ts)]]; +mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) -> + [[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As]. +%% This is a bit lame: service_info works to build this list and out +%% of something like what we want here and then we take it apart. + +mk_peer(Vs) -> + [Type, Ref, State, Opts, WPid, TPid, SApps, Caps] + = get_values(Vs, [type,ref,state,options,watchdog,peer,apps,caps]), [Ref, State, [{type, Type} | Opts], s(WPid), s(TPid), SApps, Caps]. get_values(Vs, Ks) -> @@ -509,9 +445,13 @@ get_values(Vs, Ks) -> s(undefined = T) -> T; +s({Pid, _Started, _State}) -> + state(Pid); +s({Pid, _Started}) -> + state(Pid). %% Collect states from watchdog/transport pids. -s(Pid) -> +state(Pid) -> MRef = erlang:monitor(process, Pid), Pid ! {state, self()}, receive @@ -541,7 +481,18 @@ fields(diameter_stats) -> [] end; -?FIELDS(diameter_service); +fields(diameter_service) -> + [started, + name, + record_info(fields, diameter_service), + peerT, + connT, + share_peers, + use_shared_peers, + shared_peers, + local_peers, + monitor]; + ?FIELDS(diameter_event); ?FIELDS(diameter_uri); ?FIELDS(diameter_avp); diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index 0c004b3edb..30c60be8e9 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -21,9 +21,8 @@ %% Test encode/decode of dictionary-related modules. Each test case %% runs multiple tests in parallel since many of the tests are just %% the same code with different in-data: implementing each test as a -%% single testcase would make for much duplication with ct's -%% requirement of one function per testcase. (Instead of allowing a -%% testcase to be an MFA instead of function name, say.) +%% single testcase would make for much duplication with ct's current +%% requirement of one function per testcase. %% -module(diameter_codec_SUITE). diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index 0cda2df8ca..6b2fda7855 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -26,7 +26,7 @@ %% / | %% CLIENT.REALM1 | %% \ | -%% ---- RELAY.REALM3 ---- SERVER2.REALM3 +%% ---- RELAY.REALM3 ---- SERVER1.REALM3 %% \ %% --- SERVER2.REALM3 %% -- cgit v1.2.3 From e4d5a206975e7718f6a95d5610ddc45b1d801c49 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Wed, 28 Sep 2011 09:04:04 +0300 Subject: Fix typer's crash for nonexisting files ... and do some small cleanups. --- lib/typer/src/typer.erl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl index e40c4f39cd..16ef7f03c2 100644 --- a/lib/typer/src/typer.erl +++ b/lib/typer/src/typer.erl @@ -466,14 +466,20 @@ write_typed_file(File, Info) -> case file:make_dir(TyperAnnDir) of {error, Reason} -> case Reason of - eexist -> %% TypEr dir exists; remove old typer files - ok = file:delete(NewFileName), + eexist -> %% TypEr dir exists; remove old typer files if they exist + case file:delete(NewFileName) of + ok -> ok; + {error, enoent} -> ok; + {error, _} -> + Msg = io_lib:format("Error in deleting file ~s\n", [NewFileName]), + fatal_error(Msg) + end, write_typed_file(File, Info, NewFileName); enospc -> Msg = io_lib:format("Not enough space in ~p\n", [Dir]), fatal_error(Msg); eacces -> - Msg = io:format("No write permission in ~p\n", [Dir]), + Msg = io_lib:format("No write permission in ~p\n", [Dir]), fatal_error(Msg); _ -> Msg = io_lib:format("Unhandled error ~s when writing ~p\n", -- cgit v1.2.3 From 1a8b1566f19578d6bd02ecdb753b8b8158c723bf Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Tue, 27 Sep 2011 14:47:13 +0200 Subject: Improve indentation in manpages The indentation after `Warning:' and `Note:' in manpages has been improved. --- lib/erl_docgen/priv/xsl/db_man.xsl | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl index c7efced3d2..1df96caa36 100644 --- a/lib/erl_docgen/priv/xsl/db_man.xsl +++ b/lib/erl_docgen/priv/xsl/db_man.xsl @@ -512,18 +512,42 @@ - .SS Note: + .LP + .RS -4 + .B + Note: + .RE - .SS Warning: + .LP + .RS -4 + .B + Warning: + .RE + + + + + + + + + + + .LP + + + + + .LP -- cgit v1.2.3 From 12014af687bc8555fce572493cadfd0cc872ed59 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 28 Sep 2011 09:57:11 +0200 Subject: Corrected documentation bug --- lib/ssl/doc/src/ssl.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 0c4c8796be..47991ca477 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -649,10 +649,10 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |

Upgrades a gen_tcp, or equivalent, socket to an ssl socket i.e. performs the ssl server-side handshake.

-

Note that the listen socket should be in {active, false} mode +

Note that the listen socket should be in {active, false} mode before telling the client that the server is ready to upgrade and calling this function, otherwise the upgrade may - or may not succeed depending on timing.

+ or may not succeed depending on timing.

-- cgit v1.2.3 From 67d4a9ae422cae2221e48fdeedf0bba3edc4ea81 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 28 Sep 2011 10:06:53 +0200 Subject: Fix make dependency blunder Missed the dependency of dictionary beams on diameter_exprecs when removing compiler modules from app file. The changed build order then caused the build to fail. --- lib/diameter/src/app/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile index ab5754f74f..a75c70d71c 100644 --- a/lib/diameter/src/app/Makefile +++ b/lib/diameter/src/app/Makefile @@ -52,6 +52,9 @@ INCDIR = ../../include include modules.mk +SPEC_MODULES = \ + $(SPEC_FILES:%.dia=%) + SPEC_ERL_FILES = \ $(SPEC_FILES:%.dia=%.erl) @@ -64,7 +67,7 @@ MODULES = \ APP_MODULES = \ $(RUNTIME_MODULES) \ - $(SPEC_FILES:%.dia=%) + $(SPEC_MODULES) TARGET_MODULES = \ $(APP_MODULES) \ @@ -186,7 +189,8 @@ release_docs_spec: # Dependencies # ---------------------------------------------------- -$(SPEC_FILES:%.dia=$(EBIN)/%.$(EMULATOR)): \ +$(SPEC_MODULES:%=$(EBIN)/%.$(EMULATOR)): \ + $(EBIN)/diameter_exprecs.$(EMULATOR) \ $(DIAMETER_TOP)/include/diameter.hrl \ $(DIAMETER_TOP)/include/diameter_gen.hrl -- cgit v1.2.3 From 993a90703712dcf8951c822f30ca4301fe1158c0 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Wed, 28 Sep 2011 11:01:49 +0200 Subject: [mnesia] Prepare release --- lib/mnesia/src/mnesia.appup.src | 2 ++ lib/mnesia/vsn.mk | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src index 3691aa249a..fe4e5e2e7a 100644 --- a/lib/mnesia/src/mnesia.appup.src +++ b/lib/mnesia/src/mnesia.appup.src @@ -1,11 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, {"4.4.16", [{restart_application, mnesia}]} ], [ + {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, {"4.4.16", [{restart_application, mnesia}]} diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index 2fa629d064..a21ab007ef 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.4.19 +MNESIA_VSN = 4.5 -- cgit v1.2.3 From 909cc850f3bd3da0e996d500ec1c27d08ad8de1a Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 28 Sep 2011 18:21:52 +0200 Subject: [erts] Fix memory leak in erts_make_stub_module (hipe loading) Code area allocation was done twice; first in read_code_header() and then in erts_make_stub_module() itself. --- erts/emulator/beam/beam_load.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index eb10ae59a8..fceb352cf3 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -634,6 +634,25 @@ bin_load(Process *c_p, ErtsProcLocks c_p_locks, goto load_error; } + /* + * Initialize code area. + */ + state.code_buffer_size = erts_next_heap_size(2048 + state.num_functions, 0); + state.code = (BeamInstr *) erts_alloc(ERTS_ALC_T_CODE, + sizeof(BeamInstr) * state.code_buffer_size); + + state.code[MI_NUM_FUNCTIONS] = state.num_functions; + state.ci = MI_FUNCTIONS + state.num_functions + 1; + + state.code[MI_ATTR_PTR] = 0; + state.code[MI_ATTR_SIZE] = 0; + state.code[MI_ATTR_SIZE_ON_HEAP] = 0; + state.code[MI_COMPILE_PTR] = 0; + state.code[MI_COMPILE_SIZE] = 0; + state.code[MI_COMPILE_SIZE_ON_HEAP] = 0; + state.code[MI_NUM_BREAKPOINTS] = 0; + + /* * Read the atom table. */ @@ -1363,24 +1382,6 @@ read_code_header(LoaderState* stp) #endif } - /* - * Initialize code area. - */ - stp->code_buffer_size = erts_next_heap_size(2048 + stp->num_functions, 0); - stp->code = (BeamInstr *) erts_alloc(ERTS_ALC_T_CODE, - sizeof(BeamInstr) * stp->code_buffer_size); - - stp->code[MI_NUM_FUNCTIONS] = stp->num_functions; - stp->ci = MI_FUNCTIONS + stp->num_functions + 1; - - stp->code[MI_ATTR_PTR] = 0; - stp->code[MI_ATTR_SIZE] = 0; - stp->code[MI_ATTR_SIZE_ON_HEAP] = 0; - stp->code[MI_COMPILE_PTR] = 0; - stp->code[MI_COMPILE_SIZE] = 0; - stp->code[MI_COMPILE_SIZE_ON_HEAP] = 0; - stp->code[MI_NUM_BREAKPOINTS] = 0; - stp->new_bs_put_strings = 0; stp->catches = 0; return 1; -- cgit v1.2.3 From b75eb2e04df5ccce6f9e62c67fbf8d8a9ac8f425 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 28 Sep 2011 18:34:43 +0200 Subject: Prevent valgrind warning for erts_alloc_permanent_cache_aligned --- erts/emulator/beam/erl_alloc.c | 25 +++++++++++++++++++++++-- erts/emulator/beam/erl_alloc.h | 16 ++-------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index bbc8a445a7..9af80dd7a9 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2960,6 +2960,29 @@ erts_allocator_options(void *proc) return res; } +void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size) +{ + UWord v = (UWord) erts_alloc(type, size + (ERTS_CACHE_LINE_SIZE-1)); + +#ifdef VALGRIND + { /* Avoid Leak_PossiblyLost */ + static UWord vg_root_set[10]; + static unsigned ix = 0; + if (ix >= sizeof(vg_root_set) / sizeof(*vg_root_set)) { + erl_exit(ERTS_ABORT_EXIT, "Too many erts_alloc_permanent_cache_aligned's\n"); + } + vg_root_set[ix++] = v; /* not thread safe */ + } +#endif + + if (v & ERTS_CACHE_LINE_MASK) { + v = (v & ~ERTS_CACHE_LINE_MASK) + ERTS_CACHE_LINE_SIZE; + } + ASSERT((v & ERTS_CACHE_LINE_MASK) == 0); + return (void*)v; +} + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Deprecated functions * * * @@ -3583,6 +3606,4 @@ install_debug_functions(void) return FENCE_SZ; } - - #endif /* #ifdef DEBUG */ diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h index c35a60da22..80cb82c393 100644 --- a/erts/emulator/beam/erl_alloc.h +++ b/erts/emulator/beam/erl_alloc.h @@ -180,11 +180,11 @@ void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size); void erts_free(ErtsAlcType_t type, void *ptr); void *erts_alloc_fnf(ErtsAlcType_t type, Uint size); void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size); -void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size); - #endif /* #if !ERTS_ALC_DO_INLINE */ +void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size); + #ifndef ERTS_CACHE_LINE_SIZE /* Assume a cache line size of 64 bytes */ # define ERTS_CACHE_LINE_SIZE ((UWord) 64) @@ -250,18 +250,6 @@ void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size) size); } -ERTS_ALC_INLINE -void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size) -{ - UWord v = (UWord) erts_alloc(type, size + (ERTS_CACHE_LINE_SIZE-1)); - - if (v & ERTS_CACHE_LINE_MASK) { - v = (v & ~ERTS_CACHE_LINE_MASK) + ERTS_CACHE_LINE_SIZE; - } - ASSERT((v & ERTS_CACHE_LINE_MASK) == 0); - return (void*)v; -} - #endif /* #if ERTS_ALC_DO_INLINE || defined(ERTS_ALC_INTERNAL__) */ typedef void (*erts_alloc_verify_func_t)(Allctr_t *); -- cgit v1.2.3 From 7bbb717e6b5af9a4526fdeac8d8e5b2c8b8ac73a Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 28 Sep 2011 19:08:13 +0200 Subject: Don't install Emakefile at release_tests Emakefile contained compile flags that caused compilation of suites to fail in some cases. common_test will generate an Emakefile and diameter has no need for one of its own. --- lib/diameter/test/Makefile | 67 ++++++++-------------------------------------- 1 file changed, 11 insertions(+), 56 deletions(-) diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 64e200584f..dba1f126dc 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -40,16 +40,6 @@ VSN = $(DIAMETER_VSN) RELSYSDIR = $(RELEASE_PATH)/diameter_test -ifeq ($(findstring win32,$(TARGET)),win32) -MAKEFILE_SRC = Makefile.win32.src -else -MAKEFILE_SRC = Makefile.src -endif - -ifeq ($(TT_DIR),) -TT_DIR = /tmp -endif - # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- @@ -67,16 +57,7 @@ TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) SUITE_MODULES = $(filter diameter_%_SUITE, $(MODULES)) SUITES = $(SUITE_MODULES:diameter_%_SUITE=%) -EMAKEFILE = Emakefile -MAKE_EMAKE = $(wildcard $(TOP)/make/make_emakefile) - -ifeq ($(MAKE_EMAKE),) -BUILDTARGET = $(TARGET_FILES) RELTEST_FILES = $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) -else -BUILDTARGET = emakebuild -RELTEST_FILES = $(EMAKEFILE) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) -endif # ---------------------------------------------------- # FLAGS @@ -84,14 +65,8 @@ endif include ../src/app/diameter.mk -ifeq ($(USE_DIAMETER_TEST_CODE),true) -ERL_COMPILE_FLAGS += -DDIAMETER_TEST_CODE=mona_lisa_spelar_doom -endif - -ifeq ($(USE_DIAMETER_HIPE),true) -ERL_COMPILE_FLAGS += +native -DDIAMETER_hipe_special=true -endif - +# This is only used to compile suite locally when running with a +# target like 'all' below. Target release_tests only installs source. ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) \ -DDIAMETER_CT=true \ -I $(DIAMETER_TOP)/src/app @@ -100,35 +75,24 @@ ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) \ # Targets # ---------------------------------------------------- -all test: $(SUITES) - -tests debug opt: $(BUILDTARGET) - -beam targets: $(TARGET_FILES) - -emakebuild: $(EMAKEFILE) +all: $(SUITES) -$(EMAKEFILE): - $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o $(EBIN) '*_SUITE_make' $(MODULES) \ - | grep -v Warning \ - > $(EMAKEFILE) +tests debug opt: $(TARGET_FILES) clean: - rm -f $(EMAKEFILE) rm -f $(TARGET_FILES) rm -f depend.mk realclean: clean + rm -rf log rm -f errs core *~ -.PHONY: all emakebuild test tests debug opt beam targets clean realclean +.PHONY: all tests debug opt clean realclean docs: info: - @echo "MAKE_EMAKE = $(MAKE_EMAKE)" - @echo "EMAKEFILE = $(EMAKEFILE)" - @echo "BUILDTARGET = $(BUILDTARGET)" + @echo "TARGET_FILES = $(TARGET_FILES)" @echo @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" @echo "ERL = $(ERL)" @@ -143,15 +107,6 @@ info: @echo help: - @echo - @echo "This Makefile controls the test of the $(APPLICATION) application." - @echo - @echo "There are two separate ways to perform the test of $(APPLICATION)." - @echo - @echo " a) Run the official OTP test-server (which we do not describe here)" - @echo - @echo " b) Run individual suites using targets in this makefile, target" - @echo " xxx running the testcases contained in $(APPLICATION)_xxx_SUITE." @echo @echo "Targets:" @echo @@ -161,10 +116,10 @@ help: @echo " $(SUITES)" @echo " Run a specific test suite." @echo - @echo " beam" + @echo " tests" @echo " Compile all test-code." @echo - @echo " clean" + @echo " clean | realclean" @echo " Remove generated files." @echo @echo " info" @@ -183,7 +138,7 @@ help: # Exit with a non-zero status if the output looks to indicate failure. # diameter_ct:run/1 itself can't tell (it seems). -$(SUITES): log targets +$(SUITES): log tests $(ERL) -noshell \ -pa $(DIAMETER_TOP)/ebin \ -sname diameter_test_$@ \ @@ -207,7 +162,7 @@ release_spec: release_docs_spec: -release_tests_spec: tests +release_tests_spec: $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(RELTEST_FILES) $(RELSYSDIR) -- cgit v1.2.3 From b7f1a0861daa57db115b358927293d98e1630810 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Wed, 28 Sep 2011 17:43:26 +0200 Subject: Add missing tests for timetrap handling and fix remaining errors OTP-9593 --- lib/common_test/src/ct_framework.erl | 8 +- lib/common_test/test/ct_error_SUITE.erl | 113 ++++++++++++++- .../error/test/timetrap_3_SUITE.erl | 146 +++++++++++++++++++ .../error/test/timetrap_4_SUITE.erl | 135 ++++++++++++++++++ .../error/test/timetrap_5_SUITE.erl | 155 +++++++++++++++++++++ .../error/test/timetrap_6_SUITE.erl | 114 +++++++++++++++ .../error/test/timetrap_7_SUITE.erl | 137 ++++++++++++++++++ .../error/test/timetrap_utils.erl | 43 ++++++ lib/test_server/src/test_server.erl | 61 +++++--- 9 files changed, 888 insertions(+), 24 deletions(-) create mode 100644 lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_3_SUITE.erl create mode 100644 lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_4_SUITE.erl create mode 100644 lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_5_SUITE.erl create mode 100644 lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_6_SUITE.erl create mode 100644 lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_7_SUITE.erl create mode 100644 lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_utils.erl diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 37ecf4f928..482c5242ce 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -204,12 +204,14 @@ init_tc2(Mod,Func,SuiteInfo,MergeResult,Config,DoInit) -> node=node(), data={Mod,FuncSpec}}), - case configure(MergedInfo1,MergedInfo1,SuiteInfo,{Func,DoInit},Config) of + case catch configure(MergedInfo1,MergedInfo1,SuiteInfo,{Func,DoInit},Config) of {suite0_failed,Reason} -> ct_util:set_testdata({curr_tc,{Mod,{suite0_failed,{require,Reason}}}}), {skip,{require_failed_in_suite0,Reason}}; {error,Reason} -> {auto_skip,{require_failed,Reason}}; + {'EXIT',Reason} -> + {auto_skip,Reason}; {ok, FinalConfig} -> case MergeResult of {error,Reason} -> @@ -1306,6 +1308,10 @@ report(What,Data) -> add_to_stats(auto_skipped); {_,{skipped,{require_failed,_}}} -> add_to_stats(auto_skipped); + {_,{skipped,{timetrap_error,_}}} -> + add_to_stats(auto_skipped); + {_,{skipped,{invalid_time_format,_}}} -> + add_to_stats(auto_skipped); {_,{skipped,_}} -> add_to_stats(user_skipped); {_,{SkipOrFail,_Reason}} -> diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index ebbf6f3bf3..d6ee8eed10 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -60,7 +60,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [cfg_error, lib_error, no_compile, timetrap_end_conf, - timetrap_normal, timetrap_extended]. + timetrap_normal, timetrap_extended, timetrap_parallel, + timetrap_fun]. groups() -> []. @@ -227,6 +228,28 @@ timetrap_parallel(Config) when is_list(Config) -> TestEvents = events_to_check(timetrap_parallel), ok = ct_test_support:verify_events(TestEvents, Events, Config). +%%%----------------------------------------------------------------- +%%% +timetrap_fun(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + Join = fun(D, S) -> filename:join(D, "error/test/"++S) end, + Suites = [Join(DataDir, "timetrap_4_SUITE"), + Join(DataDir, "timetrap_5_SUITE"), + Join(DataDir, "timetrap_6_SUITE"), + Join(DataDir, "timetrap_7_SUITE")], + {Opts,ERPid} = setup([{suite,Suites}], Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(timetrap_fun, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(timetrap_fun), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + + %%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- @@ -814,7 +837,7 @@ test_events(timetrap_parallel) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{1,1,7}}, + {?eh,start_info,{1,1,8}}, {?eh,tc_done,{timetrap_3_SUITE,init_per_suite,ok}}, {parallel, [{?eh,tc_start, @@ -826,8 +849,11 @@ test_events(timetrap_parallel) -> {?eh,tc_start,{timetrap_3_SUITE,tc2}}, {?eh,tc_start,{timetrap_3_SUITE,tc3}}, {?eh,tc_start,{timetrap_3_SUITE,tc4}}, + {?eh,tc_start,{timetrap_3_SUITE,tc5}}, {?eh,tc_start,{timetrap_3_SUITE,tc6}}, {?eh,tc_start,{timetrap_3_SUITE,tc7}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc5,ok}}, {?eh,tc_done, {timetrap_3_SUITE,tc1,{failed,{timetrap_timeout,500}}}}, {?eh,tc_done, @@ -842,11 +868,90 @@ test_events(timetrap_parallel) -> {timetrap_3_SUITE,tc4,{failed,{timetrap_timeout,2000}}}}, {?eh,tc_done, {timetrap_3_SUITE,tc3,{failed,{timetrap_timeout,3000}}}}, - {?eh,test_stats,{0,7,{0,0}}}, + {?eh,test_stats,{1,7,{0,0}}}, {?eh,tc_start, {timetrap_3_SUITE,{end_per_group,g1,[parallel]}}}, {?eh,tc_done, {timetrap_3_SUITE,{end_per_group,g1,[parallel]},ok}}]}, {?eh,tc_done,{timetrap_3_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, - {?eh,stop_logging,[]}]. + {?eh,stop_logging,[]}]; + +test_events(timetrap_fun) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,start_info,{4,4,17}}, + {?eh,tc_done,{timetrap_4_SUITE,init_per_suite,ok}}, + {?eh,tc_start,{timetrap_4_SUITE,tc0}}, + {?eh,tc_done, + {timetrap_4_SUITE,tc0,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_start,{timetrap_4_SUITE,tc1}}, + {?eh,tc_done, + {timetrap_4_SUITE,tc1,{failed,{timetrap_timeout,2000}}}}, + {?eh,tc_start,{timetrap_4_SUITE,tc2}}, + {?eh,tc_done, + {timetrap_4_SUITE,tc2,{failed,{timetrap_timeout,500}}}}, + {?eh,tc_start,{timetrap_4_SUITE,tc3}}, + {?eh,tc_done, + {timetrap_4_SUITE,tc3,{failed,{timetrap_timeout,1000}}}}, + {?eh,test_stats,{0,4,{0,0}}}, + {?eh,tc_done,{timetrap_4_SUITE,end_per_suite,ok}}, + + {?eh,tc_done,{timetrap_5_SUITE,init_per_suite,ok}}, + {?eh,tc_start,{timetrap_5_SUITE,tc0}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc0,{failed,{timetrap_timeout,1000}}}}, + {?eh,test_stats,{0,5,{0,0}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc1}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc1,{skipped,{timetrap_error,kaboom}}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc2}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc2,{skipped,{timetrap_error,kaboom}}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc3}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc3, + {skipped,{invalid_time_format,{timetrap_utils,timetrap_val,[5000]}}}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc4}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc4,{skipped,{invalid_time_format,'_'}}}}, + {?eh,test_stats,{0,5,{0,4}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc5}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc5,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc6}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc6,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_start,{timetrap_5_SUITE,tc7}}, + {?eh,tc_done, + {timetrap_5_SUITE,tc7,{failed,{timetrap_timeout,1000}}}}, + {?eh,test_stats,{0,8,{0,4}}}, + {?eh,tc_done,{timetrap_5_SUITE,end_per_suite,ok}}, + + {?eh,tc_start,{timetrap_6_SUITE,init_per_suite}}, + {?eh,tc_done, + {timetrap_6_SUITE,init_per_suite,{skipped,{timetrap_error,kaboom}}}}, + {?eh,tc_auto_skip, + {timetrap_6_SUITE,tc0,{fw_auto_skip,{timetrap_error,kaboom}}}}, + {?eh,test_stats,{0,8,{0,5}}}, + {?eh,tc_auto_skip, + {timetrap_6_SUITE,end_per_suite,{fw_auto_skip,{timetrap_error,kaboom}}}}, + + {?eh,tc_done,{timetrap_7_SUITE,init_per_suite,ok}}, + {?eh,tc_start,{timetrap_7_SUITE,tc0}}, + {?eh,tc_done, + {timetrap_7_SUITE,tc0,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_start,{timetrap_7_SUITE,tc1}}, + {?eh,tc_done, + {timetrap_7_SUITE,tc1,{failed,{timetrap_timeout,2000}}}}, + {?eh,tc_start,{timetrap_7_SUITE,tc2}}, + {?eh,tc_done, + {timetrap_7_SUITE,tc2,{failed,{timetrap_timeout,500}}}}, + {?eh,tc_start,{timetrap_7_SUITE,tc3}}, + {?eh,tc_done, + {timetrap_7_SUITE,tc3,{failed,{timetrap_timeout,1000}}}}, + {?eh,test_stats,{0,12,{0,5}}}, + {?eh,tc_done,{timetrap_7_SUITE,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_3_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_3_SUITE.erl new file mode 100644 index 0000000000..8271b23afe --- /dev/null +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_3_SUITE.erl @@ -0,0 +1,146 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(timetrap_3_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(TO, 3). + +%%-------------------------------------------------------------------- +%% Function: suite() -> Info +%% Info = [tuple()] +%%-------------------------------------------------------------------- +suite() -> + [{timetrap,{seconds,?TO}}]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_group(_GroupName, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: groups() -> [Group] +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% N = integer() | forever +%%-------------------------------------------------------------------- +groups() -> + [{g1,[parallel],[tc0,tc1,tc2,tc3,tc4,tc5,tc6,tc7]}]. + +%%-------------------------------------------------------------------- +%% Function: all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%%-------------------------------------------------------------------- +all() -> + [{group,g1}]. + +tc0() -> + [{timetrap,2000}]. +tc0(_) -> + ct:comment("TO after 2 sec"), + ct:sleep({seconds,5}), + ok. + +tc1() -> + [{timetrap,500}]. +tc1(_) -> + ct:comment("TO after 1/2 sec"), + ct:sleep({seconds,5}), + ok. + +tc2() -> + [{timetrap,1000}]. +tc2(_) -> + ct:comment("TO after 1 sec"), + ct:sleep({seconds,5}), + ok. + +tc3(_) -> + ct:comment(io_lib:format("TO after ~w sec", [?TO])), + ct:sleep({seconds,5}), + ok. + +tc4() -> + [{timetrap,2000}]. +tc4(_) -> + ct:comment(io_lib:format("TO after 2 sec", [])), + ct:sleep({seconds,5}), + ok. + +tc5() -> + [{timetrap,2000}]. +tc5(_) -> + ct:comment("No timeout"), + ct:sleep({seconds,1}), + ok. + +tc6() -> + [{timetrap,1000}]. +tc6(_) -> + ct:comment("TO after 1 sec"), + ct:sleep({seconds,5}), + ok. + +tc7() -> + [{timetrap,1500}]. +tc7(_) -> + ct:comment("TO after 1 1/2 sec"), + ct:sleep({seconds,5}), + ok. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_4_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_4_SUITE.erl new file mode 100644 index 0000000000..d902454f09 --- /dev/null +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_4_SUITE.erl @@ -0,0 +1,135 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(timetrap_4_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(TO, 1). + +%%-------------------------------------------------------------------- +%% Function: suite() -> Info +%% Info = [tuple()] +%%-------------------------------------------------------------------- +suite() -> + [{timetrap,{timetrap_utils,timetrap_val,[{seconds,?TO}]}}]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_group(_GroupName, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config0) -> +%% void() | {save_config,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_testcase(_, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: groups() -> [Group] +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% N = integer() | forever +%%-------------------------------------------------------------------- +groups() -> + []. + +%%-------------------------------------------------------------------- +%% Function: all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%%-------------------------------------------------------------------- +all() -> + [tc0,tc1,tc2,tc3]. + +tc0(_) -> + ct:comment(io_lib:format("TO after ~w sec", [?TO])), + ct:sleep({seconds,5}), + ok. + +tc1() -> + [{timetrap,{timetrap_utils,timetrap_val,[2000]}}]. +tc1(_) -> + ct:comment("TO after 2 sec"), + ct:sleep({seconds,5}), + ok. + +tc2() -> + [{timetrap,fun() -> timetrap_utils:timetrap_val(500) end}]. +tc2(_) -> + ct:comment("TO after 0.5 sec"), + ct:sleep(1000), + ok. + +tc3(_) -> + ct:comment(io_lib:format("TO after ~w sec", [?TO])), + ct:sleep({seconds,5}), + ok. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_5_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_5_SUITE.erl new file mode 100644 index 0000000000..c5d4b5062e --- /dev/null +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_5_SUITE.erl @@ -0,0 +1,155 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(timetrap_5_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(TO, 1). + +%%-------------------------------------------------------------------- +%% Function: suite() -> Info +%% Info = [tuple()] +%%-------------------------------------------------------------------- +suite() -> + [{timetrap, fun() -> timetrap_utils:timetrap_val({seconds,?TO}) end}]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_group(_GroupName, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config0) -> +%% void() | {save_config,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_testcase(_, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: groups() -> [Group] +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% N = integer() | forever +%%-------------------------------------------------------------------- +groups() -> + []. + +%%-------------------------------------------------------------------- +%% Function: all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%%-------------------------------------------------------------------- +all() -> + [tc0,tc1,tc2,tc3,tc4,tc5,tc6,tc7]. + +tc0(_) -> + ct:comment(io_lib:format("TO after ~w sec", [?TO])), + ct:sleep({seconds,5}), + ok. + +tc1() -> + [{timetrap,{timetrap_utils,timetrap_exit,[kaboom]}}]. +tc1(_) -> + exit(this_should_not_execute). + +tc2() -> + [{timetrap,fun() -> exit(kaboom) end}]. +tc2(_) -> + exit(this_should_not_execute). + +tc3() -> + [{timetrap,{timetrap_utils,timetrap_err_mfa,[]}}]. +tc3(_) -> + exit(this_should_not_execute). + +tc4() -> + [{timetrap,fun() -> timetrap_utils:timetrap_err_fun() end}]. +tc4(_) -> + exit(this_should_not_execute). + +tc5() -> + [{timetrap,{timetrap_utils,timetrap_timeout,[{seconds,40}, + {seconds,1}]}}]. +tc5(_) -> + ct:comment("TO after 40+1 sec"), + ct:sleep({seconds,42}), + ok. + +tc6() -> + [{timetrap,fun() -> ct:sleep(6000), 1000 end}]. +tc6(_) -> + ct:comment("TO after 6+1 sec"), + ct:sleep({seconds,10}). + +tc7(_) -> + ct:comment(io_lib:format("TO after ~w sec", [?TO])), + ct:sleep({seconds,5}), + ok. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_6_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_6_SUITE.erl new file mode 100644 index 0000000000..90467ff752 --- /dev/null +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_6_SUITE.erl @@ -0,0 +1,114 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(timetrap_6_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(TO, 1). + +%%-------------------------------------------------------------------- +%% Function: suite() -> Info +%% Info = [tuple()] +%%-------------------------------------------------------------------- +suite() -> + [{timetrap, fun() -> exit(kaboom) end}]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_group(_GroupName, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config0) -> +%% void() | {save_config,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_testcase(_, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: groups() -> [Group] +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% N = integer() | forever +%%-------------------------------------------------------------------- +groups() -> + []. + +%%-------------------------------------------------------------------- +%% Function: all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%%-------------------------------------------------------------------- +all() -> + [tc0]. + +tc0(_) -> + ok. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_7_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_7_SUITE.erl new file mode 100644 index 0000000000..b25b7770a7 --- /dev/null +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_7_SUITE.erl @@ -0,0 +1,137 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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(timetrap_7_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(TO, 1). +-define(HANG, 6). + +%%-------------------------------------------------------------------- +%% Function: suite() -> Info +%% Info = [tuple()] +%%-------------------------------------------------------------------- +suite() -> + [{timetrap,{timetrap_utils,timetrap_timeout,[{seconds,?HANG}, + {seconds,?TO}]}}]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config0) -> void() | {save_config,Config1} +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% GroupName = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_group(_GroupName, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%% Reason = term() +%%-------------------------------------------------------------------- +init_per_testcase(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config0) -> +%% void() | {save_config,Config1} +%% TestCase = atom() +%% Config0 = Config1 = [tuple()] +%%-------------------------------------------------------------------- +end_per_testcase(_, _Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: groups() -> [Group] +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% N = integer() | forever +%%-------------------------------------------------------------------- +groups() -> + []. + +%%-------------------------------------------------------------------- +%% Function: all() -> GroupsAndTestCases | {skip,Reason} +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% TestCase = atom() +%% Reason = term() +%%-------------------------------------------------------------------- +all() -> + [tc0,tc1,tc2,tc3]. + +tc0(_) -> + ct:comment(io_lib:format("TO after ~w+~w sec", [?HANG,?TO])), + ct:sleep({seconds,5}), + ok. + +tc1() -> + [{timetrap,{timetrap_utils,timetrap_val,[2000]}}]. +tc1(_) -> + ct:comment("TO after 2 sec"), + ct:sleep({seconds,5}), + ok. + +tc2() -> + [{timetrap,fun() -> timetrap_utils:timetrap_val(500) end}]. +tc2(_) -> + ct:comment("TO after 0.5 sec"), + ct:sleep(1000), + ok. + +tc3(_) -> + ct:comment(io_lib:format("TO after ~w+~w sec", [?HANG,?TO])), + ct:sleep({seconds,5}), + ok. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_utils.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_utils.erl new file mode 100644 index 0000000000..fcde6cd701 --- /dev/null +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_utils.erl @@ -0,0 +1,43 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2011. 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(timetrap_utils). + +-export([timetrap_val/1, + timetrap_err_fun/0, + timetrap_err_mfa/0, + timetrap_exit/1, + timetrap_timeout/2]). + +timetrap_val(Val) -> + Val. + +timetrap_err_fun() -> + fun() -> 5000 end. + +timetrap_err_mfa() -> + {?MODULE,timetrap_val,[5000]}. + +timetrap_exit(Reason) -> + exit(Reason). + +timetrap_timeout(Sleep, Val) -> + ct:sleep(Sleep), + Val. + diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index e1a139af6f..12625e3c00 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -1921,30 +1921,53 @@ time_ms({seconds,N}) -> seconds(N); time_ms({Other,_N}) -> format("=== ERROR: Invalid time specification: ~p. " "Should be seconds, minutes, or hours.~n", [Other]), - exit({invalid_time_spec,Other}); + exit({invalid_time_format,Other}); time_ms(Ms) when is_integer(Ms) -> Ms; time_ms(infinity) -> infinity; time_ms(Fun) when is_function(Fun) -> - try Fun() of - Val -> time_ms1(Val) - catch - _:Error -> - exit({timetrap_error,Error}) - end; -time_ms({M,F,A}) when is_atom(M), is_atom(F), is_list(A) -> - try apply(M, F, A) of - Val -> time_ms1(Val) - catch - _:Error -> + time_ms_apply(Fun); +time_ms({M,F,A}=MFA) when is_atom(M), is_atom(F), is_list(A) -> + time_ms_apply(MFA); +time_ms(Other) -> exit({invalid_time_format,Other}). + +time_ms_apply(Func) -> + time_ms_apply(Func, [5000,30000,60000,infinity]). + +time_ms_apply(Func, TOs) -> + Apply = fun() -> + case Func of + {M,F,A} -> + exit({self(),apply(M, F, A)}); + Fun -> + exit({self(),Fun()}) + end + end, + Pid = spawn(Apply), + Ref = monitor(process, Pid), + time_ms_wait(Func, Pid, Ref, TOs). + +time_ms_wait(Func, Pid, Ref, [TO|TOs]) -> + receive + {'DOWN',Ref,process,Pid,{Pid,Result}} -> + time_ms_check(Result); + {'DOWN',Ref,process,Pid,Error} -> exit({timetrap_error,Error}) + after + TO -> + format("=== WARNING: No return from timetrap function ~p~n", [Func]), + time_ms_wait(Func, Pid, Ref, TOs) end; -time_ms(Other) -> exit({invalid_time_spec,Other}). - -time_ms1(MFA = {M,F,A}) when is_atom(M), is_atom(F), is_list(A) -> - exit({invalid_time_spec,MFA}); -time_ms1(Fun) when is_function(Fun) -> - exit({invalid_time_spec,Fun}); -time_ms1(Other) -> +%% this clause will never execute if 'infinity' is in TOs list, that's ok! +time_ms_wait(Func, Pid, Ref, []) -> + demonitor(Ref), + exit(Pid, kill), + exit({timetrap_error,{no_return_from_timetrap_function,Func}}). + +time_ms_check(MFA = {M,F,A}) when is_atom(M), is_atom(F), is_list(A) -> + exit({invalid_time_format,MFA}); +time_ms_check(Fun) when is_function(Fun) -> + exit({invalid_time_format,Fun}); +time_ms_check(Other) -> time_ms(Other). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From e78be5c09eda6a8738d07d801dd8935f3eaa5400 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 29 Sep 2011 00:21:27 +0200 Subject: Add documentation on timetraps and start flags --- lib/common_test/doc/src/common_test_app.xml | 32 +++++++++++++++++++------- lib/common_test/doc/src/write_test_chapter.xml | 14 +++++++---- lib/common_test/src/ct.erl | 2 +- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index 57b032b3fd..f58b2ab0a9 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -133,9 +133,15 @@ {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} | {stylesheet,CSSFile} | {ct_hooks, CTHs} - Time = MilliSec | {seconds,integer()} | {minutes,integer()} - | {hours,integer()} + Time = TimeVal | TimeFunc + TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | + {hours,integer()} + TimeFunc = {Mod,Func,Args} | Fun MilliSec = integer() + Mod = atom() + Func = atom() + Args = list() + Fun = fun() Required = Key | {Key,SubKeys} Key = atom() SubKeys = SubKey | [SubKey] @@ -161,7 +167,9 @@ test case is allowed to take (including init_per_testcase/2 and end_per_testcase/2). If the timetrap time is exceeded, the test case fails with reason - timetrap_timeout.

+ timetrap_timeout. If a TimeFunc function is specified, + it will be called initially and must return a value on + TimeVal format.

The require tag specifies configuration variables that are required by test cases in the suite. If the required @@ -248,7 +256,7 @@ -

MANDATORY (only if one or more groups are defined)

+

OPTIONAL

This function is called before execution of a test case group. It typically contains initialization which is common for @@ -279,7 +287,7 @@ -

MANDATORY (only if one or more groups are defined)

+

OPTIONAL

This function is called after the execution of a test case group is finished. It is meant to be used for cleaning up after init_per_group/2. @@ -353,9 +361,15 @@ Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} - Time = MilliSec | {seconds,integer()} | {minutes,integer()} - | {hours,integer()} + Time = TimeVal | TimeFunc + TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | + {hours,integer()} + TimeFunc = {Mod,Func,Args} | Fun MilliSec = integer() + Mod = atom() + Func = atom() + Args = list() + Fun = fun() Required = Key | {Key,SubKeys} Key = atom() SubKeys = SubKey | [SubKey] @@ -378,7 +392,9 @@ exceeded, the test case fails with reason timetrap_timeout. init_per_testcase/2 and end_per_testcase/2 are included in the - timetrap time.

+ timetrap time. If a TimeFunc function is specified, + it will be called before the test case (or init_per_testcase/2) + and must return a value on TimeVal format.

The require tag specifies configuration variables that are required by the test case. If the required diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index 3f9fdb7121..e35888e68f 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -280,6 +280,8 @@ the timetrap time is exceeded, the test case fails with reason timetrap_timeout. Note that init_per_testcase and end_per_testcase are included in the timetrap time. + Please see the Timetrap + section for more details.

userdata @@ -699,8 +701,8 @@
- Timetrap timeouts + Timetrap timeouts

The default time limit for a test case is 30 minutes, unless a timetrap is specified either by the suite info function or a test case info function. The timetrap timeout value defined @@ -723,6 +725,13 @@ multipled by multiply_timetraps, and possibly scaled up if scale_timetraps is enabled, the function ct:sleep/1 may be called.

+

A function (fun or MFA) may be specified as timetrap value + in the suite- and test case info function, e.g:

+

{timetrap,{test_utils,get_timetrap_value,[?MODULE,system_start]}}

+

The function will be called initially by Common Test (before execution + of the suite or the test case) and must return a time value such as an + integer (millisec), or a {SecMinOrHourTag,Time} tuple. More + information can be found in the common_test reference manual.

@@ -818,6 +827,3 @@
- - - diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 4c215d1b1e..f3c2029734 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -151,7 +151,7 @@ run(TestDirs) -> %%% {refresh_logs,LogDir} | {logopts,LogOpts} | {basic_html,Bool} | %%% {ct_hooks, CTHs} %%% TestDirs = [string()] | string() -%%% Suites = [string()] | string() +%%% Suites = [string()] | [atom()] | string() | atom() %%% Cases = [atom()] | atom() %%% Groups = [atom()] | atom() %%% TestSpecs = [string()] | string() -- cgit v1.2.3 From 5f04095f2c991a1d2e2c40bfa609342ac9ff9ebe Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 29 Sep 2011 15:17:37 +0200 Subject: Correct "Missing Suites" link OTP-9592 --- lib/common_test/src/ct_logs.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 3798f26f7b..faec461775 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -838,6 +838,7 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, "" end end, + CtRunDir = filename:dirname(filename:dirname(Link)), {Lbl,Timestamp,Node,AllInfo} = case All of {true,OldRuns} -> @@ -847,7 +848,6 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, _ -> NodeOrDate end, N = ["",Node1,"\n"], - CtRunDir = filename:dirname(filename:dirname(Link)), L = ["",Label,"\n"], T = ["",timestamp(CtRunDir),"\n"], CtLogFile = filename:join(CtRunDir,?ct_log_name), @@ -866,7 +866,7 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, if NotBuilt == 0 -> ["",integer_to_list(NotBuilt),"\n"]; true -> - ["", + ["", integer_to_list(NotBuilt),"\n"] end, FailStr = -- cgit v1.2.3 From 921b3c97880bef41215f258ffcc3aa718db736c3 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 29 Sep 2011 17:26:01 +0200 Subject: Remove forgotten dbg --- lib/diameter/test/diameter_relay_SUITE.erl | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index 0cda2df8ca..a5f6808940 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -147,13 +147,6 @@ end_per_group(_, _) -> init_per_suite(Config) -> ok = diameter:start(), - - dbg:tracer(port, dbg:trace_port(file, "relay.dbg")), - dbg:p(all,c), - dbg:tpl(diameter_service, x), - dbg:tp(?MODULE, x), - - [S1,S2,S3,S4] = S = [server(N, ?DICT_COMMON) || N <- [?SERVER1, ?SERVER2, ?SERVER3, -- cgit v1.2.3 From f1f8e2ff2c7f53ae9de3c7bb27402f8cc6f8532a Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 21 Sep 2011 17:50:48 +0200 Subject: Use now instead of os:timestamp This is done in order to improve timing when testing debug builds, especially ppc debug builds. --- erts/emulator/test/busy_port_SUITE.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl index 8365e1c540..2cb01f5a8c 100644 --- a/erts/emulator/test/busy_port_SUITE.erl +++ b/erts/emulator/test/busy_port_SUITE.erl @@ -495,12 +495,12 @@ hs_busy_pcmd(Prt, Opts, StartFun, EndFun) -> P = spawn_link(fun () -> erlang:yield(), Tester ! {self(), doing_port_command}, - Start = os:timestamp(), + Start = now(), Res = try {return, port_command(Prt, [], Opts)} catch Exception:Error -> {Exception, Error} end, - End = os:timestamp(), + End = now(), Time = round(timer:now_diff(End, Start)/1000), Tester ! {self(), port_command_result, Res, Time} end), -- cgit v1.2.3 From 702505ef8a077b07ec9cb4845bb780d4c68e22ec Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 21 Sep 2011 18:05:49 +0200 Subject: Double timeout to make sure debug builds pass --- erts/emulator/test/distribution_SUITE.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index e4af5c00a6..05dbffc819 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -331,7 +331,7 @@ receiver2(Num, TotSize) -> link_to_busy(doc) -> "Test that link/1 to a busy distribution port works."; link_to_busy(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(30)), + ?line Dog = test_server:timetrap(test_server:seconds(60)), ?line {ok, Node} = start_node(link_to_busy), ?line Recv = spawn(Node, erlang, apply, [fun sink/1, [link_to_busy_sink]]), @@ -378,7 +378,7 @@ tail_applied_linker(Pid) -> exit_to_busy(doc) -> "Test that exit/2 to a busy distribution port works."; exit_to_busy(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(30)), + ?line Dog = test_server:timetrap(test_server:seconds(60)), ?line {ok, Node} = start_node(exit_to_busy), Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of -- cgit v1.2.3 From 9b2b8c8652032c216c4f14d54fa24a2492c8325b Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 22 Sep 2011 09:47:42 +0200 Subject: Extend slave start timeout for windows tests --- lib/common_test/test/ct_test_support.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 31381abc40..e85e8e6ad3 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -25,6 +25,7 @@ -include_lib("test_server/include/test_server.hrl"). -include_lib("common_test/include/ct_event.hrl"). +-include_lib("common_test/include/ct.hrl"). -export([init_per_suite/1, init_per_suite/2, end_per_suite/1, init_per_testcase/2, end_per_testcase/2, @@ -46,9 +47,10 @@ init_per_suite(Config) -> init_per_suite(Config, Level) -> case os:type() of {win32, _} -> - %% Extend timeout for windows as starting node + %% Extend timeout to 1 hour for windows as starting node %% can take a long time there - test_server:timetrap( 120000 * test_server:timetrap_scale_factor()); + test_server:timetrap( 60*60*1000 * + test_server:timetrap_scale_factor()); _ -> ok end, -- cgit v1.2.3 From c058ca00728fbdbb7cef535a8beb13abbaa58cb7 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 26 Sep 2011 12:25:59 +0200 Subject: Allow out of memory exception for max_port checks --- erts/emulator/test/port_SUITE.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index eac56a867d..0a1ef5a78f 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -724,6 +724,8 @@ open_ports(Name, Settings) -> []; system_limit -> []; + enomem -> + []; Other -> ?line test_server:fail({open_ports, Other}) end; -- cgit v1.2.3 From 8b06e8921f7e2f9d907df7edd8daf11ee24a0a1e Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 26 Sep 2011 19:04:25 +0200 Subject: Extend time to wait for zone files to be loaded This change was made in order to make slow solaris machines work. --- lib/kernel/test/inet_res_SUITE_data/run-named | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named index b418607d48..7caa3756ef 100755 --- a/lib/kernel/test/inet_res_SUITE_data/run-named +++ b/lib/kernel/test/inet_res_SUITE_data/run-named @@ -2,7 +2,7 @@ ## ## %CopyrightBegin% ## -## Copyright Ericsson AB 2009. All Rights Reserved. +## Copyright Ericsson AB 2009-2011. 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 @@ -155,7 +155,7 @@ $NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 /dev/null 2>&1; wait $NAMED >/dev/null 2>&1" \ 0 1 2 3 15 -sleep 1 # Give name server time to load its zone files +sleep 2 # Give name server time to load its zone files echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED]..." while read LINE; do test :"$LINE" = :'quit' && break -- cgit v1.2.3 From a176db06b4de2354a385813409a3340c85c3b341 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 26 Sep 2011 19:13:03 +0200 Subject: Use static port for old solaris versions Solaris version before 10 have some problem with releasing addresses after doing a gen_udp:open, which causes inet_res to get a econnrefused. With this fix we hope that the static port will not collide with anything. --- lib/kernel/test/inet_res_SUITE.erl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index 6064a9b2d9..8a3d220e46 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -117,9 +117,15 @@ ns_init(ZoneDir, PrivDir, DataDir) -> case os:type() of {unix,_} when ZoneDir =:= undefined -> undefined; {unix,_} -> - {ok,S} = gen_udp:open(0, [{reuseaddr,true}]), - {ok,PortNum} = inet:port(S), - gen_udp:close(S), + PortNum = case {os:type(),os:version()} of + {{unix,solaris},{M,V,_}} when M =< 5, V < 10 -> + 11895 + random:uniform(100); + _ -> + {ok,S} = gen_udp:open(0, [{reuseaddr,true}]), + {ok,PNum} = inet:port(S), + gen_udp:close(S), + PNum + end, RunNamed = filename:join(DataDir, ?RUN_NAMED), NS = {{127,0,0,1},PortNum}, P = erlang:open_port({spawn_executable,RunNamed}, -- cgit v1.2.3 From 22a3818adb4e3433d7ab9f34e0ade06fdf10d8d6 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 27 Sep 2011 12:03:04 +0200 Subject: Skip getaddr_v6 test if on the ipv4_only host --- lib/kernel/test/inet_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 1bb173a3ac..aaa20b7398 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -294,7 +294,7 @@ t_getaddr_v6(Config) when is_list(Config) -> ?line {Name,FullName,IPStr,_IP,_,IP_46_Str,IP46} = ct:get_config(test_host_ipv4_only), case {inet:getaddr(IP_46_Str, inet6),inet:getaddr(Name, inet6)} of - {{ok,IP46},{ok,_}} -> + {{ok,IP46},{ok,V4Addr}} when V4Addr /= {0,0,0,0,0,0,0,1} -> %% Since we suceeded in parsing an IPv6 address string and %% look up the name, this computer fully supports IPv6. ?line {ok,IP46} = inet:getaddr(IP46, inet6), -- cgit v1.2.3 From bb98bf86894527817e0d00aa87286a4291937d03 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 27 Sep 2011 12:20:41 +0200 Subject: Remove test_server path instead of cwd for clash test With the introduction of common_test as test framework the working directory of the tests changed to be the emulator_test directory. So we now have to remove the ../test_server directory instead. This change only affect tests run with a emulator which has not been installed. --- lib/kernel/test/code_SUITE.erl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 86cccebc29..f7d56eed48 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -573,11 +573,13 @@ add_del_path(Config) when is_list(Config) -> clash(Config) when is_list(Config) -> DDir = ?config(data_dir,Config)++"clash/", P = code:get_path(), + [TestServerPath|_] = [Path || Path <- code:get_path(), + re:run(Path,"test_server/?$",[]) /= nomatch], %% test non-clashing entries - %% remove "." to prevent clash with test-server path - ?line true = code:del_path("."), + %% remove TestServerPath to prevent clash with test-server path + ?line true = code:del_path(TestServerPath), ?line true = code:add_path(DDir++"foobar-0.1/ebin"), ?line true = code:add_path(DDir++"zork-0.8/ebin"), test_server:capture_start(), @@ -589,8 +591,8 @@ clash(Config) when is_list(Config) -> %% test clashing entries - %% remove "." to prevent clash with test-server path - ?line true = code:del_path("."), + %% remove TestServerPath to prevent clash with test-server path + ?line true = code:del_path(TestServerPath), ?line true = code:add_path(DDir++"foobar-0.1/ebin"), ?line true = code:add_path(DDir++"foobar-0.1.ez/foobar-0.1/ebin"), test_server:capture_start(), @@ -603,9 +605,9 @@ clash(Config) when is_list(Config) -> %% test "Bad path can't read" - %% remove "." to prevent clash with test-server path + %% remove TestServerPath to prevent clash with test-server path Priv = ?config(priv_dir, Config), - ?line true = code:del_path("."), + ?line true = code:del_path(TestServerPath), TmpEzFile = Priv++"foobar-0.tmp.ez", ?line {ok, _} = file:copy(DDir++"foobar-0.1.ez", TmpEzFile), ?line true = code:add_path(TmpEzFile++"/foobar-0.1/ebin"), -- cgit v1.2.3 From d41617d9969253d9e66270beebac843865036baa Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 27 Sep 2011 17:14:08 +0200 Subject: Skip create_big_boot on platforms without crypto This has to be done as many other applications depend on that crypto is present. --- lib/kernel/test/code_SUITE.erl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index f7d56eed48..b677f34ed0 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -81,6 +81,13 @@ init_per_suite(Config) -> end_per_suite(Config) -> Config. +init_per_testcase(big_boot_embedded, Config) -> + case catch crypto:start() of + ok -> + init_per_testcase(do_big_boot_embedded, Config); + _Else -> + {skip, "Needs crypto!"} + end; init_per_testcase(_Func, Config) -> Dog=?t:timetrap(?t:minutes(5)), P=code:get_path(), -- cgit v1.2.3 From 5acac472723ef5cac6a944caf7b7ec4320c003e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 29 Sep 2011 18:10:19 +0200 Subject: Update copyright years --- INSTALL.md | 2 +- erts/doc/src/alt_dist.xml | 2 +- erts/doc/src/erlsrv.xml | 2 +- erts/doc/src/start_erl.xml | 2 +- erts/emulator/beam/bif.tab | 2 +- erts/emulator/beam/erl_afit_alloc.c | 2 +- erts/emulator/beam/erl_ao_firstfit_alloc.c | 2 +- erts/emulator/beam/erl_ao_firstfit_alloc.h | 2 +- erts/emulator/beam/erl_bestfit_alloc.c | 2 +- erts/emulator/beam/erl_bestfit_alloc.h | 2 +- erts/emulator/beam/erl_bif_trace.c | 2 +- erts/emulator/beam/erl_bits.h | 2 +- erts/emulator/beam/erl_goodfit_alloc.c | 2 +- erts/emulator/beam/erl_init.c | 2 +- erts/emulator/beam/erl_instrument.c | 2 +- erts/emulator/beam/external.h | 2 +- erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c | 2 +- erts/emulator/utils/beam_makeops | 2 +- erts/epmd/src/epmd_cli.c | 2 +- erts/epmd/src/epmd_int.h | 2 +- erts/etc/win32/erlsrv/erlsrv_interactive.c | 2 +- erts/etc/win32/erlsrv/erlsrv_interactive.h | 2 +- erts/etc/win32/start_erl.c | 2 +- erts/example/matrix_nif.c | 2 +- erts/include/internal/ethread_header_config.h.in | 2 +- erts/lib_src/common/erl_printf.c | 2 +- erts/preloaded/src/prim_zip.erl | 2 +- lib/asn1/doc/src/asn1ct.xml | 2 +- lib/asn1/test/test_compile_options.erl | 2 +- lib/compiler/src/beam_disasm.erl | 2 +- lib/compiler/src/sys_pre_expand.erl | 2 +- lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl | 2 +- lib/dialyzer/src/dialyzer_typesig.erl | 2 +- lib/docbuilder/doc/src/notes.xml | 2 +- lib/erl_docgen/priv/xsl/db_pdf_params.xsl | 2 +- lib/erl_interface/doc/src/ei.xml | 2 +- lib/erl_interface/src/encode/encode_atom.c | 2 +- lib/erl_interface/src/encode/encode_string.c | 2 +- lib/erl_interface/src/legacy/erl_fix_alloc.c | 2 +- lib/erl_interface/test/port_call_SUITE_data/Makefile.src | 2 +- lib/et/doc/src/notes.xml | 2 +- lib/gs/contribs/bonk/sounder.erl | 2 +- lib/gs/contribs/cols/cols.erl | 2 +- lib/gs/contribs/mandel/mandel.erl | 2 +- lib/gs/contribs/othello/othello_board.erl | 2 +- lib/gs/examples/calc2.erl | 2 +- lib/hipe/main/hipe.hrl.src | 2 +- lib/hipe/regalloc/hipe_node_sets.erl | 2 +- lib/hipe/rtl/hipe_rtl_lcm.erl | 2 +- lib/ic/src/ic.erl | 2 +- lib/inets/Makefile | 2 +- lib/inets/doc/src/notes_history.xml | 2 +- lib/inets/src/http_client/httpc_cookie.erl | 2 +- lib/inets/src/http_server/httpd_conf.erl | 2 +- lib/inets/src/http_server/httpd_esi.erl | 2 +- lib/inets/src/http_server/httpd_request.erl | 2 +- lib/inets/src/http_server/mod_auth_mnesia.erl | 2 +- lib/inets/test/httpd_test_lib.erl | 2 +- lib/kernel/src/code_server.erl | 2 +- lib/odbc/c_src/odbcserver.h | 2 +- lib/odbc/doc/src/databases.xml | 2 +- lib/odbc/src/odbc_internal.hrl | 2 +- lib/os_mon/c_src/cpu_sup.c | 2 +- lib/os_mon/doc/src/notes.xml | 2 +- lib/parsetools/doc/src/leex.xml | 2 +- lib/parsetools/src/yecc.erl | 2 +- lib/percept/src/percept_db.erl | 2 +- lib/runtime_tools/doc/src/dbg.xml | 2 +- lib/sasl/examples/src/Makefile | 2 +- lib/snmp/Makefile | 2 +- lib/snmp/src/compile/snmpc_lib.erl | 2 +- lib/snmp/src/manager/snmpm_mpd.erl | 2 +- lib/ssl/doc/src/ssl_protocol.xml | 2 +- lib/ssl/src/ssl_ssl2.erl | 2 +- lib/stdlib/doc/src/unicode_usage.xml | 2 +- lib/stdlib/src/dets_v8.erl | 2 +- lib/stdlib/src/erl_compile.erl | 2 +- lib/stdlib/src/eval_bits.erl | 2 +- lib/syntax_tools/doc/src/notes.xml | 2 +- lib/toolbar/src/toolbar_toolconfig.erl | 2 +- lib/tools/doc/src/instrument.xml | 2 +- lib/tv/doc/src/notes.xml | 2 +- lib/webtool/doc/src/notes.xml | 2 +- lib/wx/api_gen/gl_gen.erl | 2 +- lib/wx/test/wxt.erl | 2 +- lib/xmerl/src/xmerl_ucs.erl | 2 +- make/otp_release_targets.mk | 2 +- system/doc/reference_manual/distributed.xml | 2 +- 88 files changed, 88 insertions(+), 88 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 24053b4793..526df8de93 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -726,7 +726,7 @@ Copyright and License %CopyrightBegin% -Copyright Ericsson AB 1998-2010. All Rights Reserved. +Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/doc/src/alt_dist.xml b/erts/doc/src/alt_dist.xml index c30e04fce7..038950b54d 100644 --- a/erts/doc/src/alt_dist.xml +++ b/erts/doc/src/alt_dist.xml @@ -4,7 +4,7 @@
- 20002010 + 20002011 Ericsson AB. All Rights Reserved. diff --git a/erts/doc/src/erlsrv.xml b/erts/doc/src/erlsrv.xml index 919caa9542..c1ecbc7b77 100644 --- a/erts/doc/src/erlsrv.xml +++ b/erts/doc/src/erlsrv.xml @@ -4,7 +4,7 @@
- 19982010 + 19982011 Ericsson AB. All Rights Reserved. diff --git a/erts/doc/src/start_erl.xml b/erts/doc/src/start_erl.xml index 6f6930af7e..92d87b095a 100644 --- a/erts/doc/src/start_erl.xml +++ b/erts/doc/src/start_erl.xml @@ -4,7 +4,7 @@
- 19982009 + 19982011 Ericsson AB. All Rights Reserved. diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 831c0b1ce6..ba30fa85b8 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2010. All Rights Reserved. +# Copyright Ericsson AB 1996-2011. 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 diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c index d397cd8848..bcc7ea04ae 100644 --- a/erts/emulator/beam/erl_afit_alloc.c +++ b/erts/emulator/beam/erl_afit_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c index 002852cdad..90d8ea7300 100644 --- a/erts/emulator/beam/erl_ao_firstfit_alloc.c +++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h index 0bf0ec8cee..6fa626f723 100644 --- a/erts/emulator/beam/erl_ao_firstfit_alloc.h +++ b/erts/emulator/beam/erl_ao_firstfit_alloc.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c index 5e3032ddaa..f2199d41a1 100644 --- a/erts/emulator/beam/erl_bestfit_alloc.c +++ b/erts/emulator/beam/erl_bestfit_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/erl_bestfit_alloc.h b/erts/emulator/beam/erl_bestfit_alloc.h index faa2d9742e..0c29662852 100644 --- a/erts/emulator/beam/erl_bestfit_alloc.h +++ b/erts/emulator/beam/erl_bestfit_alloc.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index fbd8757751..7a08182e18 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * Copyright Ericsson AB 1999-2011. 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 diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h index 3309ea706b..388d943755 100644 --- a/erts/emulator/beam/erl_bits.h +++ b/erts/emulator/beam/erl_bits.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * Copyright Ericsson AB 1999-2011. 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 diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c index 1cc508ac5a..8322b233ac 100644 --- a/erts/emulator/beam/erl_goodfit_alloc.c +++ b/erts/emulator/beam/erl_goodfit_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2010. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 0173fd40f6..e5fd2547a0 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2010. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. 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 diff --git a/erts/emulator/beam/erl_instrument.c b/erts/emulator/beam/erl_instrument.c index 04ea004ef7..963c8b3c58 100644 --- a/erts/emulator/beam/erl_instrument.c +++ b/erts/emulator/beam/erl_instrument.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2010. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. 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 diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h index 72fe74baf2..671b8b8781 100644 --- a/erts/emulator/beam/external.h +++ b/erts/emulator/beam/external.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * Copyright Ericsson AB 1996-2011. 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 diff --git a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c index 0e4065c26b..7c8137dc83 100644 --- a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c +++ b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010. All Rights Reserved. + * Copyright Ericsson AB 2010-2011. 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 diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops index 354439b5e3..ebf7db3277 100755 --- a/erts/emulator/utils/beam_makeops +++ b/erts/emulator/utils/beam_makeops @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2010. All Rights Reserved. +# Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c index 2377c0dfe7..74408e3ebe 100644 --- a/erts/epmd/src/epmd_cli.c +++ b/erts/epmd/src/epmd_cli.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index a2d7559f9d..14d05c3f19 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -2,7 +2,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.c b/erts/etc/win32/erlsrv/erlsrv_interactive.c index 4c990a694d..736eabac79 100644 --- a/erts/etc/win32/erlsrv/erlsrv_interactive.c +++ b/erts/etc/win32/erlsrv/erlsrv_interactive.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.h b/erts/etc/win32/erlsrv/erlsrv_interactive.h index 602da24575..23e69e508d 100644 --- a/erts/etc/win32/erlsrv/erlsrv_interactive.h +++ b/erts/etc/win32/erlsrv/erlsrv_interactive.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/etc/win32/start_erl.c b/erts/etc/win32/start_erl.c index 6ca7dd9b99..28c8e55bd3 100644 --- a/erts/etc/win32/start_erl.c +++ b/erts/etc/win32/start_erl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/erts/example/matrix_nif.c b/erts/example/matrix_nif.c index 43f9526ae3..404329e36c 100644 --- a/erts/example/matrix_nif.c +++ b/erts/example/matrix_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010. All Rights Reserved. + * Copyright Ericsson AB 2010-2011. 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 diff --git a/erts/include/internal/ethread_header_config.h.in b/erts/include/internal/ethread_header_config.h.in index 1fb630cb78..1f82db8693 100644 --- a/erts/include/internal/ethread_header_config.h.in +++ b/erts/include/internal/ethread_header_config.h.in @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * Copyright Ericsson AB 2004-2011. 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 diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c index 6aa4569d44..108a8bb531 100644 --- a/erts/lib_src/common/erl_printf.c +++ b/erts/lib_src/common/erl_printf.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * Copyright Ericsson AB 2005-2011. 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 diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index 5dc8e3ca13..392a9feb45 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index 50458b4a9a..29b5d4be75 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -4,7 +4,7 @@
- 19972010 + 19972011 Ericsson AB. All Rights Reserved. diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl index 5cb212eddf..a622d5bfd2 100644 --- a/lib/asn1/test/test_compile_options.erl +++ b/lib/asn1/test/test_compile_options.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. 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 diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl index bb62bb04b3..5c4d8e12b5 100644 --- a/lib/compiler/src/beam_disasm.erl +++ b/lib/compiler/src/beam_disasm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. 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 diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl index dd6f24e21f..249bd7a8e7 100644 --- a/lib/compiler/src/sys_pre_expand.erl +++ b/lib/compiler/src/sys_pre_expand.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl index 5dbe6f6b2f..b7643fb30d 100644 --- a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl +++ b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. 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 diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index 06863d89a7..30aec59d22 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. 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 diff --git a/lib/docbuilder/doc/src/notes.xml b/lib/docbuilder/doc/src/notes.xml index d04c8dd839..ef6523889d 100644 --- a/lib/docbuilder/doc/src/notes.xml +++ b/lib/docbuilder/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20072010 + 20072011 Ericsson AB. All Rights Reserved. diff --git a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl index d2f0350cf1..4d9c08d0c3 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2010. All Rights Reserved. + # Copyright Ericsson AB 2009-2011. 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 diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml index 76e02a6858..539e16d837 100644 --- a/lib/erl_interface/doc/src/ei.xml +++ b/lib/erl_interface/doc/src/ei.xml @@ -4,7 +4,7 @@
- 20012010 + 20012011 Ericsson AB. All Rights Reserved. diff --git a/lib/erl_interface/src/encode/encode_atom.c b/lib/erl_interface/src/encode/encode_atom.c index b1a4479034..6f41f045e0 100644 --- a/lib/erl_interface/src/encode/encode_atom.c +++ b/lib/erl_interface/src/encode/encode_atom.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/lib/erl_interface/src/encode/encode_string.c b/lib/erl_interface/src/encode/encode_string.c index 593bbf2b6d..d00d2f3e81 100644 --- a/lib/erl_interface/src/encode/encode_string.c +++ b/lib/erl_interface/src/encode/encode_string.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. 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 diff --git a/lib/erl_interface/src/legacy/erl_fix_alloc.c b/lib/erl_interface/src/legacy/erl_fix_alloc.c index ca09fc3b8b..2ed0dd1470 100644 --- a/lib/erl_interface/src/legacy/erl_fix_alloc.c +++ b/lib/erl_interface/src/legacy/erl_fix_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/erl_interface/test/port_call_SUITE_data/Makefile.src b/lib/erl_interface/test/port_call_SUITE_data/Makefile.src index 0799187d64..a512494aa3 100644 --- a/lib/erl_interface/test/port_call_SUITE_data/Makefile.src +++ b/lib/erl_interface/test/port_call_SUITE_data/Makefile.src @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# Copyright Ericsson AB 2001-2011. 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 diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml index e3be8422c8..7082948d94 100644 --- a/lib/et/doc/src/notes.xml +++ b/lib/et/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20022010 + 20022011 Ericsson AB. All Rights Reserved. diff --git a/lib/gs/contribs/bonk/sounder.erl b/lib/gs/contribs/bonk/sounder.erl index 899f20d4e0..e6f69a1616 100644 --- a/lib/gs/contribs/bonk/sounder.erl +++ b/lib/gs/contribs/bonk/sounder.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/gs/contribs/cols/cols.erl b/lib/gs/contribs/cols/cols.erl index 439eb717f7..111c9a58f1 100644 --- a/lib/gs/contribs/cols/cols.erl +++ b/lib/gs/contribs/cols/cols.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/gs/contribs/mandel/mandel.erl b/lib/gs/contribs/mandel/mandel.erl index 579f8e487b..0f1df5c665 100644 --- a/lib/gs/contribs/mandel/mandel.erl +++ b/lib/gs/contribs/mandel/mandel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/gs/contribs/othello/othello_board.erl b/lib/gs/contribs/othello/othello_board.erl index 6ccb79b7e4..212ba9bfe1 100644 --- a/lib/gs/contribs/othello/othello_board.erl +++ b/lib/gs/contribs/othello/othello_board.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/gs/examples/calc2.erl b/lib/gs/examples/calc2.erl index 9969a6c40f..0e841397f6 100644 --- a/lib/gs/examples/calc2.erl +++ b/lib/gs/examples/calc2.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src index ec55c707ef..e74f31b19d 100644 --- a/lib/hipe/main/hipe.hrl.src +++ b/lib/hipe/main/hipe.hrl.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. 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 diff --git a/lib/hipe/regalloc/hipe_node_sets.erl b/lib/hipe/regalloc/hipe_node_sets.erl index 0bb21d7506..be43ff2bfd 100644 --- a/lib/hipe/regalloc/hipe_node_sets.erl +++ b/lib/hipe/regalloc/hipe_node_sets.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. 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 diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl index d45ab4ed46..9224623c8b 100644 --- a/lib/hipe/rtl/hipe_rtl_lcm.erl +++ b/lib/hipe/rtl/hipe_rtl_lcm.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. 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 diff --git a/lib/ic/src/ic.erl b/lib/ic/src/ic.erl index e22179fe42..50fad921c4 100644 --- a/lib/ic/src/ic.erl +++ b/lib/ic/src/ic.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 diff --git a/lib/inets/Makefile b/lib/inets/Makefile index f4c2746b0a..4765a2ca3c 100644 --- a/lib/inets/Makefile +++ b/lib/inets/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2010. All Rights Reserved. +# Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml index f70ce5cf46..151bec375e 100644 --- a/lib/inets/doc/src/notes_history.xml +++ b/lib/inets/doc/src/notes_history.xml @@ -4,7 +4,7 @@
- 20042010 + 20042011 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl index 1addbe944d..69900bae65 100644 --- a/lib/inets/src/http_client/httpc_cookie.erl +++ b/lib/inets/src/http_client/httpc_cookie.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. 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 diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index d1b1ea0e14..5352eb8bb9 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl index aac5645282..000874d0a3 100644 --- a/lib/inets/src/http_server/httpd_esi.erl +++ b/lib/inets/src/http_server/httpd_esi.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. 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 diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index 90f8bdd912..a04bcc2778 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. 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 diff --git a/lib/inets/src/http_server/mod_auth_mnesia.erl b/lib/inets/src/http_server/mod_auth_mnesia.erl index b7b9520649..91beb0e062 100644 --- a/lib/inets/src/http_server/mod_auth_mnesia.erl +++ b/lib/inets/src/http_server/mod_auth_mnesia.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 2903aaafa5..581461fe03 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. 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 diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 85bbff9cc3..e3d22e7999 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. 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 diff --git a/lib/odbc/c_src/odbcserver.h b/lib/odbc/c_src/odbcserver.h index 314fbf32c6..56b6148777 100644 --- a/lib/odbc/c_src/odbcserver.h +++ b/lib/odbc/c_src/odbcserver.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2010. All Rights Reserved. + * Copyright Ericsson AB 2002-2011. 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 diff --git a/lib/odbc/doc/src/databases.xml b/lib/odbc/doc/src/databases.xml index 09f5a5af5b..34e1d51255 100644 --- a/lib/odbc/doc/src/databases.xml +++ b/lib/odbc/doc/src/databases.xml @@ -4,7 +4,7 @@
- 20022010 + 20022011 Ericsson AB. All Rights Reserved. diff --git a/lib/odbc/src/odbc_internal.hrl b/lib/odbc/src/odbc_internal.hrl index c0e7d9657b..bd80cdc659 100644 --- a/lib/odbc/src/odbc_internal.hrl +++ b/lib/odbc/src/odbc_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. 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 diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c index e3bdbd1489..9c5f9a6aa5 100644 --- a/lib/os_mon/c_src/cpu_sup.c +++ b/lib/os_mon/c_src/cpu_sup.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. 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 diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml index 3b5dbe3146..0a088ca8b6 100644 --- a/lib/os_mon/doc/src/notes.xml +++ b/lib/os_mon/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20042010 + 20042011 Ericsson AB. All Rights Reserved. diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index 1fa426a79e..d5c24c303d 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -4,7 +4,7 @@
- 20092009 + 20092011 Ericsson AB. All Rights Reserved. diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index 354d56527d..b0792a6ed8 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/percept/src/percept_db.erl b/lib/percept/src/percept_db.erl index 61b68ce44f..68eb38d298 100644 --- a/lib/percept/src/percept_db.erl +++ b/lib/percept/src/percept_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. 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 diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml index 4e32bd5c0d..f26789fa21 100644 --- a/lib/runtime_tools/doc/src/dbg.xml +++ b/lib/runtime_tools/doc/src/dbg.xml @@ -4,7 +4,7 @@
- 19962009 + 19962011 Ericsson AB. All Rights Reserved. diff --git a/lib/sasl/examples/src/Makefile b/lib/sasl/examples/src/Makefile index c58f651696..9cf0d4c25d 100644 --- a/lib/sasl/examples/src/Makefile +++ b/lib/sasl/examples/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2010. All Rights Reserved. +# Copyright Ericsson AB 2010-2011. 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 diff --git a/lib/snmp/Makefile b/lib/snmp/Makefile index c55eff04c6..4264531112 100644 --- a/lib/snmp/Makefile +++ b/lib/snmp/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl index a0a35e91c4..38bb8f3ac6 100644 --- a/lib/snmp/src/compile/snmpc_lib.erl +++ b/lib/snmp/src/compile/snmpc_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl index 627838e3d4..103c87d32b 100644 --- a/lib/snmp/src/manager/snmpm_mpd.erl +++ b/lib/snmp/src/manager/snmpm_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. 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 diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml index ca5cc8bc7a..ff6c769f6c 100644 --- a/lib/ssl/doc/src/ssl_protocol.xml +++ b/lib/ssl/doc/src/ssl_protocol.xml @@ -4,7 +4,7 @@
- 20032010 + 20032011 Ericsson AB. All Rights Reserved. diff --git a/lib/ssl/src/ssl_ssl2.erl b/lib/ssl/src/ssl_ssl2.erl index 30a3a5fc98..a9ab6a2678 100644 --- a/lib/ssl/src/ssl_ssl2.erl +++ b/lib/ssl/src/ssl_ssl2.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. 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 diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml index b48ad8c1f3..0fa7de0a5c 100644 --- a/lib/stdlib/doc/src/unicode_usage.xml +++ b/lib/stdlib/doc/src/unicode_usage.xml @@ -5,7 +5,7 @@
1999 - 2010 + 2011 Ericsson AB. All Rights Reserved. diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl index 299b037c28..cdd38d5604 100644 --- a/lib/stdlib/src/dets_v8.erl +++ b/lib/stdlib/src/dets_v8.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. 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 diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl index d833f626bf..ff032b129c 100644 --- a/lib/stdlib/src/erl_compile.erl +++ b/lib/stdlib/src/erl_compile.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl index 2c7192a7e7..1ffa6ea328 100644 --- a/lib/stdlib/src/eval_bits.erl +++ b/lib/stdlib/src/eval_bits.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. 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 diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml index ec2dd762b8..5948f7ada3 100644 --- a/lib/syntax_tools/doc/src/notes.xml +++ b/lib/syntax_tools/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20072010 + 20072011 Ericsson AB. All Rights Reserved. diff --git a/lib/toolbar/src/toolbar_toolconfig.erl b/lib/toolbar/src/toolbar_toolconfig.erl index 693a7b4570..6dccb7ba72 100644 --- a/lib/toolbar/src/toolbar_toolconfig.erl +++ b/lib/toolbar/src/toolbar_toolconfig.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml index a7c62c8770..b7e48ea306 100644 --- a/lib/tools/doc/src/instrument.xml +++ b/lib/tools/doc/src/instrument.xml @@ -4,7 +4,7 @@
- 19982009 + 19982011 Ericsson AB. All Rights Reserved. diff --git a/lib/tv/doc/src/notes.xml b/lib/tv/doc/src/notes.xml index b3f2f5587f..77a6a43d51 100644 --- a/lib/tv/doc/src/notes.xml +++ b/lib/tv/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20042010 + 20042011 Ericsson AB. All Rights Reserved. diff --git a/lib/webtool/doc/src/notes.xml b/lib/webtool/doc/src/notes.xml index b7e6f0421c..b626ad2178 100644 --- a/lib/webtool/doc/src/notes.xml +++ b/lib/webtool/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20042010 + 20042011 Ericsson AB. All Rights Reserved. diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl index b665d949b3..8998d341e7 100644 --- a/lib/wx/api_gen/gl_gen.erl +++ b/lib/wx/api_gen/gl_gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 diff --git a/lib/wx/test/wxt.erl b/lib/wx/test/wxt.erl index 2f52c58f26..c14d3f8647 100644 --- a/lib/wx/test/wxt.erl +++ b/lib/wx/test/wxt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 diff --git a/lib/xmerl/src/xmerl_ucs.erl b/lib/xmerl/src/xmerl_ucs.erl index feb16070a0..6550a9d954 100644 --- a/lib/xmerl/src/xmerl_ucs.erl +++ b/lib/xmerl/src/xmerl_ucs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. 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 diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk index 229612630d..7cd827b5af 100644 --- a/make/otp_release_targets.mk +++ b/make/otp_release_targets.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# Copyright Ericsson AB 1997-2011. 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 diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml index 9c8e88250c..d0eac78404 100644 --- a/system/doc/reference_manual/distributed.xml +++ b/system/doc/reference_manual/distributed.xml @@ -4,7 +4,7 @@
- 20032009 + 20032011 Ericsson AB. All Rights Reserved. -- cgit v1.2.3 From ae69c5d45911607b1a162a141d193a04ee6dc213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 29 Sep 2011 18:32:01 +0200 Subject: Update primary bootstrap --- bootstrap/bin/start.boot | Bin 5330 -> 5330 bytes bootstrap/bin/start_clean.boot | Bin 5330 -> 5330 bytes bootstrap/lib/compiler/ebin/beam_asm.beam | Bin 9028 -> 9028 bytes bootstrap/lib/compiler/ebin/beam_disasm.beam | Bin 23268 -> 23260 bytes bootstrap/lib/compiler/ebin/compile.beam | Bin 33652 -> 34108 bytes bootstrap/lib/compiler/ebin/sys_pre_expand.beam | Bin 14156 -> 14048 bytes bootstrap/lib/kernel/ebin/code.beam | Bin 6284 -> 6284 bytes bootstrap/lib/kernel/ebin/code_server.beam | Bin 23736 -> 23788 bytes bootstrap/lib/kernel/ebin/hipe_unified_loader.beam | Bin 11460 -> 11460 bytes bootstrap/lib/kernel/ebin/inet.beam | Bin 18124 -> 18124 bytes bootstrap/lib/kernel/ebin/inet_config.beam | Bin 8280 -> 7644 bytes bootstrap/lib/kernel/ebin/inet_dns.beam | Bin 18712 -> 18472 bytes bootstrap/lib/kernel/include/inet_sctp.hrl | 2 +- bootstrap/lib/stdlib/ebin/beam_lib.beam | Bin 16504 -> 16528 bytes bootstrap/lib/stdlib/ebin/dets.beam | Bin 48400 -> 48400 bytes bootstrap/lib/stdlib/ebin/erl_compile.beam | Bin 4736 -> 4672 bytes bootstrap/lib/stdlib/ebin/erl_internal.beam | Bin 4980 -> 4996 bytes bootstrap/lib/stdlib/ebin/erl_scan.beam | Bin 30424 -> 30476 bytes bootstrap/lib/stdlib/ebin/erl_tar.beam | Bin 14320 -> 14072 bytes bootstrap/lib/stdlib/ebin/io_lib_fread.beam | Bin 6836 -> 6772 bytes bootstrap/lib/stdlib/ebin/otp_internal.beam | Bin 8928 -> 9016 bytes bootstrap/lib/stdlib/ebin/sofs.beam | Bin 37972 -> 37972 bytes bootstrap/lib/stdlib/ebin/supervisor.beam | Bin 16400 -> 16472 bytes bootstrap/lib/stdlib/ebin/zip.beam | Bin 24552 -> 24552 bytes bootstrap/lib/stdlib/include/erl_bits.hrl | 2 +- bootstrap/lib/stdlib/include/erl_compile.hrl | 2 +- bootstrap/lib/stdlib/include/ms_transform.hrl | 2 +- bootstrap/lib/stdlib/include/qlc.hrl | 2 +- 28 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot index 875f1b1c8b..62f3290116 100644 Binary files a/bootstrap/bin/start.boot and b/bootstrap/bin/start.boot differ diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot index 875f1b1c8b..62f3290116 100644 Binary files a/bootstrap/bin/start_clean.boot and b/bootstrap/bin/start_clean.boot differ diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam index 5719592cae..8a8eb1c79e 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_asm.beam and b/bootstrap/lib/compiler/ebin/beam_asm.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam index c8e2b27623..bf852e06d8 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_disasm.beam and b/bootstrap/lib/compiler/ebin/beam_disasm.beam differ diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam index c4b31874cc..472695269c 100644 Binary files a/bootstrap/lib/compiler/ebin/compile.beam and b/bootstrap/lib/compiler/ebin/compile.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam index 7b4d278e30..22ab9bf85a 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam and b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam differ diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam index 960b96ce4c..b8cbad759b 100644 Binary files a/bootstrap/lib/kernel/ebin/code.beam and b/bootstrap/lib/kernel/ebin/code.beam differ diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam index 3d66c1c282..d2f141ef57 100644 Binary files a/bootstrap/lib/kernel/ebin/code_server.beam and b/bootstrap/lib/kernel/ebin/code_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam index a53e6f8800..184951f734 100644 Binary files a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam and b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam index faac3fc921..44be711f59 100644 Binary files a/bootstrap/lib/kernel/ebin/inet.beam and b/bootstrap/lib/kernel/ebin/inet.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam index b3061fffa1..04a01392a7 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_config.beam and b/bootstrap/lib/kernel/ebin/inet_config.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam index cfd46c29da..4a79e7e358 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_dns.beam and b/bootstrap/lib/kernel/ebin/inet_dns.beam differ diff --git a/bootstrap/lib/kernel/include/inet_sctp.hrl b/bootstrap/lib/kernel/include/inet_sctp.hrl index 3c072cc1db..169ba013aa 100644 --- a/bootstrap/lib/kernel/include/inet_sctp.hrl +++ b/bootstrap/lib/kernel/include/inet_sctp.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2009. 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 diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam index d29c13189a..cf325b8394 100644 Binary files a/bootstrap/lib/stdlib/ebin/beam_lib.beam and b/bootstrap/lib/stdlib/ebin/beam_lib.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam index 002b3c9229..8c9b7cecd5 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets.beam and b/bootstrap/lib/stdlib/ebin/dets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam index 18693b47a3..518c0bca31 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_compile.beam and b/bootstrap/lib/stdlib/ebin/erl_compile.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam index 8d080bdacc..cb54e8c9e5 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_internal.beam and b/bootstrap/lib/stdlib/ebin/erl_internal.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam index 51082779b8..28d9460820 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_scan.beam and b/bootstrap/lib/stdlib/ebin/erl_scan.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam index 7cf0571935..27ebd9251a 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_tar.beam and b/bootstrap/lib/stdlib/ebin/erl_tar.beam differ diff --git a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam index bebe0a6c75..74ef63f2a4 100644 Binary files a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam and b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam differ diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam index 2fbda80a5e..0621fcdc25 100644 Binary files a/bootstrap/lib/stdlib/ebin/otp_internal.beam and b/bootstrap/lib/stdlib/ebin/otp_internal.beam differ diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam index 8cbcfb55de..faf5bd0f44 100644 Binary files a/bootstrap/lib/stdlib/ebin/sofs.beam and b/bootstrap/lib/stdlib/ebin/sofs.beam differ diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam index 4e46676a20..54c09f5a66 100644 Binary files a/bootstrap/lib/stdlib/ebin/supervisor.beam and b/bootstrap/lib/stdlib/ebin/supervisor.beam differ diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam index 74f7c6a208..25c4fc8167 100644 Binary files a/bootstrap/lib/stdlib/ebin/zip.beam and b/bootstrap/lib/stdlib/ebin/zip.beam differ diff --git a/bootstrap/lib/stdlib/include/erl_bits.hrl b/bootstrap/lib/stdlib/include/erl_bits.hrl index aca213c08c..54ebe58585 100644 --- a/bootstrap/lib/stdlib/include/erl_bits.hrl +++ b/bootstrap/lib/stdlib/include/erl_bits.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2009. 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 diff --git a/bootstrap/lib/stdlib/include/erl_compile.hrl b/bootstrap/lib/stdlib/include/erl_compile.hrl index 2e0d90dfad..f779c4382c 100644 --- a/bootstrap/lib/stdlib/include/erl_compile.hrl +++ b/bootstrap/lib/stdlib/include/erl_compile.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2009. 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 diff --git a/bootstrap/lib/stdlib/include/ms_transform.hrl b/bootstrap/lib/stdlib/include/ms_transform.hrl index 2b89a4df2f..9937d48fef 100644 --- a/bootstrap/lib/stdlib/include/ms_transform.hrl +++ b/bootstrap/lib/stdlib/include/ms_transform.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2011. All Rights Reserved. +%% Copyright Ericsson AB 2002-2009. 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 diff --git a/bootstrap/lib/stdlib/include/qlc.hrl b/bootstrap/lib/stdlib/include/qlc.hrl index cccedcbd2c..067fb83060 100644 --- a/bootstrap/lib/stdlib/include/qlc.hrl +++ b/bootstrap/lib/stdlib/include/qlc.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2009. 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 -- cgit v1.2.3 From 345992c1e82eb2e876139248cc50eb4df029a5f5 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 29 Sep 2011 17:06:25 +0200 Subject: Create temporary fix for problem with parallel test cases OTP-9600 --- lib/test_server/src/test_server.erl | 40 ++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 12625e3c00..244207e140 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -749,7 +749,8 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) -> {read_comment,From} -> From ! {self(),read_comment,Comment}, run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,CurrConf); - {set_curr_conf,NewCurrConf} -> + {set_curr_conf,From,NewCurrConf} -> + From ! {self(),set_curr_conf,ok}, run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,Comment,NewCurrConf); {'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} -> RetVal = {Time/1000000,Value,mod_loc(Loc),Opts,Comment}, @@ -973,10 +974,19 @@ spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why, spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, {timetrap_timeout,TVal}=Why,_Loc,SendTo,Comment) -> + %%! This is a temporary fix that keeps Test Server alive during + %%! execution of a parallel test case group, when sometimes + %%! this clause gets called with EndConf == undefined. See OTP-9594 + %%! for more info. + EndConf1 = if EndConf == undefined -> + [{tc_status,{failed,{Mod,end_per_testcase,Why}}}]; + true -> + EndConf + end, FwCall = fun() -> {RetVal,Report} = - case proplists:get_value(tc_status, EndConf) of + case proplists:get_value(tc_status, EndConf1) of undefined -> E = {failed,{Mod,end_per_testcase,Why}}, {E,E}; @@ -986,9 +996,9 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, E = {failed,{Mod,end_per_testcase,Why}}, {Result,E} end, - FailLoc = proplists:get_value(tc_fail_loc, EndConf), + FailLoc = proplists:get_value(tc_fail_loc, EndConf1), case catch do_end_tc_call(Mod,Func, FailLoc, - {Pid,Report,[EndConf]}, Why) of + {Pid,Report,[EndConf1]}, Why) of {'EXIT',FwEndTCErr} -> exit({fw_notify_done,end_tc,FwEndTCErr}); _ -> @@ -1160,7 +1170,8 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> %% call user callback function if defined NewConf1 = user_callback(TCCallback, Mod, Func, init, NewConf), %% save current state in controller loop - group_leader() ! {set_curr_conf,{{Mod,Func},NewConf1}}, + sync_send(group_leader(),set_curr_conf,{{Mod,Func},NewConf1}, + 5000, fun() -> exit(no_answer_from_group_leader) end), put(test_server_loc, {Mod,Func}), %% execute the test case {{T,Return},Loc} = {ts_tc(Mod, Func, [NewConf1]),get_loc()}, @@ -1188,7 +1199,8 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> %% call user callback function if defined EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf), %% update current state in controller loop - group_leader() ! {set_curr_conf,EndConf1}, + sync_send(group_leader(),set_curr_conf,EndConf1, + 5000, fun() -> exit(no_answer_from_group_leader) end), {FWReturn1,TSReturn1,EndConf2} = case end_per_testcase(Mod, Func, EndConf1) of SaveCfg1={save_config,_} -> @@ -1208,7 +1220,8 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> {FWReturn,TSReturn,EndConf1} end, %% clear current state in controller loop - group_leader() ! {set_curr_conf,undefined}, + sync_send(group_leader(),set_curr_conf,undefined, + 5000, fun() -> exit(no_answer_from_group_leader) end), put(test_server_init_or_end_conf,undefined), case do_end_tc_call(Mod,Func, Loc, {FWReturn1,[EndConf2]}, TSReturn1) of @@ -2016,6 +2029,19 @@ hours(N) -> trunc(N * 1000 * 60 * 60). minutes(N) -> trunc(N * 1000 * 60). seconds(N) -> trunc(N * 1000). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% sync_send(Pid,Tag,Msg,Timeout,DoAfter) -> Result +%% +sync_send(Pid,Tag,Msg,Timeout,DoAfter) -> + Pid ! {Tag,self(),Msg}, + receive + {Pid,Tag,Result} -> + Result + after Timeout -> + DoAfter() + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% timecall(M,F,A) -> {Time,Val} %% Time = float() -- cgit v1.2.3 From ff916887efb0db7b4c093f768e5240d879fa85c9 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 30 Sep 2011 11:01:20 +0200 Subject: Rid ct_telnet of doc build warnings OTP-9572 --- lib/common_test/src/ct_telnet.erl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index c6f5fd7df4..71a784870c 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -245,7 +245,6 @@ cmdf(Connection,CmdFormat,Args) -> %%% Data = [string()] %%% @doc Send a telnet command and wait for prompt %%% (uses a format string and list of arguments to build the command). -%%%----------------------------------------------------------------- cmdf(Connection,CmdFormat,Args,Timeout) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), cmd(Connection,Cmd,Timeout). @@ -360,15 +359,15 @@ expect(Connection,Patterns) -> %%% will also be a HaltReason returned.

%%% %%%

Examples:
-%%% expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}], -%%% [sequence,{halt,[{nnn,"NNN"}]}]).
will try to match +%%% expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}], +%%% [sequence,{halt,[{nnn,"NNN"}]}]).
will try to match %%% "ABC" first and then "XYZ", but if "NNN" appears the function will %%% return {error,{nnn,["NNN"]}}. If both "ABC" and "XYZ" %%% are matched, the function will return %%% {ok,[AbcMatch,XyzMatch]}.

%%% -%%%

expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}], -%%% [{repeat,2},{halt,[{nnn,"NNN"}]}]).
will try to match +%%%

expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}], +%%% [{repeat,2},{halt,[{nnn,"NNN"}]}]).
will try to match %%% "ABC" or "XYZ" twice. If "NNN" appears the function will return %%% with HaltReason = {nnn,["NNN"]}.

%%% -- cgit v1.2.3 From 09fbbccd5a8638601e44c605cd887f90b85d7d60 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 30 Sep 2011 13:26:59 +0200 Subject: Update documentation OTP-9396 OTP-9372 OTP-9155 --- lib/common_test/doc/src/ct_run.xml | 7 ++++-- lib/common_test/doc/src/run_test_chapter.xml | 35 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml index 1ab563d74f..9045646733 100644 --- a/lib/common_test/doc/src/ct_run.xml +++ b/lib/common_test/doc/src/ct_run.xml @@ -83,7 +83,7 @@ Run tests from command line
 	ct_run [-dir TestDir1 TestDir2 .. TestDirN] |
-	[-suite Suite1 Suite2 .. SuiteN
+	[[-dir TestDir] -suite Suite1 Suite2 .. SuiteN
 	 [[-group Group1 Group2 .. GroupN] [-case Case1 Case2 .. CaseN]]]
 	[-step [config | keep_inactive]]
 	[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
@@ -92,6 +92,7 @@
 	[-decrypt_key Key] | [-decrypt_file KeyFile]
 	[-label Label]
 	[-logdir LogDir]
+	[-logopts LogOpts]
 	[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
 	[-stylesheet CSSFile]
 	[-cover CoverCfgFile]
@@ -117,6 +118,7 @@
 	[-decrypt_key Key] | [-decrypt_file KeyFile]
 	[-label Label]
 	[-logdir LogDir]
+	[-logopts LogOpts]
 	[-allow_user_terms]
 	[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
 	[-stylesheet CSSFile]
@@ -138,10 +140,11 @@
     
         ct_run -vts [-browser Browser]
         [-dir TestDir1 TestDir2 .. TestDirN] |
-        [-suite Suite [[-group Group] [-case Case]]]
+        [[dir TestDir] -suite Suite [[-group Group] [-case Case]]]
 	[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
 	[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
          ConfigString2 and .. and CallbackModuleN ConfigStringN]
+	[-logopts LogOpts]
 	[-decrypt_key Key] | [-decrypt_file KeyFile]
 	[-include InclDir1 InclDir2 .. InclDirN]
 	[-no_auto_compile]
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index e944f215f6..d3c6847d85 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -128,6 +128,15 @@
     

$ ct_run -suite $SYS1_TEST/setup_SUITE -case start stop

$ ct_run -suite $SYS1_TEST/setup_SUITE -group installation -case start stop

+

It is also possible to combine the dir, suite and group/case flags. E.g, to run + x_SUITE and y_SUITE in directory testdir:

+ +

$ ct_run -dir ./testdir -suite x_SUITE y_SUITE

+ +

This has the same effect as calling:

+ +

$ ct_run -suite ./testdir/x_SUITE ./testdir/y_SUITE

+

Other flags that may be used with ct_run:

]]>, specifies where the HTML log files are to be written. @@ -165,6 +174,8 @@ ]]>, points out a file containing a decryption key for encrypted configuration files. , switches off html enhancements that might not be compatible with older browsers. + ]]>, makes it possible to modify aspects of the logging behaviour, see + Log options below.

Directories passed to Common Test may have either relative or absolute paths.

@@ -645,6 +656,30 @@ to follow test progress simply by refreshing pages in the HTML browser. Statistics totals are not presented until a test is complete however.

+
+ + Log options +

With the logopts start flag, it's possible to specify + options that modify some aspects of the logging behaviour. + Currently, the following options are available:

+ + no_src + no_nl + +

With no_src, the html version of the test suite source + code will not be generated during the test run (and consequently + not be available in the log file system).

+

With no_nl, Common Test will not add a newline character + (\n) to the end of an output string that it receives from a call to e.g. + io:format/2, and which it prints to the test case log.

+

For example, if a test is started with:

+

$ ct_run -suite my_SUITE -logopts no_src

+

then printouts during the test made by successive calls to io:format("x"), + will appear in the test case log as:

+

xxx

+

instead of each x printed on a new line, which is the default behaviour.

+
+
-- cgit v1.2.3 From b69adb23ccc7e05ca3e15f4c765d20da5225b337 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 30 Sep 2011 19:49:19 +0200 Subject: Touch crypto to provoke patch release (again) --- lib/crypto/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile index 2a8fc6acfd..6db5b03912 100644 --- a/lib/crypto/Makefile +++ b/lib/crypto/Makefile @@ -36,4 +36,4 @@ SPECIAL_TARGETS = include $(ERL_TOP)/make/otp_subdir.mk -# touched by patch 1176 +# touched by patch 1178 -- cgit v1.2.3 From 7a087c36e29cc1d12c856054a94772e86b95ee06 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 3 Oct 2011 11:31:00 +0200 Subject: [ssl] Step version for patch 1178 No source change. Building with dynamic linking towards OpenSSL v0.9.8 --- lib/ssl/src/ssl.appup.src | 3 ++- lib/ssl/vsn.mk | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 29674f30da..6b4b62abc2 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.1.5.1", [{restart_application, ssl}]}, {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, @@ -10,7 +11,7 @@ {"4.0.1", [{restart_application, ssl}]} ], [ - {"4.1.5", [{restart_application, ssl}]}, + {"4.1.5.1", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 64a7603c44..deb554d73d 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 4.1.5.1 +SSL_VSN = 4.1.5.2 -- cgit v1.2.3 From eb8de5aa37948e45ebc4d18244b626ea68f5e5b7 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 16 Sep 2011 10:10:16 +0200 Subject: Add payload test --- lib/ssl/test/ssl_dist_SUITE.erl | 51 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 7325e97ff5..f54eb29062 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -39,7 +39,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [basic]. + [basic, payload]. groups() -> []. @@ -132,6 +132,55 @@ basic(Config) when is_list(Config) -> stop_ssl_node(NH2), success(Config). + +payload(doc) -> + ["Test that send a lot of data between the ssl distributed noes"]; +payload(suite) -> + []; +payload(Config) when is_list(Config) -> + NH1 = start_ssl_node(Config), + Node1 = NH1#node_handle.nodename, + NH2 = start_ssl_node(Config), + Node2 = NH2#node_handle.nodename, + + pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), + + [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end), + [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end), + + %% + %% Check that we are able to communicate over the erlang + %% distribution between the ssl nodes. + %% + Ref = make_ref(), + spawn(fun () -> + apply_on_ssl_node( + NH1, + fun () -> + send_to_tstcntrl({Ref, self()}), + receive + {From, Msg} -> + From ! {self(), Msg} + end + end) + end), + receive + {Ref, SslPid} -> + ok = apply_on_ssl_node( + NH2, + fun () -> + Msg = crypto:rand_bytes(100000), + SslPid ! {self(), Msg}, + receive + {SslPid, Msg} -> + ok + end + end) + end, + stop_ssl_node(NH1), + stop_ssl_node(NH2), + success(Config). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% Internal functions %% -- cgit v1.2.3 From e0ab75e4206f16d8d073e9f31c487bc1d4ab84b7 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 23 Sep 2011 10:58:55 +0200 Subject: Remove ssl_prim calls that are remains from the old ssl distribution --- lib/ssl/src/inet_tls_dist.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index f42c076460..115527aae0 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -136,9 +136,9 @@ check_ip(Socket) -> end. get_ifs(Socket) -> - case ssl_prim:peername(Socket) of + case inet:peername(Socket) of {ok, {IP, _}} -> - case ssl_prim:getif(Socket) of + case inet:getif(Socket) of {ok, IFs} -> {ok, IFs, IP}; Error -> Error end; -- cgit v1.2.3 From e2ecc6e0db2064d072ad68b7c0a3d1bcf7c27c3a Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 23 Sep 2011 11:02:18 +0200 Subject: Improve code structure --- lib/ssl/src/ssl_tls_dist_proxy.erl | 47 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index 1a998a0f34..8993582fe8 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -126,11 +126,9 @@ get_tcp_address(Socket) -> family = inet }. -accept_loop(Proxy, Type, Listen, Extra) -> +accept_loop(Proxy, erts = Type, Listen, Extra) -> process_flag(priority, max), - case Type of - erts -> - case gen_tcp:accept(Listen) of + case gen_tcp:accept(Listen) of {ok, Socket} -> Extra ! {accept,self(),Socket,inet,proxy}, receive @@ -142,30 +140,31 @@ accept_loop(Proxy, Type, Listen, Extra) -> exit(unsupported_protocol) end; Error -> - exit(Error) + exit(Error) + end, + accept_loop(Proxy, Type, Listen, Extra); + +accept_loop(Proxy, world = Type, Listen, Extra) -> + process_flag(priority, max), + case gen_tcp:accept(Listen) of + {ok, Socket} -> + Opts = get_ssl_options(server), + case ssl:ssl_accept(Socket, Opts) of + {ok, SslSocket} -> + PairHandler = + spawn_link(fun() -> + setup_connection(SslSocket, Extra) + end), + ok = ssl:controlling_process(SslSocket, PairHandler), + flush_old_controller(PairHandler, SslSocket); + _ -> + gen_tcp:close(Socket) end; - world -> - case gen_tcp:accept(Listen) of - {ok, Socket} -> - Opts = get_ssl_options(server), - case ssl:ssl_accept(Socket, Opts) of - {ok, SslSocket} -> - PairHandler = - spawn_link(fun() -> - setup_connection(SslSocket, Extra) - end), - ok = ssl:controlling_process(SslSocket, PairHandler), - flush_old_controller(PairHandler, SslSocket); - _ -> - gen_tcp:close(Socket) - end; - Error -> - exit(Error) - end + Error -> + exit(Error) end, accept_loop(Proxy, Type, Listen, Extra). - try_connect(Port) -> case gen_tcp:connect({127,0,0,1}, Port, [{active, false}, {packet,?PPRE}]) of R = {ok, _S} -> -- cgit v1.2.3 From 9102b1733eb4e71333a521763aeff32a59de9672 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Tue, 4 Oct 2011 11:07:10 +0200 Subject: Prepare release --- lib/crypto/doc/src/notes.xml | 17 +++++++++++++++++ lib/crypto/vsn.mk | 2 +- lib/ssl/doc/src/notes.xml | 19 ++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index 55f8cc90ca..d9398783ee 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -30,6 +30,23 @@

This document describes the changes made to the Crypto application.

+
Crypto 2.0.3.2 + +
Fixed Bugs and Malfunctions + + +

+ Changed crypto and ssl to be dynamically linked to + OpenSSL and use version 0.9.8 of OpenSSL (instead of + 0.9.7) on PowerPC.

+

+ Own Id: OTP-9603 Aux Id: seq11912

+
+
+
+ +
+
Crypto 2.0.3.1
Improvements and New Features diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index 547c33c07f..facb68bdd6 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.3.1 +CRYPTO_VSN = 2.0.3.2 diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index b2d17925fd..b7e716ab8c 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -30,7 +30,24 @@

This document describes the changes made to the SSL application.

-
+
SSL 4.1.5.2 + +
Fixed Bugs and Malfunctions + + +

+ Changed crypto and ssl to be dynamically linked to + OpenSSL and use version 0.9.8 of OpenSSL (instead of + 0.9.7) on PowerPC.

+

+ Own Id: OTP-9603 Aux Id: seq11912

+
+
+
+ +
+ +
SSL 4.1.5
Improvements and New Features -- cgit v1.2.3 From b6dc1a844eab061d0a7153d46e7e68296f15a504 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Tue, 4 Oct 2011 12:06:58 +0200 Subject: Prepare release --- erts/doc/src/notes.xml | 338 ++++++++++++++++++++++++++++++++++ lib/asn1/doc/src/notes.xml | 19 ++ lib/asn1/vsn.mk | 2 +- lib/common_test/doc/src/notes.xml | 223 ++++++++++++++++++++++ lib/compiler/doc/src/notes.xml | 28 +++ lib/compiler/vsn.mk | 2 +- lib/cosFileTransfer/doc/src/notes.xml | 16 +- lib/cosFileTransfer/vsn.mk | 2 +- lib/crypto/doc/src/notes.xml | 25 +++ lib/crypto/vsn.mk | 2 +- lib/dialyzer/doc/src/notes.xml | 109 +++++++++++ lib/dialyzer/vsn.mk | 2 +- lib/diameter/doc/src/notes.xml | 129 +++++++++++++ lib/docbuilder/doc/src/notes.xml | 16 ++ lib/edoc/doc/src/notes.xml | 51 +++++ lib/erl_docgen/doc/src/notes.xml | 46 ++++- lib/erl_docgen/vsn.mk | 2 +- lib/erl_interface/doc/src/notes.xml | 47 +++++ lib/erl_interface/vsn.mk | 2 +- lib/et/doc/src/notes.xml | 14 ++ lib/et/vsn.mk | 2 +- lib/eunit/doc/src/notes.xml | 57 ++++++ lib/eunit/vsn.mk | 2 +- lib/gs/doc/src/notes.xml | 16 +- lib/gs/vsn.mk | 2 +- lib/hipe/doc/src/notes.xml | 63 +++++++ lib/hipe/vsn.mk | 2 +- lib/kernel/doc/src/notes.xml | 56 ++++++ lib/mnesia/doc/src/notes.xml | 45 ++++- lib/observer/doc/src/notes.xml | 16 ++ lib/observer/vsn.mk | 2 +- lib/odbc/doc/src/notes.xml | 44 ++++- lib/orber/doc/src/notes.xml | 16 +- lib/orber/vsn.mk | 2 +- lib/os_mon/doc/src/notes.xml | 14 ++ lib/os_mon/vsn.mk | 2 +- lib/parsetools/doc/src/notes.xml | 46 +++++ lib/parsetools/vsn.mk | 2 +- lib/percept/doc/src/notes.xml | 26 +++ lib/percept/vsn.mk | 2 +- lib/public_key/doc/src/notes.xml | 17 ++ lib/public_key/vsn.mk | 2 +- lib/reltool/doc/src/notes.xml | 30 ++- lib/reltool/vsn.mk | 2 +- lib/runtime_tools/doc/src/notes.xml | 17 ++ lib/runtime_tools/vsn.mk | 2 +- lib/sasl/doc/src/notes.xml | 98 ++++++++++ lib/sasl/vsn.mk | 2 +- lib/ssl/doc/src/notes.xml | 54 +++++- lib/stdlib/doc/src/notes.xml | 162 ++++++++++++++++ lib/test_server/doc/src/notes.xml | 144 +++++++++++++++ lib/toolbar/doc/src/notes.xml | 16 ++ lib/toolbar/vsn.mk | 2 +- lib/tools/doc/src/notes.xml | 38 ++++ lib/tools/vsn.mk | 2 +- lib/typer/vsn.mk | 2 +- lib/webtool/doc/src/notes.xml | 16 ++ lib/webtool/vsn.mk | 2 +- lib/wx/doc/src/notes.xml | 33 ++++ lib/wx/vsn.mk | 2 +- lib/xmerl/doc/src/notes.xml | 57 ++++++ lib/xmerl/vsn.mk | 2 +- 62 files changed, 2160 insertions(+), 34 deletions(-) diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 9bba5e2cf7..4cef9669dd 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,344 @@

This document describes the changes made to the ERTS application.

+
Erts 5.8.5 + +
Fixed Bugs and Malfunctions + + +

+ Several bugs concerning constant binary constructions + such as <<0:4294967295>> have been corrected. + Depending on the actual size of the binary and the type + of run-time system (32-bit, halfword, 64-bit), such + expression could either crash the run-time system or make + the loader refuse loading of the module.

+

+ Own Id: OTP-9284

+
+ +

+ The Erlsrv utility failed to stop the erlang machine if + no StopAction was defined when the service was stopped. + This is now corrected.

+

+ Own Id: OTP-9344

+
+ +

+ Due to a bug in glibc the runtime system could abort + while trying to destroy a mutex. A fix for this was + introduced in R14B02. This fix did, however, not solve + the problem. The runtime system will now issue a warning + instead of aborting.

+

+ Own Id: OTP-9373 Aux Id: OTP-9009

+
+ +

+ Replace atom in DRV macro in prim_file with string

+

+ An experimental version of Dialyzer discovered that the + atom that replaced the DRV macro in prim_file ends up in + calls to erlang:open_port({spawn, Driver}, Portopts) as + the Driver argument. The documentation states that this + call requires a string there.

+

+ This change is also consistent with the one introduced in + commit 0f03b1e9d2bef3bc830c31a369261af4c5234727 by Kostis + Sagonas.

+

+ Own Id: OTP-9377

+
+ +

+ Fix typos in the epmd documentation (Thanks to Holger + Weiß )

+

+ Own Id: OTP-9387

+
+ +

+ Fix faulty integer terms created by NIF API from 64-bit + integers on halfword emulator. (Thanks to Paolo Negri and + Paul Davis)

+

+ Own Id: OTP-9394

+
+ +

+ Fix epmd crash on vxworks caused by faulty + argument to select() system call.

+

+ Own Id: OTP-9427 Aux Id: seq11855

+
+ +

+ The ets:test_ms function could in rare cases truncate the + error messages. This is now corrected.

+

+ Own Id: OTP-9435

+
+ +

+ Fix bug related to hibernate and HiPE (clear + F_HIBERNATE_SCHED flag)

+

+ F_HIBERNATE_SCHED flag that was introduced in + b7ecdcd1ae9e11b8f75e must be cleared in hipe_mode_switch + as well. Otherwise, processes running HiPE code that + hibernate, wake up and then trap into a BIF will not be + rescheduled.(Thanks to Paul Guyot)

+

+ Own Id: OTP-9452

+
+ +

+ Fix bug in FreeBSD topology detection code (Thanks to + Paul Guyot)

+

+ Own Id: OTP-9453

+
+ +

+ Fix use of logical operator && with constant + operand instead of bitwise & (Thanks to Cristian + Greco)

+

+ Own Id: OTP-9454

+
+ +

+ inet: error if fd does not match socket domain

+

+ If an IPv4 fd is opened as an IPv6 socket, unexpected + behaviour can occur. For example, if an IPv4 UDP socket + is opened and passed into Erlang as an IPv6 socket, the + first 3 bytes (corresponding to 1 byte representing the + protocol family, 2 bytes set to the port) are stripped + from the payload. The cause of the UDP payload truncation + happens in inet_drv.c:packet_inet_input when a call to + inet_get_address fails silently because the family is set + to PF_INET6 but the buffer len is the size of an IPv4 + struct sockaddr_in.

+

+ (Thanks to Andrew Tunnell-Jones for finding the bug and + the test case!)

+

+ Own Id: OTP-9455

+
+ +

+ erts: use a union to avoid strict aliasing issues

+

+ Use a union for pointer type conversion to avoid compiler + warnings about strict-aliasing violations with gcc-4.1. + gcc >= 4.2 does not emit the warning. erts: adapt + matrix_nif to R14 erl_nif API changes (Thanks To Tuncer + Ayaz)

+

+ Own Id: OTP-9487

+
+ +

+ fix 64-bit issues in the garbage collection (Thanks to + Richard Carlsson)

+

+ Own Id: OTP-9488

+
+ +

+ epmd: fix compiler warnings

+

+ Suppress compiler warnings about ignored return values. + (Thanks to Michael Santos )

+

+ Own Id: OTP-9500

+
+ +

+ Fix non-existing function (erlang:disconnect/1) in + distributed reference manual (Thanks to Fabian Król)

+

+ Own Id: OTP-9504

+
+ +

+ Document fdatasync -lrt requirement (SunOS <= 5.10) + (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9512

+
+ +

+ Let epmd ignore empty ERL_EPMD_ADDRESS

+

+ If the environment variable ERL_EPMD_ADDRESS is set to + the empty string, empd now behaves like it does by + default when ERL_EPMD_ADDRESS is unset. That is, in this + case, epmd now listens on all available interfaces + instead of using only the loopback interface, which + happened because epmd added the loopback address to the + (in this case empty) list of addresses specified via + ERL_EPMD_ADDRESS.

+

+ Also, epmd now ignores ERL_EPMD_ADDRESS if it contains + only separator characters (comma and space).

+

+ The same applies to epmd's -address option.(Thanks to + Holger Weiß)

+

+ Own Id: OTP-9525

+
+ +

+ Remove dead code in erl_compile (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9527

+
+ +

+ Add erlang:external_size/2 BIF

+

+ This BIF's second parameter is a list of options. + Currently the only allowed option is {minor_version, + Version} where version is either 0 (default) or 1. + (Thanks to Filipe David Manana )

+

+ Own Id: OTP-9528

+
+ +

+ Fix enif_compare on 64bits machines

+

+ In 64bits machines the Sint type has a size of 8 bytes, + while on 32bits machines it has a 4 bytes size. + enif_compare was ignoring this and therefore returning + incorrect values when the result of the CMP function + (which returns a Sint value) doesn't fit in 4 bytes. + (Thanks to Filipe David Manana)

+

+ Own Id: OTP-9533

+
+ +

+ Implement or fix -Werror option

+

+ If -Werror is enabled and there are warnings no output + file is written. Also make sure that error/warning + reporting is consistent. (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9536

+
+ +

In some rare cases we did not have a run queue when + scheduling misc ops. This is now fixed.

+

+ Own Id: OTP-9537

+
+ +

Remove misc. compiler warnings

+

+ Own Id: OTP-9542

+
+ +

+ Two bugs in gen_sctp has been corrected: getopts/setopts + hence also send could only be called from socket owner, + and options 'linger', 'rcvbuf' and 'sndbuf' was read from + wrong protocol layer hence read wrong values by getopts.

+

+ Own Id: OTP-9544

+
+ +

+ Erlang/OTP can now be built on MacOS X Lion.

+

+ Own Id: OTP-9547

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+ +

+ Fix potential errors inspired by running cppcheck(1) + (Thanks to Christian von Roques)

+

+ Own Id: OTP-9557

+
+ +

When auxiliary work was enqueued on a scheduler, the + wakeup of the scheduler in order to handle this work + could be lost. Wakeups in order to handle ordinary work + were not effected by this bug. The bug only effected + runtime systems with SMP support as follows:

+ Deallocation of some ETS data structures could be + delayed. On Linux systems not using the NPTL + thread library (typically ancient systems with kernel + versions prior to 2.6) and Windows systems, the {Port, + {exit_status, Status}} message from a terminating + port program could be delayed. That is, it only effected + port programs which had been started by passing + exit_status as an option to + open_port/2. +

+ Own Id: OTP-9567

+
+ +

+ Handle rare race in the crypto key server functionality

+

+ Own Id: OTP-9586

+
+
+
+ + +
Improvements and New Features + + +

Types and specifications have been added.

+

+ Own Id: OTP-9356

+
+ +

+ New allocator strategy "address order first fit". May + ease the emptying of memory carriers and thereby real + release of memory back to the OS.

+

+ Own Id: OTP-9424

+
+ +

+ The new erlang:check_old_code/1 BIF checks whether + a module has old code.

+

+ Own Id: OTP-9495

+
+ +

Update documentation and specifications of some of + the zlib functions.

+

+ Own Id: OTP-9506

+
+ +

+ Detect the available CPUs on IRIX

+

+ Add support for querying the number of configured and + online processors on SGI systems running IRIX.(Thanks to + Holger Weiß)

+

+ Own Id: OTP-9531

+
+
+
+ +
+
Erts 5.8.4
Fixed Bugs and Malfunctions diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml index 5e221c03e9..52d770c9f6 100644 --- a/lib/asn1/doc/src/notes.xml +++ b/lib/asn1/doc/src/notes.xml @@ -31,6 +31,25 @@

This document describes the changes made to the asn1 application.

+
Asn1 1.6.18 + +
Fixed Bugs and Malfunctions + + +

+ Implement or fix -Werror option

+

+ If -Werror is enabled and there are warnings no output + file is written. Also make sure that error/warning + reporting is consistent. (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9536

+
+
+
+ +
+
Asn1 1.6.17
Fixed Bugs and Malfunctions diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk index 36e082c8ba..b1132155e6 100644 --- a/lib/asn1/vsn.mk +++ b/lib/asn1/vsn.mk @@ -1,2 +1,2 @@ #next version number to use is 1.6.15 | 1.7 | 2.0 -ASN1_VSN = 1.6.17 +ASN1_VSN = 1.6.18 diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index 826b3c598d..af96ef621f 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -32,6 +32,229 @@ notes.xml +
Common_Test 1.5.5 + +
Fixed Bugs and Malfunctions + + +

+ An error in how comments are colored in the test suite + overview html log file has been corrected. As result, a + new framework callback function, format_comment/1, has + been introduced.

+

+ Own Id: OTP-9237

+
+ +

+ Automatically generated init- and end-configuration + functions for test case groups caused incorrect execution + order of test cases. This has been corrected.

+

+ Own Id: OTP-9369

+
+ +

+ If multiple directories were specified with the 'logdir' + flag/option, Common Test would crash. This has been fixed + so that an error is properly reported instead.

+

+ Own Id: OTP-9370

+
+ +

+ If ct:log/2 was called with bad arguments, this could + cause the Common Test IO handling process to crash. This + fault has been corrected.

+

+ Own Id: OTP-9371 Aux Id: OTP-8933

+
+ +

+ A bug has been fixed that made Test Server call the + end_tc/3 framework function with an incorrect module name + as first argument.

+

+ Own Id: OTP-9379 Aux Id: seq11863

+
+ +

+ If a timetrap timeout occured during execution of of a + function in a lib module (i.e. a function called directly + or indirectly from a test case), the Suite argument in + the end_tc/3 framework callback function would not + correctly contain the name of the test suite, but the lib + module. (This would only happen if the lib module was + compiled with ct.hrl included). This error has been + solved.

+

+ Own Id: OTP-9398

+
+ +

+ Corrections of the vts mode. It will now report errors + (about e.g. incorrect config files) instead of crashing + or hanging. Furthermore, the requirement that the test + directory name must have a "_test" suffix has been + removed. Also, a workaround has been implemented for the + limitation that the file browser (in many web browsers) + will only return the basic file name, not the full + directory path (which made it impossible to have config + files in other directories than the main test directory).

+

+ Own Id: OTP-9429

+
+ +

+ Add a proplist() type

+

+ Recently I was adding specs to an API and found that + there is no canonical proplist() type defined. (Thanks to + Ryan Zezeski)

+

+ Own Id: OTP-9499

+
+ +

+ It is now possible to use the 'step' flag/option to run + the debugger for test suites that contain test case + groups. This previously caused Common Test to crash. If + 'step config' is specified, breakpoints are now also + automatically set on init_per_group and end_per_group. + Note that breakpoints are always set automatically on + test case functions and this is true also for grouped + cases.

+

+ Own Id: OTP-9518 Aux Id: OTP-8933

+
+ +

+ The test index page was not refreshed at the start of + each test suite which made it impossible to follow test + execution by means of refreshing the browser window (no + links to follow). This has been fixed.

+

+ Own Id: OTP-9520 Aux Id: OTP-8933

+
+ +

+ If a test suite would start with a test case group + defined without the init_per_group/2 and end_per_group/2 + function, init_per_suite/1 would not execute initially + and logging of the test run would fail. This error has + been fixed.

+

+ Own Id: OTP-9584

+
+ +

+ The "Missing Suites" link from the top level index page + was incorrect and has been fixed.

+

+ Own Id: OTP-9592

+
+
+
+ + +
Improvements and New Features + + +

+ Various corrections and updates to improve the handling + and reporting of errors.

+

+ Own Id: OTP-8933

+
+ +

+ The dir and suite start option can now be used in + combination. E.g. executing my_SUITE in directory + my_tests can either be specified as "ct_run -suite + my_tests/my_SUITE" or as "ct_run -dir my_tests -suite + my_SUITE". Furthermore, the specification: + ct:run_test([{suite,["./my_SUITE"]},{testcase,t1}]) is + now interpreted as + ct:run_test([{suite,"./my_SUITE"},{testcase,t1}]), i.e. + only testcase t1 in test suite my_SUITE - not all cases - + will be executed.

+

+ Own Id: OTP-9155

+
+ +

+ A new option, 'logopts', has been introduced, to make it + possible to modify some aspects of the logging behaviour + in Common Test (or Test Server). For example, whenever an + io printout is made, test_server adds newline (\n) to the + end of the output string. This may not always be a + preferred action and can therefore be disabled by means + of "ct_run ... -logopts no_nl" (or ct:run_test([..., + {logopts,[no_nl]}])). A new framework callback function, + get_logopts/0, has been introduced (see the ct_framework + module for details).

+

+ Own Id: OTP-9372 Aux Id: OTP-9396

+
+ +

+ A new option, 'logopts', has been introduced, to make it + possible to modify some aspects of the logging behaviour + in Common Test (or Test Server). For example, if the html + version of the test suite source code should not be + generated during the test run (and consequently be + unavailable in the log file system), the feature may be + disabled by means of "ct_run ... -logopts no_src" (or + ct:run_test([..., {logopts,[no_src]}])). A new framework + callback function, get_logopts/0, has been introduced + (see the ct_framework module for details).

+

+ Own Id: OTP-9396 Aux Id: seq11869, OTP-9372

+
+ +

+ CT Hooks can now be assigned a priority. The priority of + a CTH determines when it should execute in relation to + other CTHs. The CTH with the lowest priority will be + executed first, CTHs with equal priority will be executed + in the order which they were installed.

+

+ Own Id: OTP-9445

+
+ +

+ It is now possible to use a tuple {M,F,A}, or a fun, as + timetrap specification in the suite info function or test + case info functions. The function must return a valid + timeout value, as documented in the common_test man page + and in the User's Guide.

+

+ Own Id: OTP-9501 Aux Id: seq11894

+
+ +

+ A new built-in common test hook has been added which + captures error_logger and SASL event and prints them in + the testcase log. To disable this (and any other built-in + hooks) pass 'enable_builtin_hooks false' to common test.

+

+ Own Id: OTP-9543

+
+ +

+ Common Test now has the possibility to have built-in + hooks which are started by default when any test is run. + To disable built-in hooks pass 'enable_builtin_hooks + false' to common test. See the common test hooks + documentation for more details.

+

+ Own Id: OTP-9564

+
+
+
+ +
+
Common_Test 1.5.4
Fixed Bugs and Malfunctions diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index dd29323787..740cbcf8eb 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -31,6 +31,34 @@

This document describes the changes made to the Compiler application.

+
Compiler 4.7.5 + +
Fixed Bugs and Malfunctions + + +

+ Compiler options given in the source code using a + -compile() attribute used to be included twice in + Mod:module_info(compile). They are now only + included once at the beginning of the list of options.

+

+ Own Id: OTP-9534

+
+ +

+ beam_disasm: Handle stripped BEAM files

+

+ beam_disasm:file/1 would crash if asked to disassemble a + stripped BEAM file without an "Attr" chunk. (Thanks to + Haitao Li)

+

+ Own Id: OTP-9571

+
+
+
+ +
+
Compiler 4.7.4
Fixed Bugs and Malfunctions diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 5863842f5b..04290c0a7f 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 4.7.4 +COMPILER_VSN = 4.7.5 diff --git a/lib/cosFileTransfer/doc/src/notes.xml b/lib/cosFileTransfer/doc/src/notes.xml index 53c207db2f..c7a4fd4504 100644 --- a/lib/cosFileTransfer/doc/src/notes.xml +++ b/lib/cosFileTransfer/doc/src/notes.xml @@ -30,7 +30,21 @@ notes.xml -
+
cosFileTransfer 1.1.12 + +
Fixed Bugs and Malfunctions + + +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ +
+ +
cosFileTransfer 1.1.11
diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk index 9d68ab2720..fe0226e3b3 100644 --- a/lib/cosFileTransfer/vsn.mk +++ b/lib/cosFileTransfer/vsn.mk @@ -1 +1 @@ -COSFILETRANSFER_VSN = 1.1.11 +COSFILETRANSFER_VSN = 1.1.12 diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index a5434ebd68..763f79e02d 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -30,6 +30,31 @@

This document describes the changes made to the Crypto application.

+
Crypto 2.0.4 + +
Fixed Bugs and Malfunctions + + +

+ crypto:rand_uniform works correctly for negative + integers. Fails with badarg exception for invalid + ranges (when Hi =< Lo) instead of returning + incorrect output.

+

+ Own Id: OTP-9526

+
+ +

+ Fix win32 OpenSSL static linking (Thanks to Dave + Cottlehuber)

+

+ Own Id: OTP-9532

+
+
+
+ +
+
Crypto 2.0.3
Fixed Bugs and Malfunctions diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index e754aabc44..33fa9b1ec3 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.3 +CRYPTO_VSN = 2.0.4 diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml index 81622a3854..17291b24f7 100755 --- a/lib/dialyzer/doc/src/notes.xml +++ b/lib/dialyzer/doc/src/notes.xml @@ -31,6 +31,115 @@

This document describes the changes made to the Dialyzer application.

+
Dialyzer 2.4.4 + +
Fixed Bugs and Malfunctions + + +

+ Update results of race_SUITE/extract_translations Update + results of small_SUITE/flatten Add codec_can and + list_to_bitstring tests Fix bug when reporting unused + functions Update Dialyzer r9c_suite results Fix dialyzer + warning on default clause for binary comprehension + (Thanks to Ivan Dubrov)

+

+ Own Id: OTP-9483

+
+ +

+ Fix server loop detection

+

+ Dialyzer does not normally emit warnings for functions + that implement non-terminating server loops. This + detection failed when some of the elements in an SCC + terminated normally (being for example list + comprehensions or other generic anonymous functions that + were included in the SCC). This patch fixes that.

+

+ Own Id: OTP-9489

+
+ +

+ Add a proplist() type

+

+ Recently I was adding specs to an API and found that + there is no canonical proplist() type defined. (Thanks to + Ryan Zezeski)

+

+ Own Id: OTP-9499

+
+ +

+ Suppress some warnings about generation of non-returning + funs

+

+ No warnings are emitted for funs that are non-returning + when the function that generates them has a contract that + specifies that it will return such a non-returning fun.

+

+ Enhance Dialyzer's inference on comparisons

+

+ This patch makes Dialyzer aware of Erlang's total + ordering of terms, enabling discrepancy detection in + cases where e.g. integer() < tuple() is treated as a + comparison that might also return false (when it is + certain to always return true).

+

+ Minor fix in dead code

+

+ Fix infinite loop in dataflow

+

+ Update r9c/{inets,mnesia} results in dialyzer's test + suite

+

+ Add origin information to #fun_var closures

+

+ (Thanks to Tuncer Ayaz and Maria Christakis)

+

+ Own Id: OTP-9529

+
+ +

+ Quote atoms if necessary in types

+

+ Atoms in some occurrences were not correctly quoted when + formatted to strings, for instance by the typer program + (Thanks to Tomas Abrahamsson)

+

+ Update Dialyzer's reference results

+

+ Own Id: OTP-9560

+
+ +

+ Fix typer's crash for nonexisting files Remove unused + macro Fix bug in dataflow Decrease tuple arity limit This + fixes a memory related crash.

+

+ Own Id: OTP-9597

+
+
+
+ + +
Improvements and New Features + + +

+ Types for several BIFs have been extended/corrected. Also + the types for types for lists:keyfind/3, + lists:keysearch/3, and lists:keyemember/3 + have been corrected. The incorrect/incomplete types could + cause false dialyzer warnings.

+

+ Own Id: OTP-9496

+
+
+
+ +
+
Dialyzer 2.4.3
Fixed Bugs and Malfunctions diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk index 10de07dfbb..a7e82b54ce 100644 --- a/lib/dialyzer/vsn.mk +++ b/lib/dialyzer/vsn.mk @@ -1 +1 @@ -DIALYZER_VSN = 2.4.3 +DIALYZER_VSN = 2.4.4 diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml index eafddd7d1e..e2723f3e99 100644 --- a/lib/diameter/doc/src/notes.xml +++ b/lib/diameter/doc/src/notes.xml @@ -36,6 +36,135 @@ first.

+
Diameter 0.10 + +
Fixed Bugs and Malfunctions + + +

+ Handle #sctp_paddr_change and #sctp_pdapi_event from + gen_sctp.

+

+ The events are enabled by default but diameter_sctp + neither disabled nor dealt with them. Reception of such + an event caused a transport process to crash.

+

+ Own Id: OTP-9538

+
+ +

+ Fix header folding bug.

+

+ A prepare_request callback from diameter can return a + diameter_header record in order to set values in the + header of an outgoing request. A fault in + diameter_lib:fold_tuple/3 caused the subsequent encode of + the outgoing request to fail.

+

+ Own Id: OTP-9577

+
+ +

+ Fix bugs in sending of answer-message replies.

+

+ 3001 (DIAMETER_COMMAND_UNSUPPORTED) was not sent since + the decode placed the AVP list in the wrong field of the + diameter_packet, causing the subsequent encode to fail. + Session-Id was also set improperly, causing encode to + fail even in this case.

+

+ Own Id: OTP-9578

+
+ +

+ Fix improper use of error_logger:info_report/2.

+

+ Function doesn't take a format string and arguments as it + was called. Instead use error_logger:info_report/1 and + use the same report format as used for warning and error + reports.

+

+ Own Id: OTP-9579

+
+ +

+ Fix and clarify semantics of peer filters.

+

+ An eval filter returning a non-true value caused the call + process to fail and the doc was vague on how an exception + was treated. Clarify that the non-tuple host/realm + filters assume messages of a certain form.

+

+ Own Id: OTP-9580

+
+ +

+ Fix and clarify relay behaviour.

+

+ Implicit filtering of the sending peer in relaying a + request could cause loop detection to be preempted in a + manner not specified by RFC3588. Reply with 3002 + (DIAMETER_UNABLE_TO_DELIVER) on anything but an answer to + a relayed request.

+

+ Own Id: OTP-9583

+
+
+
+ + +
Improvements and New Features + + +

+ @id required in dictionary files only when @messages is + specified.

+

+ @id defines an application identifier and this is used + only when sending or receiving messages. A dictionary can + define only AVP's however, to be included by other + dictionaries using @inherits, in which case it makes no + sense to require @id.

+

+ Note that message definitions are not inherited with + @inherits, only AVP's

+

+ Own Id: OTP-9467

+
+ +

+ Allow @enum when AVP is defined in an inherited + dictionary.

+

+ 3GPP standards (for one) extend the values allowed for + RFC 3588 AVP's of type Enumerated. Previously, extending + an AVP was only possible by completely redefining the + AVP.

+

+ Own Id: OTP-9469

+
+ +

+ Migrate testsuites to pure common test and add both + suites and testcases.

+

+ Own Id: OTP-9553

+
+ +

+ Requests of arbitrary form.

+

+ diameter:call/4 can be passed anything, as long as the + subsequent prepare_request callback returns a term that + can be encoded.

+

+ Own Id: OTP-9581

+
+
+
+ +
+
diameter 0.9 diff --git a/lib/docbuilder/doc/src/notes.xml b/lib/docbuilder/doc/src/notes.xml index ef6523889d..95f24ea9ca 100644 --- a/lib/docbuilder/doc/src/notes.xml +++ b/lib/docbuilder/doc/src/notes.xml @@ -31,6 +31,22 @@

This document describes the changes made to the DocBuilder application.

+
Docbuilder 0.9.8.11 + +
Improvements and New Features + + +

+ The docbuilder application has been deprecated and will + be removed in the R15 release.

+

+ Own Id: OTP-9509

+
+
+
+ +
+
Docbuilder 0.9.8.10
Fixed Bugs and Malfunctions diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml index 31a54788e5..b220067bbe 100644 --- a/lib/edoc/doc/src/notes.xml +++ b/lib/edoc/doc/src/notes.xml @@ -31,6 +31,57 @@

This document describes the changes made to the EDoc application.

+
Edoc 0.7.9 + +
Fixed Bugs and Malfunctions + + +

no_return is a new built-in type.

+

+ Own Id: OTP-9350

+
+ +

+ synchronized with edoc development version

+

+ forgot to ensure that xmerl is found in path for + include_lib to work

+

+ fix -spec declaration that doesn't work in R13B04

+

+ eliminate warnings about unused imports

+

+ removed CVS-keywords from source files (Thanks to Richard + Carlsson )

+

+ Own Id: OTP-9463

+
+ +

+ Add a proplist() type

+

+ Recently I was adding specs to an API and found that + there is no canonical proplist() type defined. (Thanks to + Ryan Zezeski)

+

+ Own Id: OTP-9499

+
+ +

+ Removed some never-matching clauses reported by dialyzer + Fix macro expansion in comments following Erlang types + URI-escape bytes as two hex digits always (reported by + Alfonso De Gregorio) Updated author e-mail Recognize some + more URI schemas in wiki text, in particular https + (Thanks to Richard Carlsson)

+

+ Own Id: OTP-9590

+
+
+
+ +
+
Edoc 0.7.8
Fixed Bugs and Malfunctions diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml index f79639769f..6a0eece56d 100644 --- a/lib/erl_docgen/doc/src/notes.xml +++ b/lib/erl_docgen/doc/src/notes.xml @@ -30,7 +30,51 @@

This document describes the changes made to the erl_docgen application.

-
Erl_Docgen 0.2.5 +
Erl_Docgen 0.2.6 + +
Fixed Bugs and Malfunctions + + +

Bug fixes.

+

+ Own Id: OTP-9360

+
+ +

The manpage generation has been improved.

+

+ Own Id: OTP-9541 Aux Id: OTP-9550

+
+ +

Fix eix file generation for new function spec + references.

+

+ Own Id: OTP-9562

+
+ +

The function signatures in the pdf files was not in a + fixed font.

+

+ Own Id: OTP-9563

+
+ +

The parts level in the system documentation was + missing in the bookmarks menu for the pdf and the + copyright year generation for PDF was not correct.

+

+ Own Id: OTP-9576

+
+ +

The indentation after Warning: and + Note: in manpages has been improved.

+

+ Own Id: OTP-9588

+
+
+
+ +
+ +
Erl_Docgen 0.2.5
Improvements and New Features diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk index cafb5287de..79c8c570bf 100644 --- a/lib/erl_docgen/vsn.mk +++ b/lib/erl_docgen/vsn.mk @@ -1,2 +1,2 @@ -ERL_DOCGEN_VSN = 0.2.5 +ERL_DOCGEN_VSN = 0.2.6 diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml index 7055fcd5c9..9a42ebfddf 100644 --- a/lib/erl_interface/doc/src/notes.xml +++ b/lib/erl_interface/doc/src/notes.xml @@ -30,6 +30,53 @@

This document describes the changes made to the Erl_interface application.

+
Erl_Interface 3.7.5 + +
Fixed Bugs and Malfunctions + + +

Align ei buffer according to size of pointers

+

+ Own Id: OTP-9390

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+ +

+ Make comment and documentation reflect code in + erl_interface/src/misc/ei_decode_term.c (Thanks to Anneli + Cuss)

+

+ Own Id: OTP-9559

+
+
+
+ + +
Improvements and New Features + + +

+ ei: integer overflow in string/atom encoding

+

+ ei_encode_atom() and ei_encode_string() use strlen() to + get the length of the buffer. As strlen() returns an + unsigned long long and both ei functions take a signed + integer, the length fields may overflow.

+

+ Check so that the results of strlen can be held in a + signed integer. (Thanks to Michael Santos)

+

+ Own Id: OTP-9530

+
+
+
+ +
+
Erl_Interface 3.7.4
Fixed Bugs and Malfunctions diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk index 75f2b7101b..601958579c 100644 --- a/lib/erl_interface/vsn.mk +++ b/lib/erl_interface/vsn.mk @@ -1 +1 @@ -EI_VSN = 3.7.4 +EI_VSN = 3.7.5 diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml index 7082948d94..acc6120fcd 100644 --- a/lib/et/doc/src/notes.xml +++ b/lib/et/doc/src/notes.xml @@ -36,6 +36,20 @@ one section in this document. The title of each section is the version number of Event Tracer (ET).

+
ET 1.4.4 + +
Fixed Bugs and Malfunctions + + +

Dialyzer warnings have been fixed.

+

+ Own Id: OTP-9470

+
+
+
+ +
+
ET 1.4.3
Fixed Bugs and Malfunctions diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk index ea98aeba11..239a72ad73 100644 --- a/lib/et/vsn.mk +++ b/lib/et/vsn.mk @@ -1 +1 @@ -ET_VSN = 1.4.3 +ET_VSN = 1.4.4 diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml index a02d76c5b9..e68330482c 100644 --- a/lib/eunit/doc/src/notes.xml +++ b/lib/eunit/doc/src/notes.xml @@ -32,6 +32,63 @@

This document describes the changes made to the EUnit application.

+
Eunit 2.2.1 + +
Fixed Bugs and Malfunctions + + +

+ Generate separate surefire XMLs for each test suite

+

+ Previously the test cases of all test suites (=modules) + were put in one and the same surefire report XML thereby + breaking the principle of least astonishment and making + post analysis harder. Assume the following layout:

+

+ src/x.erl src/y.erl test/x_tests.erl test/y_tests.erl

+

+ The results for both x_tests and y_tests were written to + only one report grouped under either module x or y + (seemingly randomly).

+

+ Now two reports, one for module x and one for y are + generated. (Thanks to Klas Johansson)

+

+ Own Id: OTP-9465

+
+ +

+ Updated to EUnit version 2.2.0

+

+ New macros assertNotMatch(Guard, Expr), + assertNotEqual(Unexpected, Expr), and + assertNotException(Class, Term, Expr).

+

+ The debugMsg macro now also prints the pid of the current + process.

+

+ When testing all modules in a directory, tests in + Module_tests.erl are no longer executed twice.

+

+ The use of regexp internally has been replaced with re. + (Thanks to Richard Carlsson)

+

+ Own Id: OTP-9505

+
+ +

+ Removed some never-matching clauses reported by dialyzer + Updated author e-mails and homepages Removed cvs keywords + from files Removed files that should not be checked in + (Thanks to Richard Carlsson)

+

+ Own Id: OTP-9591

+
+
+
+ +
+
Eunit 2.1.7
Fixed Bugs and Malfunctions diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk index d933085bbc..b0a77a225b 100644 --- a/lib/eunit/vsn.mk +++ b/lib/eunit/vsn.mk @@ -1 +1 @@ -EUNIT_VSN = 2.2.0 +EUNIT_VSN = 2.2.1 diff --git a/lib/gs/doc/src/notes.xml b/lib/gs/doc/src/notes.xml index 744efbd4fc..c32db495a1 100644 --- a/lib/gs/doc/src/notes.xml +++ b/lib/gs/doc/src/notes.xml @@ -30,7 +30,21 @@

This document describes the changes made to the GS application.

-
GS 1.5.13 +
GS 1.5.14 + +
Fixed Bugs and Malfunctions + + +

Remove misc. compiler warnings

+

+ Own Id: OTP-9542

+
+
+
+ +
+ +
GS 1.5.13
Improvements and New Features diff --git a/lib/gs/vsn.mk b/lib/gs/vsn.mk index 4c91857572..4894c6c13a 100644 --- a/lib/gs/vsn.mk +++ b/lib/gs/vsn.mk @@ -1,2 +1,2 @@ -GS_VSN = 1.5.13 +GS_VSN = 1.5.14 diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml index 4eb188f76f..6b601e3039 100644 --- a/lib/hipe/doc/src/notes.xml +++ b/lib/hipe/doc/src/notes.xml @@ -30,6 +30,69 @@

This document describes the changes made to HiPE.

+
Hipe 3.8.1 + +
Fixed Bugs and Malfunctions + + +

+ Clean up hipe.hrl.src (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9511

+
+ +

+ Fix bug with binary pattern matching of floats of + variable size

+

+ Pattern matching of floats with variable size + (<<F:S/float>>) did always fail. Judging from + similar code for ints, this bug is simply a typo.(Thanks + to Paul Guyot)

+

+ Own Id: OTP-9556

+
+ +

+ Quote atoms if necessary in types

+

+ Atoms in some occurrences were not correctly quoted when + formatted to strings, for instance by the typer program + (Thanks to Tomas Abrahamsson)

+

+ Update Dialyzer's reference results

+

+ Own Id: OTP-9560

+
+ +

+ Fix typer's crash for nonexisting files Remove unused + macro Fix bug in dataflow Decrease tuple arity limit This + fixes a memory related crash.

+

+ Own Id: OTP-9597

+
+
+
+ + +
Improvements and New Features + + +

+ Types for several BIFs have been extended/corrected. Also + the types for types for lists:keyfind/3, + lists:keysearch/3, and lists:keyemember/3 + have been corrected. The incorrect/incomplete types could + cause false dialyzer warnings.

+

+ Own Id: OTP-9496

+
+
+
+ +
+
Hipe 3.8
Fixed Bugs and Malfunctions diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk index 58ebe68401..65e04ff7fa 100644 --- a/lib/hipe/vsn.mk +++ b/lib/hipe/vsn.mk @@ -1 +1 @@ -HIPE_VSN = 3.8 +HIPE_VSN = 3.8.1 diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index fc8360b3d1..ec57b03bd9 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -30,6 +30,62 @@

This document describes the changes made to the Kernel application.

+
Kernel 2.14.5 + +
Fixed Bugs and Malfunctions + + +

+ Fix type of Packet arg of gen_tcp:send/2 and + gen_udp:send/4

+

+ The type is marked as a binary() or a string() but in + practice it can be an iodata(). The test suite was + updated to confirm the gen_tcp/2 and gen_udp:send/4 + functions accept iodata() (iolists) packets. (Thanks to + Filipe David Manana)

+

+ Own Id: OTP-9514

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ + +
Improvements and New Features + + +

The types and specifications of the inet modules have + been improved.

+

+ Own Id: OTP-9260

+
+ +

Types and specifications have been added.

+

+ Own Id: OTP-9356

+
+ +

Contracts in STDLIB and Kernel have been improved and + type errors have been corrected.

+

+ Own Id: OTP-9485

+
+ +

Update documentation and specifications of some of + the zlib functions.

+

+ Own Id: OTP-9506

+
+
+
+ +
+
Kernel 2.14.4
Fixed Bugs and Malfunctions diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 7f50dc049a..8ef573a948 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -38,7 +38,50 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.

-
Mnesia 4.4.19 +
Mnesia 4.5 + +
Fixed Bugs and Malfunctions + + +

+ Fix protocol issues. Mnesia-4.4.19 could not communicate + with to older nodes.

+

+ Own Id: OTP-9473

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ + +
Improvements and New Features + + +

+ Dump the log even if no transactions have been invoked on + local node, otherwise the log will grow forever with + decisions from the other nodes who have tables on disk. + Thanks Marek Majkowski.

+

+ Own Id: OTP-9551

+
+ +

+ Use dedicated api for clear_table, i.e. instead of + match_delete use delete_all_objects. Thanks KukHyun Lee.

+

+ Own Id: OTP-9558

+
+
+
+ +
+ +
Mnesia 4.4.19
Fixed Bugs and Malfunctions diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml index 73eb992323..baa1354268 100644 --- a/lib/observer/doc/src/notes.xml +++ b/lib/observer/doc/src/notes.xml @@ -31,6 +31,22 @@

This document describes the changes made to the Observer application.

+
Observer 0.9.10 + +
Fixed Bugs and Malfunctions + + +

+ Do not install *.bat files on non-win32 machines (Thanks + to Hans Ulrich Niedermann)

+

+ Own Id: OTP-9515

+
+
+
+ +
+
Observer 0.9.9
Improvements and New Features diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk index 14c8f54ba3..76e2f591fa 100644 --- a/lib/observer/vsn.mk +++ b/lib/observer/vsn.mk @@ -1 +1 @@ -OBSERVER_VSN = 0.9.9 +OBSERVER_VSN = 0.9.10 diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml index e15e7dea7d..9c6ca8a017 100644 --- a/lib/odbc/doc/src/notes.xml +++ b/lib/odbc/doc/src/notes.xml @@ -31,7 +31,49 @@

This document describes the changes made to the odbc application.

-
ODBC 2.10.10 +
ODBC 2.10.11 + +
Fixed Bugs and Malfunctions + + +

+ When using output parameters the internal odbc state was + not correctly cleaned causing the next call to + param_query to misbehave.

+

+ Own Id: OTP-9444

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ + +
Improvements and New Features + + +

+ Add code to handle old ODBC drivers on solaris. Also adds + tests with MySQL.

+

+ Own Id: OTP-8407

+
+ +

+ Odbc now supports SQL_WLONGVARCHAR, thanks to Hanfei Shen + for the patch.

+

+ Own Id: OTP-8493

+
+
+
+ +
+ +
ODBC 2.10.10
Fixed Bugs and Malfunctions diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index 231872f958..c8477d9252 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -32,7 +32,21 @@ notes.xml -
+
Orber 3.6.22 + +
Fixed Bugs and Malfunctions + + +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ +
+ +
Orber 3.6.21
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index 35aabd51cd..29b21e8e01 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1,3 +1,3 @@ -ORBER_VSN = 3.6.21 +ORBER_VSN = 3.6.22 diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml index 0a088ca8b6..f641bbd828 100644 --- a/lib/os_mon/doc/src/notes.xml +++ b/lib/os_mon/doc/src/notes.xml @@ -30,6 +30,20 @@

This document describes the changes made to the OS_Mon application.

+
Os_Mon 2.2.7 + +
Fixed Bugs and Malfunctions + + +

Remove misc. compiler warnings

+

+ Own Id: OTP-9542

+
+
+
+ +
+
Os_Mon 2.2.6
Fixed Bugs and Malfunctions diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk index 2d583a398b..f000e24a8f 100644 --- a/lib/os_mon/vsn.mk +++ b/lib/os_mon/vsn.mk @@ -1 +1 @@ -OS_MON_VSN = 2.2.6 +OS_MON_VSN = 2.2.7 diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml index 77b3a1a657..0c611db1ec 100644 --- a/lib/parsetools/doc/src/notes.xml +++ b/lib/parsetools/doc/src/notes.xml @@ -30,6 +30,52 @@

This document describes the changes made to the Parsetools application.

+
Parsetools 2.0.6 + +
Fixed Bugs and Malfunctions + + +

Dialyzer warnings have been removed.

+

+ Own Id: OTP-8318

+
+ +

+ yecc: add warnings_as_errors option(Thanks to Tuncer + ayaz)

+

+ Own Id: OTP-9376

+
+ +

+ Fix incorrect order of pseudo variables in yecc example

+

+ The example is for converting from infix to prefix. This + change uses to correct ordering of the triplet. (Thanks + to Garret Smith)

+

+ Own Id: OTP-9484

+
+ +

+ Implement or fix -Werror option

+

+ If -Werror is enabled and there are warnings no output + file is written. Also make sure that error/warning + reporting is consistent. (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9536

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ +
+
Parsetools 2.0.5
Improvements and New Features diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk index 812bf21f03..093523f0e7 100644 --- a/lib/parsetools/vsn.mk +++ b/lib/parsetools/vsn.mk @@ -1 +1 @@ -PARSETOOLS_VSN = 2.0.5 +PARSETOOLS_VSN = 2.0.6 diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml index 33bfa7baab..95c2bbda56 100644 --- a/lib/percept/doc/src/notes.xml +++ b/lib/percept/doc/src/notes.xml @@ -32,6 +32,32 @@

This document describes the changes made to the Percept application.

+
Percept 0.8.6 + +
Fixed Bugs and Malfunctions + + +

+ Fix message handling in select requests

+

+ percept_db used to send results in untagged messages, and + use a non selective receive to extract them. When percept + is used from the shell process, this can confuse other + messages with the actual result.

+

+ Add a tag to the message to be {result, Result}. Add + demonitor to avoid keeping DOWN message in the queue fix + one spec in do_start/0

+

+ (Thanks to Ahmed Omar)

+

+ Own Id: OTP-9490

+
+
+
+ +
+
Percept 0.8.5
Fixed Bugs and Malfunctions diff --git a/lib/percept/vsn.mk b/lib/percept/vsn.mk index 2a302991aa..3b4d9bbb64 100644 --- a/lib/percept/vsn.mk +++ b/lib/percept/vsn.mk @@ -1 +1 @@ -PERCEPT_VSN = 0.8.5 +PERCEPT_VSN = 0.8.6 diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml index 9d77750ea2..efd4a37eb9 100644 --- a/lib/public_key/doc/src/notes.xml +++ b/lib/public_key/doc/src/notes.xml @@ -34,6 +34,23 @@ notes.xml +
Public_Key 0.13 + +
Fixed Bugs and Malfunctions + + +

+ replace "a ssl" with "an ssl" reindent + pkix_path_validation/3 Trivial documentation fixes + (Thanks to Christian von Roques )

+

+ Own Id: OTP-9464

+
+
+
+ +
+
Public_Key 0.12
Improvements and New Features diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 3c6b012152..66ac78a65d 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.12 +PUBLIC_KEY_VSN = 0.13 diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml index 324d69675e..5304b996a4 100644 --- a/lib/reltool/doc/src/notes.xml +++ b/lib/reltool/doc/src/notes.xml @@ -37,7 +37,35 @@ thus constitutes one section in this document. The title of each section is the version number of Reltool.

-
Reltool 0.5.6 +
Reltool 0.5.7 + +
Fixed Bugs and Malfunctions + + +

+ If a module was duplicated in the library directories + visible to reltool, and the configuration did not point + out which file to use, then reltool:start would always + fail. A pop-up is added which asks if you want to + continue with a safe and minimal configuration.

+

+ Own Id: OTP-9383

+
+ +

+ wx would sometimes crash due to an empty radiobox on the + 'releases' tab of the system window. This radiobox is + removed, and replaced by a listbox which will always + contain at least kernel and stdlib applications.

+

+ Own Id: OTP-9384

+
+
+
+ +
+ +
Reltool 0.5.6
Fixed Bugs and Malfunctions diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk index 227b1c80a2..751f9bb6db 100644 --- a/lib/reltool/vsn.mk +++ b/lib/reltool/vsn.mk @@ -1 +1 @@ -RELTOOL_VSN = 0.5.6 +RELTOOL_VSN = 0.5.7 diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml index 599be62241..0bb76e1ea4 100644 --- a/lib/runtime_tools/doc/src/notes.xml +++ b/lib/runtime_tools/doc/src/notes.xml @@ -31,6 +31,23 @@

This document describes the changes made to the Runtime_Tools application.

+
Runtime_Tools 1.8.6 + +
Improvements and New Features + + +

+ Two new built-in trace pattern aliases have been added: + caller_trace (c) and caller_exception_trace (cx). See the + dbg:ltp/0 documentation for more info.

+

+ Own Id: OTP-9458

+
+
+
+ +
+
Runtime_Tools 1.8.5
Improvements and New Features diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk index 6ed98f697e..0bcd261861 100644 --- a/lib/runtime_tools/vsn.mk +++ b/lib/runtime_tools/vsn.mk @@ -1 +1 @@ -RUNTIME_TOOLS_VSN = 1.8.5 +RUNTIME_TOOLS_VSN = 1.8.6 diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml index d4460d47b4..01cdc4b29e 100644 --- a/lib/sasl/doc/src/notes.xml +++ b/lib/sasl/doc/src/notes.xml @@ -30,6 +30,104 @@

This document describes the changes made to the SASL application.

+
SASL 2.1.10 + +
Fixed Bugs and Malfunctions + + +

+ The release_handler functionality on windows services was + broken. This has been corrected.

+

+ Own Id: OTP-9306

+
+ +

+ If a new version of an application did not include any + erlang module changes, the code path of the application + was not updated by the release_handler unless a + 'load_object_code' instruction was added for the + application. This would be a problem if e.g. only some + files in the priv dir were changed since calls to + code:lib_dir or code:priv_dir would then point to the old + location of the application. This has been corrected - + now code:replace_path/2 will be called for all + applications that are changed (i.e. when the + application's vsn is changed in the .rel file).

+

+ Own Id: OTP-9402

+
+ +

+ The appup instruction 'delete_module' would cause a crash + during upgrade if the module to be deleted was not + loaded. This has been corrected.

+

+ Own Id: OTP-9417

+
+ +

+ If a path was given as ONLY 'ebin' and not for example + './ebin', then systools:make_tar would fail with a + function_clause exception in filename:join/1. This + has been corrected. (Thanks to Nikola Skoric for + reporting).

+

+ Own Id: OTP-9507

+
+ +

+ Implement or fix -Werror option

+

+ If -Werror is enabled and there are warnings no output + file is written. Also make sure that error/warning + reporting is consistent. (Thanks to Tuncer Ayaz)

+

+ Own Id: OTP-9536

+
+ +

+ Improved error information for timeouts during + release_handler:install_release.

+

+ This patch addresses two cases where a timeout will occur + during upgrade. 1) if a supervisor is suspended (call to + get children from supervisor will hang) 2) if the child + spec for a supervisor incorrectly states that it is a + worker with a dynamic set of modules (call to get modules + from gen_event will hang)

+

+ An error report will now be printed, and the return value + of release_handler:install_release will indicate what + happened. (Thanks to joe williams)

+

+ Own Id: OTP-9546

+
+
+
+ + +
Improvements and New Features + + +

+ release_handler:install_release could be very slow + when there are many processes in the system. Some + optimization work has been done both in erts and in the + release handler in order to improve this.

+

+ A new option, purge, is added to + release_handler:check_install_release which can be + called first in order to speed up the execution of + release_handler:install_release.

+

+ Own Id: OTP-9395

+
+
+
+ +
+
SASL 2.1.9.4
Fixed Bugs and Malfunctions diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index 26dc2c1448..2db134af48 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 2.1.9.4 +SASL_VSN = 2.1.10 diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index e090b4e1ef..5df2632149 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -30,7 +30,59 @@

This document describes the changes made to the SSL application.

-
+
SSL 4.1.6 + +
Fixed Bugs and Malfunctions + + +

+ replace "a ssl" with "an ssl" reindent + pkix_path_validation/3 Trivial documentation fixes + (Thanks to Christian von Roques )

+

+ Own Id: OTP-9464

+
+
+
+ + +
Improvements and New Features + + +

+ Adds function clause to avoid denial of service attack. + Thanks to Vinod for reporting this vulnerability.

+

+ Own Id: OTP-9364

+
+ +

+ Error handling code now takes care of inet:getopts/2 and + inets:setopts/2 crashes. Thanks to Richard Jones for + reporting this.

+

+ Own Id: OTP-9382

+
+ +

+ Support explicit use of packet option httph and httph_bin

+

+ Own Id: OTP-9461

+
+ +

+ Decoding of hello extensions could fail to come to the + correct conclusion due to an error in a binary match + pattern. Thanks to Ben Murphy.

+

+ Own Id: OTP-9589

+
+
+
+ +
+ +
SSL 4.1.5
Improvements and New Features diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index 36089f2603..d9c220b996 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -30,6 +30,168 @@

This document describes the changes made to the STDLIB application.

+
STDLIB 1.17.5 + +
Fixed Bugs and Malfunctions + + +

+ erl_tar:extract failed when executed inside a directory + with some parent directory to which the user has no read + access. This has been corrected.

+

+ Own Id: OTP-9368

+
+ +

A bug in erl_scan:set_attribute/3 has been + fixed.

+

+ Own Id: OTP-9412

+
+ +

The contract of io_lib:fread() has been + corrected.

+

+ Own Id: OTP-9413 Aux Id: seq11873

+
+ +

+ A crash in io_lib:fread/2 when end of input data was + encountered while trying to match literal characters, + which should return {more,_,_,_} but instead crashed, has + been corrected. Reported by Klas Johansson.

+

+ A similar peculiarity for io:fread when encountering end + of file before any field data has also been corrected.

+

+ Own Id: OTP-9439

+
+ +

The contract of timer:now_diff() has been + corrected. (Thanks to Alex Morarash).

+

+ Own Id: OTP-9450

+
+ +

+ Fix minor typo in gen_fsm documentation (Thanks to Haitao + Li)

+

+ Own Id: OTP-9456

+
+ +

The contracts of zip:zip_list_dir/1 and + zip:zip_get/2 have been corrected.

+

+ Own Id: OTP-9471 Aux Id: seq11887, OTP-9472

+
+ +

A bug in zip:zip_open() has been fixed.

+

+ Own Id: OTP-9472 Aux Id: seq11887, OTP-9471

+
+ +

+ Fix trivial documentation errors(Thanks to Matthias Lang)

+

+ Own Id: OTP-9498

+
+ +

+ Add a proplist() type

+

+ Recently I was adding specs to an API and found that + there is no canonical proplist() type defined. (Thanks to + Ryan Zezeski)

+

+ Own Id: OTP-9499

+
+ +

+ fix supervisors restarting temporary children

+

+ In the current implementation of supervisors, temporary + children should never be restarted. However, when a + temporary child is restarted as part of a one_for_all or + rest_for_one strategy where the failing process is not + the temporary child, the supervisor still tries to + restart it.

+

+ Because the supervisor doesn't keep some of the MFA + information of temporary children, this causes the + supervisor to hit its restart limit and crash.

+

+ This patch fixes the behaviour by inserting a clause in + terminate_children/2-3 (private function) that will omit + temporary children when building a list of killed + processes, to avoid having the supervisor trying to + restart them again.

+

+ Only supervisors in need of restarting children used the + list, so the change should be of no impact for the + functions that called terminate_children/2-3 only to kill + all children.

+

+ The documentation has been modified to make this + behaviour more explicit. (Thanks to Fred Hebert)

+

+ Own Id: OTP-9502

+
+ +

+ fix broken edoc annotations (Thanks to Richard Carlsson)

+

+ Own Id: OTP-9516

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+ +

+ Handle rare race in the crypto key server functionality

+

+ Own Id: OTP-9586

+
+
+
+ + +
Improvements and New Features + + +

Types and specifications have been added.

+

+ Own Id: OTP-9356

+
+ +

The contracts of the queue module have been + modified.

+

+ Own Id: OTP-9418

+
+ +

Contracts in STDLIB and Kernel have been improved and + type errors have been corrected.

+

+ Own Id: OTP-9485

+
+ +

+ Types for several BIFs have been extended/corrected. Also + the types for types for lists:keyfind/3, + lists:keysearch/3, and lists:keyemember/3 + have been corrected. The incorrect/incomplete types could + cause false dialyzer warnings.

+

+ Own Id: OTP-9496

+
+
+
+ +
+
STDLIB 1.17.4
Fixed Bugs and Malfunctions diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml index 50923b1b03..beeff55ffe 100644 --- a/lib/test_server/doc/src/notes.xml +++ b/lib/test_server/doc/src/notes.xml @@ -32,6 +32,150 @@ notes.xml +
Test_Server 3.4.5 + +
Fixed Bugs and Malfunctions + + +

+ An error in how comments are colored in the test suite + overview html log file has been corrected. As result, a + new framework callback function, format_comment/1, has + been introduced.

+

+ Own Id: OTP-9237

+
+ +

+ Test Server did not release SASL TTY handlers + (sasl_report_tty_h and error_logger_tty_h) properly after + each test run. This error has been fixed.

+

+ Own Id: OTP-9311

+
+ +

+ Automatically generated init- and end-configuration + functions for test case groups caused incorrect execution + order of test cases. This has been corrected.

+

+ Own Id: OTP-9369

+
+ +

+ If ct:log/2 was called with bad arguments, this could + cause the Common Test IO handling process to crash. This + fault has been corrected.

+

+ Own Id: OTP-9371 Aux Id: OTP-8933

+
+ +

+ A bug has been fixed that made Test Server call the + end_tc/3 framework function with an incorrect module name + as first argument.

+

+ Own Id: OTP-9379 Aux Id: seq11863

+
+ +

+ If end_per_testcase caused a timetrap timeout, the actual + test case status was discarded and the test case logged + as successful (even if the case had actually failed + before the call to end_per_testcase). This fault has been + fixed.

+

+ Own Id: OTP-9397

+
+ +

+ If a timetrap timeout occured during execution of of a + function in a lib module (i.e. a function called directly + or indirectly from a test case), the Suite argument in + the end_tc/3 framework callback function would not + correctly contain the name of the test suite, but the lib + module. (This would only happen if the lib module was + compiled with ct.hrl included). This error has been + solved.

+

+ Own Id: OTP-9398

+
+ +

+ Add a proplist() type

+

+ Recently I was adding specs to an API and found that + there is no canonical proplist() type defined. (Thanks to + Ryan Zezeski)

+

+ Own Id: OTP-9499

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+ +

+ If a test suite would start with a test case group + defined without the init_per_group/2 and end_per_group/2 + function, init_per_suite/1 would not execute initially + and logging of the test run would fail. This error has + been fixed.

+

+ Own Id: OTP-9584

+
+
+
+ + +
Improvements and New Features + + +

+ A new option, 'logopts', has been introduced, to make it + possible to modify some aspects of the logging behaviour + in Common Test (or Test Server). For example, whenever an + io printout is made, test_server adds newline (\n) to the + end of the output string. This may not always be a + preferred action and can therefore be disabled by means + of "ct_run ... -logopts no_nl" (or ct:run_test([..., + {logopts,[no_nl]}])). A new framework callback function, + get_logopts/0, has been introduced (see the ct_framework + module for details).

+

+ Own Id: OTP-9372 Aux Id: OTP-9396

+
+ +

+ A new option, 'logopts', has been introduced, to make it + possible to modify some aspects of the logging behaviour + in Common Test (or Test Server). For example, if the html + version of the test suite source code should not be + generated during the test run (and consequently be + unavailable in the log file system), the feature may be + disabled by means of "ct_run ... -logopts no_src" (or + ct:run_test([..., {logopts,[no_src]}])). A new framework + callback function, get_logopts/0, has been introduced + (see the ct_framework module for details).

+

+ Own Id: OTP-9396 Aux Id: seq11869, OTP-9372

+
+ +

+ It is now possible to use a tuple {M,F,A}, or a fun, as + timetrap specification in the suite info function or test + case info functions. The function must return a valid + timeout value, as documented in the common_test man page + and in the User's Guide.

+

+ Own Id: OTP-9501 Aux Id: seq11894

+
+
+
+ +
+
Test_Server 3.4.4
Fixed Bugs and Malfunctions diff --git a/lib/toolbar/doc/src/notes.xml b/lib/toolbar/doc/src/notes.xml index e2a3c22684..ffca2c5fbf 100644 --- a/lib/toolbar/doc/src/notes.xml +++ b/lib/toolbar/doc/src/notes.xml @@ -31,6 +31,22 @@

This document describes the changes made to the Toolbar application.

+
Toolbar 1.4.2 + +
Fixed Bugs and Malfunctions + + +

+ Improve spelling throughout documentation, code comments + and error messages

+

+ Own Id: OTP-9555

+
+
+
+ +
+
Toolbar 1.4.1
Improvements and New Features diff --git a/lib/toolbar/vsn.mk b/lib/toolbar/vsn.mk index 47d18e29f0..105303d785 100644 --- a/lib/toolbar/vsn.mk +++ b/lib/toolbar/vsn.mk @@ -1,4 +1,4 @@ -TOOLBAR_VSN = 1.4.1 +TOOLBAR_VSN = 1.4.2 diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index 02d92fc4e7..17506fb6e2 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -30,6 +30,44 @@

This document describes the changes made to the Tools application.

+
Tools 2.6.6.5 + +
Fixed Bugs and Malfunctions + + +

+ Teach the emacs mode to compile yecc and leex files

+

+ If visiting a .yrl or .xrl file in emacs with + erlang-mode, then the `erlang-compile' function (normally + bound to C-c C-k), now knows how to compile yecc and leex + files, and then, if that compilation succeeds, also + compiles the resulting .erl files.

+

+ Also introduce a `erlang-compile-command-function-alist' + to make it possible to hook in other functions for + computing compilation commands/expressions, depending on + file name. (Thanks to Tomas Abrahamsson )

+

+ Own Id: OTP-9503

+
+
+
+ + +
Improvements and New Features + + +

Bugs in xref(3) have been fixed. (Thanks to Matthias + Lang.)

+

+ Own Id: OTP-9416

+
+
+
+ +
+
Tools 2.6.6.4
Fixed Bugs and Malfunctions diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 6999c695e6..2d63a33554 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1 +1 @@ -TOOLS_VSN = 2.6.6.4 +TOOLS_VSN = 2.6.6.5 diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk index fe8faabdf8..9e73aed286 100644 --- a/lib/typer/vsn.mk +++ b/lib/typer/vsn.mk @@ -1 +1 @@ -TYPER_VSN = 0.9.1 +TYPER_VSN = 0.9.2 diff --git a/lib/webtool/doc/src/notes.xml b/lib/webtool/doc/src/notes.xml index b626ad2178..c58a440937 100644 --- a/lib/webtool/doc/src/notes.xml +++ b/lib/webtool/doc/src/notes.xml @@ -31,6 +31,22 @@

This document describes the changes made to the Webtool application.

+
WebTool 0.8.9 + +
Fixed Bugs and Malfunctions + + +

+ Do not install *.bat files on non-win32 machines (Thanks + to Hans Ulrich Niedermann)

+

+ Own Id: OTP-9515

+
+
+
+ +
+
WebTool 0.8.8
Fixed Bugs and Malfunctions diff --git a/lib/webtool/vsn.mk b/lib/webtool/vsn.mk index d687b4ff81..2643be866e 100644 --- a/lib/webtool/vsn.mk +++ b/lib/webtool/vsn.mk @@ -1 +1 @@ -WEBTOOL_VSN=0.8.8 +WEBTOOL_VSN=0.8.9 diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml index 26d1f892b2..7bd8d18592 100644 --- a/lib/wx/doc/src/notes.xml +++ b/lib/wx/doc/src/notes.xml @@ -31,6 +31,39 @@

This document describes the changes made to the wxErlang application.

+
Wx 0.99 + +
Fixed Bugs and Malfunctions + + +

+ wx: fix obsolete guard warning (list/1) (Thanks to Tuncer + Ayaz)

+

+ Own Id: OTP-9513

+
+ +

XML files have been corrected.

+

+ Own Id: OTP-9550 Aux Id: OTP-9541

+
+
+
+ + +
Improvements and New Features + + +

+ Support virtual tables in wxListCtrl.

+

+ Own Id: OTP-9415

+
+
+
+ +
+
Wx 0.98.10
Fixed Bugs and Malfunctions diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk index 02899f4115..8685c633d4 100644 --- a/lib/wx/vsn.mk +++ b/lib/wx/vsn.mk @@ -1 +1 @@ -WX_VSN = 0.98.10 +WX_VSN = 0.99 diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index 697823eee2..15c42d6f6a 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -31,6 +31,63 @@

This document describes the changes made to the Xmerl application.

+
Xmerl 1.2.10 + +
Fixed Bugs and Malfunctions + + +

Fixed a schema search bug in xmerl_xsd.

A + new flag was needed in the xsd_state record so if the + state is saved there is an incompatibility and a state + conversion is needed.

+

+ *** INCOMPATIBILITY with R14B03 ***

+

+ Own Id: OTP-9410

+
+ +

Fixed xmerl_scan problems with entities in attribute + values.

+

+ Own Id: OTP-9411

+
+ +

Streaming bug in xmerl_scan.

If the + continuation_fun runs out of input at the end of an + attribute value then it crashed. (Thanks to Simon + Cornish)

+

+ Own Id: OTP-9457

+
+ +

+ Fixed xmerl_ucs UCS2 little endian en/decoding

+

+ Corrected number of shift bytes in + xmerl_ucs:char_to_ucs2le and recursive call from + from_ucs2le to from_ucs4le. (Thanks to Michal Ptaszek)

+

+ Own Id: OTP-9548

+
+ +

+ Add latin9 (iso-8859-15) support in xmerl_ucs (Thanks to + David Julien)

+

+ Own Id: OTP-9552

+
+ +

+ Improve spelling throughout documentation, code comments + and error messages

+

+ Own Id: OTP-9555

+
+
+
+ +
+
Xmerl 1.2.9
Fixed Bugs and Malfunctions diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index 965a0ae7b4..82df8fdeef 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -1 +1 @@ -XMERL_VSN = 1.2.9 +XMERL_VSN = 1.2.10 -- cgit v1.2.3 From 8a9bfcdc30c3609d025d361518a0238a9585147c Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 3 Oct 2011 12:16:30 +0200 Subject: Better option handling Also cleaned up old gaurds. --- lib/ssl/doc/src/ssl_distribution.xml | 8 +- lib/ssl/src/ssl_tls_dist_proxy.erl | 54 +++++----- lib/ssl/test/ssl_dist_SUITE.erl | 145 ++++++++++++++++++++------- lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem | 5 + 4 files changed, 145 insertions(+), 67 deletions(-) create mode 100644 lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml index a2c7370ddc..4ae4ead3ee 100644 --- a/lib/ssl/doc/src/ssl_distribution.xml +++ b/lib/ssl/doc/src/ssl_distribution.xml @@ -175,7 +175,7 @@ Eshell V5.0 (abort with ^G)

One can specify the simpler SSL options certfile, keyfile, password, cacertfile, verify, reuse_sessions, - secure_renegotiation, depth, hibernate_after and ciphers (use old + secure_renegotiate, depth, hibernate_after and ciphers (use old string format) by adding the prefix server_ or client_ to the option name. The server can also take the options dhfile and fail_if_no_peer_cert (also prefixed). @@ -201,7 +201,7 @@ Eshell V5.0 (abort with ^G) $ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls -ssl_dist_opt server_certfile "/home/me/ssl/erlserver.pem" - -ssl_dist_opt server_secure_renegotiation true client_secure_renegotiate true + -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true -sname ssl_test Erlang (BEAM) emulator version 5.0 [source] @@ -224,7 +224,7 @@ Eshell V5.0 (abort with ^G) $ ERL_FLAGS="-boot /home/me/ssl/start_ssl -proto_dist inet_tls -ssl_dist_opt server_certfile /home/me/ssl/erlserver.pem - -ssl_dist_opt server_secure_renegotiation true client_secure_renegotiate true" + -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true" $ export ERL_FLAGS $ erl -sname ssl_test Erlang (BEAM) emulator version 5.0 [source] @@ -237,7 +237,7 @@ Eshell V5.0 (abort with ^G) {boot,["/home/me/ssl/start_ssl"]}, {proto_dist,["inet_tls"]}, {ssl_dist_opt,["server_certfile","/home/me/ssl/erlserver.pem"]}, - {ssl_dist_opt,["server_secure_renegotiation","true", + {ssl_dist_opt,["server_secure_renegotiate","true", "client_secure_renegotiate","true"] {home,["/home/me"]}]

The init:get_arguments() call verifies that the correct diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index 8993582fe8..d63eada571 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -243,60 +243,60 @@ loop_conn(World, Erts) -> get_ssl_options(Type) -> case init:get_argument(ssl_dist_opt) of {ok, Args} -> - [{erl_dist, true} | ssl_options(Type, Args)]; + [{erl_dist, true} | ssl_options(Type, lists:append(Args))]; _ -> [{erl_dist, true}] end. ssl_options(_,[]) -> []; -ssl_options(server, [["client_" ++ _, _Value]|T]) -> +ssl_options(server, ["client_" ++ _, _Value |T]) -> ssl_options(server,T); -ssl_options(client, [["server_" ++ _, _Value]|T]) -> +ssl_options(client, ["server_" ++ _, _Value|T]) -> ssl_options(client,T); -ssl_options(server, [["server_certfile", Value]|T]) -> +ssl_options(server, ["server_certfile", Value|T]) -> [{certfile, Value} | ssl_options(server,T)]; -ssl_options(client, [["client_certfile", Value]|T]) -> +ssl_options(client, ["client_certfile", Value | T]) -> [{certfile, Value} | ssl_options(client,T)]; -ssl_options(server, [["server_cacertfile", Value]|T]) -> +ssl_options(server, ["server_cacertfile", Value|T]) -> [{cacertfile, Value} | ssl_options(server,T)]; -ssl_options(client, [["client_cacertfile", Value]|T]) -> +ssl_options(client, ["client_cacertfile", Value|T]) -> [{cacertfile, Value} | ssl_options(client,T)]; -ssl_options(server, [["server_keyfile", Value]|T]) -> +ssl_options(server, ["server_keyfile", Value|T]) -> [{keyfile, Value} | ssl_options(server,T)]; -ssl_options(client, [["client_keyfile", Value]|T]) -> +ssl_options(client, ["client_keyfile", Value|T]) -> [{keyfile, Value} | ssl_options(client,T)]; -ssl_options(server, [["server_password", Value]|T]) -> +ssl_options(server, ["server_password", Value|T]) -> [{password, Value} | ssl_options(server,T)]; -ssl_options(client, [["client_password", Value]|T]) -> +ssl_options(client, ["client_password", Value|T]) -> [{password, Value} | ssl_options(client,T)]; -ssl_options(server, [["server_verify", Value]|T]) -> +ssl_options(server, ["server_verify", Value|T]) -> [{verify, atomize(Value)} | ssl_options(server,T)]; -ssl_options(client, [["client_verify", Value]|T]) -> +ssl_options(client, ["client_verify", Value|T]) -> [{verify, atomize(Value)} | ssl_options(client,T)]; -ssl_options(server, [["server_reuse_sessions", Value]|T]) -> +ssl_options(server, ["server_reuse_sessions", Value|T]) -> [{reuse_sessions, atomize(Value)} | ssl_options(server,T)]; -ssl_options(client, [["client_reuse_sessions", Value]|T]) -> +ssl_options(client, ["client_reuse_sessions", Value|T]) -> [{reuse_sessions, atomize(Value)} | ssl_options(client,T)]; -ssl_options(server, [["server_secure_renegotiation", Value]|T]) -> - [{secure_renegotiation, atomize(Value)} | ssl_options(server,T)]; -ssl_options(client, [["client_secure_renegotiation", Value]|T]) -> - [{secure_renegotiation, atomize(Value)} | ssl_options(client,T)]; -ssl_options(server, [["server_depth", Value]|T]) -> +ssl_options(server, ["server_secure_renegotiate", Value|T]) -> + [{secure_renegotiate, atomize(Value)} | ssl_options(server,T)]; +ssl_options(client, ["client_secure_renegotiate", Value|T]) -> + [{secure_renegotiate, atomize(Value)} | ssl_options(client,T)]; +ssl_options(server, ["server_depth", Value|T]) -> [{depth, list_to_integer(Value)} | ssl_options(server,T)]; -ssl_options(client, [["client_depth", Value]|T]) -> +ssl_options(client, ["client_depth", Value|T]) -> [{depth, list_to_integer(Value)} | ssl_options(client,T)]; -ssl_options(server, [["server_hibernate_after", Value]|T]) -> +ssl_options(server, ["server_hibernate_after", Value|T]) -> [{hibernate_after, list_to_integer(Value)} | ssl_options(server,T)]; -ssl_options(client, [["client_hibernate_after", Value]|T]) -> +ssl_options(client, ["client_hibernate_after", Value|T]) -> [{hibernate_after, list_to_integer(Value)} | ssl_options(client,T)]; -ssl_options(server, [["server_ciphers", Value]|T]) -> +ssl_options(server, ["server_ciphers", Value|T]) -> [{ciphers, Value} | ssl_options(server,T)]; -ssl_options(client, [["client_ciphers", Value]|T]) -> +ssl_options(client, ["client_ciphers", Value|T]) -> [{ciphers, Value} | ssl_options(client,T)]; -ssl_options(server, [["server_dhfile", Value]|T]) -> +ssl_options(server, ["server_dhfile", Value|T]) -> [{dhfile, Value} | ssl_options(server,T)]; -ssl_options(server, [["server_fail_if_no_peer_cert", Value]|T]) -> +ssl_options(server, ["server_fail_if_no_peer_cert", Value|T]) -> [{fail_if_no_peer_cert, atomize(Value)} | ssl_options(server,T)]; ssl_options(_,_) -> exit(malformed_ssl_dist_opt). diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index f54eb29062..23e9268f9b 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -35,11 +35,12 @@ nodename} ). +%% Test server callback functions suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [basic, payload]. + [basic, payload, plain_options, plain_verify_options]. groups() -> []. @@ -50,10 +51,12 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. -init_per_suite(Config) -> +init_per_suite(Config0) -> try crypto:start() of ok -> - add_ssl_opts_config(Config) + Config = add_ssl_opts_config(Config0), + setup_certs(Config), + Config catch _:_ -> {skip, "Crypto did not start"} end. @@ -62,24 +65,19 @@ end_per_suite(Config) -> application:stop(crypto), Config. -init_per_testcase(Case, Config) when list(Config) -> +init_per_testcase(Case, Config) when is_list(Config) -> Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)), [{watchdog, Dog},{testcase, Case}|Config]. -end_per_testcase(_Case, Config) when list(Config) -> +end_per_testcase(_Case, Config) when is_list(Config) -> Dog = ?config(watchdog, Config), ?t:timetrap_cancel(Dog), ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% Testcases %% -%% %% - +%%-------------------------------------------------------------------- +%% Test cases starts here. +%%-------------------------------------------------------------------- basic(doc) -> ["Test that two nodes can connect via ssl distribution"]; -basic(suite) -> - []; basic(Config) when is_list(Config) -> NH1 = start_ssl_node(Config), Node1 = NH1#node_handle.nodename, @@ -132,11 +130,9 @@ basic(Config) when is_list(Config) -> stop_ssl_node(NH2), success(Config). - +%%-------------------------------------------------------------------- payload(doc) -> ["Test that send a lot of data between the ssl distributed noes"]; -payload(suite) -> - []; payload(Config) when is_list(Config) -> NH1 = start_ssl_node(Config), Node1 = NH1#node_handle.nodename, @@ -148,10 +144,6 @@ payload(Config) when is_list(Config) -> [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end), [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end), - %% - %% Check that we are able to communicate over the erlang - %% distribution between the ssl nodes. - %% Ref = make_ref(), spawn(fun () -> apply_on_ssl_node( @@ -180,13 +172,57 @@ payload(Config) when is_list(Config) -> stop_ssl_node(NH1), stop_ssl_node(NH2), success(Config). +%%-------------------------------------------------------------------- +plain_options(doc) -> + ["Test specifying additional options"]; +plain_options(Config) when is_list(Config) -> + DistOpts = "-ssl_dist_opt server_secure_renegotiate true " + "client_secure_renegotiate true " + "server_reuse_sessions true client_reuse_sessions true " + "client_verify verify_none server_verify verify_none " + "server_depth 1 client_depth 1 " + "server_hibernate_after 500 client_hibernate_after 500", + + NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]), + Node1 = NH1#node_handle.nodename, + NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]), + Node2 = NH2#node_handle.nodename, + + pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% Internal functions %% -%% %% + [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end), + [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end), + + stop_ssl_node(NH1), + stop_ssl_node(NH2), + success(Config). +%%-------------------------------------------------------------------- +plain_verify_options(doc) -> + ["Test specifying additional options"]; +plain_verify_options(Config) when is_list(Config) -> + DistOpts = "-ssl_dist_opt server_secure_renegotiate true " + "client_secure_renegotiate true " + "server_reuse_sessions true client_reuse_sessions true " + "server_hibernate_after 500 client_hibernate_after 500", + + NH1 = start_ssl_node([{additional_dist_opts, DistOpts}, {many_verify_opts, true} | Config]), + Node1 = NH1#node_handle.nodename, + NH2 = start_ssl_node([{additional_dist_opts, DistOpts}, {many_verify_opts, true} | Config]), + Node2 = NH2#node_handle.nodename, + + pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), + + [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end), + [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end), + + stop_ssl_node(NH1), + stop_ssl_node(NH2), + success(Config). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- -%% %% ssl_node side api %% @@ -201,7 +237,7 @@ send_to_tstcntrl(Message) -> %% test_server side api %% -apply_on_ssl_node(Node, M, F, A) when atom(M), atom(F), list(A) -> +apply_on_ssl_node(Node, M, F, A) when is_atom(M), is_atom(F), is_list(A) -> Ref = make_ref(), send_to_ssl_node(Node, {apply, self(), Ref, M, F, A}), receive @@ -243,7 +279,7 @@ start_ssl_node(Config) -> start_ssl_node(Config, XArgs) -> Name = mk_node_name(Config), SSL = ?config(ssl_opts, Config), - SSLDistOpts = setup_dist_opts(Name, ?config(priv_dir, Config)), + SSLDistOpts = setup_dist_opts(Config), start_ssl_node_raw(Name, SSL ++ " " ++ SSLDistOpts ++ XArgs). start_ssl_node_raw(Name, Args) -> @@ -253,7 +289,7 @@ start_ssl_node_raw(Name, Args) -> CmdLine = mk_node_cmdline(ListenPort, Name, Args), ?t:format("Attempting to start ssl node ~s: ~s~n", [Name, CmdLine]), case open_port({spawn, CmdLine}, []) of - Port when port(Port) -> + Port when is_port(Port) -> unlink(Port), erlang:port_close(Port), case await_ssl_node_up(Name, LSock) of @@ -412,7 +448,7 @@ tstsrvr_con_loop(Name, Socket, Parent) -> %% % cnct2tstsrvr() is called via command line arg -run ... -cnct2tstsrvr([Host, Port]) when list(Host), list(Port) -> +cnct2tstsrvr([Host, Port]) when is_list(Host), is_list(Port) -> %% Spawn connection handler on ssl node side ConnHandler = spawn(fun () -> @@ -455,7 +491,7 @@ notify_ssl_node_up(Socket) -> send_to_tstsrvr(Term) -> case catch ets:lookup_element(test_server_info, test_server_handler, 2) of - Hndlr when pid(Hndlr) -> + Hndlr when is_pid(Hndlr) -> Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok; _ -> receive after 200 -> ok end, @@ -536,8 +572,9 @@ do_append_files([F|Fs], RF) -> ok = file:write(RF, Data), do_append_files(Fs, RF). -setup_dist_opts(Name, PrivDir) -> - NodeDir = filename:join([PrivDir, Name]), +setup_certs(Config) -> + PrivDir = ?config(priv_dir, Config), + NodeDir = filename:join([PrivDir, "Certs"]), RGenDir = filename:join([NodeDir, "rand_gen"]), ok = file:make_dir(NodeDir), ok = file:make_dir(RGenDir), @@ -552,10 +589,46 @@ setup_dist_opts(Name, PrivDir) -> CC = filename:join([CDir, "cert.pem"]), CK = filename:join([CDir, "key.pem"]), CKC = filename:join([CDir, "keycert.pem"]), - append_files([CK, CC], CKC), - "-proto_dist inet_tls " - ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " " - ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " ". + append_files([CK, CC], CKC). + +setup_dist_opts(Config) -> + PrivDir = ?config(priv_dir, Config), + DataDir = ?config(data_dir, Config), + Dhfile = filename:join([DataDir, "dHParam.pem"]), + NodeDir = filename:join([PrivDir, "Certs"]), + SDir = filename:join([NodeDir, "server"]), + CDir = filename:join([NodeDir, "client"]), + SC = filename:join([SDir, "cert.pem"]), + SK = filename:join([SDir, "key.pem"]), + SKC = filename:join([SDir, "keycert.pem"]), + SCA = filename:join([CDir, "cacerts.pem"]), + CC = filename:join([CDir, "cert.pem"]), + CK = filename:join([CDir, "key.pem"]), + CKC = filename:join([CDir, "keycert.pem"]), + CCA = filename:join([SDir, "cacerts.pem"]), + + DistOpts = case proplists:get_value(many_verify_opts, Config, false) of + false -> + "-proto_dist inet_tls " + ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " " + ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " "; + true -> + "-proto_dist inet_tls " + ++ "-ssl_dist_opt server_certfile " ++ SC ++ " " + ++ "-ssl_dist_opt server_keyfile " ++ SK ++ " " + ++ "-ssl_dist_opt server_cacertfile " ++ SCA ++ " " + ++ "-ssl_dist_opt server_verify verify_peer " + ++ "-ssl_dist_opt server_fail_if_no_peer_cert true " + ++ "-ssl_dist_opt server_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA " + ++ "-ssl_dist_opt server_dhfile " ++ Dhfile ++ " " + ++ "-ssl_dist_opt client_certfile " ++ CC ++ " " + ++ "-ssl_dist_opt client_keyfile " ++ CK ++ " " + ++ "-ssl_dist_opt client_cacertfile " ++ CCA ++ " " + ++ "-ssl_dist_opt client_verify verify_peer " + ++ "-ssl_dist_opt client_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA " + end, + MoreOpts = proplists:get_value(additional_dist_opts, Config, []), + DistOpts ++ MoreOpts. %% %% Start scripts etc... diff --git a/lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem b/lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem new file mode 100644 index 0000000000..feb581da30 --- /dev/null +++ b/lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAMY5VmCZ22ZEy/KO8kjt94PH7ZtSG0Z0zitlMlvd4VsNkDzXsVeu+wkH +FGDC3h3vgv6iwXGCbmrSOVk/FPZbzLhwZ8aLnkUFOBbOvVvb1JptQwOt8mf+eScG +M2gGBktheQV5Nf1IrzOctG7VGt+neiqb/Y86uYCcDdL+M8++0qnLAgEC +-----END DH PARAMETERS----- -- cgit v1.2.3 From b138f9e6879e44732e681d368704345acdf26b1b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 29 Sep 2011 09:08:31 +0200 Subject: Add tls support to capabilities exchange To upgrade a connection to TLS or not, that is the question. It is possible for us to send a CER offering both NO_INBAND_SECURITY and TLS and for the peer to answer likewise: RFC 3588 doesn't make clear that a CEA should be unambiguous about the choice of security. Thus, if TLS is offered then assume the server is prepared to for a handshake. Similarly, when receiving a CER, choose TLS if it's offered and be unambiguous about our choice in CEA. There is no ssl:maybe_accept that would let us receive a handshake if it comes or another message if it doesn't. The choice of TLS should probably be made into a callback so that an application can decide based on the peer's Origin-Realm for example. Such a callback could also be used to reject a CER/CEA. Handle Inband-Security-Id values other than NO_INBAND_SECURITY and TLS by assuming that they require no intervention by the transport module, treating them like NO_INBAND_SECURITY. Whether or not this is reasonable (or useful) is unclear. There may be a need for more sychronization than we have on offer. (Having to do something before taking the connection up for example.) Note that diameter_peer_fsm must be upgraded before diameter_capx because of the new return value from diameter_capx:recv_CEA/2. --- lib/diameter/src/app/diameter_capx.erl | 145 ++++++++++++++++------------- lib/diameter/src/app/diameter_peer_fsm.erl | 87 +++++++++++------ 2 files changed, 140 insertions(+), 92 deletions(-) diff --git a/lib/diameter/src/app/diameter_capx.erl b/lib/diameter/src/app/diameter_capx.erl index aa5318e79d..138e76411e 100644 --- a/lib/diameter/src/app/diameter_capx.erl +++ b/lib/diameter/src/app/diameter_capx.erl @@ -62,6 +62,7 @@ -define(NOSECURITY, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_SECURITY'). -define(NO_INBAND_SECURITY, 0). +-define(TLS, 1). %% =========================================================================== @@ -80,7 +81,7 @@ recv_CER(CER, Svc) -> try_it([fun rCER/2, CER, Svc]). -spec recv_CEA(#diameter_base_CEA{}, #diameter_service{}) - -> tried({['Unsigned32'()], #diameter_caps{}}). + -> tried({['Unsigned32'()], ['Unsigned32'()], #diameter_caps{}}). recv_CEA(CEA, Svc) -> try_it([fun rCEA/2, CEA, Svc]). @@ -126,10 +127,11 @@ mk_caps(Caps0, Opts) -> set_cap({Key, _}, _) -> ?THROW({duplicate, Key}). -cap(K, V) when K == 'Origin-Host'; - K == 'Origin-Realm'; - K == 'Vendor-Id'; - K == 'Product-Name' -> +cap(K, V) + when K == 'Origin-Host'; + K == 'Origin-Realm'; + K == 'Vendor-Id'; + K == 'Product-Name' -> V; cap('Host-IP-Address', Vs) @@ -139,11 +141,8 @@ cap('Host-IP-Address', Vs) cap('Firmware-Revision', V) -> [V]; -%% Not documented but accept it as long as it's what we support. -cap('Inband-Security-Id', [0] = Vs) -> %% NO_INBAND_SECURITY - Vs; - -cap(K, Vs) when K /= 'Inband-Security-Id', is_list(Vs) -> +cap(_, Vs) + when is_list(Vs) -> Vs; cap(K, V) -> @@ -161,28 +160,10 @@ ipaddr(A) -> %% %% Build a CER record to send to a remote peer. -bCER(#diameter_caps{origin_host = Host, - origin_realm = Realm, - host_ip_address = Addrs, - vendor_id = Vid, - product_name = Name, - origin_state_id = OSI, - supported_vendor_id = SVid, - auth_application_id = AuId, - acct_application_id = AcId, - vendor_specific_application_id = VSA, - firmware_revision = Rev}) -> - #diameter_base_CER{'Origin-Host' = Host, - 'Origin-Realm' = Realm, - 'Host-IP-Address' = Addrs, - 'Vendor-Id' = Vid, - 'Product-Name' = Name, - 'Origin-State-Id' = OSI, - 'Supported-Vendor-Id' = SVid, - 'Auth-Application-Id' = AuId, - 'Acct-Application-Id' = AcId, - 'Vendor-Specific-Application-Id' = VSA, - 'Firmware-Revision' = Rev}. +%% Use the fact that diameter_caps has the same field names as CER. +bCER(#diameter_caps{} = Rec) -> + #diameter_base_CER{} + = list_to_tuple([diameter_base_CER | tl(tuple_to_list(Rec))]). %% rCER/2 %% @@ -219,19 +200,16 @@ bCER(#diameter_caps{origin_host = Host, %% That is, each side sends all of its capabilities and is responsible for %% not sending commands that the peer doesn't support. -%% TODO: Make it an option to send only common applications in CEA to -%% allow backwards compatibility, and also because there are likely -%% servers that expect this. Or maybe a callback. - %% 6.10. Inband-Security-Id AVP %% %% NO_INBAND_SECURITY 0 %% This peer does not support TLS. This is the default value, if the %% AVP is omitted. +%% +%% TLS 1 +%% This node supports TLS security, as defined by [TLS]. rCER(CER, #diameter_service{capabilities = LCaps} = Svc) -> - #diameter_base_CER{'Inband-Security-Id' = RIS} - = CER, #diameter_base_CEA{} = CEA = cea_from_cer(bCER(LCaps)), @@ -241,56 +219,95 @@ rCER(CER, #diameter_service{capabilities = LCaps} = Svc) -> {SApps, RCaps, - build_CEA([] == SApps, - RIS, - lists:member(?NO_INBAND_SECURITY, RIS), - CEA#diameter_base_CEA{'Result-Code' = ?SUCCESS, - 'Inband-Security-Id' = []})}. + build_CEA(SApps, + LCaps, + RCaps, + CEA#diameter_base_CEA{'Result-Code' = ?SUCCESS})}. -%% TODO: 5.3 of RFC3588 says we MUST return DIAMETER_NO_COMMON_APPLICATION +%% TODO: 5.3 of RFC 3588 says we MUST return DIAMETER_NO_COMMON_APPLICATION %% in the CEA and SHOULD disconnect the transport. However, we have %% no way to guarantee the send before disconnecting. -build_CEA(true, _, _, CEA) -> +build_CEA([], _, _, CEA) -> CEA#diameter_base_CEA{'Result-Code' = ?NOAPP}; -build_CEA(false, [_|_], false, CEA) -> - CEA#diameter_base_CEA{'Result-Code' = ?NOSECURITY}; -build_CEA(false, [_|_], true, CEA) -> - CEA#diameter_base_CEA{'Inband-Security-Id' = [?NO_INBAND_SECURITY]}; -build_CEA(false, [], false, CEA) -> - CEA. + +build_CEA(_, LCaps, RCaps, CEA) -> + case common_security(LCaps, RCaps) of + [] -> + CEA#diameter_base_CEA{'Result-Code' = ?NOSECURITY}; + [_] = IS -> + CEA#diameter_base_CEA{'Inband-Security-Id' = IS} + end. + +%% common_security/2 + +common_security(#diameter_caps{inband_security_id = LS}, + #diameter_caps{inband_security_id = RS}) -> + cs(LS, RS). + +%% Unspecified is equivalent to NO_INBAND_SECURITY. +cs([], RS) -> + cs([?NO_INBAND_SECURITY], RS); +cs(LS, []) -> + cs(LS, [?NO_INBAND_SECURITY]); + +%% Agree on TLS if both parties support it. When sending CEA, this is +%% to ensure the peer is clear that we will be expecting a TLS +%% handshake since there is no ssl:maybe_accept that would allow the +%% peer to choose between TLS or not upon reception of our CEA. When +%% receiving CEA it deals with a server that isn't explicit about its choice. +%% TODO: Make the choice configurable. +cs(LS, RS) -> + Is = ordsets:to_list(ordsets:intersection(ordsets:from_list(LS), + ordsets:from_list(RS))), + case lists:member(?TLS, Is) of + true -> + [?TLS]; + false when [] == Is -> + Is; + false -> + [hd(Is)] %% probably NO_INBAND_SECURITY + end. +%% The only two values defined by RFC 3588 are NO_INBAND_SECURITY and +%% TLS but don't enforce this. In theory this allows some other +%% security mechanism we don't have to know about, although in +%% practice something there may be a need for more synchronization +%% than notification by way of an event subscription offers. %% cea_from_cer/1 +%% CER is a subset of CEA, the latter adding Result-Code and a few +%% more AVP's. cea_from_cer(#diameter_base_CER{} = CER) -> lists:foldl(fun(F,A) -> to_cea(CER, F, A) end, #diameter_base_CEA{}, record_info(fields, diameter_base_CER)). to_cea(CER, Field, CEA) -> - try ?BASE:'#info-'(diameter_base_CEA, {index, Field}) of - N -> - setelement(N, CEA, ?BASE:'#get-'(Field, CER)) + try ?BASE:'#get-'(Field, CER) of + V -> ?BASE:'#set-'({Field, V}, CEA) catch - error: _ -> - CEA + error: _ -> CEA end. - + %% rCEA/2 -rCEA(CEA, #diameter_service{capabilities = LCaps} = Svc) - when is_record(CEA, diameter_base_CEA) -> - #diameter_base_CEA{'Result-Code' = RC} - = CEA, - +rCEA(#diameter_base_CEA{'Result-Code' = RC} + = CEA, + #diameter_service{capabilities = LCaps} + = Svc) -> RC == ?SUCCESS orelse ?THROW({'Result-Code', RC}), RCaps = capx_to_caps(CEA), SApps = common_applications(LCaps, RCaps, Svc), - [] == SApps andalso ?THROW({no_common_apps, LCaps, RCaps}), + [] == SApps andalso ?THROW(no_common_applications), + + IS = common_security(LCaps, RCaps), + + [] == IS andalso ?THROW(no_common_security), - {SApps, RCaps}; + {SApps, IS, RCaps}; rCEA(CEA, _Svc) -> ?THROW({invalid, CEA}). diff --git a/lib/diameter/src/app/diameter_peer_fsm.erl b/lib/diameter/src/app/diameter_peer_fsm.erl index 0252fb3809..282fa2742f 100644 --- a/lib/diameter/src/app/diameter_peer_fsm.erl +++ b/lib/diameter/src/app/diameter_peer_fsm.erl @@ -52,6 +52,9 @@ -define(GOAWAY, ?'DIAMETER_BASE_DISCONNECT-CAUSE_DO_NOT_WANT_TO_TALK_TO_YOU'). -define(REBOOT, ?'DIAMETER_BASE_DISCONNECT-CAUSE_REBOOTING'). +-define(NO_INBAND_SECURITY, 0). +-define(TLS, 1). + -define(LOOP_TIMEOUT, 2000). %% RFC 3588: @@ -195,10 +198,8 @@ handle_info(T, #state{} = State) -> ?LOG(stop, T), x(T, State) catch - throw: {?MODULE, close = C, Reason} -> - ?LOG(C, {Reason, T}), - x(Reason, State); - throw: {?MODULE, abort, Reason} -> + throw: {?MODULE, Tag, Reason} -> + ?LOG(Tag, {Reason, T}), {stop, {shutdown, Reason}, State} end. @@ -281,10 +282,9 @@ transition(shutdown, _) -> %% DPR already send: ensure expected timeout %% Request to close the transport connection. transition({close = T, Pid}, #state{parent = Pid, - transport = TPid} - = S) -> + transport = TPid}) -> diameter_peer:close(TPid), - close(T,S); + {stop, T}; %% DPA reception has timed out. transition(dpa_timeout, _) -> @@ -418,11 +418,11 @@ rcv('CER' = N, Pkt, #state{state = recv_CER} = S) -> %% Anything but CER/CEA in a non-Open state is an error, as is %% CER/CEA in anything but recv_CER/Wait-CEA. -rcv(Name, _, #state{state = PS} = S) +rcv(Name, _, #state{state = PS}) when PS /= 'Open'; Name == 'CER'; Name == 'CEA' -> - close({Name, PS}, S); + {stop, {Name, PS}}; rcv(N, Pkt, S) when N == 'DWR'; @@ -497,15 +497,20 @@ build_answer('CER', #diameter_service{capabilities = #diameter_caps{origin_host = OH}} = Svc, - {SupportedApps, #diameter_caps{origin_host = DH} = RCaps, CEA} + {SupportedApps, + #diameter_caps{origin_host = DH} = RCaps, + #diameter_base_CEA{'Result-Code' = RC} + = CEA} = recv_CER(CER, S), try - [] == SupportedApps - andalso ?THROW({no_common_application, 5010}), + 2001 == RC %% DIAMETER_SUCCESS + orelse ?THROW({sent_CEA, RC}), register_everywhere({?MODULE, connection, OH, DH}) orelse ?THROW({election_lost, 4003}), - {CEA, [fun open/4, Pkt, SupportedApps, RCaps]} + #diameter_base_CEA{'Inband-Security-Id' = [IS]} + = CEA, + {CEA, [fun open/5, Pkt, SupportedApps, RCaps, {accept, IS}]} catch ?FAILURE({Reason, RC}) -> {answer('CER', S) ++ [{'Result-Code', RC}], @@ -613,7 +618,7 @@ recv_CER(CER, #state{service = Svc}) -> handle_CEA(#diameter_packet{header = #diameter_header{version = V}, bin = Bin} = Pkt, - #state{service = Svc} + #state{service = #diameter_service{capabilities = LCaps}} = S) when is_binary(Bin) -> ?LOG(recv, 'CEA'), @@ -626,7 +631,11 @@ handle_CEA(#diameter_packet{header = #diameter_header{version = V}, [] == Errors orelse close({errors, Errors}, S), - {SApps, #diameter_caps{origin_host = DH} = RCaps} = recv_CEA(CEA, S), + {SApps, [IS], #diameter_caps{origin_host = DH} = RCaps} + = recv_CEA(CEA, S), + + #diameter_caps{origin_host = OH} + = LCaps, %% Ensure that we don't already have a connection to the peer in %% question. This isn't the peer election of 3588 except in the @@ -634,40 +643,62 @@ handle_CEA(#diameter_packet{header = #diameter_header{version = V}, %% receive a CER/CEA, the first that arrives wins the right to a %% connection with the peer. - #diameter_service{capabilities = #diameter_caps{origin_host = OH}} - = Svc, - register_everywhere({?MODULE, connection, OH, DH}) - orelse - close({'CEA', DH}, S), + orelse close({'CEA', DH}, S), - open(DPkt, SApps, RCaps, S). + open(DPkt, SApps, RCaps, {connect, IS}, S). %% recv_CEA/2 recv_CEA(CEA, #state{service = Svc} = S) -> case diameter_capx:recv_CEA(CEA, Svc) of - {ok, {[], _}} -> + {ok, {_,_}} -> %% return from old code + close({'CEA', update}, S); + {ok, {[], _, _}} -> close({'CEA', no_common_application}, S); - {ok, T} -> + {ok, {_, [], _}} -> + close({'CEA', no_common_security}, S); + {ok, {_,_,_} = T} -> T; {error, Reason} -> close({'CEA', Reason}, S) end. -%% open/4 +%% open/5 -open(Pkt, SupportedApps, RCaps, #state{parent = Pid, - service = Svc} - = S) -> - #diameter_service{capabilities = #diameter_caps{origin_host = OH} +open(Pkt, SupportedApps, RCaps, {Type, IS}, #state{parent = Pid, + service = Svc} + = S) -> + #diameter_service{capabilities = #diameter_caps{origin_host = OH, + inband_security_id = LS} = LCaps} = Svc, #diameter_caps{origin_host = DH} = RCaps, + + tls_ack(lists:member(?TLS, LS), Type, IS, S), Pid ! {open, self(), {OH,DH}, {capz(LCaps, RCaps), SupportedApps, Pkt}}, + S#state{state = 'Open'}. +%% We've advertised TLS support: tell the transport the result +%% and expect a reply when the handshake is complete. +tls_ack(true, Type, IS, #state{transport = TPid} = S) -> + Ref = make_ref(), + MRef = erlang:monitor(process, TPid), + TPid ! {diameter, {tls, Ref, Type, IS == ?TLS}}, + receive + {diameter, {tls, Ref}} -> + erlang:demonitor(MRef, [flush]); + {'DOWN', MRef, process, _, _} = T -> + close({tls_ack, T}, S) + end; + +%% Or not. Don't send anything to the transport so that transports +%% not supporting TLS work as before without modification. +tls_ack(false, _, _, _) -> + ok. + capz(#diameter_caps{} = L, #diameter_caps{} = R) -> #diameter_caps{} = list_to_tuple([diameter_caps | lists:zip(tl(tuple_to_list(L)), -- cgit v1.2.3 From 10aa701bf7bf390303a499c99cdf1372eb911680 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 2 Oct 2011 01:33:42 +0200 Subject: Lift recursion in tcp message reception up the call chain When an initial message is received and TLS is a possibility, must wait for a message from the peer process before either commencing a handshake or receiving more messages. --- lib/diameter/src/transport/diameter_tcp.erl | 58 +++++++++++++++-------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index 653c114471..2c01037063 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -385,74 +385,78 @@ transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) -> %% using Nagle. recv(Bin, #transport{parent = Pid, frag = Head} = S) -> - S#transport{frag = recv(Pid, Head, Bin)}. + case recv1(Head, Bin) of + {Msg, B} when is_binary(Msg) -> + diameter_peer:recv(Pid, Msg), + recv(B, S#transport{frag = <<>>}); + Frag -> + S#transport{frag = Frag} + end. -%% recv/3 +%% recv1/2 %% No previous fragment. -recv(Pid, <<>>, Bin) -> - rcv(Pid, Bin); +recv1(<<>>, Bin) -> + rcv(Bin); -recv(Pid, {TRef, Head}, Bin) -> +recv1({TRef, Head}, Bin) -> erlang:cancel_timer(TRef), - rcv(Pid, Head, Bin). + rcv(Head, Bin). -%% rcv/3 +%% rcv/2 %% Not even the first four bytes of the header. -rcv(Pid, Head, Bin) +rcv(Head, Bin) when is_binary(Head) -> - rcv(Pid, <>); + rcv(<>); %% Or enough to know how many bytes to extract. -rcv(Pid, {Len, N, Head, Acc}, Bin) -> - rcv(Pid, Len, N + size(Bin), Head, [Bin | Acc]). +rcv({Len, N, Head, Acc}, Bin) -> + rcv(Len, N + size(Bin), Head, [Bin | Acc]). -%% rcv/5 +%% rcv/4 %% Extract a message for which we have all bytes. -rcv(Pid, Len, N, Head, Acc) +rcv(Len, N, Head, Acc) when Len =< N -> - rcv(Pid, rcv1(Pid, Len, bin(Head, Acc))); + rcv1(Len, bin(Head, Acc)); %% Wait for more packets. -rcv(_, Len, N, Head, Acc) -> +rcv(Len, N, Head, Acc) -> {start_timer(), {Len, N, Head, Acc}}. %% rcv/2 %% Nothing left. -rcv(_, <<>> = Bin) -> +rcv(<<>> = Bin) -> Bin; %% Well, this isn't good. Chances are things will go south from here %% but if we're lucky then the bytes we have extend to an intended %% message boundary and we can recover by simply discarding them, %% which is the result of receiving them. -rcv(Pid, <<_:1/binary, Len:24, _/binary>> = Bin) +rcv(<<_:1/binary, Len:24, _/binary>> = Bin) when Len < 20 -> - diameter_peer:recv(Pid, Bin), - <<>>; + {Bin, <<>>}; %% Enough bytes to extract a message. -rcv(Pid, <<_:1/binary, Len:24, _/binary>> = Bin) +rcv(<<_:1/binary, Len:24, _/binary>> = Bin) when Len =< size(Bin) -> - rcv(Pid, rcv1(Pid, Len, Bin)); + rcv1(Len, Bin); %% Or not: wait for more packets. -rcv(_, <<_:1/binary, Len:24, _/binary>> = Head) -> +rcv(<<_:1/binary, Len:24, _/binary>> = Head) -> {start_timer(), {Len, size(Head), Head, []}}; %% Not even 4 bytes yet. -rcv(_, Head) -> +rcv(Head) -> {start_timer(), Head}. -%% rcv1/3 +%% rcv1/2 -rcv1(Pid, Len, Bin) -> +rcv1(Len, Bin) -> <> = Bin, - diameter_peer:recv(Pid, Msg), - Rest. + {Msg, Rest}. %% bin/[12] -- cgit v1.2.3 From 804d96e755a65a17cfe0d67698b834bdda11afe5 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 3 Oct 2011 15:30:55 +0200 Subject: Handle tls notification for tcp If TLS has been configured on Inband-Security-Id then the transport process receives a message from the peer_fsm process indicating whether or not to upgrade to TLS. The current draft of RFC 3588 deprecates (but retains for backwards compatibility) the use of Inband-Security-Id for negotiating TLS, adding the possibility of TLS having be negotiated before capabilities exchange. This commit handles the deprecated case. --- lib/diameter/src/transport/diameter_tcp.erl | 105 +++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 10 deletions(-) diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index 2c01037063..e0b68237c2 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -71,8 +71,8 @@ {socket :: inet:socket(), %% accept or connect socket parent :: pid(), %% of process that started us module :: module(), %% gen_tcp-like module - frag = <<>> :: binary() | {tref(), frag()}}). %% message fragment - + frag = <<>> :: binary() | {tref(), frag()}, %% message fragment + ssl :: boolean() | [term()]}). %% ssl options %% The usual transport using gen_tcp can be replaced by anything %% sufficiently gen_tcp-like by passing a 'module' option as the first %% (for simplicity) transport option. The transport_module diameter_etcp @@ -122,12 +122,14 @@ i({T, Ref, Mod, Pid, Opts, Addrs}) %% that does nothing but kill us with the parent until call %% returns. {ok, MPid} = diameter_tcp_sup:start_child(#monitor{parent = Pid}), - Sock = i(T, Ref, Mod, Pid, Opts, Addrs), + {[SslOpts], Rest} = proplists:split(Opts, [ssl_options]), + Sock = i(T, Ref, Mod, Pid, Rest, Addrs), MPid ! {stop, self()}, %% tell the monitor to die setopts(Mod, Sock), #transport{parent = Pid, module = Mod, - socket = Sock}; + socket = Sock, + ssl = ssl_opts(Mod, SslOpts)}; %% A monitor process to kill the transport if the parent dies. i(#monitor{parent = Pid, transport = TPid} = S) -> @@ -151,6 +153,14 @@ i({listen, LRef, APid, {Mod, Opts, Addrs}}) -> true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}), start_timer(#listener{socket = LSock}). +ssl_opts(_, []) -> + false; +ssl_opts(Mod, [{ssl_options, Opts}]) + when is_list(Opts) -> + [{Mod, tcp, tcp_closed} | Opts]; +ssl_opts(_, L) -> + ?ERROR({ssl_options, L}). + %% i/6 i(accept, Ref, Mod, Pid, Opts, Addrs) -> @@ -258,6 +268,8 @@ handle_info(T, #monitor{} = S) -> %% # code_change/3 %% --------------------------------------------------------------------------- +code_change(_, {transport, _, _, _, _} = S, _) -> + {ok, #transport{} = list_to_tuple(tuple_to_list(S) ++ [false])}; code_change(_, State, _) -> {ok, State}. @@ -332,17 +344,56 @@ t(T,S) -> %% transition/2 +%% Initial incoming message when we might need to upgrade to TLS: +%% don't request another message until we know. +transition({tcp, Sock, Bin}, #transport{socket = Sock, + parent = Pid, + frag = Head, + module = M, + ssl = Opts} + = S) + when is_list(Opts) -> + case recv1(Head, Bin) of + {Msg, B} when is_binary(Msg) -> + diameter_peer:recv(Pid, Msg), + S#transport{frag = B}; + Frag -> + setopts(M, Sock), + S#transport{frag = Frag} + end; + %% Incoming message. -transition({tcp, Sock, Data}, #transport{socket = Sock, - module = M} - = S) -> +transition({P, Sock, Bin}, #transport{socket = Sock, + module = M, + ssl = B} + = S) + when P == tcp, not B; + P == ssl, B -> + setopts(M, Sock), + recv(Bin, S); + +%% Capabilties exchange has decided on whether or not to run over TLS. +transition({diameter, {tls, Ref, Type, B}}, #transport{parent = Pid} + = S) -> + #transport{socket = Sock, + module = M} + = NS + = tls_handshake(Type, B, S), + Pid ! {diameter, {tls, Ref}}, setopts(M, Sock), - recv(Data, S); + NS#transport{ssl = B}; -transition({tcp_closed, Sock}, #transport{socket = Sock}) -> +transition({C, Sock}, #transport{socket = Sock, + ssl = B}) + when C == tcp_closed, not B; + C == ssl_closed, B -> stop; -transition({tcp_error, Sock, _Reason} = T, #transport{socket = Sock} = S) -> +transition({E, Sock, _Reason} = T, #transport{socket = Sock, + ssl = B} + = S) + when E == tcp_error, not B; + E == ssl_error, B -> ?ERROR({T,S}); %% Outgoing message. @@ -379,6 +430,29 @@ transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) -> %% Crash on anything unexpected. +%% tls_handshake/3 +%% +%% In the case that no tls message is received (eg. the service hasn't +%% been configured to advertise TLS support) we will simply never ask +%% for another TCP message, which will force the watchdog to +%% eventually take us down. + +tls_handshake(Type, true, #transport{socket = Sock, + ssl = Opts} + = S) -> + is_list(Opts) orelse ?ERROR({tls, Opts}), + {ok, SSock} = tls(Type, Sock, Opts), + S#transport{socket = SSock, + module = ssl}; + +tls_handshake(_, false, S) -> + S. + +tls(connect, Sock, Opts) -> + ssl:connect(Sock, Opts); +tls(accept, Sock, Opts) -> + ssl:ssl_accept(Sock, Opts). + %% recv/2 %% %% Reassemble fragmented messages and extract multple message sent @@ -509,6 +583,8 @@ connect(Mod, Host, Port, Opts) -> send(gen_tcp, Sock, Bin) -> gen_tcp:send(Sock, Bin); +send(ssl, Sock, Bin) -> + ssl:send(Sock, Bin); send(M, Sock, Bin) -> M:send(Sock, Bin). @@ -516,6 +592,8 @@ send(M, Sock, Bin) -> setopts(gen_tcp, Sock, Opts) -> inet:setopts(Sock, Opts); +setopts(ssl, Sock, Opts) -> + ssl:setopts(Sock, Opts); setopts(M, Sock, Opts) -> M:setopts(Sock, Opts). @@ -531,5 +609,12 @@ setopts(M, Sock) -> lport(gen_tcp, Sock) -> inet:port(Sock); +lport(ssl, Sock) -> + case ssl:sockname(Sock) of + {ok, {_Addr, PortNr}} -> + {ok, PortNr}; + {error, _} = No -> + No + end; lport(M, Sock) -> M:port(Sock). -- cgit v1.2.3 From 68c94d9b8db4773259c323cd428cf4bf20931869 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 2 Oct 2011 12:09:34 +0200 Subject: Close transport if tls is requested over sctp RFC 3588 requires that a Diameter server support TLS but in practise this seems to mean TLS over SCTP since there are limitations with running over SCTP: see RFC 6083 (DTLS over SCTP), which is a response to RFC 3436 (TLS over SCTP). The current RFC 3588 draft acknowledges this by equating the Inband-Security-Id value TLS with TLS/TCP and DTLS/SCTP but underlying support for DTLS is still thin on the ground. --- lib/diameter/src/transport/diameter_sctp.erl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index 46473e7bf1..cb024c77b1 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -411,6 +411,14 @@ transition({diameter, {send, Msg}}, S) -> transition({diameter, {close, Pid}}, #transport{parent = Pid}) -> stop; +%% TLS over SCTP is described in RFC 3436 but has limitations as +%% described in RFC 6083. The latter describes DTLS over SCTP, which +%% addresses these limitations, DTLS itself being described in RFC +%% 4347. TLS is primarily used over TCP, which the current RFC 3588 +%% draft acknowledges by equating TLS with TLS/TCP and DTLS/SCTP. +transition({diameter, {tls, _Ref, _Type, _Bool}}, _) -> + stop; + %% Listener process has died. transition({'DOWN', _, process, Pid, _}, #transport{mode = {accept, Pid}}) -> stop; -- cgit v1.2.3 From 30a7d3935e57bd4c6b7e64f8b25eb0a11c0e7c80 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 3 Oct 2011 15:31:27 +0200 Subject: Documentation updates --- lib/diameter/doc/src/diameter.xml | 21 ++++++++++++++++ lib/diameter/doc/src/diameter_soc.xml | 10 +++++--- lib/diameter/doc/src/diameter_tcp.xml | 34 +++++++++++++++++++++++--- lib/diameter/doc/src/diameter_transport.xml | 38 +++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 6 deletions(-) diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 2cad70e3bc..43c497f50a 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -367,6 +367,19 @@ capabilities exchange message. Optional, defaults to the empty list.

+{'Inband-Security-Id', [Unsigned32()]} + +

+Values of Inband-Security-Id AVPs sent in an outgoing +capabilities exchange message. +Optional, defaults to the empty list, which is equivalent to a +list containing only 0 (= NO_INBAND_SECURITY).

+ +

+If 1 (= TLS) is specified then TLS is selected if the CER/CEA received +from the peer offers it.

+
+ {'Acct-Application-Id', [Unsigned32()]}

@@ -683,6 +696,14 @@ in question.

AVP's used to construct outgoing CER/CEA messages. Any AVP specified takes precedence over a corresponding value specified for the service in question.

+ +

+Specifying a capability as a transport option +may be particularly appropriate for Inband-Security-Id in case +TLS is desired over TCP as implemented by +diameter_tcp(3) but +not over SCTP as implemented by +diameter_sctp(3).

{watchdog_timer, TwInit} diff --git a/lib/diameter/doc/src/diameter_soc.xml b/lib/diameter/doc/src/diameter_soc.xml index 4f8581a904..6b9ef9f756 100644 --- a/lib/diameter/doc/src/diameter_soc.xml +++ b/lib/diameter/doc/src/diameter_soc.xml @@ -57,9 +57,13 @@ including the P Flag in the AVP header.

-There is no TLS support. -It's unclear (aka uninvestigated) how TLS would impact -diameter but IPsec can be used without it needing to know.

+There is no TLS support over SCTP. +RFC 3588 requires that a Diameter server support TLS but in +practise this seems to mean TLS over SCTP since there are limitations +with running over SCTP: see RFC 6083 (DTLS over SCTP), which is a +response to RFC 3436 (TLS over SCTP). +The current RFC 3588 draft acknowledges this by equating +TLS with TLS/TCP and DTLS/SCTP but we do not yet support DTLS.

diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml index a502e53972..916700927f 100644 --- a/lib/diameter/doc/src/diameter_tcp.xml +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -43,7 +43,9 @@ It can be specified as the value of a transport_module option to diameter:add_transport/2 and implements the behaviour documented in -diameter_transport(3).

+diameter_transport(3). +TLS security is supported, a connection being upgraded if +TLS is negotiated during capabilities exchange.

@@ -60,10 +62,14 @@ and implements the behaviour documented in Type = connect | accept Ref = reference() Svc = #diameter_service{} -Opt = {raddr, ip_address()} | {rport, integer()} | term() +Opt = OwnOpt | TlsOpt | TcpOpt Pid = pid() LAddr = ip_address() Reason = term() +OwnOpt = {raddr, ip_address()} + | {rport, integer()} +TlsOpt = {ssl_options, list()} +TcpOpt = term() @@ -74,8 +80,11 @@ marker="diameter_transport#start">diameter_transport(3).

The only diameter_tcp-specific argument is the options list. Options raddr and rport specify the remote address -and port for a connecting transport and not valid for a listening +and port for a connecting transport and are not valid for a listening transport. +Option ssl_options specifies options to be passed +to ssl:connect/2 of ssl:ssl_accept/2 in case capabilities exchange +results in TLS being chosen for inband security. Remaining options are any accepted by gen_tcp:connect/3 for a connecting transport, or gen_tcp:listen/2 for a listening transport, with the exception of binary, packet and active. @@ -84,6 +93,24 @@ to specify the local listening port, the default being the standardized 3868 if unspecified. Note that option ip specifies the local address.

+

+The ssl_options option must be specified if and only if +the transport in question has specified an Inband-Security-Id +AVP with value TLS on the relevant call to +start_service/2 or +add_transport/2, +so that the transport process will receive notification of +whether or not to commence with a TLS handshake following capabilities +exchange. +Failing to specify ssl_options on a TLS-capable transport +for which TLS is negotiated will cause TLS handshake to fail. +Failing to specify TLS capability when ssl_options has been +specified will cause the transport process to wait for a notification +that will not be forthcoming, which will eventually cause the RFC 3539 +watchdog to take down the connection.

+

If the service specifies more than one Host-IP-Address and option ip is unspecified then then the @@ -104,6 +131,7 @@ The returned local address list has length one.

SEE ALSO

+diameter(3), diameter_transport(3)

diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml index 37cc871e75..087a90b099 100644 --- a/lib/diameter/doc/src/diameter_transport.xml +++ b/lib/diameter/doc/src/diameter_transport.xml @@ -143,6 +143,34 @@ connection. Pid is the pid() of the parent process.

+{diameter, {tls, Ref, Type, Bool}} + +

+Indication of whether or not capabilities exchange has selected +inband security using TLS. +Ref is a reference() that must be included in the +{diameter, {tls, Ref}} reply message to the transport's +parent process (see below). +Type is either connect or accept depending on +whether the process has been started for a connecting or listening +transport respectively. +Bool is a boolean() indicating whether or not the transport connection +should be upgraded to TLS.

+ +

+If TLS is requested (Bool = true) then a connecting process should +initiate a TLS handshake with the peer and an accepting process should +prepare to accept a handshake. +A successful handshake should be followed by a {diameter, {tls, Ref}} +message to the parent process. +A failed handshake should cause the process to exit.

+ +

+This message is only sent to a transport process over whose +Inband-Security-Id configuration has indicated support for +TLS.

+
+

@@ -184,6 +212,16 @@ How the transport_data is used/interpreted is up to the transport module.

+{diameter, {tls, Ref}} + +

+Acknowledgment of a successful TLS handshake. +Ref is the reference() received in the +{diameter, {tls, Ref, Type, Bool}} message in response +to which the reply is sent. +A transport must exit if a handshake is not successful.

+
+
-- cgit v1.2.3 From 8998476269bf308e92b004f00e5ae3636f08541e Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 3 Oct 2011 00:56:18 +0200 Subject: Add tls testsuite --- lib/diameter/test/diameter_tls_SUITE.erl | 347 +++++++++++++++++++++ .../test/diameter_tls_SUITE_data/Makefile.ca | 43 +++ lib/diameter/test/modules.mk | 3 +- 3 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 lib/diameter/test/diameter_tls_SUITE.erl create mode 100644 lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl new file mode 100644 index 0000000000..466f7af138 --- /dev/null +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -0,0 +1,347 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. 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% +%% + +%% +%% Tests of traffic between four Diameter nodes connected as follows. +%% +%% ---- SERVER.REALM1 +%% / +%% CLIENT.REALM0 ----- SERVER.REALM2 +%% \ +%% ---- SERVER.REALM3 +%% +%% The first two connections are established over TLS, the third not. +%% + +-module(diameter_tls_SUITE). + +-export([suite/0, + all/0, + groups/0, + init_per_group/2, + end_per_group/2, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([send1/1, + send2/1, + send3/1, + remove_transports/1, + stop_services/1]). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-ifdef(DIAMETER_CT). +-include("diameter_gen_base_rfc3588.hrl"). +-else. +-include_lib("diameter/include/diameter_gen_base_rfc3588.hrl"). +-endif. + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_ct.hrl"). + +%% =========================================================================== + +-define(ADDR, {127,0,0,1}). + +-define(CLIENT, "CLIENT.REALM0"). +-define(SERVER1, "SERVER.REALM1"). +-define(SERVER2, "SERVER.REALM2"). +-define(SERVER3, "SERVER.REALM3"). + +-define(DICT_COMMON, ?DIAMETER_DICT_COMMON). + +-define(APP_ALIAS, the_app). +-define(APP_ID, ?DICT_COMMON:id()). + +-define(NO_INBAND_SECURITY, 0). +-define(TLS, 1). + +%% Config for diameter:start_service/2. +-define(SERVICE(Host, Dict), + [{'Origin-Host', Host}, + {'Origin-Realm', realm(Host)}, + {'Host-IP-Address', [?ADDR]}, + {'Vendor-Id', 12345}, + {'Product-Name', "OTP/diameter"}, + {'Inband-Security-Id', [?NO_INBAND_SECURITY]}, + {'Auth-Application-Id', [Dict:id()]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, Dict}, + {module, ?MODULE}, + {answer_errors, callback}]}]). + +%% Config for diameter:add_transport/2. In the listening case, listen +%% on a free port that we then lookup using the implementation detail +%% that diameter_tcp registers the port with diameter_reg. +-define(CONNECT(PortNr, Caps, Opts), + {connect, [{transport_module, diameter_tcp}, + {transport_config, [{raddr, ?ADDR}, + {rport, PortNr}, + {ip, ?ADDR}, + {port, 0} + | Opts]}, + {capabilities, Caps}]}). +-define(LISTEN(Caps, Opts), + {listen, [{transport_module, diameter_tcp}, + {transport_config, [{ip, ?ADDR}, {port, 0} | Opts]}, + {capabilities, Caps}]}). + +-define(SUCCESS, 2001). + +-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [{group, N} || {N, _, _} <- groups()] + ++ [remove_transports, stop_services]. + +groups() -> + Ts = tc(), + [{all, [], Ts}, + {p, [parallel], Ts}]. + +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + +init_per_suite(Config) -> + ok = ssl:start(), + ok = diameter:start(), + + Dir = proplists:get_value(priv_dir, Config), + Servers = [server(?SERVER1, + inband_security([?TLS]), + ssl_options(Dir, "server1")), + server(?SERVER2, + inband_security([?NO_INBAND_SECURITY, ?TLS]), + ssl_options(Dir, "server2")), + server(?SERVER3, + [], + [])], + + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)), + + true = diameter:subscribe(?CLIENT), + + Connections = connect(?CLIENT, + Servers, + inband_security([?NO_INBAND_SECURITY, ?TLS]), + ssl_options(Dir, "client")), + + [{transports, lists:zip(Servers, Connections)} | Config]. + +end_per_suite(_Config) -> + ok = diameter:stop(), + ok = ssl:stop(). + +%% Testcases to run when services are started and connections +%% established. These are trivial, the interesting stuff is setting up +%% the connections in init_per_suite/2. +tc() -> + [send1, + send2, + send3]. + +%% =========================================================================== + +inband_security(Ids) -> + [{'Inband-Security-Id', Ids}]. + +ssl_options(Dir, Base) -> + {Key, Cert} = make_cert(Dir, Base ++ "_key.pem", Base ++ "_ca.pem"), + [{ssl_options, [{certfile, Cert}, {keyfile, Key}]}]. + +server(Host, Caps, Opts) -> + ok = diameter:start_service(Host, ?SERVICE(Host, ?DICT_COMMON)), + {ok, LRef} = diameter:add_transport(Host, ?LISTEN(Caps, Opts)), + {LRef, portnr(LRef)}. + +connect(Host, {_LRef, PortNr}, Caps, Opts) -> + {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr, Caps, Opts)), + ok = receive + #diameter_event{service = Host, + info = {up, Ref, _, _, #diameter_packet{}}} -> + ok + after 2000 -> + false + end, + Ref; +connect(Host, Ports, Caps, Opts) -> + [connect(Host, P, Caps, Opts) || P <- Ports]. + +portnr(LRef) -> + portnr(LRef, 20). + +portnr(LRef, N) + when 0 < N -> + case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of + [{T, _Pid}] -> + {_, _, {LRef, {_Addr, LSock}}} = T, + {ok, PortNr} = inet:port(LSock), + PortNr; + [] -> + receive after 50 -> ok end, + portnr(LRef, N-1) + end. + +realm(Host) -> + tl(lists:dropwhile(fun(C) -> C /= $. end, Host)). + +make_cert(Dir, Keyfile, Certfile) -> + [K,C] = Paths = [filename:join([Dir, F]) || F <- [Keyfile, Certfile]], + + KCmd = join(["openssl genrsa -out", K, "2048"]), + CCmd = join(["openssl req -new -x509 -key", K, "-out", C, "-days 7", + "-subj /C=SE/ST=./L=Stockholm/CN=www.erlang.org"]), + + %% Hope for the best and only check that files are written. + os:cmd(KCmd), + os:cmd(CCmd), + + [_,_] = [T || P <- Paths, {ok, T} <- [file:read_file_info(P)]], + + {K,C}. + +join(Strs) -> + string:join(Strs, " "). + +%% =========================================================================== + +%% Send an STR intended for a specific server and expect success. +send1(_Config) -> + call(?SERVER1). +send2(_Config) -> + call(?SERVER2). +send3(_Config) -> + call(?SERVER3). + +%% Remove the client transports and expect the corresponding server +%% transport to go down. +remove_transports(Config) -> + Ts = proplists:get_value(transports, Config), + + true = diameter:subscribe(?SERVER1), + true = diameter:subscribe(?SERVER2), + true = diameter:subscribe(?SERVER3), + + lists:map(fun disconnect/1, Ts). + +disconnect({{LRef, _PortNr}, CRef}) -> + ok = diameter:remove_transport(?CLIENT, CRef), + ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok + after 2000 -> false + end. + +stop_services(_Config) -> + S = [?CLIENT, ?SERVER1, ?SERVER2, ?SERVER3], + Ok = [ok || _ <- S], + Ok = [diameter:stop_service(H) || H <- S]. + +%% =========================================================================== + +call(Server) -> + Realm = realm(Server), + Req = ['STR', {'Destination-Realm', Realm}, + {'Termination-Cause', ?LOGOUT}, + {'Auth-Application-Id', ?APP_ID}], + #diameter_base_STA{'Result-Code' = ?SUCCESS, + 'Origin-Host' = Server, + 'Origin-Realm' = Realm} + = call(Req, [{filter, realm}]). + +call(Req, Opts) -> + diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). + +set([H|T], Vs) -> + [H | Vs ++ T]. + +%% =========================================================================== +%% diameter callbacks + +%% peer_up/3 + +peer_up(_SvcName, _Peer, State) -> + State. + +%% peer_down/3 + +peer_down(_SvcName, _Peer, State) -> + State. + +%% pick_peer/4 + +pick_peer([Peer], _, ?CLIENT, _State) -> + {ok, Peer}. + +%% prepare_request/3 + +prepare_request(#diameter_packet{msg = Req}, + ?CLIENT, + {_Ref, Caps}) -> + #diameter_caps{origin_host = {OH, _}, + origin_realm = {OR, _}} + = Caps, + + {send, set(Req, [{'Session-Id', diameter:session_id(OH)}, + {'Origin-Host', OH}, + {'Origin-Realm', OR}])}. + +%% prepare_retransmit/3 + +prepare_retransmit(_Pkt, false, _Peer) -> + discard. + +%% handle_answer/4 + +handle_answer(Pkt, _Req, ?CLIENT, _Peer) -> + #diameter_packet{msg = Rec, errors = []} = Pkt, + Rec. + +%% handle_error/4 + +handle_error(Reason, _Req, ?CLIENT, _Peer) -> + {error, Reason}. + +%% handle_request/3 + +handle_request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId}}, + OH, + {_Ref, #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR, _}}}) + when OH /= ?CLIENT -> + {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS, + 'Session-Id' = SId, + 'Origin-Host' = OH, + 'Origin-Realm' = OR}}. diff --git a/lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca b/lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca new file mode 100644 index 0000000000..3f2645add0 --- /dev/null +++ b/lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca @@ -0,0 +1,43 @@ +# -*- makefile -*- +# %CopyrightBegin% +# +# Copyright Ericsson AB 2011. 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% + +# +# Certificates are now generated from the suite itself but the +# makefile itself is still useful. +# + +KEYS = $(HOSTS:%=%_key.pem) +CERTS = $(HOSTS:%=%_ca.pem) + +all: $(CERTS) + +%_ca.pem: %_key.pem + openssl req -new -x509 -key $< -out $@ -days 1095 \ + -subj '/C=SE/ST=./L=Stockholm/CN=www.erlang.org' + +%_key.pem: + openssl genrsa -out $@ 2048 + +clean: + rm -f $(CERTS) + +realclean: clean + rm -f $(KEYS) + +.PRECIOUS: $(KEYS) +.PHONY: all clean realclean diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index c6f709dc36..7c691c302b 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -34,7 +34,8 @@ MODULES = \ diameter_watchdog_SUITE \ diameter_transport_SUITE \ diameter_traffic_SUITE \ - diameter_relay_SUITE + diameter_relay_SUITE \ + diameter_tls_SUITE INTERNAL_HRL_FILES = \ diameter_ct.hrl -- cgit v1.2.3 From 82934adca7cd26777025bc9ae1b87b45d2a55fe2 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 4 Oct 2011 17:28:57 +0200 Subject: Add tls support at connection establishment This is the method added in draft-ietf-dime-rfc3588bis, whereby a TLS handshake immediately follows connection establishment and CER/CEA is sent over the secured connection. --- lib/diameter/doc/src/diameter_tcp.xml | 34 ++-- lib/diameter/src/transport/diameter_tcp.erl | 64 +++++-- lib/diameter/test/diameter_tls_SUITE.erl | 274 ++++++++++++++++------------ 3 files changed, 224 insertions(+), 148 deletions(-) diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml index 916700927f..210ae9fdfe 100644 --- a/lib/diameter/doc/src/diameter_tcp.xml +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -44,8 +44,9 @@ It can be specified as the value of a transport_module option to marker="diameter#add_transport">diameter:add_transport/2 and implements the behaviour documented in diameter_transport(3). -TLS security is supported, a connection being upgraded if -TLS is negotiated during capabilities exchange.

+TLS security is supported, both as an upgrade following +capabilities exchange as specified by RFC 3588 and +at connection establishment as in the current draft standard.

@@ -62,14 +63,15 @@ TLS is negotiated during capabilities exchange.

Type = connect | accept Ref = reference() Svc = #diameter_service{} -Opt = OwnOpt | TlsOpt | TcpOpt +Opt = OwnOpt | SslOpt | OtherOpt Pid = pid() LAddr = ip_address() Reason = term() OwnOpt = {raddr, ip_address()} - | {rport, integer()} -TlsOpt = {ssl_options, list()} -TcpOpt = term() + | {rport, integer()} + | {port, integer()} +SslOpt = {ssl_options, true | list()} +OtherOpt = term() @@ -82,19 +84,23 @@ The only diameter_tcp-specific argument is the options list. Options raddr and rport specify the remote address and port for a connecting transport and are not valid for a listening transport. -Option ssl_options specifies options to be passed -to ssl:connect/2 of ssl:ssl_accept/2 in case capabilities exchange -results in TLS being chosen for inband security. -Remaining options are any accepted by gen_tcp:connect/3 for -a connecting transport, or gen_tcp:listen/2 for a listening transport, -with the exception of binary, packet and active. +Option ssl_options must be specified for a transport +that must be able to support TLS: a value of true results in a +TLS handshake immediately upon connection establishment while +list() specifies options to be passed to ssl:connect/2 of ssl:ssl_accept/2 +after capabilities exchange if TLS is negotiated. +Remaining options are any accepted by ssl:connect/3 or gen_tcp:connect/3 for +a connecting transport, or ssl:listen/3 or gen_tcp:listen/2 for +a listening transport, depending on whether or not {ssl_options, true} +has been specified. +Options binary, packet and active cannot be specified. Also, option port can be specified for a listening transport to specify the local listening port, the default being the standardized 3868 if unspecified. Note that option ip specifies the local address.

-The ssl_options option must be specified if and only if +An ssl_options list must be specified if and only if the transport in question has specified an Inband-Security-Id AVP with value TLS on the relevant call to add_transport/2, so that the transport process will receive notification of whether or not to commence with a TLS handshake following capabilities exchange. -Failing to specify ssl_options on a TLS-capable transport +Failing to specify an options list on a TLS-capable transport for which TLS is negotiated will cause TLS handshake to fail. Failing to specify TLS capability when ssl_options has been specified will cause the transport process to wait for a notification diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index e0b68237c2..33b9daf0d9 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -45,6 +45,9 @@ -define(LISTENER_TIMEOUT, 30000). -define(FRAGMENT_TIMEOUT, 1000). +%% cb_info passed to ssl. +-define(TCP_CB(Mod), {Mod, tcp, tcp_closed, tcp_error}). + %% The same gen_server implementation supports three different kinds %% of processes: an actual transport process, one that will club it to %% death should the parent die before a connection is established, and @@ -122,14 +125,15 @@ i({T, Ref, Mod, Pid, Opts, Addrs}) %% that does nothing but kill us with the parent until call %% returns. {ok, MPid} = diameter_tcp_sup:start_child(#monitor{parent = Pid}), - {[SslOpts], Rest} = proplists:split(Opts, [ssl_options]), - Sock = i(T, Ref, Mod, Pid, Rest, Addrs), + {SslOpts, Rest} = ssl(Opts), + Sock = i(T, Ref, Mod, Pid, SslOpts, Rest, Addrs), MPid ! {stop, self()}, %% tell the monitor to die - setopts(Mod, Sock), + M = if SslOpts -> ssl; true -> Mod end, + setopts(M, Sock), #transport{parent = Pid, - module = Mod, + module = M, socket = Sock, - ssl = ssl_opts(Mod, SslOpts)}; + ssl = SslOpts}; %% A monitor process to kill the transport if the parent dies. i(#monitor{parent = Pid, transport = TPid} = S) -> @@ -153,15 +157,29 @@ i({listen, LRef, APid, {Mod, Opts, Addrs}}) -> true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}), start_timer(#listener{socket = LSock}). -ssl_opts(_, []) -> +ssl(Opts) -> + {[SslOpts], Rest} = proplists:split(Opts, [ssl_options]), + {ssl_opts(SslOpts), Rest}. + +ssl_opts([]) -> false; -ssl_opts(Mod, [{ssl_options, Opts}]) +ssl_opts([{ssl_options, true}]) -> + true; +ssl_opts([{ssl_options, Opts}]) when is_list(Opts) -> - [{Mod, tcp, tcp_closed} | Opts]; -ssl_opts(_, L) -> + Opts; +ssl_opts(L) -> ?ERROR({ssl_options, L}). -%% i/6 +%% i/7 + +%% Establish a TLS connection before capabilities exchange ... +i(Type, Ref, Mod, Pid, true, Opts, Addrs) -> + i(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs); + +%% ... or not. +i(Type, Ref, Mod, Pid, _, Opts, Addrs) -> + i(Type, Ref, Mod, Pid, Opts, Addrs). i(accept, Ref, Mod, Pid, Opts, Addrs) -> {LAddr, LSock} = listener(Ref, {Mod, Opts, Addrs}), @@ -437,14 +455,25 @@ transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) -> %% for another TCP message, which will force the watchdog to %% eventually take us down. +%% TLS has already been established with the connection. +tls_handshake(_, _, #transport{ssl = true} = S) -> + S; + +%% Capabilities exchange negotiated TLS but transport was not +%% configured with an options list. +tls_handshake(_, true, #transport{ssl = false}) -> + ?ERROR(no_ssl_options); + +%% Capabilities exchange negotiated TLS: upgrade the connection. tls_handshake(Type, true, #transport{socket = Sock, + module = M, ssl = Opts} = S) -> - is_list(Opts) orelse ?ERROR({tls, Opts}), - {ok, SSock} = tls(Type, Sock, Opts), + {ok, SSock} = tls(Type, Sock, [{cb_info, ?TCP_CB(M)} | Opts]), S#transport{socket = SSock, module = ssl}; +%% Capabilities exchange has not negotiated TLS. tls_handshake(_, false, S) -> S. @@ -567,15 +596,18 @@ flush(_, S) -> %% accept/2 -accept(gen_tcp, LSock) -> - gen_tcp:accept(LSock); +accept(ssl, LSock) -> + case ssl:transport_accept(LSock) of + {ok, Sock} -> + {ssl:ssl_accept(Sock), Sock}; + {error, _} = No -> + No + end; accept(Mod, LSock) -> Mod:accept(LSock). %% connect/4 -connect(gen_tcp, Host, Port, Opts) -> - gen_tcp:connect(Host, Port, Opts); connect(Mod, Host, Port, Opts) -> Mod:connect(Host, Port, Opts). diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index 466f7af138..8cf135cebf 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -18,15 +18,17 @@ %% %% -%% Tests of traffic between four Diameter nodes connected as follows. +%% Tests of traffic between six Diameter nodes connected as follows. %% -%% ---- SERVER.REALM1 +%% ---- SERVER.REALM1 (TLS after capabilities exchange) %% / -%% CLIENT.REALM0 ----- SERVER.REALM2 +%% / ---- SERVER.REALM2 (ditto) +%% | / +%% CLIENT.REALM0 ----- SERVER.REALM3 (no security) +%% | \ +%% \ ---- SERVER.REALM4 (TLS at connection establishment) %% \ -%% ---- SERVER.REALM3 -%% -%% The first two connections are established over TLS, the third not. +%% ---- SERVER.REALM5 (ditto) %% -module(diameter_tls_SUITE). @@ -43,6 +45,8 @@ -export([send1/1, send2/1, send3/1, + send4/1, + send5/1, remove_transports/1, stop_services/1]). @@ -73,6 +77,10 @@ -define(SERVER1, "SERVER.REALM1"). -define(SERVER2, "SERVER.REALM2"). -define(SERVER3, "SERVER.REALM3"). +-define(SERVER4, "SERVER.REALM4"). +-define(SERVER5, "SERVER.REALM5"). + +-define(SERVERS, [?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4, ?SERVER5]). -define(DICT_COMMON, ?DIAMETER_DICT_COMMON). @@ -113,13 +121,12 @@ {capabilities, Caps}]}). -define(SUCCESS, 2001). - -define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT'). %% =========================================================================== suite() -> - [{timetrap, {seconds, 10}}]. + [{timetrap, {seconds, 15}}]. all() -> [{group, N} || {N, _, _} <- groups()] @@ -141,24 +148,14 @@ init_per_suite(Config) -> ok = diameter:start(), Dir = proplists:get_value(priv_dir, Config), - Servers = [server(?SERVER1, - inband_security([?TLS]), - ssl_options(Dir, "server1")), - server(?SERVER2, - inband_security([?NO_INBAND_SECURITY, ?TLS]), - ssl_options(Dir, "server2")), - server(?SERVER3, - [], - [])], + Servers = [server(S, sopts(S, Dir)) || S <- ?SERVERS], ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)), - true = diameter:subscribe(?CLIENT), - Connections = connect(?CLIENT, - Servers, - inband_security([?NO_INBAND_SECURITY, ?TLS]), - ssl_options(Dir, "client")), + Opts = ssl_options(Dir, "client"), + Connections = [connect(?CLIENT, S, copts(N, Opts)) + || {S,N} <- lists:zip(Servers, ?SERVERS)], [{transports, lists:zip(Servers, Connections)} | Config]. @@ -172,72 +169,12 @@ end_per_suite(_Config) -> tc() -> [send1, send2, - send3]. - -%% =========================================================================== - -inband_security(Ids) -> - [{'Inband-Security-Id', Ids}]. - -ssl_options(Dir, Base) -> - {Key, Cert} = make_cert(Dir, Base ++ "_key.pem", Base ++ "_ca.pem"), - [{ssl_options, [{certfile, Cert}, {keyfile, Key}]}]. - -server(Host, Caps, Opts) -> - ok = diameter:start_service(Host, ?SERVICE(Host, ?DICT_COMMON)), - {ok, LRef} = diameter:add_transport(Host, ?LISTEN(Caps, Opts)), - {LRef, portnr(LRef)}. - -connect(Host, {_LRef, PortNr}, Caps, Opts) -> - {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr, Caps, Opts)), - ok = receive - #diameter_event{service = Host, - info = {up, Ref, _, _, #diameter_packet{}}} -> - ok - after 2000 -> - false - end, - Ref; -connect(Host, Ports, Caps, Opts) -> - [connect(Host, P, Caps, Opts) || P <- Ports]. - -portnr(LRef) -> - portnr(LRef, 20). - -portnr(LRef, N) - when 0 < N -> - case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of - [{T, _Pid}] -> - {_, _, {LRef, {_Addr, LSock}}} = T, - {ok, PortNr} = inet:port(LSock), - PortNr; - [] -> - receive after 50 -> ok end, - portnr(LRef, N-1) - end. - -realm(Host) -> - tl(lists:dropwhile(fun(C) -> C /= $. end, Host)). - -make_cert(Dir, Keyfile, Certfile) -> - [K,C] = Paths = [filename:join([Dir, F]) || F <- [Keyfile, Certfile]], - - KCmd = join(["openssl genrsa -out", K, "2048"]), - CCmd = join(["openssl req -new -x509 -key", K, "-out", C, "-days 7", - "-subj /C=SE/ST=./L=Stockholm/CN=www.erlang.org"]), - - %% Hope for the best and only check that files are written. - os:cmd(KCmd), - os:cmd(CCmd), - - [_,_] = [T || P <- Paths, {ok, T} <- [file:read_file_info(P)]], - - {K,C}. - -join(Strs) -> - string:join(Strs, " "). + send3, + send4, + send5]. %% =========================================================================== +%% testcases %% Send an STR intended for a specific server and expect success. send1(_Config) -> @@ -246,46 +183,22 @@ send2(_Config) -> call(?SERVER2). send3(_Config) -> call(?SERVER3). +send4(_Config) -> + call(?SERVER4). +send5(_Config) -> + call(?SERVER5). %% Remove the client transports and expect the corresponding server %% transport to go down. remove_transports(Config) -> Ts = proplists:get_value(transports, Config), - - true = diameter:subscribe(?SERVER1), - true = diameter:subscribe(?SERVER2), - true = diameter:subscribe(?SERVER3), - + [] = [T || S <- ?SERVERS, T <- [diameter:subscribe(S)], T /= true], lists:map(fun disconnect/1, Ts). -disconnect({{LRef, _PortNr}, CRef}) -> - ok = diameter:remove_transport(?CLIENT, CRef), - ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok - after 2000 -> false - end. - stop_services(_Config) -> - S = [?CLIENT, ?SERVER1, ?SERVER2, ?SERVER3], - Ok = [ok || _ <- S], - Ok = [diameter:stop_service(H) || H <- S]. - -%% =========================================================================== - -call(Server) -> - Realm = realm(Server), - Req = ['STR', {'Destination-Realm', Realm}, - {'Termination-Cause', ?LOGOUT}, - {'Auth-Application-Id', ?APP_ID}], - #diameter_base_STA{'Result-Code' = ?SUCCESS, - 'Origin-Host' = Server, - 'Origin-Realm' = Realm} - = call(Req, [{filter, realm}]). - -call(Req, Opts) -> - diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). - -set([H|T], Vs) -> - [H | Vs ++ T]. + Hs = [?CLIENT | ?SERVERS], + Ok = [ok || _ <- Hs], + Ok = [diameter:stop_service(H) || H <- Hs]. %% =========================================================================== %% diameter callbacks @@ -345,3 +258,128 @@ handle_request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId}}, 'Session-Id' = SId, 'Origin-Host' = OH, 'Origin-Realm' = OR}}. + +%% =========================================================================== +%% support functions + +call(Server) -> + Realm = realm(Server), + Req = ['STR', {'Destination-Realm', Realm}, + {'Termination-Cause', ?LOGOUT}, + {'Auth-Application-Id', ?APP_ID}], + #diameter_base_STA{'Result-Code' = ?SUCCESS, + 'Origin-Host' = Server, + 'Origin-Realm' = Realm} + = call(Req, [{filter, realm}]). + +call(Req, Opts) -> + diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). + +set([H|T], Vs) -> + [H | Vs ++ T]. + +disconnect({{LRef, _PortNr}, CRef}) -> + ok = diameter:remove_transport(?CLIENT, CRef), + ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok + after 2000 -> false + end. + +realm(Host) -> + tl(lists:dropwhile(fun(C) -> C /= $. end, Host)). + +inband_security(Ids) -> + [{'Inband-Security-Id', Ids}]. + +ssl_options(Dir, Base) -> + {Key, Cert} = make_cert(Dir, Base ++ "_key.pem", Base ++ "_ca.pem"), + [{ssl_options, [{certfile, Cert}, {keyfile, Key}]}]. + +make_cert(Dir, Keyfile, Certfile) -> + [K,C] = Paths = [filename:join([Dir, F]) || F <- [Keyfile, Certfile]], + + KCmd = join(["openssl genrsa -out", K, "2048"]), + CCmd = join(["openssl req -new -x509 -key", K, "-out", C, "-days 7", + "-subj /C=SE/ST=./L=Stockholm/CN=www.erlang.org"]), + + %% Hope for the best and only check that files are written. + os:cmd(KCmd), + os:cmd(CCmd), + + [_,_] = [T || P <- Paths, {ok, T} <- [file:read_file_info(P)]], + + {K,C}. + +join(Strs) -> + string:join(Strs, " "). + +%% server/2 + +server(Host, {Caps, Opts}) -> + ok = diameter:start_service(Host, ?SERVICE(Host, ?DICT_COMMON)), + {ok, LRef} = diameter:add_transport(Host, ?LISTEN(Caps, Opts)), + {LRef, portnr(LRef)}. + +sopts(?SERVER1, Dir) -> + {inband_security([?TLS]), + ssl_options(Dir, "server1")}; +sopts(?SERVER2, Dir) -> + {inband_security([?NO_INBAND_SECURITY, ?TLS]), + ssl_options(Dir, "server2")}; +sopts(?SERVER3, _) -> + {[], []}; +sopts(?SERVER4, Dir) -> + {[], ssl(ssl_options(Dir, "server4"))}; +sopts(?SERVER5, Dir) -> + {[], ssl(ssl_options(Dir, "server5"))}. + +ssl([{ssl_options = T, Opts}]) -> + [{T, true} | Opts]. + +portnr(LRef) -> + portnr(LRef, 20). + +portnr(LRef, N) + when 0 < N -> + case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of + [{T, _Pid}] -> + {_, _, {LRef, {_Addr, LSock}}} = T, + {ok, PortNr} = to_portnr(LSock) , + PortNr; + [] -> + receive after 500 -> ok end, + portnr(LRef, N-1) + end. + +to_portnr(Sock) + when is_port(Sock) -> + inet:port(Sock); +to_portnr(Sock) -> + case ssl:sockname(Sock) of + {ok, {_,N}} -> + {ok, N}; + No -> + No + end. + +%% connect/3 + +connect(Host, {_LRef, PortNr}, {Caps, Opts}) -> + {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr, Caps, Opts)), + ok = receive + #diameter_event{service = Host, + info = {up, Ref, _, _, #diameter_packet{}}} -> + ok + after 2000 -> + false + end, + Ref. + +copts(S, Opts) + when S == ?SERVER1; + S == ?SERVER2; + S == ?SERVER3 -> + {inband_security([?NO_INBAND_SECURITY, ?TLS]), Opts}; +copts(S, Opts) + when S == ?SERVER4; + S == ?SERVER5 -> + {[], ssl(Opts)}. -- cgit v1.2.3 From c002a636022d9910288a8612d03c6edd5c1a6962 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 4 Oct 2011 18:06:53 +0200 Subject: Clarify that ssl must be started for TLS support Also update app testsuite to allow for "undefined" calls from diameter_tcp to ssl. --- lib/diameter/doc/src/diameter_tcp.xml | 4 ++++ lib/diameter/test/diameter_app_SUITE.erl | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml index 210ae9fdfe..e6b53383c0 100644 --- a/lib/diameter/doc/src/diameter_tcp.xml +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -48,6 +48,10 @@ TLS security is supported, both as an upgrade following capabilities exchange as specified by RFC 3588 and at connection establishment as in the current draft standard.

+

+Note that the ssl application is required for TLS and must be started +before configuring TLS capability on diameter transports.

+ diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 104785b4e6..15a98d4441 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -147,14 +147,13 @@ appvsn(Name) -> %% =========================================================================== %% # xref/1 %% -%% Ensure that no function in our application calls an undefined function. +%% Ensure that no function in our application calls an undefined function +%% or one in an application we haven't specified as a dependency. (Almost.) %% =========================================================================== xref(Config) -> App = fetch(app, Config), - Mods = fetch(modules, App) -- [diameter_codegen, diameter_dbg], - %% Skip modules that aren't required at runtime and that have - %% dependencies beyond those applications listed in the app file. + Mods = fetch(modules, App), {ok, XRef} = xref:start(make_name(xref_test_name)), ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]), @@ -164,7 +163,10 @@ xref(Config) -> %% stop xref from complaining about calls to module erlang, which %% was previously in kernel. Erts isn't an application however, in %% the sense that there's no .app file, and isn't listed in - %% applications. Seems less than ideal. + %% applications. Seems less than ideal. Also, diameter_tcp does + %% call ssl despite ssl not being listed as a dependency in the + %% app file since ssl is only required for TLS security: it's up + %% to a client who wants TLS it to start ssl. ok = lists:foreach(fun(A) -> add_application(XRef, A) end, [?APP, erts | fetch(applications, App)]), @@ -173,7 +175,11 @@ xref(Config) -> xref:stop(XRef), %% Only care about calls from our own application. - [] = lists:filter(fun({{M,_,_},_}) -> lists:member(M, Mods) end, Undefs). + [] = lists:filter(fun({{F,_,_},{T,_,_}}) -> + lists:member(F, Mods) + andalso {F,T} /= {diameter_tcp, ssl} + end, + Undefs). add_application(XRef, App) -> add_application(XRef, App, code:lib_dir(App)). -- cgit v1.2.3 From dce08a5f07935e89f8d049376ff660cf59184e85 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 18 Aug 2011 11:58:45 +0200 Subject: Simplify depend.sed for better compatibility Sed on Solaris doesn't remember matches after branching. --- lib/diameter/doc/src/depend.sed | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/diameter/doc/src/depend.sed b/lib/diameter/doc/src/depend.sed index 5973c4586e..42de597f15 100644 --- a/lib/diameter/doc/src/depend.sed +++ b/lib/diameter/doc/src/depend.sed @@ -21,14 +21,18 @@ # massaged in Makefile. # -/^\([^<]*\)<\/com>/b rf -/^\([^<]*\)<\/module>/b rf +/^/b c +/^/b c /^/!d +# Chapter: html basename is same as xml. s@@$(HTMLDIR)/%FILE%.html: %FILE%.xml@ q -:rf -s@@$(HTMLDIR)/\1.html: %FILE%.xml@ +# Reference: html basename is from contents of com/module element. +:c +s@^[^>]*>@@ +s@<.*@@ +s@.*@$(HTMLDIR)/&.html: %FILE%.xml@ q -- cgit v1.2.3 From afaae9dc224c9b57eb4cbf6465e8adbac0264871 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 7 Oct 2011 13:28:23 +0200 Subject: Skip tls testsuite if there's no openssl --- lib/diameter/test/diameter_tls_SUITE.erl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index 8cf135cebf..c0a9603e04 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -144,6 +144,11 @@ end_per_group(_, _) -> ok. init_per_suite(Config) -> + init(os:find_executable("openssl"), Config). + +init(false, _) -> + {skip, no_openssl}; +init(_, Config) -> ok = ssl:start(), ok = diameter:start(), -- cgit v1.2.3 From 0edb6a4d2d76960846fd04ecce3aa00b3348691b Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 30 May 2010 20:02:39 +0300 Subject: Add '-callback' attribute to language syntax Behaviours may define specs for their callbacks using the familiar spec syntax, replacing the '-spec' keyword with '-callback'. Simple lint checks are performed to ensure that no callbacks are defined twice and all types referred are declared. These attributes can be then used by tools to provide documentation to the behaviour or find discrepancies in the callback definitions in the callback module. --- lib/compiler/src/compile.erl | 2 ++ lib/stdlib/src/erl_lint.erl | 25 +++++++++++++++++++++++-- lib/stdlib/src/erl_parse.yrl | 10 +++++++--- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 15849957e7..bfa7c6cedd 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -1512,6 +1512,8 @@ restore_expand_module([{attribute,Line,opaque,[Type]}|Fs]) -> [{attribute,Line,opaque,Type}|restore_expand_module(Fs)]; restore_expand_module([{attribute,Line,spec,[Arg]}|Fs]) -> [{attribute,Line,spec,Arg}|restore_expand_module(Fs)]; +restore_expand_module([{attribute,Line,callback,[Arg]}|Fs]) -> + [{attribute,Line,callback,Arg}|restore_expand_module(Fs)]; restore_expand_module([F|Fs]) -> [F|restore_expand_module(Fs)]; restore_expand_module([]) -> []. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index dd0b9bc2ab..0d8773ff0d 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -123,6 +123,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> called= [] :: [{fa(),line()}], %Called functions usage = #usage{} :: #usage{}, specs = dict:new() :: dict(), %Type specifications + callbacks = dict:new() :: dict(), %Callback types types = dict:new() :: dict(), %Type definitions exp_types=gb_sets:empty():: gb_set() %Exported types }). @@ -310,8 +311,6 @@ format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) -> format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}) -> io_lib:format("undefined callback function ~w/~w (behaviour '~w')", [Func,Arity,Behaviour]); -format_error({undefined_behaviour_func, {Func,Arity,_Spec}, Behaviour}) -> - format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}); format_error({undefined_behaviour,Behaviour}) -> io_lib:format("behaviour ~w undefined", [Behaviour]); format_error({undefined_behaviour_callbacks,Behaviour}) -> @@ -348,12 +347,16 @@ format_error({type_syntax, Constr}) -> io_lib:format("bad ~w type", [Constr]); format_error({redefine_spec, {M, F, A}}) -> io_lib:format("spec for ~w:~w/~w already defined", [M, F, A]); +format_error({redefine_callback, {M, F, A}}) -> + io_lib:format("callback ~w:~w/~w already defined", [M, F, A]); format_error({spec_fun_undefined, {M, F, A}}) -> io_lib:format("spec for undefined function ~w:~w/~w", [M, F, A]); format_error({missing_spec, {F,A}}) -> io_lib:format("missing specification for function ~w/~w", [F, A]); format_error(spec_wrong_arity) -> "spec has the wrong arity"; +format_error(callback_wrong_arity) -> + "callback has the wrong arity"; format_error({imported_predefined_type, Name}) -> io_lib:format("referring to built-in type ~w as a remote type; " "please take out the module name", [Name]); @@ -747,6 +750,8 @@ attribute_state({attribute,L,opaque,{TypeName,TypeDef,Args}}, St) -> type_def(opaque, L, TypeName, TypeDef, Args, St); attribute_state({attribute,L,spec,{Fun,Types}}, St) -> spec_decl(L, Fun, Types, St); +attribute_state({attribute,L,callback,{Fun,Types}}, St) -> + callback_decl(L, Fun, Types, St); attribute_state({attribute,L,on_load,Val}, St) -> on_load(L, Val, St); attribute_state({attribute,_L,_Other,_Val}, St) -> % Ignore others @@ -2770,6 +2775,20 @@ spec_decl(Line, MFA0, TypeSpecs, St0 = #lint{specs = Specs, module = Mod}) -> false -> check_specs(TypeSpecs, Arity, St1) end. +%% callback_decl(Line, Fun, Types, State) -> State. + +callback_decl(Line, MFA0, TypeSpecs, + St0 = #lint{callbacks = Callbacks, module = Mod}) -> + MFA = case MFA0 of + {F, Arity} -> {Mod, F, Arity}; + {_M, _F, Arity} -> MFA0 + end, + St1 = St0#lint{callbacks = dict:store(MFA, Line, Callbacks)}, + case dict:is_key(MFA, Callbacks) of + true -> add_error(Line, {redefine_callback, MFA}, St1); + false -> check_specs(TypeSpecs, Arity, St1) + end. + check_specs([FunType|Left], Arity, St0) -> {FunType1, CTypes} = case FunType of @@ -3275,6 +3294,8 @@ modify_line1({attribute,L,record,{Name,Fields}}, Mf) -> {attribute,Mf(L),record,{Name,modify_line1(Fields, Mf)}}; modify_line1({attribute,L,spec,{Fun,Types}}, Mf) -> {attribute,Mf(L),spec,{Fun,modify_line1(Types, Mf)}}; +modify_line1({attribute,L,callback,{Fun,Types}}, Mf) -> + {attribute,Mf(L),callback,{Fun,modify_line1(Types, Mf)}}; modify_line1({attribute,L,type,{TypeName,TypeDef,Args}}, Mf) -> {attribute,Mf(L),type,{TypeName,modify_line1(TypeDef, Mf), modify_line1(Args, Mf)}}; diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index bd5d65a1e1..709bd83e6f 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -62,7 +62,7 @@ char integer float atom string var '==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<=' '<<' '>>' '!' '=' '::' '..' '...' -'spec' % helper +'spec' 'callback' % helper dot. Expect 2. @@ -77,6 +77,7 @@ attribute -> '-' atom attr_val : build_attribute('$2', '$3'). attribute -> '-' atom typed_attr_val : build_typed_attribute('$2','$3'). attribute -> '-' atom '(' typed_attr_val ')' : build_typed_attribute('$2','$4'). attribute -> '-' 'spec' type_spec : build_type_spec('$2', '$3'). +attribute -> '-' 'callback' type_spec : build_type_spec('$2', '$3'). type_spec -> spec_fun type_sigs : {'$1', '$2'}. type_spec -> '(' spec_fun type_sigs ')' : {'$2', '$3'}. @@ -549,6 +550,8 @@ Erlang code. ErrorInfo :: error_info(). parse_form([{'-',L1},{atom,L2,spec}|Tokens]) -> parse([{'-',L1},{'spec',L2}|Tokens]); +parse_form([{'-',L1},{atom,L2,callback}|Tokens]) -> + parse([{'-',L1},{'callback',L2}|Tokens]); parse_form(Tokens) -> parse(Tokens). @@ -603,7 +606,8 @@ build_typed_attribute({atom,La,Attr},_) -> _ -> ret_err(La, "bad attribute") end. -build_type_spec({spec,La}, {SpecFun, TypeSpecs}) -> +build_type_spec({Kind,La}, {SpecFun, TypeSpecs}) + when (Kind =:= spec) or (Kind =:= callback) -> NewSpecFun = case SpecFun of {atom, _, Fun} -> @@ -617,7 +621,7 @@ build_type_spec({spec,La}, {SpecFun, TypeSpecs}) -> %% Old style spec. Allow this for now. {Mod,Fun,Arity} end, - {attribute,La,spec,{NewSpecFun, TypeSpecs}}. + {attribute,La,Kind,{NewSpecFun, TypeSpecs}}. find_arity_from_specs([Spec|_]) -> %% Use the first spec to find the arity. If all are not the same, -- cgit v1.2.3 From 493262e2f024d3a0773b8a062c24de84b5cf21d5 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 30 May 2010 23:42:34 +0300 Subject: Automatically generate 'behaviour_info' function from '-callback' attributes 'behaviour_info(callbacks)' is a special function that is defined in a module which describes a behaviour and returns a list of its callbacks. This function is now automatically generated using the '-callback' specs. An error is returned by lint if user defines both '-callback' attributes and the behaviour_info/1 function. If no type info is needed for a callback use a generic spec for it. --- lib/compiler/src/sys_pre_expand.erl | 36 ++++++++++++++++++++++++++++++++++-- lib/stdlib/src/erl_lint.erl | 23 ++++++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl index 249bd7a8e7..0fa1fea09f 100644 --- a/lib/compiler/src/sys_pre_expand.erl +++ b/lib/compiler/src/sys_pre_expand.erl @@ -43,6 +43,7 @@ mod_imports, %Module Imports compile=[], %Compile flags attributes=[], %Attributes + callbacks=[], %Callbacks defined=[], %Defined functions vcount=0, %Variable counter func=[], %Current function @@ -172,10 +173,41 @@ define_functions(Forms, #expand{defined=Predef}=St) -> end, Predef, Forms), St#expand{defined=ordsets:from_list(Fs)}. -module_attrs(St) -> - {[{attribute,Line,Name,Val} || {Name,Line,Val} <- St#expand.attributes],St}. +module_attrs(#expand{attributes=Attributes}=St) -> + Attrs = [{attribute,Line,Name,Val} || {Name,Line,Val} <- Attributes], + Callbacks = [Callback || {_,_,callback,_}=Callback <- Attrs], + {Attrs,St#expand{callbacks=Callbacks}}. module_predef_funcs(St) -> + {Mpf1,St1}=module_predef_func_beh_info(St), + {Mpf2,St2}=module_predef_funcs_mod_info(St1), + {Mpf1++Mpf2,St2}. + +module_predef_func_beh_info(#expand{callbacks=[]}=St) -> + {[], St}; +module_predef_func_beh_info(#expand{callbacks=Callbacks,defined=Defined, + exports=Exports}=St) -> + PreDef=[{behaviour_info,1}], + PreExp=PreDef, + {[gen_beh_info(Callbacks)], + St#expand{defined=union(from_list(PreDef), Defined), + exports=union(from_list(PreExp), Exports)}}. + +gen_beh_info(Callbacks) -> + List = make_list(Callbacks), + {function,0,behaviour_info,1, + [{clause,0,[{atom,0,callbacks}],[], + [List]}]}. + +make_list([]) -> {nil,0}; +make_list([{_,_,_,[{{Name,Arity},_}]}|Rest]) -> + {cons,0, + {tuple,0, + [{atom,0,Name}, + {integer,0,Arity}]}, + make_list(Rest)}. + +module_predef_funcs_mod_info(St) -> PreDef = [{module_info,0},{module_info,1}], PreExp = PreDef, {[{function,0,module_info,0, diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 0d8773ff0d..78b996d94b 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -319,6 +319,9 @@ format_error({undefined_behaviour_callbacks,Behaviour}) -> format_error({ill_defined_behaviour_callbacks,Behaviour}) -> io_lib:format("behaviour ~w callback functions erroneously defined", [Behaviour]); +format_error({behaviour_info, {_M,F,A}}) -> + io_lib:format("cannot define callback attibute for ~w/~w when " + "behaviour_info is defined",[F,A]); %% --- types and specs --- format_error({singleton_typevar, Name}) -> io_lib:format("type variable ~w is only used once (is unbound)", [Name]); @@ -845,7 +848,8 @@ post_traversal_check(Forms, St0) -> StB = check_unused_types(Forms, StA), StC = check_untyped_records(Forms, StB), StD = check_on_load(StC), - check_unused_records(Forms, StD). + StE = check_unused_records(Forms, StD), + check_callback_information(StE). %% check_behaviour(State0) -> State %% Check that the behaviour attribute is valid. @@ -1144,6 +1148,23 @@ check_unused_records(Forms, St0) -> St0 end. +check_callback_information(#lint{callbacks = Callbacks, + defined = Defined} = State) -> + case gb_sets:is_member({behaviour_info,1}, Defined) of + false -> State; + true -> + case dict:size(Callbacks) of + 0 -> State; + _ -> + CallbacksList = dict:to_list(Callbacks), + FoldL = + fun({Fa,Line},St) -> + add_error(Line, {behaviour_info, Fa}, St) + end, + lists:foldl(FoldL, State, CallbacksList) + end + end. + %% For storing the import list we use the orddict module. %% We know an empty set is []. -- cgit v1.2.3 From 8ea0c7c566d2c356f273806c42615f31b9e946d3 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 10 May 2011 18:31:02 +0300 Subject: Update the documentation with information on the callback attribute --- system/doc/design_principles/spec_proc.xml | 48 ++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index f0f62891b6..a1c862e004 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -411,30 +411,48 @@ loop(...) ->

To implement a user-defined behaviour, write code similar to code for a special process but calling functions in a callback module for handling specific tasks.

-

If it is desired that the compiler should warn for missing - callback functions, as it does for the OTP behaviours, implement - and export the function:

+

If it is desired that the compiler should warn for missing callback + functions, as it does for the OTP behaviours, add callback attributes in the + behaviour module to describe the expected callbacks:

+ +-callback Name1(Arg1_1, Arg1_2, ..., Arg1_N1) -> Res1. +-callback Name2(Arg2_1, Arg2_2, ..., Arg2_N2) -> Res2. +... +-callback NameM(ArgM_1, ArgM_2, ..., ArgM_NM) -> ResM. +

where NameX are the names of the expected callbacks and + ArgX_Y, ResX are types as they are described in Specifications + for functions in Types and + Function Specifications. The whole syntax of spec attributes is + supported by callback attributes.

+

Alternatively you may directly implement and export the function:

behaviour_info(callbacks) -> [{Name1,Arity1},...,{NameN,ArityN}]. -

where each {Name,Arity} specifies the name and arity of - a callback function.

+

where each {Name,Arity} specifies the name and arity of a callback + function. This function is otherwise automatically generated by the compiler + using the callback attributes.

When the compiler encounters the module attribute - -behaviour(Behaviour). in a module Mod, it will call - Behaviour:behaviour_info(callbacks) and compare the result - with the set of functions actually exported from Mod, and - issue a warning if any callback function is missing.

+ -behaviour(Behaviour). in a module Mod, it will call + Behaviour:behaviour_info(callbacks) and compare the result with the + set of functions actually exported from Mod, and issue a warning if + any callback function is missing.

Example:

%% User-defined behaviour module -module(simple_server). -export([start_link/2,...]). --export([behaviour_info/1]). -behaviour_info(callbacks) -> - [{init,1}, - {handle_req,1}, - {terminate,0}]. +-callback init(State :: term()) -> 'ok'. +-callback handle_req(Req :: term(), State :: term()) -> {'ok', Reply :: term()}. +-callback terminate() -> 'ok'. + +%% Alternatively you may define: +%% +%% -export([behaviour_info/1]). +%% behaviour_info(callbacks) -> +%% [{init,1}, +%% {handle_req,2}, +%% {terminate,0}]. start_link(Name, Module) -> proc_lib:start_link(?MODULE, init, [self(), Name, Module]). @@ -452,7 +470,7 @@ init(Parent, Name, Module) -> -module(db). -behaviour(simple_server). --export([init/0, handle_req/1, terminate/0]). +-export([init/0, handle_req/2, terminate/0]). ...
-- cgit v1.2.3 From 570594df20b0780333c2b6ba4ff7cfd6a0b02395 Mon Sep 17 00:00:00 2001 From: Henrik Nord Date: Fri, 7 Oct 2011 17:16:54 +0200 Subject: Update primary bootstrap --- bootstrap/lib/compiler/ebin/beam_asm.beam | Bin 11096 -> 11096 bytes bootstrap/lib/compiler/ebin/beam_disasm.beam | Bin 24976 -> 24968 bytes bootstrap/lib/compiler/ebin/compile.beam | Bin 36380 -> 36920 bytes bootstrap/lib/compiler/ebin/sys_pre_expand.beam | Bin 15848 -> 16504 bytes bootstrap/lib/kernel/ebin/code_server.beam | Bin 25896 -> 25956 bytes bootstrap/lib/kernel/ebin/hipe_unified_loader.beam | Bin 12540 -> 12540 bytes bootstrap/lib/kernel/ebin/inet.beam | Bin 19688 -> 19688 bytes bootstrap/lib/stdlib/ebin/beam_lib.beam | Bin 18192 -> 18220 bytes bootstrap/lib/stdlib/ebin/dets.beam | Bin 53204 -> 53204 bytes bootstrap/lib/stdlib/ebin/erl_compile.beam | Bin 5140 -> 5076 bytes bootstrap/lib/stdlib/ebin/erl_internal.beam | Bin 4996 -> 5016 bytes bootstrap/lib/stdlib/ebin/erl_lint.beam | Bin 83840 -> 84792 bytes bootstrap/lib/stdlib/ebin/erl_parse.beam | Bin 70760 -> 71068 bytes bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam | Bin 4772 -> 4936 bytes bootstrap/lib/stdlib/ebin/otp_internal.beam | Bin 9052 -> 9140 bytes bootstrap/lib/stdlib/ebin/sofs.beam | Bin 41096 -> 41096 bytes bootstrap/lib/stdlib/ebin/supervisor.beam | Bin 18064 -> 18136 bytes 17 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam index 2679b0993f..c14ccc2e7b 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_asm.beam and b/bootstrap/lib/compiler/ebin/beam_asm.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam index 49b49871dd..0d4f028d48 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_disasm.beam and b/bootstrap/lib/compiler/ebin/beam_disasm.beam differ diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam index da1d7a2922..4985e3d6da 100644 Binary files a/bootstrap/lib/compiler/ebin/compile.beam and b/bootstrap/lib/compiler/ebin/compile.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam index b4129dc7aa..9d1629d9d4 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam and b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam differ diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam index 55f7fbdc9d..9ed647a94b 100644 Binary files a/bootstrap/lib/kernel/ebin/code_server.beam and b/bootstrap/lib/kernel/ebin/code_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam index 873b717651..b638157e11 100644 Binary files a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam and b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam index cb028e612a..0c4607063d 100644 Binary files a/bootstrap/lib/kernel/ebin/inet.beam and b/bootstrap/lib/kernel/ebin/inet.beam differ diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam index c2592e3dbc..67a8554abe 100644 Binary files a/bootstrap/lib/stdlib/ebin/beam_lib.beam and b/bootstrap/lib/stdlib/ebin/beam_lib.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam index 9cd59e7a76..b53a1357ff 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets.beam and b/bootstrap/lib/stdlib/ebin/dets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam index 6435fcbab5..deb6b97657 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_compile.beam and b/bootstrap/lib/stdlib/ebin/erl_compile.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam index 592989520b..07e7f2a377 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_internal.beam and b/bootstrap/lib/stdlib/ebin/erl_internal.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam index c2b6549490..c0c8cd7cdd 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_lint.beam and b/bootstrap/lib/stdlib/ebin/erl_lint.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam index d885821f52..097c378dbd 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_parse.beam and b/bootstrap/lib/stdlib/ebin/erl_parse.beam differ diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam index e1542991b2..886bba634c 100644 Binary files a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam and b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam differ diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam index c0c236fecb..f22f936f42 100644 Binary files a/bootstrap/lib/stdlib/ebin/otp_internal.beam and b/bootstrap/lib/stdlib/ebin/otp_internal.beam differ diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam index 90bbb671eb..b1bc6498a6 100644 Binary files a/bootstrap/lib/stdlib/ebin/sofs.beam and b/bootstrap/lib/stdlib/ebin/sofs.beam differ diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam index b9d50e231b..54ff535fc3 100644 Binary files a/bootstrap/lib/stdlib/ebin/supervisor.beam and b/bootstrap/lib/stdlib/ebin/supervisor.beam differ -- cgit v1.2.3 From 9bb4ba879b613fc1986ac37c027a16884f3814fe Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Wed, 10 Nov 2010 20:00:52 +0200 Subject: Add '-callback' attributes in stdlib's behaviours Replace the behaviour_info(callbacks) export in stdlib's behaviours with -callback' attributes for all the callbacks. --- lib/stdlib/src/gen_event.erl | 75 +++++++++++++++--------------------- lib/stdlib/src/gen_fsm.erl | 41 +++++++++++++++----- lib/stdlib/src/gen_server.erl | 35 ++++++++++++----- lib/stdlib/src/supervisor.erl | 16 +++----- lib/stdlib/src/supervisor_bridge.erl | 9 ++--- 5 files changed, 98 insertions(+), 78 deletions(-) diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl index d1dd074fba..9879b76391 100644 --- a/lib/stdlib/src/gen_event.erl +++ b/lib/stdlib/src/gen_event.erl @@ -36,8 +36,6 @@ add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3, swap_sup_handler/3, which_handlers/1, call/3, call/4, wake_hib/4]). --export([behaviour_info/1]). - -export([init_it/6, system_continue/3, system_terminate/4, @@ -60,14 +58,6 @@ %%% API %%%========================================================================= --spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}]. - -behaviour_info(callbacks) -> - [{init,1},{handle_event,2},{handle_call,2},{handle_info,2}, - {terminate,2},{code_change,3}]; -behaviour_info(_Other) -> - undefined. - %% gen_event:start(Handler) -> {ok, Pid} | {error, What} %% gen_event:add_handler(Handler, Mod, Args) -> ok | Other %% gen_event:notify(Handler, Event) -> ok @@ -78,41 +68,36 @@ behaviour_info(_Other) -> %% gen_event:which_handler(Handler) -> [Mod] %% gen_event:stop(Handler) -> ok - -%% handlers must export -%% Mod:init(Args) -> {ok, State} | Other -%% Mod:handle_event(Event, State) -> -%% {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2} -%% Mod:handle_info(Info, State) -> -%% {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2} -%% Mod:handle_call(Query, State) -> -%% {ok, Reply, State'} | {remove_handler, Reply} | -%% {swap_handler, Reply, Args1,State1,Mod2,Args2} -%% Mod:terminate(Args, State) -> Val - - -%% add_handler(H, Mod, Args) -> ok | Other -%% Mod:init(Args) -> {ok, State} | Other - -%% delete_handler(H, Mod, Args) -> Val -%% Mod:terminate(Args, State) -> Val - -%% notify(H, Event) -%% Mod:handle_event(Event, State) -> -%% {ok, State1} -%% remove_handler -%% Mod:terminate(remove_handler, State) is called -%% the return value is ignored -%% {swap_handler, Args1, State1, Mod2, Args2} -%% State2 = Mod:terminate(Args1, State1) is called -%% the return value is chained into the new module and -%% Mod2:init({Args2, State2}) is called -%% Other -%% Mod:terminate({error, Other}, State) is called -%% The return value is ignored -%% call(H, Mod, Query) -> Val -%% call(H, Mod, Query, Timeout) -> Val -%% Mod:handle_call(Query, State) -> as above +-callback init(InitArgs :: term()) -> + {ok, State :: term()} | + {ok, State :: term(), hibernate}. +-callback handle_event(Event :: term(), State :: term()) -> + {ok, NewState :: term()} | + {ok, NewState :: term(), hibernate} | + {swap_handler, Args1 :: term(), NewState :: term(), + Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | + remove_handler. +-callback handle_call(Request :: term(), State :: term()) -> + {ok, Reply :: term(), NewState :: term()} | + {ok, Reply :: term(), NewState :: term(), hibernate} | + {swap_handler, Reply :: term(), Args1 :: term(), NewState :: term(), + Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | + {remove_handler, Reply :: term()}. +-callback handle_info(Info :: term(), State :: term()) -> + {ok, NewState :: term()} | + {ok, NewState :: term(), hibernate} | + {swap_handler, Args1 :: term(), NewState :: term(), + Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} | + remove_handler. +-callback terminate(Args :: (term() | {stop, Reason :: term()} | + stop | remove_handler | + {error, {'EXIT', Reason :: term()}} | + {error, term()}), + State :: term()) -> + term(). +-callback code_change(OldVsn :: (term() | {down, term()}), + State :: term(), Extra :: term()) -> + {ok, NewState :: term()}. %%--------------------------------------------------------------------------- diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index ea21136bdb..3db8c9f4f2 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -113,8 +113,6 @@ start_timer/2,send_event_after/2,cancel_timer/1, enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/6]). --export([behaviour_info/1]). - %% Internal exports -export([init_it/6, system_continue/3, @@ -128,13 +126,38 @@ %%% Interface functions. %%% --------------------------------------------------- --spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}]. - -behaviour_info(callbacks) -> - [{init,1},{handle_event,3},{handle_sync_event,4},{handle_info,3}, - {terminate,3},{code_change,4}]; -behaviour_info(_Other) -> - undefined. +-callback init(Args :: term()) -> + {ok, StateName :: atom(), StateData :: term()} | + {ok, StateName :: atom(), StateData :: term(), timeout() | hibernate} | + {stop, Reason :: term()} | ignore. +-callback handle_event(Event :: term(), StateName :: atom(), + StateData :: term()) -> + {next_state, NextStateName :: atom(), NewStateData :: term()} | + {next_state, NextStateName :: atom(), NewStateData :: term(), + timeout() | hibernate} | + {stop, Reason :: term(), NewStateData :: term()}. +-callback handle_sync_event(Event :: term(), From :: {pid(), Tag :: term()}, + StateName :: atom(), StateData :: term()) -> + {reply, Reply :: term(), NextStateName :: atom(), NewStateData :: term()} | + {reply, Reply :: term(), NextStateName :: atom(), NewStateData :: term(), + timeout() | hibernate} | + {next_state, NextStateName :: atom(), NewStateData :: term()} | + {next_state, NextStateName :: atom(), NewStateData :: term(), + timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewStateData :: term()} | + {stop, Reason :: term(), NewStateData :: term()}. +-callback handle_info(Info :: term(), StateName :: atom(), + StateData :: term()) -> + {next_state, NextStateName :: atom(), NewStateData :: term()} | + {next_state, NextStateName :: atom(), NewStateData :: term(), + timeout() | hibernate} | + {stop, Reason :: normal | term(), NewStateData :: term()}. +-callback terminate(Reason :: normal | shutdown | {shutdown, term()} + | term(), StateName :: atom(), StateData :: term()) -> + term(). +-callback code_change(OldVsn :: term() | {down, term()}, StateName :: atom(), + StateData :: term(), Extra :: term()) -> + {ok, NextStateName :: atom(), NewStateData :: term()}. %%% --------------------------------------------------- %%% Starts a generic state machine. diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index b8ea3a4de2..dd0ef74f30 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -94,8 +94,6 @@ multi_call/2, multi_call/3, multi_call/4, enter_loop/3, enter_loop/4, enter_loop/5, wake_hib/5]). --export([behaviour_info/1]). - %% System exports -export([system_continue/3, system_terminate/4, @@ -111,13 +109,32 @@ %%% API %%%========================================================================= --spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}]. - -behaviour_info(callbacks) -> - [{init,1},{handle_call,3},{handle_cast,2},{handle_info,2}, - {terminate,2},{code_change,3}]; -behaviour_info(_Other) -> - undefined. +-callback init(Args :: term()) -> + {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} | + {stop, Reason :: term()} | ignore. +-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: term()) -> + {reply, Reply :: term(), NewState :: term()} | + {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: term()} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_cast(Request :: term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_info(Info :: timeout() | term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | + term()), + State :: term()) -> + term(). +-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), + Extra :: term()) -> + {ok, NewState :: term()}. %%% ----------------------------------------------------------------- %%% Starts a generic server. diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 36cc7f4f4b..9da0d52f8c 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -27,8 +27,6 @@ which_children/1, count_children/1, check_childspecs/1]). --export([behaviour_info/1]). - %% Internal exports -export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]). -export([handle_cast/2]). @@ -90,14 +88,12 @@ -define(is_simple(State), State#state.strategy =:= simple_one_for_one). -%%-------------------------------------------------------------------------- - --spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}]. - -behaviour_info(callbacks) -> - [{init,1}]; -behaviour_info(_Other) -> - undefined. +-callback init(Args :: term()) -> + {ok, {{RestartStrategy :: strategy(), + MaxR :: non_neg_integer(), + MaxT :: non_neg_integer()}, + [ChildSpec :: child_spec()]}} + | ignore. %%% --------------------------------------------------- %%% This is a general process supervisor built upon gen_server.erl. diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl index 555cb5a66f..e8405ab9a4 100644 --- a/lib/stdlib/src/supervisor_bridge.erl +++ b/lib/stdlib/src/supervisor_bridge.erl @@ -22,15 +22,14 @@ %% External exports -export([start_link/2, start_link/3]). --export([behaviour_info/1]). %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]). -export([code_change/3]). -behaviour_info(callbacks) -> - [{init,1},{terminate,2}]; -behaviour_info(_Other) -> - undefined. +-callback init(Args :: term()) -> + {ok, Pid :: pid(), State :: term()} | ignore | {error, Error :: term()}. +-callback terminate(Reason :: (shutdown | term()), State :: term()) -> + Ignored :: term(). %%%----------------------------------------------------------------- %%% This is a rewrite of supervisor_bridge from BS.3. -- cgit v1.2.3 From 1d3544d9b5c4bc2cad99b220f44aa370703dbc6b Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 8 Jun 2010 23:19:13 +0300 Subject: Add callback specs to inets_service module following possibly deprecated comments --- lib/inets/src/inets_app/inets_service.erl | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl index e9eb9892f2..f89dac195c 100644 --- a/lib/inets/src/inets_app/inets_service.erl +++ b/lib/inets/src/inets_app/inets_service.erl @@ -20,24 +20,20 @@ -module(inets_service). --export([behaviour_info/1]). - -behaviour_info(callbacks) -> - [{start_standalone, 1}, - {start_service, 1}, - {stop_service, 1}, - {services, 0}, - {service_info, 1}]; -behaviour_info(_) -> - undefined. - %% Starts service stand-alone %% start_standalone(Config) -> % {ok, Pid} | {error, Reason} %% :start_link(Config). +-callback start_standalone(Config :: term()) -> + {ok, pid()} | {error, Reason :: term()}. + %% Starts service as part of inets %% start_service(Config) -> % {ok, Pid} | {error, Reason} %% :start_child(Config). + +-callback start_service(Config :: term()) -> + {ok, pid()} | {error, Reason :: term()}. + %% Stop service %% stop_service(Pid) -> % ok | {error, Reason} %% :stop_child(maybe_map_pid_to_other_ref(Pid)). @@ -51,6 +47,9 @@ behaviour_info(_) -> %% Error %% end. +-callback stop_service(Service :: term()) -> + ok | {error, Reason :: term()}. + %% Returns list of running services. Services started as stand alone %% are not listed %% services() -> % [{Service, Pid}] @@ -59,7 +58,12 @@ behaviour_info(_) -> %% [{httpc, Pid} || {_, Pid, _, _} <- %% supervisor:which_children(httpc_profile_sup)]. +-callback services() -> + [{Service :: term(), pid()}]. -%% service_info() -> [{Property, Value}] | {error, Reason} +%% service_info() -> {ok, [{Property, Value}]} | {error, Reason} %% ex: httpc:service_info() -> [{profile, ProfileName}] %% httpd:service_info() -> [{host, Host}, {port, Port}] + +-callback service_info(Service :: term()) -> + {ok, [{Property :: term(), Value :: term()}]} | {error, Reason :: term()}. -- cgit v1.2.3 From 3ae841405f4005b52950a74727578deea2aee209 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 8 Jun 2010 23:53:43 +0300 Subject: Add callback specs to tftp module following internet documentation --- lib/inets/src/tftp/tftp.erl | 47 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/inets/src/tftp/tftp.erl b/lib/inets/src/tftp/tftp.erl index bfdb4c0030..b33c0a98f4 100644 --- a/lib/inets/src/tftp/tftp.erl +++ b/lib/inets/src/tftp/tftp.erl @@ -215,8 +215,6 @@ start/0 ]). --export([behaviour_info/1]). - %% Application local functions -export([ start_standalone/1, @@ -227,13 +225,50 @@ ]). -behaviour_info(callbacks) -> - [{prepare, 6}, {open, 6}, {read, 1}, {write, 2}, {abort, 3}]; -behaviour_info(_) -> - undefined. +-type peer() :: {PeerType :: inet | inet6, + PeerHost :: inet:ip_address(), + PeerPort :: port()}. + +-type access() :: read | write. + +-type options() :: [{Key :: string(), Value :: string()}]. + +-type error_code() :: undef | enoent | eacces | enospc | + badop | eexist | baduser | badopt | + integer(). + +-callback prepare(Peer :: peer(), + Access :: access(), + Filename :: file:name(), + Mode :: string(), + SuggestedOptions :: options(), + InitialState :: [] | [{root_dir, string()}]) -> + {ok, AcceptedOptions :: options(), NewState :: term()} | + {error, {Code :: error_code(), string()}}. + +-callback open(Peer :: peer(), + Access :: access(), + Filename :: file:name(), + Mode :: string(), + SuggestedOptions :: options(), + State :: [] | [{root_dir, string()}] | term()) -> + {ok, AcceptedOptions :: options(), NewState :: term()} | + {error, {Code :: error_code(), string()}}. + +-callback read(State :: term()) -> {more, binary(), NewState :: term()} | + {last, binary(), integer()} | + {error, {Code :: error_code(), string()}}. + +-callback write(binary(), State :: term()) -> + {more, NewState :: term()} | + {last, FileSize :: integer()} | + {error, {Code :: error_code(), string()}}. + +-callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'. -include("tftp.hrl"). + %%------------------------------------------------------------------- %% read_file(RemoteFilename, LocalFilename, Options) -> %% {ok, LastCallbackState} | {error, Reason} -- cgit v1.2.3 From ed72d05e27fcf1d4f649014ffd7a1c2878b5b010 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 8 Jun 2010 20:55:26 +0300 Subject: Add callback specs into 'application' module in kernel --- lib/kernel/src/application.erl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index fa3a4c3d36..caac4d926c 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -28,8 +28,6 @@ -export([get_application/0, get_application/1, info/0]). -export([start_type/0]). --export([behaviour_info/1]). - %%%----------------------------------------------------------------- -type start_type() :: 'normal' @@ -59,12 +57,12 @@ %%------------------------------------------------------------------ --spec behaviour_info(atom()) -> 'undefined' | [{atom(), byte()}]. +-callback start(StartType :: normal | {takeover, node()} | {failover, node()}, + StartArgs :: term()) -> + {ok, pid()} | {ok, pid(), State :: term()} | {error, Reason :: term}. -behaviour_info(callbacks) -> - [{start,2},{stop,1}]; -behaviour_info(_Other) -> - undefined. +-callback stop(State :: term()) -> + term(). %%%----------------------------------------------------------------- %%% This module is API towards application_controller and -- cgit v1.2.3 From ac2810603b7aaad24129fadf887d9e8deff31d2f Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 7 Oct 2011 16:26:45 +0200 Subject: Make testsuites more robust in case of init failure In particular, move code out of init_per_suite since failure causes end_per_suite to be skipped. Cleanup is simpler if both init and cleanup happen as testcases. --- lib/diameter/test/diameter_relay_SUITE.erl | 207 +++++++++++++------------ lib/diameter/test/diameter_traffic_SUITE.erl | 94 ++++++----- lib/diameter/test/diameter_transport_SUITE.erl | 17 +- lib/diameter/test/diameter_util.erl | 23 ++- 4 files changed, 197 insertions(+), 144 deletions(-) diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index d3d1fe690a..60babd0b9a 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -37,20 +37,22 @@ all/0, groups/0, init_per_group/2, - end_per_group/2, - init_per_suite/1, - end_per_suite/1]). + end_per_group/2]). %% testcases --export([send1/1, +-export([start/1, + start_services/1, + connect/1, + send1/1, send2/1, send3/1, send4/1, send_loop/1, send_timeout_1/1, send_timeout_2/1, - remove_transports/1, - stop_services/1]). + disconnect/1, + stop_services/1, + stop/1]). %% diameter callbacks -export([peer_up/3, @@ -73,6 +75,8 @@ %% =========================================================================== +-define(util, diameter_util). + -define(ADDR, {127,0,0,1}). -define(CLIENT, "CLIENT.REALM1"). @@ -83,6 +87,10 @@ -define(SERVER3, "SERVER1.REALM3"). -define(SERVER4, "SERVER2.REALM3"). +-define(SERVICES, [?CLIENT, + ?RELAY1, ?RELAY2, + ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4]). + -define(DICT_COMMON, ?DIAMETER_DICT_COMMON). -define(DICT_RELAY, ?DIAMETER_DICT_RELAY). @@ -131,13 +139,15 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, N} || {N, _, _} <- groups()] - ++ [remove_transports, stop_services]. + [start, start_services, connect] + ++ tc() + ++ [{group, all}, + disconnect, + stop_services, + stop]. groups() -> - Ts = tc(), - [{all, [], Ts}, - {p, [parallel], Ts}]. + [{all, [parallel], tc()}]. init_per_group(_, Config) -> Config. @@ -145,32 +155,7 @@ init_per_group(_, Config) -> end_per_group(_, _) -> ok. -init_per_suite(Config) -> - ok = diameter:start(), - [S1,S2,S3,S4] = S = [server(N, ?DICT_COMMON) || N <- [?SERVER1, - ?SERVER2, - ?SERVER3, - ?SERVER4]], - [R1,R2] = R = [server(N, ?DICT_RELAY) || N <- [?RELAY1, ?RELAY2]], - - ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)), - - true = diameter:subscribe(?RELAY1), - true = diameter:subscribe(?RELAY2), - true = diameter:subscribe(?CLIENT), - - [C1,C2] = connect(?RELAY1, [S1,S2]), - [C3,C4] = connect(?RELAY2, [S3,S4]), - [C5,C6] = connect(?CLIENT, [R1,R2]), - - C7 = connect(?RELAY1, R2), - - [{transports, {S, R, [C1,C2,C3,C4,C5,C6,C7]}} | Config]. - -end_per_suite(_Config) -> - ok = diameter:stop(). - -%% Testcases to run when services are started and connections +%% Traffic cases run when services are started and connections %% established. tc() -> [send1, @@ -181,43 +166,65 @@ tc() -> send_timeout_1, send_timeout_2]. -server(Host, Dict) -> - ok = diameter:start_service(Host, ?SERVICE(Host, Dict)), - {ok, LRef} = diameter:add_transport(Host, ?LISTEN), - {LRef, portnr(LRef)}. +%% =========================================================================== +%% start/stop testcases -connect(Host, {_LRef, PortNr}) -> - {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr)), - ok = receive - #diameter_event{service = Host, - info = {up, Ref, _, _, #diameter_packet{}}} -> - ok - after 2000 -> - false - end, - Ref; -connect(Host, Ports) -> - [connect(Host, P) || P <- Ports]. +start(_Config) -> + ok = diameter:start(). -portnr(LRef) -> - portnr(LRef, 20). +start_services(_Config) -> + S = [server(N, ?DICT_COMMON) || N <- [?SERVER1, + ?SERVER2, + ?SERVER3, + ?SERVER4]], + R = [server(N, ?DICT_RELAY) || N <- [?RELAY1, ?RELAY2]], -portnr(LRef, N) - when 0 < N -> - case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of - [{T, _Pid}] -> - {_, _, {LRef, {_Addr, LSock}}} = T, - {ok, PortNr} = inet:port(LSock), - PortNr; - [] -> - receive after 50 -> ok end, - portnr(LRef, N-1) - end. + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)), -realm(Host) -> - tl(lists:dropwhile(fun(C) -> C /= $. end, Host)). + {save_config, S ++ R}. + +connect(Config) -> + {_, [S1,S2,S3,S4,R1,R2] = SR} = proplists:get_value(saved_config, Config), + + true = diameter:subscribe(?RELAY1), + true = diameter:subscribe(?RELAY2), + true = diameter:subscribe(?CLIENT), + + [R1S1,R1S2] = connect(?RELAY1, [S1,S2]), + [R2S3,R2S4] = connect(?RELAY2, [S3,S4]), + [CR1,CR2] = connect(?CLIENT, [R1,R2]), + + R1R2 = connect(?RELAY1, R2), + + ?util:write_priv(Config, "cfg", SR ++ [R1S1,R1S2,R2S3,R2S4,CR1,CR2,R1R2]). + +%% Remove the client transports and expect the corresponding server +%% transport to go down. +disconnect(Config) -> + [S1,S2,S3,S4,R1,R2,R1S1,R1S2,R2S3,R2S4,CR1,CR2,R1R2] + = ?util:read_priv(Config, "cfg"), + + [?CLIENT | Svcs] = ?SERVICES, + [] = [{S,T} || S <- Svcs, T <- [diameter:subscribe(S)], T /= true], + + disconnect(?RELAY1, S1, R1S1), + disconnect(?RELAY1, S2, R1S2), + disconnect(?RELAY2, S3, R2S3), + disconnect(?RELAY2, S4, R2S4), + disconnect(?CLIENT, R1, CR1), + disconnect(?CLIENT, R2, CR2), + disconnect(?RELAY1, R2, R1R2). + +stop_services(_Config) -> + [] = [{H,T} || H <- ?SERVICES, + T <- [diameter:stop_service(H)], + T /= ok]. + +stop(_Config) -> + ok = diameter:stop(). %% =========================================================================== +%% traffic testcases %% Send an STR intended for a specific server and expect success. send1(_Config) -> @@ -254,40 +261,50 @@ send_timeout(Tmo) -> {'Re-Auth-Request-Type', ?AUTHORIZE_ONLY}], call(Req, [{filter, realm}, {timeout, Tmo}]). -%% Remove the client transports and expect the corresponding server -%% transport to go down. -remove_transports(Config) -> - {[S1,S2,S3,S4], [R1,R2], [C1,C2,C3,C4,C5,C6,C7]} - = proplists:get_value(transports, Config), - - true = diameter:subscribe(?SERVER1), - true = diameter:subscribe(?SERVER2), - true = diameter:subscribe(?SERVER3), - true = diameter:subscribe(?SERVER4), - true = diameter:subscribe(?RELAY1), - true = diameter:subscribe(?RELAY2), +%% =========================================================================== + +realm(Host) -> + tl(lists:dropwhile(fun(C) -> C /= $. end, Host)). + +server(Host, Dict) -> + ok = diameter:start_service(Host, ?SERVICE(Host, Dict)), + {ok, LRef} = diameter:add_transport(Host, ?LISTEN), + {LRef, portnr(LRef)}. + +portnr(LRef) -> + portnr(LRef, 20). + +portnr(LRef, N) + when 0 < N -> + case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of + [{T, _Pid}] -> + {_, _, {LRef, {_Addr, LSock}}} = T, + {ok, PortNr} = inet:port(LSock), + PortNr; + [] -> + receive after 50 -> ok end, + portnr(LRef, N-1) + end. - disconnect(S1, ?RELAY1, C1), - disconnect(S2, ?RELAY1, C2), - disconnect(S3, ?RELAY2, C3), - disconnect(S4, ?RELAY2, C4), - disconnect(R1, ?CLIENT, C5), - disconnect(R2, ?CLIENT, C6), - disconnect(R2, ?RELAY1, C7). +connect(Host, {_LRef, PortNr}) -> + {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr)), + ok = receive + #diameter_event{service = Host, + info = {up, Ref, _, _, #diameter_packet{}}} -> + ok + after 2000 -> + false + end, + Ref; +connect(Host, Ports) -> + [connect(Host, P) || P <- Ports]. -disconnect({LRef, _PortNr}, Client, CRef) -> +disconnect(Client, {LRef, _PortNr}, CRef) -> ok = diameter:remove_transport(Client, CRef), ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok after 2000 -> false end. -stop_services(_Config) -> - S = [?CLIENT, ?RELAY1, ?RELAY2, ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4], - Ok = [ok || _ <- S], - Ok = [diameter:stop_service(H) || H <- S]. - -%% =========================================================================== - call(Server) -> Realm = realm(Server), Req = ['STR', {'Destination-Realm', Realm}, diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 8c85323222..f6905473b7 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -26,15 +26,16 @@ -export([suite/0, all/0, groups/0, - init_per_suite/1, - end_per_suite/1, init_per_group/2, end_per_group/2, init_per_testcase/2, end_per_testcase/2]). %% testcases --export([result_codes/1, +-export([start/1, + start_services/1, + add_transports/1, + result_codes/1, send_ok/1, send_arbitrary/1, send_unknown/1, @@ -73,7 +74,8 @@ send_multiple_filters_3/1, send_anything/1, remove_transports/1, - stop_services/1]). + stop_services/1, + stop/1]). %% diameter callbacks -export([peer_up/3, @@ -96,6 +98,8 @@ %% =========================================================================== +-define(util, diameter_util). + -define(ADDR, {127,0,0,1}). -define(CLIENT, "CLIENT"). @@ -177,30 +181,18 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [result_codes | [{group, N} || {N, _, _} <- groups()]] - ++ [remove_transports, stop_services]. + [start, start_services, add_transports, result_codes + | [{group, N} || {N, _, _} <- groups()]] + ++ [remove_transports, stop_services, stop]. groups() -> Ts = tc(), - [{E, [], Ts} || E <- ?ENCODINGS] - ++ [{?P(E), [parallel], Ts} || E <- ?ENCODINGS]. + [{grp(E,P), P, Ts} || E <- ?ENCODINGS, P <- [[], [parallel]]]. -init_per_suite(Config) -> - ok = diameter:start(), - ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)), - ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)), - {ok, LRef} = diameter:add_transport(?SERVER, ?LISTEN), - true = diameter:subscribe(?CLIENT), - {ok, CRef} = diameter:add_transport(?CLIENT, ?CONNECT(portnr())), - {up, CRef, _Peer, _Config, #diameter_packet{}} - = receive #diameter_event{service = ?CLIENT, info = I} -> I - after 2000 -> false - end, - true = diameter:unsubscribe(?CLIENT), - [{transports, {LRef, CRef}} | Config]. - -end_per_suite(_Config) -> - ok = diameter:stop(). +grp(E, []) -> + E; +grp(E, [parallel]) -> + ?P(E). init_per_group(Name, Config) -> E = case ?L(Name) of @@ -276,6 +268,45 @@ portnr(N) portnr(N-1) end. +%% =========================================================================== +%% start/stop testcases + +start(_Config) -> + ok = diameter:start(). + +start_services(_Config) -> + ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)), + ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)). + +add_transports(Config) -> + {ok, LRef} = diameter:add_transport(?SERVER, ?LISTEN), + true = diameter:subscribe(?CLIENT), + {ok, CRef} = diameter:add_transport(?CLIENT, ?CONNECT(portnr())), + {up, CRef, _Peer, _Cfg, #diameter_packet{}} + = receive #diameter_event{service = ?CLIENT, info = I} -> I + after 2000 -> false + end, + true = diameter:unsubscribe(?CLIENT), + ?util:write_priv(Config, "transport", {LRef, CRef}). + +%% Remove the client transport and expect the server transport to +%% go down. +remove_transports(Config) -> + {LRef, CRef} = ?util:read_priv(Config, "transport"), + true = diameter:subscribe(?SERVER), + ok = diameter:remove_transport(?CLIENT, CRef), + {down, LRef, _, _} + = receive #diameter_event{service = ?SERVER, info = I} -> I + after 2000 -> false + end. + +stop_services(_Config) -> + ok = diameter:stop_service(?CLIENT), + ok = diameter:stop_service(?SERVER). + +stop(_Config) -> + ok = diameter:stop(). + %% =========================================================================== %% Ensure that result codes have the expected values. @@ -532,21 +563,6 @@ send_anything(Config) -> #diameter_base_STA{'Result-Code' = ?SUCCESS} = call(Config, anything). -%% Remove the client transport and expect the server transport to -%% go down. -remove_transports(Config) -> - {LRef, CRef} = proplists:get_value(transports, Config), - true = diameter:subscribe(?SERVER), - ok = diameter:remove_transport(?CLIENT, CRef), - {down, LRef, _, _} - = receive #diameter_event{service = ?SERVER, info = I} -> I - after 2000 -> false - end. - -stop_services(_Config) -> - {ok, ok} = {diameter:stop_service(?CLIENT), - diameter:stop_service(?SERVER)}. - %% =========================================================================== call(Config, Req) -> diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index d545859fe8..064e5caa67 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -33,10 +33,12 @@ end_per_suite/1]). %% testcases --export([tcp_accept/1, +-export([start/1, + tcp_accept/1, tcp_connect/1, sctp_accept/1, - sctp_connect/1]). + sctp_connect/1, + stop/1]). -export([accept/1, connect/1, @@ -101,7 +103,7 @@ suite() -> [{timetrap, {minutes, 2}}]. all() -> - [{group, all} | tc()]. + [start | tc()] ++ [{group, all}, stop]. groups() -> [{all, [parallel], tc()}]. @@ -119,10 +121,17 @@ end_per_group(_, _) -> ok. init_per_suite(Config) -> - ok = diameter:start(), [{sctp, have_sctp()} | Config]. end_per_suite(_Config) -> + ok. + +%% =========================================================================== + +start(_Config) -> + ok = diameter:start(). + +stop(_Config) -> ok = diameter:stop(). %% =========================================================================== diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 99f4fa1977..f9942c3408 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -28,7 +28,8 @@ fold/3, foldl/3, scramble/1, - ps/0]). + write_priv/3, + read_priv/2]). -define(L, atom_to_list). @@ -150,11 +151,6 @@ s(Acc, L) -> {H, [T|Rest]} = lists:split(random:uniform(length(L)) - 1, L), s([T|Acc], H ++ Rest). -%% ps/0 - -ps() -> - [{P, process_info(P)} || P <- erlang:processes()]. - %% eval/1 eval({M,[F|A]}) @@ -175,3 +171,18 @@ eval(L) eval(F) when is_function(F,0) -> F(). + +%% write_priv/3 + +write_priv(Config, Name, Term) -> + Dir = proplists:get_value(priv_dir, Config), + Path = filename:join([Dir, Name]), + ok = file:write_file(Path, term_to_binary(Term)). + +%% read_priv/2 + +read_priv(Config, Name) -> + Dir = proplists:get_value(priv_dir, Config), + Path = filename:join([Dir, Name]), + {ok, Bin} = file:read_file(Path), + binary_to_term(Bin). -- cgit v1.2.3 From fb76a9149fddd06c5d06f2199193a4f976256533 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 6 Oct 2011 12:05:36 +0200 Subject: gen_sctp:open/0-2 might return {error, eprotonosupport} Previously error:badarg was raise if there was no underlying support for SCTP. Handle both new and old failure until OTP-9239 is merged. --- lib/diameter/test/diameter_transport_SUITE.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index d545859fe8..6ae06266f6 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -180,7 +180,9 @@ have_sctp() -> try gen_sctp:open() of {ok, Sock} -> gen_sctp:close(Sock), - true + true; + {error, eprotonosupport} -> %% fail on any other reason + false catch error: badarg -> false -- cgit v1.2.3 From 942e68d3f93ce686a16d27716892e7c0d2e5872b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 7 Oct 2011 17:01:06 +0200 Subject: Move init/end_per_suite into testcases See ac2810603b7aaad24129fadf887d9e8deff31d2f. --- lib/diameter/test/diameter_tls_SUITE.erl | 103 ++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 37 deletions(-) diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index c0a9603e04..90e32c834f 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -42,13 +42,19 @@ end_per_suite/1]). %% testcases --export([send1/1, +-export([start_ssl/1, + start_diameter/1, + start_services/1, + add_transports/1, + send1/1, send2/1, send3/1, send4/1, send5/1, remove_transports/1, - stop_services/1]). + stop_services/1, + stop_diameter/1, + stop_ssl/1]). %% diameter callbacks -export([peer_up/3, @@ -71,6 +77,8 @@ %% =========================================================================== +-define(util, diameter_util). + -define(ADDR, {127,0,0,1}). -define(CLIENT, "CLIENT.REALM0"). @@ -129,8 +137,12 @@ suite() -> [{timetrap, {seconds, 15}}]. all() -> - [{group, N} || {N, _, _} <- groups()] - ++ [remove_transports, stop_services]. + [start_ssl, + start_diameter, + start_services, + add_transports] + ++ [{group, N} || {N, _, _} <- groups()] + ++ [remove_transports, stop_services, stop_diameter, stop_ssl]. groups() -> Ts = tc(), @@ -144,42 +156,71 @@ end_per_group(_, _) -> ok. init_per_suite(Config) -> - init(os:find_executable("openssl"), Config). + case os:find_executable("openssl") of + false -> + {skip, no_openssl}; + _ -> + Config + end. + +end_per_suite(_Config) -> + ok. + +%% Testcases to run when services are started and connections +%% established. +tc() -> + [send1, + send2, + send3, + send4, + send5]. + +%% =========================================================================== +%% testcases + +start_ssl(_Config) -> + ok = ssl:start(). -init(false, _) -> - {skip, no_openssl}; -init(_, Config) -> - ok = ssl:start(), - ok = diameter:start(), +start_diameter(_Config) -> + ok = diameter:start(). +start_services(Config) -> Dir = proplists:get_value(priv_dir, Config), Servers = [server(S, sopts(S, Dir)) || S <- ?SERVERS], ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)), + + {save_config, [Dir | Servers]}. + +add_transports(Config) -> + {_, [Dir | Servers]} = proplists:get_value(saved_config, Config), + true = diameter:subscribe(?CLIENT), Opts = ssl_options(Dir, "client"), Connections = [connect(?CLIENT, S, copts(N, Opts)) || {S,N} <- lists:zip(Servers, ?SERVERS)], - [{transports, lists:zip(Servers, Connections)} | Config]. + ?util:write_priv(Config, "cfg", lists:zip(Servers, Connections)). -end_per_suite(_Config) -> - ok = diameter:stop(), - ok = ssl:stop(). -%% Testcases to run when services are started and connections -%% established. These are trivial, the interesting stuff is setting up -%% the connections in init_per_suite/2. -tc() -> - [send1, - send2, - send3, - send4, - send5]. +%% Remove the client transports and expect the corresponding server +%% transport to go down. +remove_transports(Config) -> + Ts = ?util:read_priv(Config, "cfg"), + [] = [T || S <- ?SERVERS, T <- [diameter:subscribe(S)], T /= true], + lists:map(fun disconnect/1, Ts). -%% =========================================================================== -%% testcases +stop_services(_Config) -> + [] = [{H,T} || H <- [?CLIENT | ?SERVERS], + T <- [diameter:stop_service(H)], + T /= ok]. + +stop_diameter(_Config) -> + ok = diameter:stop(). + +stop_ssl(_Config) -> + ok = ssl:stop(). %% Send an STR intended for a specific server and expect success. send1(_Config) -> @@ -193,18 +234,6 @@ send4(_Config) -> send5(_Config) -> call(?SERVER5). -%% Remove the client transports and expect the corresponding server -%% transport to go down. -remove_transports(Config) -> - Ts = proplists:get_value(transports, Config), - [] = [T || S <- ?SERVERS, T <- [diameter:subscribe(S)], T /= true], - lists:map(fun disconnect/1, Ts). - -stop_services(_Config) -> - Hs = [?CLIENT | ?SERVERS], - Ok = [ok || _ <- Hs], - Ok = [diameter:stop_service(H) || H <- Hs]. - %% =========================================================================== %% diameter callbacks -- cgit v1.2.3