final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query0( InetSocketAddress nameServerAddr, DnsQuestion question, DnsRecord[] additionals, boolean flush, ChannelPromise writePromise, Promise<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>> promise) { assert !writePromise.isVoid(); final Promise<AddressedEnvelope<DnsResponse, InetSocketAddress>> castPromise = cast( checkNotNull(promise, "promise")); try { new DnsQueryContext(this, nameServerAddr, question, additionals, castPromise) .query(flush, writePromise); return castPromise; } catch (Exception e) { return castPromise.setFailure(e); } }
void query(boolean flush, ChannelPromise writePromise) { final DnsQuestion question = question(); final InetSocketAddress nameServerAddr = nameServerAddr(); final DatagramDnsQuery query = new DatagramDnsQuery(null, nameServerAddr, id); query.setRecursionDesired(recursionDesired); query.addRecord(DnsSection.QUESTION, question); for (DnsRecord record: additionals) { query.addRecord(DnsSection.ADDITIONAL, record); } if (optResource != null) { query.addRecord(DnsSection.ADDITIONAL, optResource); } if (logger.isDebugEnabled()) { logger.debug("{} WRITE: [{}: {}], {}", parent.ch, id, nameServerAddr, question); } sendQuery(query, flush, writePromise); }
private void writeQuery(final DnsQuery query, final boolean flush, final ChannelPromise writePromise) { final ChannelFuture writeFuture = flush ? parent.ch.writeAndFlush(query, writePromise) : parent.ch.write(query, writePromise); if (writeFuture.isDone()) { onQueryWriteCompletion(writeFuture); } else { writeFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) { onQueryWriteCompletion(writeFuture); } }); } }
private void setFailure(String message, Throwable cause) { final InetSocketAddress nameServerAddr = nameServerAddr(); final StringBuilder buf = new StringBuilder(message.length() + 64); buf.append('[') .append(nameServerAddr) .append("] ") .append(message) .append(" (no stack trace available)"); final DnsNameResolverException e; if (cause == null) { // This was caused by an timeout so use DnsNameResolverTimeoutException to allow the user to // handle it special (like retry the query). e = new DnsNameResolverTimeoutException(nameServerAddr, question(), buf.toString()); } else { e = new DnsNameResolverException(nameServerAddr, question(), buf.toString(), cause); } promise.tryFailure(e); }
void finish(AddressedEnvelope<? extends DnsResponse, InetSocketAddress> envelope) { final DnsResponse res = envelope.content(); if (res.count(DnsSection.QUESTION) != 1) { logger.warn("Received a DNS response with invalid number of questions: {}", envelope); return; } if (!question().equals(res.recordAt(DnsSection.QUESTION))) { logger.warn("Received a mismatching DNS response: {}", envelope); return; } setSuccess(envelope); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { try { final DatagramDnsResponse res = (DatagramDnsResponse) msg; final int queryId = res.id(); if (logger.isDebugEnabled()) { logger.debug("{} RECEIVED: [{}: {}], {}", ch, queryId, res.sender(), res); } final DnsQueryContext qCtx = queryContextManager.get(res.sender(), queryId); if (qCtx == null) { logger.warn("{} Received a DNS response with an unknown ID: {}", ch, queryId); return; } qCtx.finish(res); } finally { ReferenceCountUtil.safeRelease(msg); } }
private void sendQuery(final DnsQuery query, final boolean flush, final ChannelPromise writePromise) { if (parent.channelFuture.isDone()) { writeQuery(query, flush, writePromise); } else { parent.channelFuture.addListener(new GenericFutureListener<Future<? super Channel>>() { @Override public void operationComplete(Future<? super Channel> future) { if (future.isSuccess()) { // If the query is done in a late fashion (as the channel was not ready yet) we always flush // to ensure we did not race with a previous flush() that was done when the Channel was not // ready yet. writeQuery(query, true, writePromise); } else { Throwable cause = future.cause(); promise.tryFailure(cause); writePromise.setFailure(cause); } } }); } }
private void onQueryWriteCompletion(ChannelFuture writeFuture) { if (!writeFuture.isSuccess()) { setFailure("failed to send a query", writeFuture.cause()); return; } // Schedule a query timeout task if necessary. final long queryTimeoutMillis = parent.queryTimeoutMillis(); if (queryTimeoutMillis > 0) { timeoutFuture = parent.ch.eventLoop().schedule(new Runnable() { @Override public void run() { if (promise.isDone()) { // Received a response before the query times out. return; } setFailure("query timed out after " + queryTimeoutMillis + " milliseconds", null); } }, queryTimeoutMillis, TimeUnit.MILLISECONDS); } }
private void setSuccess(AddressedEnvelope<? extends DnsResponse, InetSocketAddress> envelope) { parent.queryContextManager.remove(nameServerAddr(), id); // Cancel the timeout task. final ScheduledFuture<?> timeoutFuture = this.timeoutFuture; if (timeoutFuture != null) { timeoutFuture.cancel(false); } Promise<AddressedEnvelope<DnsResponse, InetSocketAddress>> promise = this.promise; if (promise.setUncancellable()) { @SuppressWarnings("unchecked") AddressedEnvelope<DnsResponse, InetSocketAddress> castResponse = (AddressedEnvelope<DnsResponse, InetSocketAddress>) envelope.retain(); promise.setSuccess(castResponse); } }
private void setFailure(String message, Throwable cause) { final InetSocketAddress nameServerAddr = nameServerAddr(); final StringBuilder buf = new StringBuilder(message.length() + 64); buf.append('[') .append(nameServerAddr) .append("] ") .append(message) .append(" (no stack trace available)"); final DnsNameResolverException e; if (cause == null) { // This was caused by an timeout so use DnsNameResolverTimeoutException to allow the user to // handle it special (like retry the query). e = new DnsNameResolverTimeoutException(nameServerAddr, question(), buf.toString()); } else { e = new DnsNameResolverException(nameServerAddr, question(), buf.toString(), cause); } promise.tryFailure(e); }
void finish(AddressedEnvelope<? extends DnsResponse, InetSocketAddress> envelope) { final DnsResponse res = envelope.content(); if (res.count(DnsSection.QUESTION) != 1) { logger.warn("Received a DNS response with invalid number of questions: {}", envelope); return; } if (!question().equals(res.recordAt(DnsSection.QUESTION))) { logger.warn("Received a mismatching DNS response: {}", envelope); return; } setSuccess(envelope); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { try { final DatagramDnsResponse res = (DatagramDnsResponse) msg; final int queryId = res.id(); if (logger.isDebugEnabled()) { logger.debug("{} RECEIVED: [{}: {}], {}", ch, queryId, res.sender(), res); } final DnsQueryContext qCtx = queryContextManager.get(res.sender(), queryId); if (qCtx == null) { logger.warn("{} Received a DNS response with an unknown ID: {}", ch, queryId); return; } qCtx.finish(res); } finally { ReferenceCountUtil.safeRelease(msg); } }
private void sendQuery(final DnsQuery query, final ChannelPromise writePromise) { if (parent.channelFuture.isDone()) { writeQuery(query, writePromise); } else { parent.channelFuture.addListener(new GenericFutureListener<Future<? super Channel>>() { @Override public void operationComplete(Future<? super Channel> future) { if (future.isSuccess()) { writeQuery(query, writePromise); } else { Throwable cause = future.cause(); promise.tryFailure(cause); writePromise.setFailure(cause); } } }); } }
private void onQueryWriteCompletion(ChannelFuture writeFuture) { if (!writeFuture.isSuccess()) { setFailure("failed to send a query", writeFuture.cause()); return; } // Schedule a query timeout task if necessary. final long queryTimeoutMillis = parent.queryTimeoutMillis(); if (queryTimeoutMillis > 0) { timeoutFuture = parent.ch.eventLoop().schedule(new Runnable() { @Override public void run() { if (promise.isDone()) { // Received a response before the query times out. return; } setFailure("query timed out after " + queryTimeoutMillis + " milliseconds", null); } }, queryTimeoutMillis, TimeUnit.MILLISECONDS); } }
private void setSuccess(AddressedEnvelope<? extends DnsResponse, InetSocketAddress> envelope) { parent.queryContextManager.remove(nameServerAddr(), id); // Cancel the timeout task. final ScheduledFuture<?> timeoutFuture = this.timeoutFuture; if (timeoutFuture != null) { timeoutFuture.cancel(false); } Promise<AddressedEnvelope<DnsResponse, InetSocketAddress>> promise = this.promise; if (promise.setUncancellable()) { @SuppressWarnings("unchecked") AddressedEnvelope<DnsResponse, InetSocketAddress> castResponse = (AddressedEnvelope<DnsResponse, InetSocketAddress>) envelope.retain(); if (!promise.trySuccess(castResponse)) { // We failed to notify the promise as it was failed before, thus we need to release the envelope envelope.release(); } } }
void query(ChannelPromise writePromise) { final DnsQuestion question = question(); final InetSocketAddress nameServerAddr = nameServerAddr(); final DatagramDnsQuery query = new DatagramDnsQuery(null, nameServerAddr, id); query.setRecursionDesired(recursionDesired); query.addRecord(DnsSection.QUESTION, question); for (DnsRecord record: additionals) { query.addRecord(DnsSection.ADDITIONAL, record); } if (optResource != null) { query.addRecord(DnsSection.ADDITIONAL, optResource); } if (logger.isDebugEnabled()) { logger.debug("{} WRITE: [{}: {}], {}", parent.ch, id, nameServerAddr, question); } sendQuery(query, writePromise); }
int add(DnsQueryContext qCtx) { final IntObjectMap<DnsQueryContext> contexts = getOrCreateContextMap(qCtx.nameServerAddr()); int id = PlatformDependent.threadLocalRandom().nextInt(65536 - 1) + 1; final int maxTries = 65535 << 1; int tries = 0; synchronized (contexts) { for (;;) { if (!contexts.containsKey(id)) { contexts.put(id, qCtx); return id; } id = id + 1 & 0xFFFF; if (++tries >= maxTries) { throw new IllegalStateException("query ID space exhausted: " + qCtx.question()); } } } }
void finish(AddressedEnvelope<? extends DnsResponse, InetSocketAddress> envelope) { final DnsResponse res = envelope.content(); if (res.count(DnsSection.QUESTION) != 1) { logger.warn("Received a DNS response with invalid number of questions: {}", envelope); return; } if (!question().equals(res.recordAt(DnsSection.QUESTION))) { logger.warn("Received a mismatching DNS response: {}", envelope); return; } setSuccess(envelope); }
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query0( InetSocketAddress nameServerAddr, DnsQuestion question, DnsRecord[] additionals, ChannelPromise writePromise, Promise<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>> promise) { assert !writePromise.isVoid(); final Promise<AddressedEnvelope<DnsResponse, InetSocketAddress>> castPromise = cast( checkNotNull(promise, "promise")); try { new DnsQueryContext(this, nameServerAddr, question, additionals, castPromise).query(writePromise); return castPromise; } catch (Exception e) { return castPromise.setFailure(e); } }
private void writeQuery(final DnsQuery query, final ChannelPromise writePromise) { final ChannelFuture writeFuture = parent.ch.writeAndFlush(query, writePromise); if (writeFuture.isDone()) { onQueryWriteCompletion(writeFuture); } else { writeFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) { onQueryWriteCompletion(writeFuture); } }); } }