private Message sendAXFR(Message query) throws IOException { Name qname = query.getQuestion().getName(); ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(qname, address, tsig); xfrin.setTimeout((int) (getTimeout() / 1000)); xfrin.setLocalAddress(localAddress); try { xfrin.run(); } catch (ZoneTransferException e) { throw new WireParseException(e.getMessage()); } List records = xfrin.getAXFR(); Message response = new Message(query.getHeader().getID()); response.getHeader().setFlag(Flags.AA); response.getHeader().setFlag(Flags.QR); response.addRecord(query.getQuestion(), Section.QUESTION); Iterator it = records.iterator(); while (it.hasNext()) response.addRecord((Record) it.next(), Section.ANSWER); return response; }
/** * Asynchronously sends a message to a single server, registering a listener to receive a callback * on success or exception. Multiple asynchronous lookups can be performed in parallel. Since the * callback may be invoked before the function returns, external synchronization is necessary. * * @param query The query to send * @param listener The object containing the callbacks. * @return An identifier, which is also a parameter in the callback */ public Object sendAsync(final Message query, final ResolverListener listener) { final Object id; synchronized (this) { id = new Integer(uniqueID++); } Record question = query.getQuestion(); String qname; if (question != null) qname = question.getName().toString(); else qname = "(none)"; String name = this.getClass() + ": " + qname; Thread thread = new ResolveThread(this, query, id, listener); thread.setName(name); thread.setDaemon(true); thread.start(); return id; }
private int uniqueID(Message m) { Record r = m.getQuestion(); return (((r.getName().hashCode() & 0xFFFF) << 16) + (r.getType() + hashCode() << 8) + (hashCode() & 0xFF)); }
/** * Sends a message to a single server and waits for a response. No checking is done to ensure that * the response is associated with the query. * * @param query The query to send. * @return The response. * @throws IOException An error occurred while sending or receiving. */ public Message send(Message query) throws IOException { if (Options.check("verbose")) System.err.println( "Sending to " + address.getAddress().getHostAddress() + ":" + address.getPort()); if (query.getHeader().getOpcode() == Opcode.QUERY) { Record question = query.getQuestion(); if (question != null && question.getType() == Type.AXFR) return sendAXFR(query); } query = (Message) query.clone(); applyEDNS(query); if (tsig != null) { tsig.apply(query, null); } byte[] out = query.toWire(Message.MAXLENGTH); int udpSize = maxUDPSize(query); boolean tcp = false; long endTime = System.currentTimeMillis() + timeoutValue; do { byte[] b_in; if (useTCP || out.length > udpSize) { tcp = true; } if (tcp) { b_in = TCPClient.sendrecv(localAddress, address, out, endTime); } else { b_in = UDPClient.sendrecv(localAddress, address, out, udpSize, endTime); } /* * Check that the response is long enough. */ if (b_in.length < Header.LENGTH) { throw new WireParseException("invalid DNS header - " + "too short"); } /* * Check that the response ID matches the query ID. We want * to check this before actually parsing the message, so that * if there's a malformed response that's not ours, it * doesn't confuse us. */ int id = ((b_in[0] & 0xFF) << 8) + (b_in[1] & 0xFF); int qid = query.getHeader().getID(); if (id != qid) { String error = "invalid message id: expected " + qid + "; got id " + id; if (tcp) { throw new WireParseException(error); } else { if (Options.check("verbose")) { System.err.println(error); } continue; } } Message response = parseMessage(b_in); verifyTSIG(query, response, b_in, tsig); if (!tcp && !ignoreTruncation && response.getHeader().getFlag(Flags.TC)) { tcp = true; continue; } return response; } while (true); }