anchor.diff:       | sockaddrs(IPs, TP, Domain)].
   
   %% -------------------------------------------------------------------------
  -
  -setopts_split(FilterTags, Opts) ->
  -    setopts_split(FilterTags, Opts, [], []).
  -%%
  -setopts_split(_FilterTags, [], True, False) ->
  -    {reverse(True), reverse(False)};
  -setopts_split(FilterTags, [Opt | Opts], True, False) ->
  -    %% ?DBG({FilterTags, Opt}),
  -    Opt_1 = conv_setopt(Opt),
  -    case member(FilterTags, setopt_categories(Opt_1)) of
  -        true ->
  -            setopts_split(FilterTags, Opts, [Opt_1 | True], False);
  -        false ->
  -            setopts_split(FilterTags, Opts, True, [Opt_1 | False])
  -    end.
  -
  -
  -%% Set operation on atom sets that are atoms or maps with atom tags.
  -%% Returns true if sets have at least one common member, false otherwise.
  -%% X is atom() or map(), Y is map().
  -member(X, Y) when is_atom(X), is_map(Y) ->
  -    case Y of
  -        #{X := _} -> true;
  -        #{} -> false
  +%% Make all options 2-tuple options.
  +%% Convert special options i.e {raw, Level, Key, Value}.
  +%% Pass through 2-tuple options with atom tag.
  +%% Reject all other terms by exit(badarg).
  +%%
  +
  +normalize_setopts(Opts) ->
  +    filtermap_opts(fun normalize_setopt/1, Opts).
  +
  +normalize_setopt(Opt) ->
  +    case Opt of
  +        {Tag, _Val} when is_atom(Tag) ->
  +            true;
  +        %%
  +        binary  -> {mode, binary};
  +        list    -> {mode, list};
  +        inet    -> {tcp_module, inet_tcp};
  +        inet6   -> {tcp_module, inet6_tcp};
  +        local   -> {tcp_module, local_tcp};
  +        {raw, Level, Key, Value} ->
  +            {raw, {Level, Key, Value}};
  +        %%
  +        _ ->
  +            exit(badarg)
  +    end.
  +
  +normalize_getopts(Opts) ->
  +    filtermap_opts(fun normalize_getopt/1, Opts).
  +
  +normalize_getopt(Opt) ->
  +    case Opt of
  +        Tag when is_boolean(Tag) -> exit(badarg);
  +        Tag when is_atom(Tag)    -> true;
  +        {raw, _}                 -> true;
  +        {raw, Level, Key, Value} -> {raw, {Level, Key, Value}};
  +        _                        -> exit(badarg)
  +    end.
  +
  +%%
  +%% -------
  +%% Split options into server start options and other options.
  +%% Convert our {sys_debug, _} option into {debug, _} (the
  +%% sys_debug option is how to pass a debug option to
  +%% gen_statem:start/3).  A {debug,VaL} opion is later
  +%% transformed into the socket option {{otp,debug}, Val}.
  +%%
  +
  +split_start_opts(Opts) ->
  +    splitmap_opts(fun split_start_opt/1, Opts).
  +
  +split_start_opt(Opt) ->
  +    case Opt of
  +        {sys_debug, Val} -> {debug, Val};
  +        _                -> false
  +    end.
  +
  +%%
  +%% -------
  +%% Verify that all options can be set with setopts/2 after
  +%% opening the socket.  They should be known socket options,
  +%% options handled by the server, or options we should ignore.
  +%% filter out the ignored options and fail for unknown options
  +%% by throwing {ErrRef, badarg}.
  +%%
  +setopts_opts(ErrRef, Opts) ->
  +    filtermap_opts(setopts_opt(ErrRef), Opts).
  +
  +setopts_opt(ErrRef) ->
  +    SocketOpts = socket_opts(),
  +    ServerOpts = server_opts(),
  +    fun ({Tag,_Val}) ->
  +            if
  +                is_map_key(Tag, SocketOpts) -> true;
  +                is_map_key(Tag, ServerOpts) -> true;
  +                true ->
  +                    case ignore_optname(Tag) of
  +                        true  -> false; % ignore -> filter out
  +                        false ->
  +                            throw({ErrRef, badarg})
  +                    end
  +            end
  +    end.
  +%%
  +%% -------
  +%% Pseudo-general option list functions
  +%%
  +
  +%% FilterMap(Opt) ->
  +%%     true  | % keep
  +%%     false | % delete
  +%%     Opt_1 | % keep Opt_1
  +%%
  +filtermap_opts(FilterMap, Opts) ->
  +    case filtermap_opts_1(FilterMap, Opts) of
  +        ok     -> Opts;
  +        Opts_1 -> Opts_1
  +    end.
  +%%
  +filtermap_opts_1(FilterMap, [Opt | Opts]) ->
  +    Opts_1 = filtermap_opts_1(FilterMap, Opts),
  +    case FilterMap(Opt) of
  +        true  when Opts_1 =:= ok -> ok;
  +        true                     -> [Opt | Opts_1];
  +        false when Opts_1 =:= ok -> Opts;
  +        false                    -> Opts_1;
  +        Opt_1 when Opts_1 =:= ok -> [Opt_1 | Opts];
  +        Opt_1                    -> [Opt_1 | Opts_1]
       end;
  -member(X, Y) when is_map(X), is_map(Y) ->
  -    maps:fold(
  -      fun (_, _, true) -> true;
  -          (Key, _, false) -> maps:is_key(Key, Y)
  -      end, false, X).
  -
  -
  -conv_setopt(binary) -> {mode, binary};
  -conv_setopt(list) -> {mode, list};
  -conv_setopt(inet) -> {tcp_module, inet_tcp};
  -conv_setopt(inet6) -> {tcp_module, inet6_tcp};
  -conv_setopt(local) -> {tcp_module, local_tcp};
  -conv_setopt(Other) -> Other.
  +filtermap_opts_1(_FilterMap, []) -> ok.
  +
  +
  +%% splitmap_opts(SplitMap, Opts) ->
  +%%     {SplitOpts, OtherOpts}
  +%%
  +%% SplitMap(Opt) ->
  +%%     true  -> % to be split
  +%%     false -> % not to split
  +%%     Opt_1 -> % split Opt_1
  +%%
  +splitmap_opts(SplitMap, Opts) ->
  +    case splitmap_opts_1(SplitMap, Opts) of
  +        ok                    -> {[], Opts};
  +        [SplitOptsR | Opts_1] -> {lists:reverse(SplitOptsR), Opts_1}
  +    end.
  +%%
  +splitmap_opts_1(SplitMap, [Opt | Opts]) ->
  +    case splitmap_opts_1(SplitMap, Opts) of
  +        ok ->
  +            case SplitMap(Opt) of
  +                false -> ok;
  +                true  -> [[]      | Opts];
  +                Opt_1 -> [[Opt_1] | Opts]
  +            end;
  +        [SplitOptsR | Opts_1] ->
  +            case SplitMap(Opt) of
  +                false -> [SplitOptsR           | [Opt | Opts_1]];
  +                true  -> [[Opt   | SplitOptsR] | Opts_1];
  +                Opt_1 -> [[Opt_1 | SplitOptsR] | Opts_1]
  +            end
  +    end;
  +splitmap_opts_1(_SplitMap, []) -> ok.
  +
  +%%
  +%% -------
  +
  +
  +
  +
  +
   
   %% Socket options
   
  -socket_setopt(Socket, {raw, Level, Key, Value}) ->
  -    socket:setopt_native(Socket, {Level,Key}, Value);
  -socket_setopt(Socket, {raw, {Level, Key, Value}}) ->
  -    socket:setopt_native(Socket, {Level,Key}, Value);
  -socket_setopt(Socket, {Tag, Value}) ->
  -    %% ?DBG({Tag, Value}),
  -    case socket_opt() of
  -        #{Tag := {Domain, _} = Opt} when is_atom(Domain) ->
  -            %% ?DBG(Opt),
  -            %% socket:setopt(Socket, otp, debug, true),
  -            Res = socket:setopt(Socket, Opt, socket_setopt_value(Tag, Value)),
  -            %% socket:setopt(Socket, otp, debug, false),
  -            Res;
  -
  -        #{Tag := DomainProps} when is_list(DomainProps) ->
  -            %% We need to lookup the domain of the socket,
  -            %% so we can select which one to use.                            
  -            %% ?DBG(Opt0),
  -            case socket:getopt(Socket, otp, domain) of
  -                {ok, Domain} ->
  -                    case lists:keysearch(Domain, 1, DomainProps) of
  -                        {value, {Domain, Level, OptKey}} ->
  -                            Opt = {Level, OptKey},
  -                            %% _ = socket:setopt(Socket, otp, debug, true),
  -                            Res = socket:setopt(Socket,
  -                                                Opt,
  -                                                socket_setopt_value(Tag,
  -                                                                    Value)),
  -                            %% _ = socket:setopt(Socket, otp, debug, false),
  -                            Res;
  -                        false ->
  -                            {error, einval}
  -                    end;
  -                {error, _} ->
  +socket_setopt(Socket, raw, Value) ->
  +    case Value of
  +        {Level, Key, Val} ->
  +            socket:setopt_native(Socket, {Level,Key}, Val);
  +        _ ->
  +            {error, einval}
  +    end;
  +socket_setopt(Socket, {Domain, _} = Opt, Value) when is_atom(Domain) ->
  +    %% ?DBG(Opt),
  +    %% socket:setopt(Socket, otp, debug, true),
  +    Res = socket:setopt(Socket, Opt, socket_setopt_value(Opt, Value)),
  +    %% socket:setopt(Socket, otp, debug, false),
  +    Res;
  +socket_setopt(Socket, DomainProps, Value) when is_list(DomainProps) ->
  +    %% We need to lookup the domain of the socket,
  +    %% so we can select which one to use.
  +    %% ?DBG(Opt0),
  +    case socket:getopt(Socket, otp, domain) of
  +        {ok, Domain} ->
  +            case lists:keysearch(Domain, 1, DomainProps) of
  +                {value, {Domain, Opt}} ->
  +                    %% _ = socket:setopt(Socket, otp, debug, true),
  +                    Res =
  +                        socket:setopt(
  +                          Socket, Opt,
  +                          socket_setopt_value(Opt, Value)),
  +                    %% _ = socket:setopt(Socket, otp, debug, false),
  +                    Res;
  +                false ->
                       {error, einval}
               end;
  -
  -        #{} ->
  +        {error, _} ->
               {error, einval}
       end.
   
  -socket_setopt_value(linger, {OnOff, Linger}) ->
  +socket_setopt_value({socket,linger}, {OnOff, Linger}) ->
       #{onoff => OnOff, linger => Linger};
  -socket_setopt_value(_Tag, Value) -> Value.
  -
  -socket_getopt(Socket, {raw, Level, Key, ValueSpec}) ->
  -    socket:getopt_native(Socket, {Level,Key}, ValueSpec);
  -socket_getopt(Socket, {raw, {Level, Key, ValueSpec}}) ->
  -    socket:getopt_native(Socket, {Level,Key}, ValueSpec);
  -socket_getopt(Socket, Tag) when is_atom(Tag) ->
  -    case socket_opt() of
  -        #{Tag := {Domain, _} = Opt} when is_atom(Domain) ->
  -            %% ?DBG({'socket_getopt - match', Tag}),
  -            %% _ = socket:setopt(Socket, otp, debug, true),
  -            Res = socket:getopt(Socket, Opt),
  -            %% ?DBG({'socket_getopt - result', Res}),
  -            %% _ = socket:setopt(Socket, otp, debug, false),
  -            socket_getopt_value(Tag, Res);
  -
  -        #{Tag := DomainProps} when is_list(DomainProps) ->
  -            %% We need to lookup the domain of the socket,
  -            %% so we can select which one to use.                            
  -            %% ?DBG({'socket_getopt - match', Tag, DomainProps}),
  -            case socket:getopt(Socket, otp, domain) of
  -                {ok, Domain} ->
  -                    %% ?DBG({'socket_getopt - domain', Tag, Domain}),
  -                    case lists:keysearch(Domain, 1, DomainProps) of
  -                        {value, {Domain, Level, OptKey}} ->
  -                            %% ?DBG({'socket_getopt - ok domain', Tag, Level, OptKey}),
  -                            Opt  = {Level, OptKey},
  -                            %% _ = socket:setopt(Socket, otp, debug, true),
  -                            Res = socket:getopt(Socket, Opt),
  -                            %% _ = socket:setopt(Socket, otp, debug, false),
  -                            %% ?DBG({'socket_getopt - result', Res}),
  -                            socket_getopt_value(Tag, Res);
  -                        false ->
  -                            %% ?DBG({'socket_getopt - invalid domain', Tag, Domain, DomainProps}),
  -                            {error, einval}
  -                    end;
  -                {error, _DReason} ->
  -                    %% ?DBG({'socket_getopt - unknown domain', Tag, _DReason}),
  +socket_setopt_value(_Opt, Value) -> Value.
  +
  +
  +socket_getopt(Socket, raw, Val) ->
  +    case Val of
  +        {Level, Key, ValueSpec} ->
  +            socket:getopt_native(Socket, {Level,Key}, ValueSpec);
  +        _ ->
  +            {error, einval}
  +    end;
  +socket_getopt(Socket, {Domain, _} = Opt, _) when is_atom(Domain) ->
  +    %% ?DBG({'socket_getopt - match', Opt}),
  +    %% _ = socket:setopt(Socket, otp, debug, true),
  +    Res = socket:getopt(Socket, Opt),
  +    %% ?DBG({'socket_getopt - result', Res}),
  +    %% _ = socket:setopt(Socket, otp, debug, false),
  +    socket_getopt_value(Opt, Res);
  +socket_getopt(Socket, DomainProps, _) when is_list(DomainProps) ->
  +    %% We need to lookup the domain of the socket,
  +    %% so we can select which one to use.
  +    %% ?DBG({'socket_getopt - match', Tag, DomainProps}),
  +    case socket:getopt(Socket, otp, domain) of
  +        {ok, Domain} ->
  +            %% ?DBG({'socket_getopt - domain', Tag, Domain}),
  +            case lists:keysearch(Domain, 1, DomainProps) of
  +                {value, {Domain, Opt}} ->
  +                    %% ?DBG({'socket_getopt - ok domain', Tag, Level, OptKey}),
  +                    %% _ = socket:setopt(Socket, otp, debug, true),
  +                    Res = socket:getopt(Socket, Opt),
  +                    %% _ = socket:setopt(Socket, otp, debug, false),
  +                    %% ?DBG({'socket_getopt - result', Res}),
  +                    socket_getopt_value(Opt, Res);
  +                false ->
  +                    %% ?DBG({'socket_getopt - invalid domain', Tag, Domain, DomainProps}),
                       {error, einval}
               end;
  -
  -        #{} = __X__ ->
  -            %% ?DBG({'socket_getopt - no match - 2', Tag, __X__}),
  +        {error, _DReason} ->
  +            %% ?DBG({'socket_getopt - unknown domain', Tag, _DReason}),
               {error, einval}
       end.
   
  -socket_getopt_value(linger, {ok, #{onoff := OnOff, linger := Linger}}) ->
  +socket_getopt_value(
  +  {socket,linger}, {ok, #{onoff := OnOff, linger := Linger}}) ->
       {ok, {OnOff, Linger}};
  -socket_getopt_value(pktoptions, {ok, PktOpts0}) when is_list(PktOpts0) ->
  -    PktOpts = [{Type, Value} || #{type := Type, value := Value} <- PktOpts0],
  -    {ok, PktOpts};
  +socket_getopt_value({Level,pktoptions}, {ok, PktOpts})
  +  when Level =:= ip,   is_list(PktOpts);
  +       Level =:= ipv6, is_list(PktOpts) ->
  +    {ok, [{Type, Value} || #{type := Type, value := Value} <- PktOpts]};
   socket_getopt_value(_Tag, {ok, _Value} = Ok) -> Ok;
   socket_getopt_value(_Tag, {error, _} = Error) -> Error.
   
  +
   socket_copy_opt(Socket, Tag, TargetSocket) when is_atom(Tag) ->
  -    case socket_opt() of
  -        #{Tag := Opt} ->
  +    case socket_opts() of
  +        #{Tag := {_Level,_Key} = Opt} ->
   	    case socket:is_supported(options, Opt) of
   		true ->
   		    case socket:getopt(Socket, Opt) of
  
positive.code: socket_recv_peek(Socket, Length) ->
      Options = [peek],
      Result = socket:recv(Socket, Length, Options, nowait),
  %%%    ?DBG({Socket, Length, Options, Result}),
      Result.
  -compile({inline, [socket_recv/2]}).
  socket_recv(Socket, Length) ->
      Result = socket:recv(Socket, Length, nowait),
  %%%    ?DBG({Socket, Length, Result}),
      Result.
  
  -compile({inline, [socket_close/1]}).
  
negative.code: state_getopts(_P, _D, _State, [], Acc) ->
      {ok, reverse(Acc)};
  state_getopts(P, D, State, [Tag | Tags], Acc) ->
      SocketOpts = socket_opts(),
      {Key, Val} =
          case Tag of
              {_, _} -> Tag; % E.g the raw option
              _ when is_atom(Tag) -> {Tag, Tag}
          end,
      case maps:is_key(Key, SocketOpts) of
          true ->
              %% options for the socket module
              %%
              case P#params.socket of
                  undefined ->
                      {error, closed};
                  Socket ->
                      %% ?DBG({'socket getopt', Tag}),
                      case
                          socket_getopt(
                            Socket, maps:get(Tag, SocketOpts), Val)
                      of
                          {ok, Value} ->
                              %% ?DBG({'socket getopt', ok, Value}),
                              state_getopts(
                                P, D, State, Tags, [{Key, Value} | Acc]);
                          {error, _Reason} ->
                              %% ?DBG({'socket getopt', error, _Reason}),
                              state_getopts(P, D, State, Tags, Acc)
                      end
                end;
          false ->
              case maps:is_key(Key, server_write_opts()) of
                  %% server options for socket send hence
                  %% duplicated in {opt,meta}
                  %%
                  true when State =:= 'closed' ->
                      %% ?DBG('server write when closed'),
                      {error, einval};
                  true ->
                      %% ?DBG('server write'),
                      Value = maps:get(Key, D),
                      state_getopts(P, D, State, Tags, [{Key, Value} | Acc]);
                  false ->
                      case maps:is_key(Key, server_read_opts()) of
                          %% server options for receive
                          %%
                          true
                            when State =:= 'closed';
                                 State =:= 'closed_read';
                                 State =:= 'closed_read_write' ->
                              %% ?DBG('server read when closed*'),
                              {error, einval};
                          true ->
                              %% ?DBG('server read'),
                              Value = maps:get(Key, D),
                              state_getopts(
                                P, D, State, Tags, [{Key, Value} | Acc]);
                          false ->
                              %% ignored and invalid options
                              %%
                              case ignore_optname(Key) of
                                  true ->
                                      %% ?DBG({ignore, Tag}),
                                      state_getopts(P, D, State, Tags, Acc);
                                  false ->
                                      %% ?DBG({extra, Tag}),
                                      {error, einval}
                              end
                      end
              end
      end.
  
  %%
  %% -------
  
  handle_info(Socket, Owner, #{active := Active} = D) -> 
      %% Read counters
  