anchor.diff:  
   -export([do_handle/3]).
   
  -% Gen server hooks
  +%% Gen server hooks
   -export([init/1,
            handle_call/3,
            handle_cast/2,
  
positive.code:          code_change/3
          ]).
  
  % Internal API
  -export([handle_message/3]).
  
  -record(state, {handlers}).
  
negative.code: %% Note: this should probably be changed to return the original packet without
  %% any answer data and with TC bit set to 1.
  handle(Message, ClientIP, _ServerIP, {throttled, ClientIP, _ReqCount}) ->
      folsom_metrics:notify({request_throttled_counter, {inc, 1}}),
      folsom_metrics:notify({request_throttled_meter, 1}),
      Message#dns_message{tc = true, aa = true, rc = ?DNS_RCODE_NOERROR};
  
  %% Message was not throttled, so handle it, then do EDNS handling, optionally
  %% append the SOA record if it is a zone transfer and complete the response
  %% by filling out count-related header fields.
  handle(Message, ClientIP, ServerIP, _) ->
      erldns_events:notify({start_handle, [{host, ClientIP}, {message, Message}]}),
      Response = folsom_metrics:histogram_timed_update(request_handled_histogram, ?MODULE, do_handle,
                                                       [Message, ClientIP, ServerIP]),
      erldns_events:notify({end_handle, [{host, ClientIP}, {message, Message}, {response, Response}]}),
      Response.
  
  do_handle(Message, ClientIP, ServerIP) when Message#dns_message.oc =:= ?DNS_OPCODE_NOTIFY ->
      gen_server:cast(erldns_manager, {handle_notify, {Message, ClientIP, ServerIP}}),
      Message#dns_message{qr = true};
  do_handle(Message, ClientIP, ServerIP) ->
      NewMessage = handle_message(Message, ClientIP, ServerIP),
      complete_response(erldns_axfr:optionally_append_soa(erldns_edns:handle(NewMessage))).
  
  %% Handle the message by hitting the packet cache and either
  %% using the cached packet or continuing with the lookup process.
  %%
  %% If the cache is missed, then the SOA (Start of Authority) is discovered here.
  %% NOTE: 15 Decemember 2014 We removed use of the packet cache module.
  handle_message(Message, ClientIP, ServerIP) ->
      handle_packet_cache_miss(Message, get_authority(Message), ClientIP, ServerIP). % SOA lookup
  
  %% If the packet is not in the cache and we are not authoritative (because there
  %% is no SOA record for this zone), then answer immediately setting the AA flag to false.
  %% If erldns is configured to use root hints then those will be added to the response.
  handle_packet_cache_miss(Message, [], _ClientIP, _ServerIP) ->
      case erldns_config:use_root_hints() of
          true ->
              {Authority, Additional} = erldns_records:root_hints(),
              Message#dns_message{aa = false, rc = ?DNS_RCODE_NOERROR, authority = Authority, additional = Additional};
          _ ->
              Message#dns_message{aa = false, rc = ?DNS_RCODE_NOERROR}
      end;
  
  %% The packet is not in the cache yet we are authoritative, so try to resolve
  %% the request. This is the point the request moves on to the erldns_resolver
  %% module.
  handle_packet_cache_miss(Message, AuthorityRecords, ClientIP, ServerIP) ->
      safe_handle_packet_cache_miss(Message#dns_message{ra = false}, AuthorityRecords, ClientIP, ServerIP).
  
  safe_handle_packet_cache_miss(Message, AuthorityRecords, ClientIP, ServerIP) ->
      case application:get_env(erldns, catch_exceptions) of
          {ok, false} ->
              Response = erldns_resolver:resolve(Message, AuthorityRecords, {ClientIP, ServerIP}),
              maybe_cache_packet(Response, Response#dns_message.aa);
          _ ->
              try erldns_resolver:resolve(Message, AuthorityRecords, {ClientIP, ServerIP}) of
                  Response -> maybe_cache_packet(Response, Response#dns_message.aa)
              catch
                  Exception:Reason ->
                      erldns_log:error("Error answering request: ~p (~p)", [Exception, Reason]),
                      Message#dns_message{aa = false, rc = ?DNS_RCODE_SERVFAIL}
              end
      end.
  
  %% We are authoritative so cache the packet and return the message.
  maybe_cache_packet(Message, true) ->
      Message;
  
  %% We are not authoritative so just return the message.
  maybe_cache_packet(Message, false) ->
      Message.
  
  %% Get the SOA authority for the current query.
  get_authority(MessageOrName) ->
      case erldns_zone_cache:get_authority(MessageOrName) of
          {ok, Authority} ->
              [Authority];
          {error, _} -> []
      end.
  
  %% Update the message counts and set the QR flag to true.
  complete_response(Message) ->
      Message#dns_message{
        anc = length(Message#dns_message.answers),
        auc = length(Message#dns_message.authority),
        adc = length(Message#dns_message.additional),
        qr = true
       }.
  