/**
* Copyright 2008 - CommonCrawl Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
**/
package org.commoncrawl.service.dns;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.commoncrawl.async.EventLoop;
import org.commoncrawl.async.Timer;
import org.commoncrawl.crawl.common.internal.CrawlEnvironment;
import org.commoncrawl.io.NIODNSCache;
import org.commoncrawl.io.NIODNSLocalResolver;
import org.commoncrawl.rpc.base.internal.AsyncClientChannel;
import org.commoncrawl.rpc.base.internal.AsyncRequest;
import org.commoncrawl.rpc.base.internal.Server;
import org.commoncrawl.rpc.base.internal.AsyncRequest.Callback;
import org.commoncrawl.rpc.base.shared.RPCException;
import org.commoncrawl.util.CCStringUtils;
import org.commoncrawl.util.IPAddressUtils;
import org.commoncrawl.util.JVMStats;
/**
*
* @author rana
*
*/
public class DNSServiceTester extends Server implements AsyncClientChannel.ConnectionCallback {
private static final Log LOG = LogFactory.getLog(DNSServiceTester.class);
EventLoop _eventLoop = null;
InetSocketAddress _address = null;
AsyncClientChannel _channel;
DNSService.AsyncStub _serviceStub;
long _connectionCookie = 0;
Semaphore _blockingSempahore = new Semaphore(0);
long _testItemCount = 0;
// long _itemsComplete = 0;
AtomicLong _itemsComplete = new AtomicLong();
File _testFile = null;
String _testName = "";
public static void main(String[] args) {
InetSocketAddress socketAddress = new InetSocketAddress(args[0],CrawlEnvironment.DNS_SERVICE_RPC_PORT);
// File testFileLocation = new File(args[1]);
if (socketAddress != null && args[1].length() != 0) {
DNSServiceTester tester = new DNSServiceTester(socketAddress,args[1]);
LOG.info("Waiting for Event Loop to Terminate");
try {
tester._eventLoop.getEventThread().join();
} catch (InterruptedException e) {
}
LOG.info("Event Loop Terminated");
}
else {
LOG.error("Invalid Local Address Specified!");
}
}
public DNSServiceTester(InetSocketAddress address,String queryName) {
_eventLoop = new EventLoop();
_address = address;
_testFile = null;;
_testName = queryName;
_eventLoop.start();
try {
start();
} catch (IOException e) {
LOG.error(CCStringUtils.stringifyException(e));
_eventLoop.stop();
return;
}
_eventLoop.setTimer(new Timer(0,false,new Timer.Callback() {
@Override
public void timerFired(Timer timer) {
connect();
}
}));
}
void connect() {
try {
_channel = new AsyncClientChannel(_eventLoop,new InetSocketAddress(0),_address,this);
_channel.open();
_serviceStub = new DNSService.AsyncStub(_channel);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
void doSimpleQuery(String dnsName) {
LOG.info("Doing Simple Query for Name:" + dnsName);
DNSQueryInfo queryInfo = new DNSQueryInfo();
queryInfo.setHostName(dnsName);
//TODO: PASS TIMEOUT VALUE TO THE DNS SERVER SERVICE
try {
_serviceStub.doQuery(queryInfo, new Callback<DNSQueryInfo,DNSQueryResponse>() {
@Override
public void requestComplete(AsyncRequest<DNSQueryInfo, DNSQueryResponse> request) {
if (request.getStatus() == AsyncRequest.Status.Success) {
if (request.getOutput().getStatus() == DNSQueryResponse.Status.SUCCESS) {
String strIPAddress = null;
String strCName = "";
String strTTL = "";
strIPAddress = IPAddressUtils.IntegerToIPAddressString(request.getOutput().getAddress());
if (request.getOutput().isFieldDirty(DNSQueryResponse.Field_CNAME)) {
strCName = request.getOutput().getCname();
}
strTTL = Long.toString(request.getOutput().getTtl());
LOG.info("DNS Query Succeeded. IP:" + strIPAddress + " CName:" + strCName + " TTL:" + strTTL);
}
else {
String strError = "UNKNOWN ERROR";
switch (request.getOutput().getStatus()) {
case DNSQueryResponse.Status.RESOLVER_FAILURE: {
strError = "RESOLVER FAILURE (";
strError += request.getOutput().getErrorDesc();
strError += ")";
}
default: {
strError = "SERVER FAILURE (";
strError += request.getOutput().getErrorDesc();
strError += ")";
}
}
LOG.info("DNS Query Failed with Error:" + strError);
}
}
else {
LOG.info("DNS Query Failed with RPC ERROR");
}
_eventLoop.stop();
}
});
}
catch (RPCException e) {
LOG.error("RPC Exception:" + CCStringUtils.stringifyException(e));
_eventLoop.stop();
}
}
void startTest(File testFileLocation) {
LOG.info("Starting Test...");
LOG.info("Loading DNS Test File:" + testFileLocation);
JVMStats.dumpMemoryStats();
FileReader reader = null;
NIODNSCache cache = NIODNSLocalResolver.getDNSCache();
try {
reader = new FileReader(testFileLocation);
BufferedReader lineReader = new BufferedReader(reader);
String line = null;
HashSet<String> hostSet = new HashSet<String>();
while ((line = lineReader.readLine()) != null) {
int firstDelimiterIdx = line.indexOf(",/");
int secondDelimiterIdx = -1;
int thirdDelimiterIdx = -1;
if (firstDelimiterIdx != -1) {
secondDelimiterIdx = line.indexOf(',',firstDelimiterIdx+2);
thirdDelimiterIdx = line.indexOf(',',secondDelimiterIdx + 1);
}
if (firstDelimiterIdx != -1 && secondDelimiterIdx != -1) {
final String hostName = line.substring(0,firstDelimiterIdx);
final String ipAddress = line.substring(firstDelimiterIdx + 2,secondDelimiterIdx);
int ipAddressInteger = IPAddressUtils.IPV4AddressStrToInteger(ipAddress);
LOG.info("Querying Service for Address for Host:" + hostName);
DNSQueryInfo queryInfo = new DNSQueryInfo();
queryInfo.setHostName(hostName);
// increase item count
_testItemCount++;
_serviceStub.doQuery(queryInfo, new Callback<DNSQueryInfo,DNSQueryResponse>() {
@Override
public void requestComplete(AsyncRequest<DNSQueryInfo, DNSQueryResponse> request) {
if (request.getOutput().getStatus() == DNSQueryResponse.Status.SUCCESS) {
LOG.info("Request Succeeded for Host:" + hostName
+ " IPAddress:" + IPAddressUtils.IntegerToIPAddressString(request.getOutput().getAddress())
+ " TTL:" + request.getOutput().getTtl() + "(" +(request.getOutput().getTtl() - System.currentTimeMillis()) + ")Source:" + request.getOutput().getSourceServer());
}
else {
LOG.info("Request Failed for Host:" + hostName + " Reason:" + request.getOutput().getErrorDesc() + " Source:" + request.getOutput().getSourceServer());
}
LOG.info("Total:" + _testItemCount + " Complete:" + _itemsComplete.get());
_itemsComplete.incrementAndGet();
// release the semaphore
_blockingSempahore.release();
}
});
}
if (_testItemCount - _itemsComplete.get() > 5000) {
LOG.info("Queued Count:" + (_testItemCount-_itemsComplete.get()) + ". Waiting for Queued Count to drop to 1000");
while (_testItemCount - _itemsComplete.get() > 1000) {
LOG.info("Waiting for Count to Go Below 1000 ("+ (_testItemCount - _itemsComplete.get()) + ")");
try {
_blockingSempahore.acquire();
} catch (InterruptedException e) {
}
}
}
}
LOG.info("Done Processing Test File. Entry Count:" + _testItemCount);
JVMStats.dumpMemoryStats();
} catch (IOException e) {
LOG.error(CCStringUtils.stringifyException(e));
}
finally {
try {
reader.close();
} catch (IOException e) {
LOG.error(CCStringUtils.stringifyException(e));
}
}
LOG.info("Waiting on all items to complete...");
while (_itemsComplete.get() != _testItemCount) {
try {
_blockingSempahore.acquire();
} catch (InterruptedException e) {
}
if (_itemsComplete.get() % 1000 == 0) {
LOG.info("Completed Another 1000 Items");
}
}
LOG.info("All items to completed...");
}
@Override
public void OutgoingChannelConnected(AsyncClientChannel channel) {
LOG.info("Connected to Service. Starting Test Thread");
new Thread(new Runnable() {
@Override
public void run() {
LOG.info("Test Thread Started...");
doSimpleQuery(_testName);
}
}).start();
}
@Override
public boolean OutgoingChannelDisconnected(AsyncClientChannel channel) {
LOG.error("Connection to DNS Service Severed. Exiting ... ");
_eventLoop.stop();
return false;
}
}