anchor.diff:  %% %CopyrightEnd%
   %%
   
  -%%% Generic connection owner process.
  -%%%
  -%%% -type handle() = pid(). A handle for using a connection implemented
  -%%% with ct_gen_conn.erl.
  +%%
  +%% Generic connection owner process.
  +%%
   
   -module(ct_gen_conn).
   
  --export([start/4, stop/1, get_conn_pid/1, check_opts/1]).
  --export([call/2, call/3, return/2, do_within_time/2]).
  --export([log/3, start_log/1, cont_log/2, cont_log_no_timestamp/2, end_log/0]).
  +-behaviour(gen_server).
  +
  +-export([start/4,
  +         stop/1,
  +         get_conn_pid/1]).
  +
  +-export([call/2,
  +         call/3,
  +         return/2,
  +         do_within_time/2]).
  +
  +-export([log/3,
  +         start_log/1,
  +         cont_log/2,
  +         cont_log_no_timestamp/2,
  +         end_log/0]).
  +
  +%% gen_server callbacks
  +-export([init/1,
  +         handle_info/2,
  +         handle_cast/2,
  +         handle_call/3,
  +         code_change/3,
  +         terminate/2]).
  +
  +%% test
  +-export([make_opts/1]).
   
   -ifdef(debug).
   -define(dbg,true).
  
positive.code: %%
  %% %CopyrightBegin%
  %%
  %% Copyright Ericsson AB 2003-2018. All Rights Reserved.
  %%
  %% Licensed under the Apache License, Version 2.0 (the "License");
  %% you may not use this file except in compliance with the License.
  
negative.code: -define(dbg,false).
  -endif.
  
  -type handle() :: pid(). %% connection-owning process spawned here
  
  -record(gen_opts, {callback  :: module(),
                     name      :: ct:target_name(),
                     address   :: term(),
                     init_data :: term(),
                     reconnect    = true  :: boolean(),
                     forward      = false :: boolean(),
                     use_existing = true  :: boolean(),
                     old          = false :: boolean(),
                     conn_pid       :: pid() | undefined,
                     cb_state       :: term(),
                     ct_util_server :: pid() | undefined}).
  
  %% ---------------------------------------------------------------------
  
  -spec start(Address, InitData, CallbackMod, [Opt])
     -> {ok, handle()} | {error, Reason :: term()}
   when Address :: term(),
        InitData :: term(),
        CallbackMod :: module(),
        Opt :: {name, Name :: ct:target_name()}
             | {use_existing_connection, boolean()}
             | {reconnect, boolean()}
             | {forward_messages, boolean()}
        ;    (Name, Address, InitData, CallbackMod)
     -> {ok, handle()} | {error, Reason :: term()}
   when Name :: ct:target_name(),
        Address :: term(),
        InitData :: term(),
        CallbackMod :: module().
  
  %% Open a connection and start the generic connection owner process.
  %%
  %% CallbackMod is a specific callback module for
  %% each type of connection (e.g. telnet, ftp, netconf). It must export:
  %%
  %%   init(Name, Address, InitData) -> {ok, ConnectionPid, State}
  %%                                  | {error,Reason}.
  %%
  %% Name defaults to undefined if unspecified.
  %%
  %% The callback modules must also export:
  %%
  %%   handle_msg(Msg, From, State) -> {reply, Reply, State}
  %%                                 | {noreply, State}
  %%                                 | {stop, Reply, State}
  %%   terminate(ConnectionPid, State) -> term()
  %%   close(Handle) -> term()
  %%
  %% A Reply of the form {retry, _} results in a new call to the server with
  %% the retry tuple as message.
  %%
  %% The close/1 callback function is actually a callback
  %% for ct_util, for closing registered connections when
  %% ct_util_server is terminated. Handle is the Pid of
  %% the ct_gen_conn process.
  %%
  %% If option reconnect is true, then the
  %% callback must also export:
  %%
  %%   reconnect(Address, State) -> {ok, ConnectionPid, State}
  %%
  %% If option forward_messages is true then
  %% the callback must also export:
  %%
  %%   handle_msg(Msg,State) -> {noreply,State}
  %%                          | {stop,State}
  %%
  %% An old interface still exists. This is used by ct_telnet, ct_ftp
  %% and ct_ssh. The start function then has an explicit
  %% Name argument, and no Opts argument.
  
  start(Address, InitData, CallbackMod, Opts) when is_list(Opts) ->
      do_start(Address, InitData, CallbackMod, Opts);
  start(Name, Address, InitData, CallbackMod) ->
      do_start(Address, InitData, CallbackMod, [{name, Name}, {old, true}]).
  
  %% ---------------------------------------------------------------------
  
  -spec stop(handle()) -> ok | {error, Reason :: term()}.
  
  %% Close the connection and stop the process managing it.
  
  stop(Handle) ->
      call(Handle, stop, 5000).
  
  %% ---------------------------------------------------------------------
  
  -spec get_conn_pid(handle()) -> pid().
  
  %% Return the connection pid associated with Handle
  
  get_conn_pid(Handle) ->
      call(Handle, get_conn_pid).
  
  %% ---------------------------------------------------------------------
  
  -spec log(Heading, Format, Args) -> ok
   when Heading :: iodata(),
        Format  :: io:format(),
        Args    :: [term()].
  
  %% Log activities on the current connection.
  %% See ct_logs:log/3
  
  log(Heading, Format, Args) ->
      log(log, [Heading, Format, Args]).
  
  %% ---------------------------------------------------------------------
  
  -spec start_log(Heading :: iodata()) -> ok.
  
  %% Log activities on the current connection.
  %% See ct_logs:start_log/1
  
  start_log(Heading) ->
      log(start_log, [Heading]).
  
  %% ---------------------------------------------------------------------
  
  -spec cont_log(Format, Args) -> ok
   when Format :: io:format(),
        Args :: [term()].
  
  %% Log activities on the current connection.
  %% See ct_logs:cont_log/2
  
  cont_log(Format,Args) ->
      log(cont_log, [Format, Args]).
  
  %% ---------------------------------------------------------------------
  
  -spec cont_log_no_timestamp(Format, Args) -> ok
   when Format :: io:format(),
        Args :: [term()].
  
  %% Log activities on the current connection.
  %% See ct_logs:cont_log/2
  
  cont_log_no_timestamp(Format, Args) ->
      log(cont_log_no_timestamp, [Format, Args]).
  
  %% ---------------------------------------------------------------------
  
  -spec end_log() -> ok.
  
  %% Log activities on the current connection.
  %% See ct_logs:end_log/0
  
  end_log() ->
      log(end_log, []).
  
  %% ---------------------------------------------------------------------
  
  -spec do_within_time(Fun, Tmo)
     -> Result
   when Fun :: fun(),
        Tmo :: non_neg_integer(),
        Result :: term().
  
  %% Return the result of evaluating Fun, or interrupt after Tmo
  %% milliseconds or if the connection is closed.
  
  do_within_time(Fun,Timeout) ->
      Self = self(),
      Silent = get(silent),
  