/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* 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 staticContent.evaluation.encDnsPingTool;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.Random;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Quartz Job for sending queries (part of the DNSPing tool).
*
* @author Jens Lindemann
*/
public class SendJob implements Job {
private long _tdiff;
private DNSPing _main;
private Random _rnd;
private boolean _ignore; // Ignore this query for measurement purposes?
/**
* Constructor for creating a new SendJob
*/
public SendJob() {
_rnd = new Random();
}
public void execute(JobExecutionContext jec) throws JobExecutionException {
JobDataMap jdm = jec.getJobDetail().getJobDataMap();
_main = (DNSPing)(jdm.get("mainclassobj"));
// Report that a new SendJob was started and determine whether the
// RTT should be ignored for measurement purposes.
_ignore = _main.reportSendJobStart();
//System.out.println("SendJob started");
// Create a new query message
byte[] query = _main.getQueryBytes();
// Start the query handling method
byte[] reply = sendQueryAndListenForReply(query);
// If the RTT should be ignored, do not report it to the DNSPing class
if(_ignore) return;
// Check whether response is valid (matching IDs and not null)
boolean validReply = false;
if (reply != null) {
if((reply[3]&0x0f) == 0) { // check whether reply code is 0 (no error)
byte[] qid = Arrays.copyOfRange(query, 0, 2);
byte[] rid = Arrays.copyOfRange(reply, 0, 2);
if (Arrays.equals(qid, rid)) {
validReply = true;
}
}
}
if(validReply) {
// If reponse is valid, report success and RTT to DNSPing
_main.responseReceived(_tdiff);
} else {
// else report an error.
_main.queryError();
}
}
/**
* Sends a query to the nameserver and waits for a response
* @param query query to send to nameserver
* @return response received from nameserver
*/
private byte[] sendQueryAndListenForReply(byte[] query) {
try {
// Open UDP socket on new port
DatagramSocket udpSock = null;
while (udpSock == null) {
try {
int port = 1024 + _rnd.nextInt(64512);
udpSock = new DatagramSocket(port);
} catch (SocketException e) {
// do nothing as this is being caught by the while loop
}
}
// Send query to nameserver
DatagramPacket sendPacket = new DatagramPacket(query,
query.length, _main._targetNSAddress, _main._targetNSPort);
long tbefore = System.nanoTime(); // record send time
// Report that a new query is being sent
_main.querySent(tbefore);
udpSock.send(sendPacket);
// Wait for a response
byte[] rcvbytes = new byte[DNSPing.MAX_MSG_SIZE];
DatagramPacket rcvPkt = new DatagramPacket(rcvbytes, rcvbytes.length);
udpSock.setSoTimeout(_main.TIMEOUT);
udpSock.receive(rcvPkt);
// Record receive time of response and calculate RTT
long tafter = System.nanoTime();
_tdiff = tafter-tbefore;
udpSock.close();
byte[] rcvDNS = new byte[rcvPkt.getLength()];
System.arraycopy(rcvPkt.getData(), rcvPkt.getOffset(), rcvDNS, 0, rcvPkt.getLength());
//System.out.println("Received response from aNS");
return rcvDNS;
} catch (SocketTimeoutException e) {
System.err.println("Query timed out.");
if(!_ignore) {
// If this is not a warmup query, report timeout to DNSPing
_main.queryTimedOut();
}
return null;
} catch (IOException e) {
System.err.println("IO error:");
System.err.println(e);
return null;
}
}
}