Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.covert.dns.collection; import io.covert.util.Pair; import io.covert.util.Utils; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.NoSuchElementException; import java.util.Random; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.collections.Bag; import org.apache.commons.collections.bag.HashBag; import org.apache.hadoop.io.Text; import org.apache.log4j.Logger; import org.xbill.DNS.DClass; import org.xbill.DNS.Message; import org.xbill.DNS.Name; import org.xbill.DNS.Rcode; import org.xbill.DNS.Record; import org.xbill.DNS.Resolver; import org.xbill.DNS.SimpleResolver; import org.xbill.DNS.TextParseException; import org.xbill.DNS.Type; public class ResolverThread extends Thread { private static final Logger LOG = Logger.getLogger(ResolverThread.class); volatile boolean keepRunning = true; Random random = new Random(); ConcurrentLinkedQueue<DnsRequest> inQueue; AtomicLong inQueueSize; ConcurrentLinkedQueue<Pair<Record, Message>> outQueue; Resolver[] resolvers; String[] nameservers; Bag rcodes = new HashBag(); long constructMessageMS = 0; long performRequestMS = 0; long parseResponseMS = 0; long totalRequestHandlingMS = 0; long numRequests = 0; long lookupsFailures = 0; long requestTimeouts = 0; long requestParseFailures = 0; public ResolverThread(ConcurrentLinkedQueue<DnsRequest> inQueue, AtomicLong inQueueSize, ConcurrentLinkedQueue<Pair<Record, Message>> outQueue, String[] nameservers, int timeoutSecs) { super(); this.inQueue = inQueue; this.inQueueSize = inQueueSize; this.outQueue = outQueue; this.nameservers = nameservers; resolvers = new Resolver[nameservers.length]; for (int i = 0; i < resolvers.length; ++i) { try { resolvers[i] = new SimpleResolver(nameservers[i]); resolvers[i].setTimeout(timeoutSecs); } catch (UnknownHostException e) { throw new RuntimeException("Could not initial resolver for host=" + nameservers[i]); } } } @Override public void run() { while (keepRunning || !inQueue.isEmpty()) { try { DnsRequest req = inQueue.remove(); inQueueSize.decrementAndGet(); long elapsed = System.currentTimeMillis(); Pair<Record, Message> resp = process(req); elapsed = System.currentTimeMillis() - elapsed; totalRequestHandlingMS += elapsed; numRequests++; if (resp != null) outQueue.add(resp); } catch (NoSuchElementException e) { Utils.sleep(100); } } } private Pair<Record, Message> process(DnsRequest req) { Record requestRecord = null; Pair<Record, Message> result = null; // pick a random nameserver int index = random.nextInt(resolvers.length); String nameserver = nameservers[index]; long elapsed = System.currentTimeMillis(); Message request; try { requestRecord = Record.newRecord(Name.fromString(req.getName()), req.getRequestType(), req.getDclass()); request = Message.newQuery(requestRecord); } catch (TextParseException e) { LOG.error("Failed to parse name: " + req); ++requestParseFailures; return null; } elapsed = System.currentTimeMillis() - elapsed; constructMessageMS += elapsed; elapsed = System.currentTimeMillis(); Message response = null; try { response = resolvers[index].send(request); rcodes.add(Rcode.string(response.getRcode())); result = new Pair<Record, Message>(requestRecord, response); } catch (SocketTimeoutException e) { LOG.error("Timed out when resolving name: " + req + " at nameserver: " + nameserver + ", reason: " + e.getMessage()); ++requestTimeouts; } catch (IOException e) { LOG.error("Failed resolving name: " + req + " at nameserver: " + nameserver + ", reason: " + e.getMessage()); ++lookupsFailures; } elapsed = System.currentTimeMillis() - elapsed; performRequestMS += elapsed; return result; } public void stopRunning() { this.keepRunning = false; } public long getConstructMessageMS() { return constructMessageMS; } public long getPerformRequestMS() { return performRequestMS; } public long getParseResponseMS() { return parseResponseMS; } public long getTotalRequestHandlingMS() { return totalRequestHandlingMS; } public long getNumRequests() { return numRequests; } public long getLookupsFailures() { return lookupsFailures; } public long getRequestParseFailures() { return requestParseFailures; } public long getRequestTimeouts() { return requestTimeouts; } public Bag getRcodes() { return rcodes; } public static void main(String[] args) throws Exception { ConcurrentLinkedQueue<DnsRequest> inQueue = new ConcurrentLinkedQueue<DnsRequest>(); AtomicLong inQueueSize = new AtomicLong(0); ConcurrentLinkedQueue<Pair<Record, Message>> outQueue = new ConcurrentLinkedQueue<Pair<Record, Message>>(); String[] nameservers = new String[] { "8.8.8.8" }; inQueue.add(new DnsRequest("www6.google.com.", Type.AAAA, DClass.IN)); inQueue.add(new DnsRequest("ipv6.google.com.", Type.AAAA, DClass.IN)); inQueue.add(new DnsRequest("gmail.com.", Type.AAAA, DClass.IN)); inQueueSize.incrementAndGet(); inQueueSize.incrementAndGet(); inQueueSize.incrementAndGet(); ResolverThread res = new ResolverThread(inQueue, inQueueSize, outQueue, nameservers, 5); res.start(); res.stopRunning(); res.join(); Pair<Record, Message> result = outQueue.remove(); System.out.println(result); result = outQueue.remove(); System.out.println(result); result = outQueue.remove(); System.out.println(result); } }