io.netty.channel.ChannelHandlerContext Scala Examples

The following examples show how to use io.netty.channel.ChannelHandlerContext. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: MessageCodec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.util

import com.wavesplatform.crypto
import com.wavesplatform.utils.ScorexLogging
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.MessageToMessageCodec

import scala.util.{Failure, Success}

@Sharable
class MessageCodec(peerDatabase: PeerDatabase) extends MessageToMessageCodec[RawBytes, Message] with ScorexLogging {

  import BasicMessagesRepo.specsByCodes

  override def encode(ctx: ChannelHandlerContext, msg: Message, out: util.List[AnyRef]): Unit = msg match {
    // Have no spec
    case r: RawBytes              => out.add(r)
    case LocalScoreChanged(score) => out.add(RawBytes(ScoreSpec.messageCode, ScoreSpec.serializeData(score)))
    case BlockForged(b)           => out.add(RawBytes.fromBlock(b))

    // With a spec
    case GetPeers             => out.add(RawBytes(GetPeersSpec.messageCode, Array[Byte]()))
    case k: KnownPeers        => out.add(RawBytes(PeersSpec.messageCode, PeersSpec.serializeData(k)))
    case g: GetBlock          => out.add(RawBytes(GetBlockSpec.messageCode, GetBlockSpec.serializeData(g)))
    case m: MicroBlockInv     => out.add(RawBytes(MicroBlockInvSpec.messageCode, MicroBlockInvSpec.serializeData(m)))
    case m: MicroBlockRequest => out.add(RawBytes(MicroBlockRequestSpec.messageCode, MicroBlockRequestSpec.serializeData(m)))

    // Version switch
    case gs: GetSignatures if isNewMsgsSupported(ctx) =>
      out.add(RawBytes(GetBlockIdsSpec.messageCode, GetBlockIdsSpec.serializeData(gs)))
    case gs: GetSignatures if GetSignaturesSpec.isSupported(gs.signatures) =>
      out.add(RawBytes(GetSignaturesSpec.messageCode, GetSignaturesSpec.serializeData(gs)))

    case s: Signatures =>
      if (isNewMsgsSupported(ctx)) {
        out.add(RawBytes(BlockIdsSpec.messageCode, BlockIdsSpec.serializeData(s)))
      } else {
        val supported = s.signatures
          .dropWhile(_.arr.length != crypto.SignatureLength)
          .takeWhile(_.arr.length == crypto.SignatureLength)
        out.add(RawBytes(SignaturesSpec.messageCode, SignaturesSpec.serializeData(s.copy(signatures = supported))))
      }

    case _ =>
      throw new IllegalArgumentException(s"Can't send message $msg to $ctx (unsupported)")
  }

  override def decode(ctx: ChannelHandlerContext, msg: RawBytes, out: util.List[AnyRef]): Unit = {
    specsByCodes(msg.code).deserializeData(msg.data) match {
      case Success(x) => out.add(x)
      case Failure(e) => block(ctx, e)
    }
  }

  protected def block(ctx: ChannelHandlerContext, e: Throwable): Unit = {
    peerDatabase.blacklistAndClose(ctx.channel(), s"Invalid message. ${e.getMessage}")
  }

  private[this] def isNewMsgsSupported(ctx: ChannelHandlerContext): Boolean = {
    val (v1, v2, _) = ctx.channel().attr(HandshakeHandler.NodeVersionAttributeKey).get()
    v1 > 1 || (v1 == 1 && v2 >= 2) // >= 1.2.0
  }
} 
Example 2
Source File: RBackendAuthHandler.scala    From Spark-2.3.1   with Apache License 2.0 5 votes vote down vote up
package org.apache.spark.api.r

import java.io.{ByteArrayOutputStream, DataOutputStream}
import java.nio.charset.StandardCharsets.UTF_8

import io.netty.channel.{Channel, ChannelHandlerContext, SimpleChannelInboundHandler}

import org.apache.spark.internal.Logging
import org.apache.spark.util.Utils


private class RBackendAuthHandler(secret: String)
  extends SimpleChannelInboundHandler[Array[Byte]] with Logging {

  override def channelRead0(ctx: ChannelHandlerContext, msg: Array[Byte]): Unit = {
    // The R code adds a null terminator to serialized strings, so ignore it here.
    val clientSecret = new String(msg, 0, msg.length - 1, UTF_8)
    try {
      require(secret == clientSecret, "Auth secret mismatch.")
      ctx.pipeline().remove(this)
      writeReply("ok", ctx.channel())
    } catch {
      case e: Exception =>
        logInfo("Authentication failure.", e)
        writeReply("err", ctx.channel())
        ctx.close()
    }
  }

  private def writeReply(reply: String, chan: Channel): Unit = {
    val out = new ByteArrayOutputStream()
    SerDe.writeString(new DataOutputStream(out), reply)
    chan.writeAndFlush(out.toByteArray())
  }

} 
Example 3
Source File: HttpUtils.scala    From Neutrino   with Apache License 2.0 5 votes vote down vote up
package com.ebay.neutrino.util

import java.net.URI

import com.ebay.neutrino.config.Host
import com.typesafe.scalalogging.slf4j.StrictLogging
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.http.HttpHeaders.{Names, Values}
import io.netty.handler.codec.http._
import io.netty.util.CharsetUtil



object HttpResponseUtils {
  import io.netty.handler.codec.http.HttpHeaderNames._
  import io.netty.handler.codec.http.HttpVersion._


  def error(status: HttpResponseStatus) = {
    // Allocate some memory for this
    val buffer = Unpooled.copiedBuffer(s"Failure: $status\r\n", CharsetUtil.UTF_8)

    // Package a response
    val response = new DefaultFullHttpResponse(HTTP_1_1, status, buffer)
    response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8")
    response
  }
} 
Example 4
Source File: MetricsAnnotationRegistryTest.scala    From Neutrino   with Apache License 2.0 5 votes vote down vote up
package com.ebay.neutrino.health

import com.codahale.metrics.annotation.{Gauge, Metered, Timed}
import com.ebay.neutrino.handler.MetricsAnnotationRegistry
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandler}
import org.scalatest.{FlatSpec, Matchers}


class MetricsAnnotationRegistryTest extends FlatSpec with Matchers {
  behavior of "Parsing Metrics Annotations"


  it should "skip class with no annotations" in {
    abstract class Test extends ChannelInboundHandler {
      override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef) {}
    }

    // No annotations for the inbound-methods
    val registry = new MetricsAnnotationRegistry
    registry.getAnnotations(classOf[Test], "channelRegistered") shouldBe empty
    registry.getAnnotations(classOf[Test], "channelRead") shouldBe empty

    // Does not implement outbound interface; should fail trying to resolve
    a [NoSuchMethodException] should be thrownBy registry.getAnnotations(classOf[Test], "write")
  }

  it should "find only marked annotation" in {
    abstract class Test extends ChannelInboundHandler {
      @Timed @Gauge @Metered
      override def channelRegistered(ctx: ChannelHandlerContext) {}
      @Timed
      override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef) {}
    }

    // No annotations for the inbound-methods
    val registry = new MetricsAnnotationRegistry
    registry.getAnnotations(classOf[Test], "channelRegistered").size shouldBe 3
    registry.getAnnotations(classOf[Test], "channelRegistered")(0) shouldBe a [Timed]
    registry.getAnnotations(classOf[Test], "channelRegistered")(1) shouldBe a [Gauge]
    registry.getAnnotations(classOf[Test], "channelRegistered")(2) shouldBe a [Metered]
    registry.getAnnotations(classOf[Test], "channelRead").size shouldBe 1
    registry.getAnnotations(classOf[Test], "channelRead")(0) shouldBe a [Timed]
  }

  it should "skip unrelated annotations" in {
    abstract class Test extends ChannelInboundHandler {
      override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef) {}
    }

    val registry = new MetricsAnnotationRegistry
    registry.getAnnotations(classOf[Test], "channelRead") shouldBe empty
  }

  // registry cachings
  it should "cache subsequent invocations" in {
    //fail("Not implemented yet...")
  }
} 
Example 5
Source File: ExampleCloseHandler.scala    From Neutrino   with Apache License 2.0 5 votes vote down vote up
package com.ebay.neutrino.handler

import com.ebay.neutrino.NeutrinoRequest
import com.typesafe.scalalogging.slf4j.StrictLogging
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelFutureListener, ChannelHandlerContext, ChannelInboundHandlerAdapter}
import io.netty.handler.codec.http._
import io.netty.util.CharsetUtil


@Sharable
class ExampleCloseHandler extends ChannelInboundHandlerAdapter with StrictLogging {


  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit =
    msg match {
      case request: NeutrinoRequest if request.uri.startsWith("/close") =>
        // Handle a 'close' request
        val status = HttpResponseStatus.OK
        val buffer = Unpooled.copiedBuffer(s"Handling /close request by closing connection.\r\n", CharsetUtil.UTF_8)
        val response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buffer)

        // Set the content-type
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8")

        // Close the connection as soon as the error message is sent.
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE)


      case _ =>
        // Fall through
        ctx.fireChannelRead(msg)
    }
} 
Example 6
Source File: HistoryReplier.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import com.wavesplatform.block.Block
import com.wavesplatform.history.History
import com.wavesplatform.network.HistoryReplier._
import com.wavesplatform.settings.SynchronizationSettings
import com.wavesplatform.utils.ScorexLogging
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}

import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}

@Sharable
class HistoryReplier(score: => BigInt, history: History, settings: SynchronizationSettings)(implicit ec: ExecutionContext)
    extends ChannelInboundHandlerAdapter
    with ScorexLogging {

  private def respondWith(ctx: ChannelHandlerContext, value: Future[Message]): Unit =
    value.onComplete {
      case Failure(e) => log.debug(s"${id(ctx)} Error processing request", e)
      case Success(value) =>
        if (ctx.channel().isOpen) {
          ctx.writeAndFlush(value)
        } else {
          log.trace(s"${id(ctx)} Channel is closed")
        }
    }

  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = msg match {
    case GetSignatures(otherSigs) =>
      respondWith(ctx, Future(Signatures(history.blockIdsAfter(otherSigs, settings.maxRollback))))

    case GetBlock(sig) =>
      respondWith(
        ctx,
        Future(history.loadBlockBytes(sig))
          .map {
            case Some((blockVersion, bytes)) =>
              RawBytes(if (blockVersion < Block.ProtoBlockVersion) BlockSpec.messageCode else PBBlockSpec.messageCode, bytes)
            case _ => throw new NoSuchElementException(s"Error loading block $sig")
          }
      )

    case MicroBlockRequest(microBlockId) =>
      respondWith(
        ctx,
        Future(history.loadMicroBlock(microBlockId)).map {
          case Some(microBlock) => RawBytes.fromMicroBlock(MicroBlockResponse(microBlock, microBlockId))
          case _                => throw new NoSuchElementException(s"Error loading microblock $microBlockId")
        }
      )

    case _: Handshake =>
      respondWith(ctx, Future(LocalScoreChanged(score)))

    case _ => super.channelRead(ctx, msg)
  }

  def cacheSizes: CacheSizes = CacheSizes(0, 0)
}

object HistoryReplier {
  case class CacheSizes(blocks: Long, microBlocks: Long)
} 
Example 7
Source File: MessageObserver.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import com.wavesplatform.block.Block
import com.wavesplatform.transaction.Transaction
import com.wavesplatform.utils.{Schedulers, ScorexLogging}
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{Channel, ChannelHandlerContext, ChannelInboundHandlerAdapter}
import monix.execution.schedulers.SchedulerService
import monix.reactive.subjects.ConcurrentSubject

@Sharable
class MessageObserver extends ChannelInboundHandlerAdapter with ScorexLogging {

  private implicit val scheduler: SchedulerService = Schedulers.fixedPool(2, "message-observer")

  private val signatures          = ConcurrentSubject.publish[(Channel, Signatures)]
  private val blocks              = ConcurrentSubject.publish[(Channel, Block)]
  private val blockchainScores    = ConcurrentSubject.publish[(Channel, BigInt)]
  private val microblockInvs      = ConcurrentSubject.publish[(Channel, MicroBlockInv)]
  private val microblockResponses = ConcurrentSubject.publish[(Channel, MicroBlockResponse)]
  private val transactions        = ConcurrentSubject.publish[(Channel, Transaction)]

  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = msg match {
    case b: Block               => blocks.onNext((ctx.channel(), b))
    case sc: BigInt             => blockchainScores.onNext((ctx.channel(), sc))
    case s: Signatures          => signatures.onNext((ctx.channel(), s))
    case mbInv: MicroBlockInv   => microblockInvs.onNext((ctx.channel(), mbInv))
    case mb: MicroBlockResponse => microblockResponses.onNext((ctx.channel(), mb))
    case tx: Transaction        => transactions.onNext((ctx.channel(), tx))
    case _                      => super.channelRead(ctx, msg)

  }

  def shutdown(): Unit = {
    signatures.onComplete()
    blocks.onComplete()
    blockchainScores.onComplete()
    microblockInvs.onComplete()
    microblockResponses.onComplete()
    transactions.onComplete()
  }
}

object MessageObserver {
  type Messages = (
      ChannelObservable[Signatures],
      ChannelObservable[Block],
      ChannelObservable[BigInt],
      ChannelObservable[MicroBlockInv],
      ChannelObservable[MicroBlockResponse],
      ChannelObservable[Transaction]
  )

  def apply(): (MessageObserver, Messages) = {
    val mo = new MessageObserver()
    (mo, (mo.signatures, mo.blocks, mo.blockchainScores, mo.microblockInvs, mo.microblockResponses, mo.transactions))
  }
} 
Example 8
Source File: PeerKey.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.net.{InetAddress, SocketAddress}

import io.netty.channel.ChannelHandlerContext
import io.netty.channel.embedded.EmbeddedChannel
import io.netty.channel.socket.SocketChannel

sealed trait PeerKey
case object PeerKey {
  case class InetPeerKey(host: InetAddress, nonce: Long)     extends PeerKey
  case class SocketPeerKey(host: SocketAddress, nonce: Long) extends PeerKey

  def apply(ctx: ChannelHandlerContext, nodeNonce: Long): Option[PeerKey] = ctx.channel() match {
    case x: SocketChannel   => Option(x.remoteAddress()).map(_.getAddress).map(PeerKey.InetPeerKey(_, nodeNonce))
    case x: EmbeddedChannel => Option(x.remoteAddress()).map(PeerKey.SocketPeerKey(_, nodeNonce))
    case x                  => throw new IllegalArgumentException(s"Can't get PeerKey from ${id(ctx)}, $x")
  }
} 
Example 9
Source File: TrafficWatcher.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import com.wavesplatform.network.message.{Message => ScorexMessage}
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelDuplexHandler, ChannelHandlerContext, ChannelPromise}
import kamon.Kamon
import kamon.metric.{Histogram, MeasurementUnit}

@Sharable
class TrafficWatcher extends ChannelDuplexHandler {

  import BasicMessagesRepo.specsByCodes

  private val outgoing: Map[ScorexMessage.MessageCode, Histogram] = specsByCodes.map {
    case (code, spec) =>
      code -> createHistogram("outgoing", spec)
  }

  private val incoming: Map[ScorexMessage.MessageCode, Histogram] = specsByCodes.map {
    case (code, spec) =>
      code -> createHistogram("incoming", spec)
  }

  private def createHistogram(dir: String, spec: BasicMessagesRepo.Spec): Histogram =
    Kamon
      .histogram("traffic", MeasurementUnit.information.bytes)
      .withTag("type", spec.messageName)
      .withTag("dir", dir)

  override def write(ctx: ChannelHandlerContext, msg: AnyRef, promise: ChannelPromise): Unit = {
    msg match {
      case x: RawBytes => outgoing.get(x.code).foreach(_.record(x.data.length))
      case _           =>
    }

    super.write(ctx, msg, promise)
  }

  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = {
    msg match {
      case x: RawBytes => incoming.get(x.code).foreach(_.record(x.data.length))
      case _           =>
    }

    super.channelRead(ctx, msg)
  }

} 
Example 10
Source File: DiscardingHandler.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import com.wavesplatform.utils.{Schedulers, ScorexLogging}
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelDuplexHandler, ChannelHandlerContext}
import monix.execution.schedulers.SchedulerService
import monix.reactive.Observable

@Sharable
class DiscardingHandler(blockchainReadiness: Observable[Boolean]) extends ChannelDuplexHandler with ScorexLogging {

  private implicit val scheduler: SchedulerService = Schedulers.fixedPool(2, "discarding-handler")
  private val lastReadiness                        = lastObserved(blockchainReadiness)

  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = msg match {
    case RawBytes(code @ (TransactionSpec.messageCode | PBTransactionSpec.messageCode), _) if !lastReadiness().contains(true) =>
      log.trace(s"${id(ctx)} Discarding incoming message $code")

    case _ => super.channelRead(ctx, msg)
  }
} 
Example 11
Source File: InboundConnectionFilter.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.net.{InetAddress, InetSocketAddress}
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger

import com.wavesplatform.utils.ScorexLogging
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelFuture, ChannelHandlerContext}
import io.netty.handler.ipfilter.AbstractRemoteAddressFilter

@Sharable
class InboundConnectionFilter(peerDatabase: PeerDatabase, maxInboundConnections: Int, maxConnectionsPerHost: Int)
    extends AbstractRemoteAddressFilter[InetSocketAddress]
    with ScorexLogging {
  private val inboundConnectionCount = new AtomicInteger(0)
  private val perHostConnectionCount = new ConcurrentHashMap[InetAddress, Int]
  private val emptyChannelFuture     = null.asInstanceOf[ChannelFuture]

  private def dec(remoteAddress: InetAddress) = {
    inboundConnectionCount.decrementAndGet()
    log.trace(s"Number of inbound connections: ${inboundConnectionCount.get()}")
    perHostConnectionCount.compute(remoteAddress, (_, cnt) => cnt - 1)
    emptyChannelFuture
  }

  override def accept(ctx: ChannelHandlerContext, remoteAddress: InetSocketAddress): Boolean = Option(remoteAddress.getAddress) match {
    case None =>
      log.debug(s"Can't obtain an address from $remoteAddress")
      false

    case Some(address) =>
      val newTotal        = inboundConnectionCount.incrementAndGet()
      val newCountPerHost = perHostConnectionCount.compute(address, (_, cnt) => Option(cnt).fold(1)(_ + 1))
      val isBlacklisted   = peerDatabase.blacklistedHosts.contains(address)

      val accepted = newTotal <= maxInboundConnections &&
        newCountPerHost <= maxConnectionsPerHost &&
        !isBlacklisted

      log.trace(
        s"Check inbound connection from $remoteAddress: new inbound total = $newTotal, " +
          s"connections with this host = $newCountPerHost, address ${if (isBlacklisted) "IS" else "is not"} blacklisted, " +
          s"${if (accepted) "is" else "is not"} accepted"
      )

      accepted
  }

  override def channelAccepted(ctx: ChannelHandlerContext, remoteAddress: InetSocketAddress): Unit =
    ctx.channel().closeFuture().addListener((_: ChannelFuture) => Option(remoteAddress.getAddress).foreach(dec))

  override def channelRejected(ctx: ChannelHandlerContext, remoteAddress: InetSocketAddress): ChannelFuture =
    Option(remoteAddress.getAddress).fold(emptyChannelFuture)(dec)
} 
Example 12
Source File: GrpcGatewayHandler.scala    From grpcgateway   with MIT License 5 votes vote down vote up
package grpcgateway.handlers

import java.nio.charset.StandardCharsets

import scalapb.GeneratedMessage
import scalapb.json4s.JsonFormat
import io.grpc.ManagedChannel
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ ChannelFutureListener, ChannelHandlerContext, ChannelInboundHandlerAdapter }
import io.netty.handler.codec.http._

import scala.concurrent.{ ExecutionContext, Future }

@Sharable
abstract class GrpcGatewayHandler(channel: ManagedChannel)(implicit ec: ExecutionContext) extends ChannelInboundHandlerAdapter {

  def name: String

  def shutdown(): Unit =
    if (!channel.isShutdown) channel.shutdown()

  def supportsCall(method: HttpMethod, uri: String): Boolean
  def unaryCall(method: HttpMethod, uri: String, body: String): Future[GeneratedMessage]

  override def channelRead(ctx: ChannelHandlerContext, msg: scala.Any): Unit = {

    msg match {
      case req: FullHttpRequest =>

        if (supportsCall(req.method(), req.uri())) {

          val body = req.content().toString(StandardCharsets.UTF_8)

          unaryCall(req.method(), req.uri(), body)
            .map(JsonFormat.toJsonString)
            .map(json => {
              buildFullHttpResponse(
                requestMsg = req,
                responseBody = json,
                responseStatus = HttpResponseStatus.OK,
                responseContentType = "application/json"
              )
            })
            .recover({ case err =>

              val (body, status) = err match {
                case e: GatewayException => e.details -> GRPC_HTTP_CODE_MAP.getOrElse(e.code, HttpResponseStatus.INTERNAL_SERVER_ERROR)
                case _ => "Internal error" -> HttpResponseStatus.INTERNAL_SERVER_ERROR
              }

              buildFullHttpResponse(
                requestMsg = req,
                responseBody = body,
                responseStatus = status,
                responseContentType = "application/text"
              )
            }).foreach(resp => {
              ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE)
            })

        } else {
          super.channelRead(ctx, msg)
        }
      case _ => super.channelRead(ctx, msg)
    }
  }
} 
Example 13
Source File: LegacyFrameCodec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.util

import com.google.common.cache.CacheBuilder
import com.wavesplatform.block.Block
import com.wavesplatform.common.utils.Base64
import com.wavesplatform.crypto
import com.wavesplatform.network.message.Message._
import com.wavesplatform.transaction.Transaction
import com.wavesplatform.utils.ScorexLogging
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled._
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.{ByteToMessageCodec, DecoderException}

import scala.concurrent.duration.FiniteDuration
import scala.util.control.NonFatal

class LegacyFrameCodec(peerDatabase: PeerDatabase, receivedTxsCacheTimeout: FiniteDuration) extends ByteToMessageCodec[Any] with ScorexLogging {

  import BasicMessagesRepo.specsByCodes
  import LegacyFrameCodec._

  private val receivedTxsCache = CacheBuilder
    .newBuilder()
    .expireAfterWrite(receivedTxsCacheTimeout.length, receivedTxsCacheTimeout.unit)
    .build[String, Object]()

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = cause match {
    case e: DecoderException => peerDatabase.blacklistAndClose(ctx.channel(), s"Corrupted message frame: $e")
    case _                   => super.exceptionCaught(ctx, cause)
  }

  override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit =
    try {
      require(in.readInt() == Magic, "invalid magic number")

      val code = in.readByte()
      require(specsByCodes.contains(code), s"Unexpected message code $code")

      val spec   = specsByCodes(code)
      val length = in.readInt()
      require(length <= spec.maxLength, s"${spec.messageName} message length $length exceeds ${spec.maxLength}")

      val dataBytes = new Array[Byte](length)
      val pushToPipeline = length == 0 || {
        val declaredChecksum = in.readSlice(ChecksumLength)
        in.readBytes(dataBytes)
        val rawChecksum    = crypto.fastHash(dataBytes)
        val actualChecksum = wrappedBuffer(rawChecksum, 0, ChecksumLength)

        require(declaredChecksum.equals(actualChecksum), "invalid checksum")
        actualChecksum.release()

        spec != TransactionSpec || {
          val actualChecksumStr = Base64.encode(rawChecksum)
          if (receivedTxsCache.getIfPresent(actualChecksumStr) == null) {
            receivedTxsCache.put(actualChecksumStr, LegacyFrameCodec.dummy)
            true
          } else false
        }
      }

      if (pushToPipeline) out.add(RawBytes(code, dataBytes))
    } catch {
      case NonFatal(e) =>
        log.warn(s"${id(ctx)} Malformed network message", e)
        peerDatabase.blacklistAndClose(ctx.channel(), s"Malformed network message: $e")
        in.resetReaderIndex() // Cancels subsequent read tries, see Netty decode() documentation
    }

  override def encode(ctx: ChannelHandlerContext, msg1: Any, out: ByteBuf): Unit = {
    val msg = msg1 match {
      case rb: RawBytes           => rb
      case tx: Transaction        => RawBytes.fromTransaction(tx)
      case block: Block           => RawBytes.fromBlock(block)
      case mb: MicroBlockResponse => RawBytes.fromMicroBlock(mb)
    }

    out.writeInt(Magic)
    out.writeByte(msg.code)
    if (msg.data.length > 0) {
      out.writeInt(msg.data.length)
      out.writeBytes(crypto.fastHash(msg.data), 0, ChecksumLength)
      out.writeBytes(msg.data)
    } else {
      out.writeInt(0)
    }
  }
}

object LegacyFrameCodec {
  val Magic         = 0x12345678
  private val dummy = new Object()
} 
Example 14
Source File: FatalErrorHandler.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.io.IOException

import com.wavesplatform.utils.{ScorexLogging, forceStopApplication}
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}

import scala.util.control.NonFatal
@Sharable
class FatalErrorHandler extends ChannelInboundHandlerAdapter with ScorexLogging {
  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = cause match {
    case ioe: IOException if ioe.getMessage == "Connection reset by peer" =>
      // https://stackoverflow.com/q/9829531
      // https://stackoverflow.com/q/1434451
      log.trace(s"${id(ctx)} Connection reset by peer")
    case NonFatal(_) =>
      log.debug(s"${id(ctx)} Exception caught", cause)
    case _ =>
      new Thread(() => {
        log.error(s"${id(ctx)} Fatal error in channel, terminating application", cause)
        forceStopApplication()
      }, "waves-platform-shutdown-thread").start()
  }
} 
Example 15
Source File: PeerSynchronizer.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.net.InetSocketAddress

import com.wavesplatform.utils.ScorexLogging
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}

import scala.concurrent.duration.FiniteDuration

class PeerSynchronizer(peerDatabase: PeerDatabase, peerRequestInterval: FiniteDuration) extends ChannelInboundHandlerAdapter with ScorexLogging {

  private var peersRequested  = false
  private var declaredAddress = Option.empty[InetSocketAddress]

  def requestPeers(ctx: ChannelHandlerContext): Unit = if (ctx.channel().isActive) {
    peersRequested = true
    ctx.writeAndFlush(GetPeers)

    ctx.executor().schedule(peerRequestInterval) {
      requestPeers(ctx)
    }
  }

  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = {
    declaredAddress.foreach(peerDatabase.touch)
    msg match {
      case hs: Handshake =>
        val rda = for {
          rda        <- hs.declaredAddress
          rdaAddress <- Option(rda.getAddress)
          ctxAddress <- ctx.remoteAddress.map(_.getAddress)
          if rdaAddress == ctxAddress
        } yield rda

        rda match {
          case None => log.debug(s"${id(ctx)} Declared address $rda does not match actual remote address ${ctx.remoteAddress.map(_.getAddress)}")
          case Some(x) =>
            log.trace(s"${id(ctx)} Touching declared address")
            peerDatabase.touch(x)
            declaredAddress = Some(x)
        }

        requestPeers(ctx)
        super.channelRead(ctx, msg)
      case GetPeers =>
        ctx.writeAndFlush(KnownPeers(peerDatabase.knownPeers.keys.toSeq))
      case KnownPeers(peers) if peersRequested =>
        peersRequested = false
        val (added, notAdded) = peers.partition(peerDatabase.addCandidate)
        log.trace(s"${id(ctx)} Added peers: ${format(added)}, not added peers: ${format(notAdded)}")
      case KnownPeers(peers) =>
        log.trace(s"${id(ctx)} Got unexpected list of known peers containing ${peers.size} entries")
      case _ =>
        super.channelRead(ctx, msg)
    }
  }

  private def format[T](xs: Iterable[T]): String = xs.mkString("[", ", ", "]")
}

object PeerSynchronizer {

  @Sharable
  class NoopPeerSynchronizer extends ChannelInboundHandlerAdapter {

    override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = {
      msg match {
        case GetPeers      =>
        case KnownPeers(_) =>
        case _ =>
          super.channelRead(ctx, msg)
      }
    }
  }

  val Disabled = new NoopPeerSynchronizer()

} 
Example 16
Source File: TrafficLogger.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import com.wavesplatform.block.Block
import com.wavesplatform.block.serialization.BlockHeaderSerializer
import com.wavesplatform.common.utils.Base64
import com.wavesplatform.network.message.{Message => ScorexMessage}
import com.wavesplatform.transaction.Transaction
import com.wavesplatform.utils.ScorexLogging
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ChannelDuplexHandler, ChannelHandlerContext, ChannelPromise}

@Sharable
class TrafficLogger(settings: TrafficLogger.Settings) extends ChannelDuplexHandler with ScorexLogging {

  import BasicMessagesRepo.specsByClasses

  private val codeOf: AnyRef => Option[Byte] = {
    val aux: PartialFunction[AnyRef, Byte] = {
      case x: RawBytes                      => x.code
      case _: Transaction                   => TransactionSpec.messageCode
      case _: BigInt | _: LocalScoreChanged => ScoreSpec.messageCode
      case _: Block | _: BlockForged        => BlockSpec.messageCode
      case x: Message                       => specsByClasses(x.getClass).messageCode
      case _: Handshake                     => HandshakeSpec.messageCode
    }

    aux.lift
  }

  override def write(ctx: ChannelHandlerContext, msg: AnyRef, promise: ChannelPromise): Unit = {
    codeOf(msg).filterNot(settings.ignoreTxMessages).foreach { code =>
      log.trace(s"${id(ctx)} <-- transmitted($code): ${stringify(msg)}")
    }

    super.write(ctx, msg, promise)
  }

  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = {
    codeOf(msg).filterNot(settings.ignoreRxMessages).foreach { code =>
      log.trace(s"${id(ctx)} --> received($code): ${stringify(msg)}")
    }

    super.channelRead(ctx, msg)
  }

  private def stringify(msg: Any): String = msg match {
    case tx: Transaction   => tx.json().toString()
    case b: Block          => s"${b.id()}, header: ${BlockHeaderSerializer.toJson(b.header, b.bytes().length, b.transactionData.length, b.signature).toString}"
    case RawBytes(_, data) => Base64.encode(data)
    case other             => other.toString
  }
}

object TrafficLogger {

  case class Settings(ignoreTxMessages: Set[ScorexMessage.MessageCode], ignoreRxMessages: Set[ScorexMessage.MessageCode])

} 
Example 17
Source File: HandshakeDecoderSpec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.nio.charset.StandardCharsets

import com.google.common.primitives.{Ints, Longs}
import com.wavesplatform.{NoShrink, TransactionGen}
import io.netty.buffer.Unpooled
import io.netty.channel.embedded.EmbeddedChannel
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}
import org.scalacheck.{Arbitrary, Gen}
import org.scalamock.scalatest.MockFactory
import org.scalatest.{FreeSpec, Matchers}
import org.scalatestplus.scalacheck.{ScalaCheckPropertyChecks => PropertyChecks}

class HandshakeDecoderSpec extends FreeSpec with Matchers with MockFactory with PropertyChecks with TransactionGen with NoShrink {

  "should read a handshake and remove itself from the pipeline" in {
    var mayBeDecodedHandshake: Option[Handshake] = None

    val channel = new EmbeddedChannel(
      new HandshakeDecoder(PeerDatabase.NoOp),
      new ChannelInboundHandlerAdapter {
        override def channelRead(ctx: ChannelHandlerContext, msg: Any): Unit = msg match {
          case x: Handshake => mayBeDecodedHandshake = Some(x)
          case _            =>
        }
      }
    )

    val origHandshake = new Handshake(
      applicationName = "wavesI",
      applicationVersion = (1, 2, 3),
      nodeName = "test",
      nodeNonce = 4,
      declaredAddress = None
    )

    val buff = Unpooled.buffer
    origHandshake.encode(buff)
    buff.writeCharSequence("foo", StandardCharsets.UTF_8)

    channel.writeInbound(buff)

    mayBeDecodedHandshake should contain(origHandshake)
  }

  private val invalidHandshakeBytes: Gen[Array[Byte]] = {
    // To bypass situations where the appNameLength > whole buffer and HandshakeDecoder waits for next bytes
    val appName  = "x" * Byte.MaxValue
    val nodeName = "y" * Byte.MaxValue

    val appNameBytes   = appName.getBytes(StandardCharsets.UTF_8)
    val versionBytes   = Array(1, 2, 3).flatMap(Ints.toByteArray)
    val nodeNameBytes  = nodeName.getBytes(StandardCharsets.UTF_8)
    val nonceBytes     = Longs.toByteArray(1)
    val timestampBytes = Longs.toByteArray(System.currentTimeMillis() / 1000)

    val validDeclaredAddressLen = Set(0, 8, 20)
    val invalidBytesGen = Gen.listOfN(3, Arbitrary.arbByte.arbitrary).filter {
      case List(appNameLen, nodeNameLen, declaredAddressLen) =>
        !(appNameLen == appNameBytes.size || nodeNameLen == nodeNameBytes.size ||
          validDeclaredAddressLen.contains(declaredAddressLen))
      case _ =>
        false
    }

    invalidBytesGen.map {
      case List(appNameLen, nodeNameLen, declaredAddressLen) =>
        Array(appNameLen) ++
          appNameBytes ++
          versionBytes ++
          Array(nodeNameLen) ++
          nodeNameBytes ++
          nonceBytes ++
          Array(declaredAddressLen) ++
          timestampBytes
    }
  }

  "should blacklist a node sends an invalid handshake" in forAll(invalidHandshakeBytes) { bytes: Array[Byte] =>
    val decoder = new SpiedHandshakeDecoder
    val channel = new EmbeddedChannel(decoder)

    val buff = Unpooled.buffer
    buff.writeBytes(bytes)

    channel.writeInbound(buff)
    decoder.blockCalls shouldBe >(0)
  }

  private class SpiedHandshakeDecoder extends HandshakeDecoder(PeerDatabase.NoOp) {
    var blockCalls = 0

    override protected def block(ctx: ChannelHandlerContext, e: Throwable): Unit = {
      blockCalls += 1
    }
  }

} 
Example 18
Source File: MessageCodecSpec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.nio.charset.StandardCharsets

import com.wavesplatform.TransactionGen
import com.wavesplatform.transaction.assets.IssueTransaction
import com.wavesplatform.transaction.{ProvenTransaction, Transaction}
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.embedded.EmbeddedChannel
import org.scalamock.scalatest.MockFactory
import org.scalatest.{FreeSpec, Matchers}
import org.scalatestplus.scalacheck.{ScalaCheckPropertyChecks => PropertyChecks}

class MessageCodecSpec extends FreeSpec with Matchers with MockFactory with PropertyChecks with TransactionGen {

  "should block a sender of invalid messages" in {
    val codec = new SpiedMessageCodec
    val ch    = new EmbeddedChannel(codec)

    ch.writeInbound(RawBytes(TransactionSpec.messageCode, "foo".getBytes(StandardCharsets.UTF_8)))
    ch.readInbound[IssueTransaction]()

    codec.blockCalls shouldBe 1
  }

  "should not block a sender of valid messages" in forAll(randomTransactionGen) { origTx: ProvenTransaction =>
    val codec = new SpiedMessageCodec
    val ch    = new EmbeddedChannel(codec)

    ch.writeInbound(RawBytes.fromTransaction(origTx))
    val decodedTx = ch.readInbound[Transaction]()

    decodedTx shouldBe origTx
    codec.blockCalls shouldBe 0
  }

  private class SpiedMessageCodec extends MessageCodec(PeerDatabase.NoOp) {
    var blockCalls = 0

    override def block(ctx: ChannelHandlerContext, e: Throwable): Unit = {
      blockCalls += 1
    }
  }

} 
Example 19
Source File: MessageEncoder.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import java.util

import io.netty.channel.{ChannelHandler, ChannelHandlerContext}
import io.netty.handler.codec.MessageToMessageEncoder
import me.jrwang.aloha.common.Logging

@ChannelHandler.Sharable
object MessageEncoder extends MessageToMessageEncoder[Message] with Logging {

  //Be aware that you need to call {@link ReferenceCounted#retain()} on messages
  //that are just passed through if they are of type {@link ReferenceCounted}.
  //This is needed as the {@link MessageToMessageEncoder} will call
  //{@link ReferenceCounted#release()} on encoded messages.

  override def encode(ctx: ChannelHandlerContext, msg: Message, out: util.List[AnyRef]): Unit = {
    val messType = msg.`type`
    //[FrameLength(long)][MessageType][Message][MessageBody(optional)]
    val headerLength = 8 + messType.encodeLength + msg.encodeLength
    val frameLength = headerLength + (if(msg.isBodyInFrame) msg.body.readableBytes() else 0)

    val header = ctx.alloc.heapBuffer(headerLength)
    header.writeLong(frameLength)
    messType.encode(header)
    msg.encode(header)
    assert(header.writableBytes() == 0)

    if (msg.isBodyInFrame) {
      out.add(new MessageWithHeader(header, msg.body, msg.body.readableBytes()))
    } else {
      out.add(header)
    }
  }
} 
Example 20
Source File: MessageDecoder.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import java.util

import io.netty.buffer.ByteBuf
import io.netty.channel.{ChannelHandler, ChannelHandlerContext}
import io.netty.handler.codec.MessageToMessageDecoder
import me.jrwang.aloha.common.Logging

@ChannelHandler.Sharable
object MessageDecoder extends MessageToMessageDecoder[ByteBuf] with Logging {

  //Be aware that you need to call {@link ReferenceCounted#retain()} on messages
  //that are just passed through if they are of type {@link ReferenceCounted}.
  //This is needed as the {@link MessageToMessageDecoder} will call
  //{@link ReferenceCounted#release()} on decoded messages.
  override def decode(ctx: ChannelHandlerContext, msg: ByteBuf, out: util.List[AnyRef]): Unit = {
    val msgType = MessageType.decode(msg)
    val decodedMsg = decode(msgType, msg)
    require(msgType == decodedMsg.`type`)
    logTrace(s"Received message ${msgType}: ${decodedMsg}")
    out.add(decodedMsg)
  }

  private def decode(msgType: MessageType, in: ByteBuf) = msgType match {
    case MessageType.RpcRequest =>
      RpcRequest.decode(in)
    case MessageType.RpcResponse =>
      RpcResponse.decode(in)
    case MessageType.RpcFailure =>
      RpcFailure.decode(in)
    case MessageType.OneWayMessage =>
      OneWayMessage.decode(in)
    case _ =>
      throw new IllegalArgumentException("Unexpected message type: " + msgType)
  }
} 
Example 21
Source File: TransportChannelHandler.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.server

import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}
import me.jrwang.aloha.common.Logging
import me.jrwang.aloha.transport.client.{TransportClient, TransportResponseHandler}
import me.jrwang.aloha.transport.message.{RequestMessage, ResponseMessage}
import me.jrwang.aloha.transport.util.NettyUtils


class TransportChannelHandler (
    val client: TransportClient,
    val responseHandler: TransportResponseHandler,
    val requestHandler: TransportRequestHandler
  ) extends ChannelInboundHandlerAdapter with Logging {

  override def channelRead(ctx: ChannelHandlerContext, request: scala.Any): Unit = {
    request match {
      case requestMessage: RequestMessage =>
        requestHandler.handle(requestMessage)
      case responseMessage: ResponseMessage =>
        responseHandler.handle(responseMessage)
      case _ => ctx.fireChannelRead(request)
    }
  }

  @throws[Exception]
  override def channelActive(ctx: ChannelHandlerContext): Unit = {
    try
      requestHandler.channelActive()
    catch {
      case e: Throwable =>
        logError("Exception from request handler while channel is active", e)
        throw e
    }
    try
      responseHandler.channelActive()
    catch {
      case e: Throwable =>
        logError("Exception from response handler while channel is active", e)
        throw e
    }
    super.channelActive(ctx)
  }

  @throws[Exception]
  override def channelInactive(ctx: ChannelHandlerContext): Unit = {
    try
      requestHandler.channelInactive()
    catch {
      case e: Throwable =>
        logError("Exception from request handler while channel is inactive", e)
        throw e
    }
    try
      responseHandler.channelInactive()
    catch {
      case e: Throwable =>
        logError("Exception from response handler while channel is inactive", e)
        throw e
    }
    super.channelInactive(ctx)
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = {
    logWarning(s"Exception in connection from ${NettyUtils.getRemoteAddress(ctx.channel())}", cause)
    requestHandler.exceptionCaught(cause)
    responseHandler.exceptionCaught(cause)
    ctx.close()
  }
} 
Example 22
Source File: UnsharableHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter6

import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter


//使用注解@Sharable标注
@Sharable
class UnsharableHandler extends ChannelInboundHandlerAdapter {
  private var count = 0

  override def channelRead(ctx: ChannelHandlerContext, msg: Any): Unit = {
    //将 count 字段的值加 1
    count += 1
    //记录方法调用,并转发给下一个ChannelHandler
    System.out.println("inboundBufferUpdated(...) called the " + count + " time")
    ctx.fireChannelRead(msg)
  }
} 
Example 23
Source File: GamePacketEncoderMoP.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import wowchat.common.{ByteUtils, Packet}

import scala.collection.mutable.ArrayBuffer

class GamePacketEncoderMoP extends GamePacketEncoderCataclysm with GamePacketsMoP18414 {

  override def encode(ctx: ChannelHandlerContext, msg: Packet, out: ByteBuf): Unit = {
    val crypt = ctx.channel.attr(CRYPT).get
    val unencrypted = isUnencryptedPacket(msg.id)

    val headerSize = 4
    val size = msg.byteBuf.writerIndex

    val array = new ArrayBuffer[Byte](headerSize)
    val header = if (unencrypted) {
      array ++= ByteUtils.shortToBytesLE(size + 2)
      array ++= ByteUtils.shortToBytesLE(msg.id)
      array.toArray
    } else {
      array ++= ByteUtils.intToBytesLE((size << 13) | (msg.id & 0x1FFF))
      crypt.encrypt(array.toArray)
    }

    logger.debug(f"SEND PACKET: ${msg.id}%04X - ${ByteUtils.toHexString(msg.byteBuf, true, false)}")

    out.writeBytes(header)
    out.writeBytes(msg.byteBuf)
    msg.byteBuf.release
  }
} 
Example 24
Source File: GamePacketDecoderCataclysm.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import java.util.zip.Inflater

import io.netty.buffer.{ByteBuf, PooledByteBufAllocator}
import io.netty.channel.ChannelHandlerContext

class GamePacketDecoderCataclysm extends GamePacketDecoderWotLK with GamePacketsCataclysm15595 {

  protected val inflater: Inflater = new Inflater

  override def channelInactive(ctx: ChannelHandlerContext): Unit = {
    inflater.end()
    super.channelInactive(ctx)
  }

  override def decompress(id: Int, byteBuf: ByteBuf): (Int, ByteBuf) = {
    if (isCompressed(id)) {
      val decompressedSize = getDecompressedSize(byteBuf)

      val compressed = new Array[Byte](byteBuf.readableBytes)
      byteBuf.readBytes(compressed)
      byteBuf.release
      val decompressed = new Array[Byte](decompressedSize)

      inflater.setInput(compressed)
      inflater.inflate(decompressed)

      val ret = PooledByteBufAllocator.DEFAULT.buffer(decompressed.length, decompressed.length)
      ret.writeBytes(decompressed)
      (getDecompressedId(id, ret), ret)
    } else {
      (id, byteBuf)
    }
  }

  def getDecompressedSize(byteBuf: ByteBuf): Int = {
    byteBuf.readIntLE
  }

  def getDecompressedId(id: Int, buf: ByteBuf): Int = {
    id ^ COMPRESSED_DATA_MASK
  }

  def isCompressed(id: Int): Boolean = {
    (id & COMPRESSED_DATA_MASK) == COMPRESSED_DATA_MASK
  }
} 
Example 25
Source File: GamePacketDecoder.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import java.util

import wowchat.common.{ByteUtils, Packet}
import com.typesafe.scalalogging.StrictLogging
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder

class GamePacketDecoder extends ByteToMessageDecoder with GamePackets with StrictLogging {

  protected val HEADER_LENGTH = 4

  private var size = 0
  private var id = 0

  override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit = {
    if (in.readableBytes < HEADER_LENGTH) {
      return
    }

    val crypt = ctx.channel.attr(CRYPT).get

    if (size == 0 && id == 0) {
      // decrypt if necessary
      val tuple = if (crypt.isInit) {
        parseGameHeaderEncrypted(in, crypt)
      } else {
        parseGameHeader(in)
      }
      id = tuple._1
      size = tuple._2
    }

    if (size > in.readableBytes) {
      return
    }

    val byteBuf = in.readBytes(size)

    // decompress if necessary
    val (newId, decompressed) = decompress(id, byteBuf)

    val packet = Packet(newId, decompressed)

    logger.debug(f"RECV PACKET: $newId%04X - ${ByteUtils.toHexString(decompressed, true, false)}")

    out.add(packet)
    size = 0
    id = 0
  }

  def parseGameHeader(in: ByteBuf): (Int, Int) = {
    val size = in.readShort - 2
    val id = in.readShortLE
    (id, size)
  }

  def parseGameHeaderEncrypted(in: ByteBuf, crypt: GameHeaderCrypt): (Int, Int) = {
    val header = new Array[Byte](HEADER_LENGTH)
    in.readBytes(header)
    val decrypted = crypt.decrypt(header)
    val size = ((decrypted(0) & 0xFF) << 8 | decrypted(1) & 0xFF) - 2
    val id = (decrypted(3) & 0xFF) << 8 | decrypted(2) & 0xFF
    (id, size)
  }

  // vanilla has no compression. starts in cata/mop
  def decompress(id: Int, in: ByteBuf): (Int, ByteBuf) = {
    (id, in)
  }
} 
Example 26
Source File: GamePacketEncoder.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import wowchat.common.{ByteUtils, Packet}
import com.typesafe.scalalogging.StrictLogging
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.MessageToByteEncoder

import scala.collection.mutable.ArrayBuffer

class GamePacketEncoder extends MessageToByteEncoder[Packet] with GamePackets with StrictLogging {

  override def encode(ctx: ChannelHandlerContext, msg: Packet, out: ByteBuf): Unit = {
    val crypt = ctx.channel.attr(CRYPT).get
    val unencrypted = isUnencryptedPacket(msg.id)

    val headerSize = if (unencrypted) 4 else 6

    val array = new ArrayBuffer[Byte](headerSize)
    array ++= ByteUtils.shortToBytes(msg.byteBuf.writerIndex + headerSize - 2)
    array ++= ByteUtils.shortToBytesLE(msg.id)
    val header = if (unencrypted) {
      array.toArray
    } else {
      array.append(0, 0)
      crypt.encrypt(array.toArray)
    }

    logger.debug(f"SEND PACKET: ${msg.id}%04X - ${ByteUtils.toHexString(msg.byteBuf, true, false)}")

    out.writeBytes(header)
    out.writeBytes(msg.byteBuf)
    msg.byteBuf.release
  }

  protected def isUnencryptedPacket(id: Int): Boolean = {
    id == CMSG_AUTH_CHALLENGE
  }
} 
Example 27
Source File: RealmPacketDecoder.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.realm

import java.util

import wowchat.common.{ByteUtils, Packet, WowChatConfig, WowExpansion}
import com.typesafe.scalalogging.StrictLogging
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder

class RealmPacketDecoder extends ByteToMessageDecoder with StrictLogging {

  private var size = 0
  private var id = 0

  override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit = {
    if (in.readableBytes == 0) {
      return
    }

    if (size == 0 && id == 0) {
      in.markReaderIndex
      id = in.readByte
      id match {
        case RealmPackets.CMD_AUTH_LOGON_CHALLENGE =>
          if (in.readableBytes < 2) {
            in.resetReaderIndex
            return
          }

          in.markReaderIndex
          in.skipBytes(1)
          val result = in.readByte
          size = if (RealmPackets.AuthResult.isSuccess(result)) {
            118
          } else {
            2
          }
          in.resetReaderIndex
        case RealmPackets.CMD_AUTH_LOGON_PROOF =>
          if (in.readableBytes < 1) {
            in.resetReaderIndex
            return
          }

          // size is error dependent
          in.markReaderIndex
          val result = in.readByte
          size = if (RealmPackets.AuthResult.isSuccess(result)) {
            if (WowChatConfig.getExpansion == WowExpansion.Vanilla) 25 else 31
          } else {
            if (WowChatConfig.getExpansion == WowExpansion.Vanilla) 1 else 3
          }
          in.resetReaderIndex
        case RealmPackets.CMD_REALM_LIST =>
          if (in.readableBytes < 2) {
            in.resetReaderIndex
            return
          }

          size = in.readShortLE
      }
    }

    if (size > in.readableBytes) {
      return
    }

    val byteBuf = in.readBytes(size)
    val packet = Packet(id, byteBuf)

    logger.debug(f"RECV REALM PACKET: $id%04X - ${ByteUtils.toHexString(byteBuf, true, false)}")

    out.add(packet)
    size = 0
    id = 0
  }
} 
Example 28
Source File: IdleStateCallback.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.common

import com.typesafe.scalalogging.StrictLogging
import io.netty.channel.{ChannelHandlerContext, ChannelInboundHandlerAdapter}
import io.netty.handler.timeout.{IdleState, IdleStateEvent}

class IdleStateCallback extends ChannelInboundHandlerAdapter with StrictLogging {

  override def userEventTriggered(ctx: ChannelHandlerContext, evt: scala.Any): Unit = {
    evt match {
      case event: IdleStateEvent =>
        val idler = event.state match {
          case IdleState.READER_IDLE => "reader"
          case IdleState.WRITER_IDLE => "writer"
          case _ => "all"
        }
        logger.error(s"Network state for $idler marked as idle!")
        ctx.close
      case _ =>
    }

    super.userEventTriggered(ctx, evt)
  }
} 
Example 29
Source File: LogEventHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter13

import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler


//扩展 SimpleChannelInboundHandler 以处理 LogEvent 消息
class LogEventHandler extends SimpleChannelInboundHandler[LogEvent] {
  @throws[Exception]
  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = {
    //当异常发生时,打印栈跟踪信息,并关闭对应的 Channel
    cause.printStackTrace()
    ctx.close()
  }

  @throws[Exception]
  override def channelRead0(ctx: ChannelHandlerContext, event: LogEvent): Unit = {
    //打印 LogEvent 的数据
    println(event)
  }
} 
Example 30
Source File: LogEventEncoder.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter13

import io.netty.channel.ChannelHandlerContext
import io.netty.channel.socket.DatagramPacket
import io.netty.handler.codec.MessageToMessageEncoder
import io.netty.util.CharsetUtil
import java.net.InetSocketAddress
import java.util


// LogEventEncoder 创建了即将被发送到指定的 InetSocketAddress 的 DatagramPacket 消息
class LogEventEncoder(remoteAddress: InetSocketAddress)
  extends MessageToMessageEncoder[LogEvent] {

  @throws[Exception]
  override protected def encode(
    channelHandlerContext: ChannelHandlerContext,
    logEvent:              LogEvent,
    out:                   util.List[AnyRef]): Unit = {
    val file = logEvent.logfile.getBytes(CharsetUtil.UTF_8)
    val msg = logEvent.msg.getBytes(CharsetUtil.UTF_8)
    val buf = channelHandlerContext.alloc.buffer(file.length + msg.length + 1)
    //将文件名写入到 ByteBuf 中
    buf.writeBytes(file)
    //添加一个 SEPARATOR
    buf.writeByte(LogEvent.SEPARATOR)
    //将日志消息写入 ByteBuf 中
    buf.writeBytes(msg)
    //将一个拥有数据和目的地地址的新 DatagramPacket 添加到出站的消息列表中
    out.add(new DatagramPacket(buf, remoteAddress))
  }
} 
Example 31
Source File: LogEventDecoder.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter13

import io.netty.channel.ChannelHandlerContext
import io.netty.channel.socket.DatagramPacket
import io.netty.handler.codec.MessageToMessageDecoder
import io.netty.util.CharsetUtil
import java.util


class LogEventDecoder extends MessageToMessageDecoder[DatagramPacket] {
  @throws[Exception]
  override protected def decode(
    ctx:            ChannelHandlerContext,
    datagramPacket: DatagramPacket,
    out:            util.List[AnyRef]): Unit = {

    //获取对 DatagramPacket 中的数据(ByteBuf)的引用
    val data = datagramPacket.content

    //获取该 SEPARATOR 的索引
    val idx = data.indexOf(0, data.readableBytes, LogEvent.SEPARATOR)

    //提取文件名
    val filename = data.slice(0, idx).toString(CharsetUtil.UTF_8)

    //提取日志消息
    val logMsg = data.slice(idx + 1, data.readableBytes).toString(CharsetUtil.UTF_8)
    //构建一个新的 LogEvent 对象,并且将它添加到(已经解码的消息的)列表中

    val event = LogEvent(datagramPacket.sender, System.currentTimeMillis, filename, logMsg)
    out.add(event)
  }
} 
Example 32
Source File: FrameHandler.scala    From lila-ws   with GNU Affero General Public License v3.0 5 votes vote down vote up
package lila.ws
package netty

import com.typesafe.scalalogging.Logger
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
import io.netty.handler.codec.http.websocketx.WebSocketFrame
import scala.concurrent.ExecutionContext

import ipc.ClientOut

final private class FrameHandler(implicit ec: ExecutionContext)
    extends SimpleChannelInboundHandler[WebSocketFrame] {

  import FrameHandler._
  import ProtocolHandler.key

  override protected def channelRead0(
      ctx: ChannelHandlerContext,
      anyFrame: WebSocketFrame
  ) =
    anyFrame match {
      case frame: TextWebSocketFrame =>
        val txt = frame.text
        if (txt.nonEmpty) {
          val limiter = ctx.channel.attr(key.limit).get
          if (limiter == null || limiter(txt)) ClientOut parse txt foreach {

            case ClientOut.Unexpected(msg) =>
              Monitor.clientOutUnexpected.increment()
              logger.info(s"Unexpected $msg")

            case ClientOut.WrongHole =>
              Monitor.clientOutWrongHole.increment()

            case out =>
              Option(ctx.channel.attr(key.client).get) match {
                case Some(clientFu) =>
                  clientFu.value match {
                    case Some(client) => client foreach (_ ! out)
                    case None         => clientFu foreach (_ ! out)
                  }
                case None => logger.warn(s"No client actor to receive $out")
              }
          }
        }
      case frame =>
        logger.info("unsupported frame type: " + frame.getClass().getName())
    }
}

private object FrameHandler {

  private val logger = Logger(getClass)
} 
Example 33
Source File: WriteHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter6

import io.netty.channel.ChannelHandlerAdapter
import io.netty.channel.ChannelHandlerContext


class WriteHandler extends ChannelHandlerAdapter {
  private var ctx: ChannelHandlerContext = _

  override def handlerAdded(ctx: ChannelHandlerContext): Unit = {
    //存储到 ChannelHandlerContext的引用以供稍后使用
    this.ctx = ctx
  }

  def send(msg: String): Unit = { //使用之前存储的到 ChannelHandlerContext的引用来发送消息
    ctx.writeAndFlush(msg)
  }
} 
Example 34
Source File: EchoClientHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter2.echoclient

import io.netty.buffer.{ ByteBuf, Unpooled }
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ ChannelHandlerContext, SimpleChannelInboundHandler }
import io.netty.util.CharsetUtil

@Sharable //标记该类的实例可以被多个 Channel 共享
class EchoClientHandler extends SimpleChannelInboundHandler[ByteBuf] {
  override def channelActive(ctx: ChannelHandlerContext): Unit = {
    //当被通知 Channel是活跃的时候,发送一条消息
    ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8))
  }

  override def channelRead0(ctx: ChannelHandlerContext, in: ByteBuf): Unit = {
    //记录已接收消息的转储
    System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8))
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = {
    //在发生异常时,记录错误并关闭Channel
    cause.printStackTrace()
    ctx.close()
  }
} 
Example 35
Source File: EchoServerHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter2.echoserver

import io.netty.buffer.{ ByteBuf, Unpooled }
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ ChannelFutureListener, ChannelHandlerContext, ChannelInboundHandlerAdapter }
import io.netty.util.CharsetUtil

@Sharable
class EchoServerHandler extends ChannelInboundHandlerAdapter {
  override def channelRead(ctx: ChannelHandlerContext, msg: Any): Unit = {
    val in = msg.asInstanceOf[ByteBuf]
    //将消息记录到控制台
    System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8))
    //将接收到的消息写给发送者,而不冲刷出站消息
    ctx.write(in)
  }

  @throws[Exception]
  override def channelReadComplete(ctx: ChannelHandlerContext): Unit = {
    //将未决消息冲刷到远程节点,并且关闭该 Channel
    ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE)
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = {
    //打印异常栈跟踪
    cause.printStackTrace()
    //关闭该Channel
    ctx.close()
  }
} 
Example 36
Source File: InvalidBootstrapClient.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.oio.OioSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    val group = new NioEventLoopGroup
    //创建一个新的 Bootstrap 类的实例,以创建新的客户端Channel
    val bootstrap = new Bootstrap
    //指定一个适用于 NIO 的 EventLoopGroup 实现
    bootstrap.group(group)
      //指定一个适用于 OIO 的 Channel 实现类
      .channel(classOf[OioSocketChannel])
      //设置一个用于处理 Channel的 I/O 事件和数据的 ChannelInboundHandler
      .handler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          @throws[Exception]
          override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
            println("Received data")
          }
        }
      }
    //尝试连接到远程节点
    val future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
    future.syncUninterruptibly
  }
} 
Example 37
Source File: BootstrapSharingEventLoopGroup.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.bootstrap.ServerBootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = { //创建 ServerBootstrap 以创建 ServerSocketChannel,并绑定它
    val bootstrap = new ServerBootstrap
    //设置 EventLoopGroup,其将提供用以处理 Channel 事件的 EventLoop
    bootstrap.group(new NioEventLoopGroup, new NioEventLoopGroup)
      //指定要使用的 Channel 实现
      .channel(classOf[NioServerSocketChannel])
      //设置用于处理已被接受的子 Channel 的 I/O 和数据的 ChannelInboundHandler
      .childHandler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          private[chapter8] var connectFuture: ChannelFuture = _

          @throws[Exception]
          override def channelActive(ctx: ChannelHandlerContext): Unit = {
            //创建一个 Bootstrap 类的实例以连接到远程主机
            val bootstrap = new Bootstrap
            //指定 Channel 的实现
            bootstrap.channel(classOf[NioSocketChannel])
              .handler(new SimpleChannelInboundHandler[ByteBuf]() {
                @throws[Exception]
                override protected def channelRead0(
                  ctx: ChannelHandlerContext,
                  in:  ByteBuf): Unit = {
                  println("Received data")
                }
              })
            //使用与分配给已被接受的子Channel相同的EventLoop
            bootstrap.group(ctx.channel.eventLoop)
            //连接到远程节点
            connectFuture = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
          }

          @throws[Exception]
          override protected def channelRead0(
            channelHandlerContext: ChannelHandlerContext,
            byteBuf:               ByteBuf): Unit = {
            if (connectFuture.isDone) {
              //当连接完成时,执行一些数据操作(如代理)
              // do something with the data
            }
          }
        }
      }

    //通过配置好的 ServerBootstrap 绑定该 ServerSocketChannel
    val future = bootstrap.bind(new InetSocketAddress(8080))
    future.addListener(new ChannelFutureListener() {
      @throws[Exception]
      override def operationComplete(channelFuture: ChannelFuture): Unit = {
        if (channelFuture.isSuccess) System.out.println("Server bound")
        else {
          System.err.println("Bind attempt failed")
          channelFuture.cause.printStackTrace()
        }
      }
    })
  }
} 
Example 38
Source File: BootstrapServer.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.ServerBootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    val group = new NioEventLoopGroup
    //创建 Server Bootstrap
    val bootstrap = new ServerBootstrap
    //设置 EventLoopGroup,其提供了用于处理 Channel 事件的EventLoop
    bootstrap.group(group)
      //指定要使用的 Channel 实现
      .channel(classOf[NioServerSocketChannel])
      //设置用于处理已被接受的子 Channel 的I/O及数据的 ChannelInboundHandler
      .childHandler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          @throws[Exception]
          override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
            System.out.println("Received data")
          }
        }
      }

    //通过配置好的 ServerBootstrap 的实例绑定该 Channel
    val future = bootstrap.bind(new InetSocketAddress(8080))
    future.addListener(new ChannelFutureListener() {
      @throws[Exception]
      override def operationComplete(channelFuture: ChannelFuture): Unit = {
        if (channelFuture.isSuccess) System.out.println("Server bound")
        else {
          System.err.println("Bind attempt failed")
          channelFuture.cause.printStackTrace()
        }
      }
    })
  }
} 
Example 39
Source File: BootstrapDatagramChannel.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.oio.OioEventLoopGroup
import io.netty.channel.socket.DatagramPacket
import io.netty.channel.socket.oio.OioDatagramChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    //创建一个 Bootstrap 的实例以创建和绑定新的数据报 Channel
    val bootstrap = new Bootstrap
    //设置 EventLoopGroup,其提供了用以处理 Channel 事件的 EventLoop
    bootstrap.group(new OioEventLoopGroup)
      //指定 Channel 的实现
      .channel(classOf[OioDatagramChannel])
      .handler(new SimpleChannelInboundHandler[DatagramPacket]() {
        @throws[Exception]
        override def channelRead0(ctx: ChannelHandlerContext, msg: DatagramPacket): Unit = {
          // Do something with the packet
        }
      })

    //调用 bind() 方法,因为该协议是无连接的
    val future = bootstrap.bind(new InetSocketAddress(0))
    future.addListener(new ChannelFutureListener() {
      @throws[Exception]
      override def operationComplete(channelFuture: ChannelFuture): Unit = {
        if (channelFuture.isSuccess)
          println("Channel bound")
        else {
          System.err.println("Bind attempt failed")
          channelFuture.cause.printStackTrace()
        }
      }
    })
  }
} 
Example 40
Source File: BootstrapClientWithOptionsAndAttrs.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelOption
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.util.AttributeKey
import java.net.InetSocketAddress
import java.lang.{ Boolean ⇒ JBoolean }


  def bootstrap(): Unit = { //创建一个 AttributeKey 以标识该属性
    val id: AttributeKey[Integer] = AttributeKey.newInstance("ID")
    //创建一个 Bootstrap 类的实例以创建客户端 Channel 并连接它们
    val bootstrap = new Bootstrap
    //设置 EventLoopGroup,其提供了用以处理 Channel 事件的 EventLoop
    bootstrap.group(new NioEventLoopGroup)
      .channel(classOf[NioSocketChannel])
      .handler(new SimpleChannelInboundHandler[ByteBuf]() {
        @throws[Exception]
        override def channelRegistered(ctx: ChannelHandlerContext): Unit = { //使用 AttributeKey 检索属性以及它的值
          val idValue = ctx.channel.attr(id).get
          // do something with the idValue
        }

        @throws[Exception]
        override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
          System.out.println("Received data")
        }
      })

    //设置 ChannelOption,其将在 connect()或者bind()方法被调用时被设置到已经创建的 Channel 上
    bootstrap
      .option[JBoolean](ChannelOption.SO_KEEPALIVE, true)
      .option[Integer](ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)

    //存储该 id 属性
    bootstrap.attr[Integer](id, 123456)

    //使用配置好的 Bootstrap 实例连接到远程主机
    val future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
    future.syncUninterruptibly
  }
} 
Example 41
Source File: MethodNotFoundHandler.scala    From grpcgateway   with MIT License 5 votes vote down vote up
package grpcgateway.handlers

import io.netty.channel.{ChannelFutureListener, ChannelHandlerContext, ChannelInboundHandlerAdapter}
import io.netty.handler.codec.http.{FullHttpRequest, HttpResponseStatus}

class MethodNotFoundHandler  extends ChannelInboundHandlerAdapter {
  override def channelRead(ctx: ChannelHandlerContext, msg: scala.Any): Unit = {
    msg match {
      case req: FullHttpRequest =>
        ctx.writeAndFlush {
          buildFullHttpResponse(
            requestMsg = req,
            responseBody = "Method isn't supported",
            responseStatus = HttpResponseStatus.BAD_REQUEST,
            responseContentType = "application/text"
          )
        }.addListener(ChannelFutureListener.CLOSE)
      case _ => super.channelRead(ctx, msg)
    }

  }
}