lib/rubydns/server.rb in rubydns-0.4.1 vs lib/rubydns/server.rb in rubydns-0.5.0

- old
+ new

@@ -168,27 +168,54 @@ answer.aa = 1 # Is this an authoritative response: 0 = No, 1 = Yes answer.rd = query.rd # Is Recursion Desired, copied from query answer.ra = 0 # Does name server support recursion: 0 = No, 1 = Yes answer.rcode = 0 # Response code: 0 = No errors - query.each_question do |question, resource_class| # There may be multiple questions per query - transaction = Transaction.new(self, query, question, resource_class, answer) + # 1/ This chain contains a reverse list of question lambdas. + chain = [] - begin - transaction.process - rescue - @logger.error "Exception thrown while processing #{transaction}!" - @logger.error "#{$!.class}: #{$!.message}" - $!.backtrace.each { |at| @logger.error at } + # 4/ Finally, the answer is given back to the calling block: + chain << lambda do + @logger.debug "Passing answer back to caller..." + yield answer + end - answer.rcode = Resolv::DNS::RCode::ServFail + # There may be multiple questions per query + query.question.reverse.each do |question, resource_class| + next_link = chain.last + + chain << lambda do + @logger.debug "Processing question #{question} #{resource_class}..." + + transaction = Transaction.new(self, query, question, resource_class, answer) + + # Call the next link in the chain: + transaction.callback do + # 3/ ... which calls the previous item in the chain, i.e. the next question to be answered: + next_link.call + end + + # If there was an error, log it and fail: + transaction.errback do |response| + @logger.error "Exception thrown while processing #{transaction}!" + @logger.error "#{response.class}: #{response.message}" + response.backtrace.each { |at| @logger.error at } + + answer.rcode = Resolv::DNS::RCode::ServFail + + chain.first.call + end + + begin + # Transaction.process will call succeed if it wasn't deferred: + transaction.process + rescue + transaction.fail($!) + end end end - if block_given? - yield answer - else - return answer - end + # 2/ We call the last lambda... + chain.last.call end end end