Netty Codec

The netty part contains the MessageToMessageCodec DnsCodec.

Usage

If you’re using sbt just add the following to your build definition:

resolvers += "bintray" at "http://jcenter.bintray.com"

libraryDependencies ++= Seq(
  "com.github.mkroli" %% "dns4s-netty" % "0.16.0")

Imports

Use the following additional imports to get started:

import com.github.mkroli.dns4s.dsl._
import com.github.mkroli.dns4s.netty._

import io.netty.util.concurrent.Future

Server

The following is an excerpt from examples/simple-netty/../DnsServer.scala:

class DnsServerHandler extends SimpleChannelInboundHandler[DnsPacket] {
  def channelRead0(ctx: ChannelHandlerContext, packet: DnsPacket): Unit = {
    Some(packet.content).collect {
      case Query(q) ~ Questions(QName(host) ~ TypeA() :: Nil) =>
        Response(q) ~ Answers(RRName(host) ~ ARecord("1.2.3.4"))
    }.foreach { msg =>
      ctx.channel.writeAndFlush(DnsPacket(msg, packet.sender))
    }
  }
}

object DnsServer extends App {
  new Bootstrap()
    .group(new NioEventLoopGroup)
    .channel(classOf[NioDatagramChannel])
    .handler(new ChannelInitializer[DatagramChannel] {
      override def initChannel(ch: DatagramChannel): Unit = {
        ch.pipeline.addLast(new DnsCodec, new DnsServerHandler)
      }
    })
    .bind(5354)
}

Client

The following is an excerpt from examples/simple-netty-client/../DnsClient.scala:

class DnsClientHandler(group: NioEventLoopGroup) extends SimpleChannelInboundHandler[DnsPacket] {
  def channelRead0(ctx: ChannelHandlerContext, packet: DnsPacket): Unit = {
    packet.content match {
      case Response(Answers(answers)) =>
        answers.collect {
          case ARecord(arecord) => println(arecord.address.getHostAddress)
        }
      case _ =>
    }
    group.shutdownGracefully()
  }
}

val group = new NioEventLoopGroup
val channel: ChannelFuture = {
  new Bootstrap()
    .group(group)
    .channel(classOf[NioDatagramChannel])
    .handler(new ChannelInitializer[DatagramChannel] {
      override def initChannel(ch: DatagramChannel): Unit = {
        ch.pipeline.addLast(new DnsCodec, new DnsClientHandler(group))
      }
    })
    .bind(0)
    .addListener(new GenericFutureListener[Future[Void]] {
      override def operationComplete(f: Future[Void]): Unit = {
        channel.channel.writeAndFlush(DnsPacket(Query ~ Questions(QName("google.de")), new InetSocketAddress("8.8.8.8", 53)))
      }
    })
}