@Override
 public void sendResponse(Throwable error) throws IOException {
   BytesStreamOutput stream;
   try {
     stream = BytesStreamOutput.Cached.cached();
     writeResponseExceptionHeader(stream);
     RemoteTransportException tx =
         new RemoteTransportException(
             transport.nodeName(),
             transport.wrapAddress(channel.getLocalAddress()),
             action,
             error);
     ThrowableObjectOutputStream too = new ThrowableObjectOutputStream(stream);
     too.writeObject(tx);
     too.close();
   } catch (NotSerializableException e) {
     stream = BytesStreamOutput.Cached.cached();
     writeResponseExceptionHeader(stream);
     RemoteTransportException tx =
         new RemoteTransportException(
             transport.nodeName(),
             transport.wrapAddress(channel.getLocalAddress()),
             action,
             new NotSerializableTransportException(error));
     ThrowableObjectOutputStream too = new ThrowableObjectOutputStream(stream);
     too.writeObject(tx);
     too.close();
   }
   ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(stream.copiedByteArray());
   buffer.setInt(0, buffer.writerIndex() - 4); // update real size.
   channel.write(buffer);
 }
Esempio n. 2
0
  /**
   * Logs out of the current IMAP session and releases all resources, including executor services.
   */
  @Override
  public synchronized void disconnect() {
    try {
      // If there is an error with the handler, dont bother logging out.
      if (!mailClientHandler.isHalted()) {
        if (mailClientHandler.idleRequested.get()) {
          log.warn("Disconnect called while IDLE, leaving idle and logging out.");
          done();
        }

        // Log out of the IMAP Server.
        channel.write(". logout\n");
      }

      currentFolder = null;
    } catch (Exception e) {
      // swallow any exceptions.
    } finally {
      // Shut down all channels and exit (leave threadpools as is--for reconnects).
      // The Netty channel close listener will fire a disconnect event to our client,
      // automatically. See connect() for details.
      try {
        channel.close().awaitUninterruptibly(config.getTimeout(), TimeUnit.MILLISECONDS);
      } catch (Exception e) {
        // swallow any exceptions.
      } finally {
        mailClientHandler.idleAcknowledged.set(false);
        mailClientHandler.disconnected();
        if (disconnectListener != null) disconnectListener.disconnected();
      }
    }
  }
  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
    getLogger(ctx.getChannel()).debug("Error while processing imap request", e.getCause());

    if (e.getCause() instanceof TooLongFrameException) {

      // Max line length exceeded
      // See RFC 2683 section 3.2.1
      //
      // "For its part, a server should allow for a command line of at
      // least
      // 8000 octets. This provides plenty of leeway for accepting
      // reasonable
      // length commands from clients. The server should send a BAD
      // response
      // to a command that does not end within the server's maximum
      // accepted
      // command length."
      //
      // See also JAMES-1190
      ImapResponseComposer composer = (ImapResponseComposer) ctx.getAttachment();
      composer.untaggedResponse(
          ImapConstants.BAD + " failed. Maximum command line length exceeded");
    } else {
      // logout on error not sure if that is the best way to handle it
      final ImapSession imapSession = (ImapSession) attributes.get(ctx.getChannel());
      if (imapSession != null) imapSession.logout();

      // Make sure we close the channel after all the buffers were flushed out
      Channel channel = ctx.getChannel();
      if (channel.isConnected()) {
        channel.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
      }
    }
  }
Esempio n. 4
0
  private boolean login() {
    try {
      channel.write(". CAPABILITY\r\n");
      if (config.getPassword() != null)
        channel.write(". login " + config.getUsername() + " " + config.getPassword() + "\r\n");
      else {
        // Use xoauth login instead.
        OAuthConfig oauth = config.getOAuthConfig();
        Preconditions.checkArgument(
            oauth != null, "Must specify a valid oauth config if not using password auth");

        //noinspection ConstantConditions
        String oauthString =
            new XoauthSasl(config.getUsername(), oauth.clientId, oauth.clientSecret)
                .build(Protocol.IMAP, oauth.accessToken, oauth.tokenSecret);

        channel.write(". AUTHENTICATE XOAUTH " + oauthString + "\r\n");
      }
      return mailClientHandler.awaitLogin();
    } catch (Exception e) {
      // Capture the wire trace and log it for some extra context here.
      StringBuilder trace = new StringBuilder();
      for (String line : mailClientHandler.getWireTrace()) {
        trace.append(line).append("\n");
      }

      log.warn(
          "Could not oauth or login for {}. Partial trace follows:\n"
              + "----begin wiretrace----\n{}\n----end wiretrace----",
          new Object[] {config.getUsername(), trace.toString(), e});
    }
    return false;
  }
Esempio n. 5
0
  /** Connects to the IMAP server logs in with the given credentials. */
  @Override
  public synchronized boolean connect(final DisconnectListener listener) {
    reset();

    ChannelFuture future =
        bootstrap.connect(new InetSocketAddress(config.getHost(), config.getPort()));

    Channel channel = future.awaitUninterruptibly().getChannel();
    if (!future.isSuccess()) {
      throw new RuntimeException("Could not connect channel", future.getCause());
    }

    this.channel = channel;
    this.disconnectListener = listener;
    if (null != listener) {
      // https://issues.jboss.org/browse/NETTY-47?page=com.atlassian.jirafisheyeplugin%3Afisheye-issuepanel#issue-tabs
      channel
          .getCloseFuture()
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                  mailClientHandler.idleAcknowledged.set(false);
                  mailClientHandler.disconnected();
                  listener.disconnected();
                }
              });
    }
    return login();
  }
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
   e.getCause().printStackTrace();
   Channel channel = e.getChannel();
   channel.close();
   System.out.println("exceptionCaught...");
 }
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
   Channel ch = e.getChannel();
   Throwable cause = e.getCause();
   if (cause instanceof TooLongFrameException) {
     sendError(ctx, HttpResponseStatus.BAD_REQUEST);
     return;
   }
   if (cause != null) {
     if (cause.getClass().equals(IOException.class)) {
       LOGGER.debug("Connection error: " + cause);
       StartStopListenerDelegate startStopListenerDelegate =
           (StartStopListenerDelegate) ctx.getAttachment();
       if (startStopListenerDelegate != null) {
         LOGGER.debug("Premature end, stopping...");
         startStopListenerDelegate.stop();
       }
     } else if (!cause.getClass().equals(ClosedChannelException.class)) {
       LOGGER.debug("Caught exception: " + cause);
     }
   }
   if (ch.isConnected()) {
     sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
   }
   e.getChannel().close();
 }
  @Override
  public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
    // Suspend incoming traffic until connected to the remote host.
    final Channel inboundChannel = e.getChannel();
    inboundChannel.setReadable(false);

    // Start the connection attempt.
    ClientBootstrap cb = new ClientBootstrap(cf);
    cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel()));
    ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort));

    outboundChannel = f.getChannel();
    f.addListener(
        new ChannelFutureListener() {
          public void operationComplete(ChannelFuture future) throws Exception {
            if (future.isSuccess()) {
              // Connection attempt succeeded:
              // Begin to accept incoming traffic.
              inboundChannel.setReadable(true);
            } else {
              // Close the connection if the connection attempt has failed.
              inboundChannel.close();
            }
          }
        });
  }
  protected void writeMessage(SMTPMessage msg) {
    Set<String> extensions = getSupportedExtensions();

    if (msg instanceof SMTPByteArrayMessage) {
      byte[] data;

      if (extensions.contains(_8BITMIME_EXTENSION)) {
        data = ((SMTPByteArrayMessage) msg).get8BitAsByteArray();
      } else {
        data = ((SMTPByteArrayMessage) msg).get7BitAsByteArray();
      }
      channel.write(createDataTerminatingChannelBuffer(data));
    } else {
      InputStream msgIn;
      try {

        if (extensions.contains(_8BITMIME_EXTENSION)) {
          msgIn = msg.get8Bit();
        } else {
          msgIn = msg.get7bit();
        }

      } catch (IOException e) {
        msgIn = IOExceptionInputStream.INSTANCE;
      }

      channel.write(new ChunkedStream(new DataTerminatingInputStream(msgIn)));
    }
  }
Esempio n. 10
0
  public void handleGameRoomJoin(Player player, Channel channel, ChannelBuffer buffer) {
    String refKey = NettyUtils.readString(buffer);

    GameRoom gameRoom = lookupService.gameRoomLookup(refKey);
    if (null != gameRoom) {
      PlayerSession playerSession = gameRoom.createPlayerSession();
      playerSession.setConnectParameter(
          NettyUtils.NETTY_CHANNEL, channel); // TODO is this required?
      gameRoom.onLogin(playerSession);
      LOG.trace("Sending GAME_ROOM_JOIN_SUCCESS to channel {}", channel.getId());
      ChannelFuture future =
          channel.write(NettyUtils.createBufferForOpcode(Events.GAME_ROOM_JOIN_SUCCESS));
      connectToGameRoom(gameRoom, playerSession, future);
      loginUdp(playerSession, buffer);
    } else {
      // Write failure and close channel.
      ChannelFuture future =
          channel.write(NettyUtils.createBufferForOpcode(Events.GAME_ROOM_JOIN_FAILURE));
      future.addListener(ChannelFutureListener.CLOSE);
      LOG.error(
          "Invalid ref key provided by client: {}. Channel {} will be closed",
          refKey,
          channel.getId());
    }
  }
  private ChannelFuture sendFile(ChannelHandlerContext ctx, Channel ch, FileChunk file)
      throws IOException {
    RandomAccessFile raf;
    try {
      raf = new RandomAccessFile(file.getFile(), "r");
    } catch (FileNotFoundException fnfe) {
      return null;
    }

    ChannelFuture writeFuture;
    if (ch.getPipeline().get(SslHandler.class) != null) {
      // Cannot use zero-copy with HTTPS.
      writeFuture = ch.write(new ChunkedFile(raf, file.startOffset(), file.length(), 8192));
    } else {
      // No encryption - use zero-copy.
      final FileRegion region =
          new DefaultFileRegion(raf.getChannel(), file.startOffset(), file.length());
      writeFuture = ch.write(region);
      writeFuture.addListener(
          new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) {
              region.releaseExternalResources();
            }
          });
    }

    return writeFuture;
  }
Esempio n. 12
0
 @Override
 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
   Channel channel = ctx.getChannel();
   if (!sessions.removeSession(channel.getId())) {
     Log.error("删除Session失败! sockId: " + channel.getId());
   }
 }
Esempio n. 13
0
  public void run() {
    // Configure the client.
    ClientBootstrap bootstrap =
        new ClientBootstrap(
            new NioClientSocketChannelFactory(
                Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));

    // Set up the event pipeline factory.
    bootstrap.setPipelineFactory(new FactorialClientPipelineFactory(count));

    // Make a new connection.
    ChannelFuture connectFuture = bootstrap.connect(new InetSocketAddress(host, port));

    // Wait until the connection is made successfully.
    Channel channel = connectFuture.awaitUninterruptibly().getChannel();

    // Get the handler instance to retrieve the answer.
    FactorialClientHandler handler = (FactorialClientHandler) channel.getPipeline().getLast();

    // Print out the answer.
    System.err.format("Factorial of %,d is: %,d", count, handler.getFactorial());

    // Shut down all thread pools to exit.
    bootstrap.releaseExternalResources();
  }
Esempio n. 14
0
 /** Stop all sockets */
 @PreDestroy
 public void stopListener() {
   for (Channel channel : channels) {
     logger.info("Stop socket on port " + channel.getLocalAddress());
     channel.unbind();
   }
 }
Esempio n. 15
0
  protected ChannelFuture sendFile(File file) {
    final RandomAccessFile raf;
    try {
      raf = new RandomAccessFile(file, "r");
      long fileLength = file.length();

      // Write the content.
      ChannelFuture writeFuture;
      if (isSSL()) {
        // Cannot use zero-copy with HTTPS.
        writeFuture = channel.write(new ChunkedFile(raf, 0, fileLength, 8192));
      } else {
        // No encryption - use zero-copy.
        final FileRegion region = new DefaultFileRegion(raf.getChannel(), 0, fileLength);
        writeFuture = channel.write(region);
      }
      writeFuture.addListener(
          new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) throws Exception {
              raf.close();
            }
          });
      return writeFuture;
    } catch (IOException e) {
      handleException(e);
      return null;
    }
  }
Esempio n. 16
0
  /**
   * Writes the given body to Netty channel. Will <b>not</b >wait until the body has been written.
   *
   * @param log logger to use
   * @param channel the Netty channel
   * @param remoteAddress the remote address when using UDP
   * @param body the body to write (send)
   * @param exchange the exchange
   * @param listener listener with work to be executed when the operation is complete
   */
  public static void writeBodyAsync(
      Logger log,
      Channel channel,
      SocketAddress remoteAddress,
      Object body,
      Exchange exchange,
      ChannelFutureListener listener) {
    ChannelFuture future;
    if (remoteAddress != null) {
      if (log.isDebugEnabled()) {
        log.debug(
            "Channel: {} remote address: {} writing body: {}",
            new Object[] {channel, remoteAddress, body});
      }
      future = channel.write(body, remoteAddress);
    } else {
      if (log.isDebugEnabled()) {
        log.debug("Channel: {} writing body: {}", new Object[] {channel, body});
      }
      future = channel.write(body);
    }

    if (listener != null) {
      future.addListener(listener);
    }
  }
Esempio n. 17
0
 private void httpRequestReceived(HttpRequest request, Channel channel) {
   HttpResponse response = getResponse(request);
   eventBus.post(response);
   channel.write(response);
   channel.disconnect();
   channel.close();
 }
Esempio n. 18
0
  public void sendRequest(MetaInfo meta) {
    System.out.println(Thread.currentThread().getId() + " start sendRequest");
    URI uri = null;
    try {
      System.out.println(meta.getParams());
      uri = new URI(meta.getUrl());
    } catch (URISyntaxException e) {
      e.printStackTrace(); // To change body of catch statement use File | Settings | File
      // Templates.
    }
    String host = uri.getHost();
    int port = 80;

    HttpRequest request =
        new DefaultHttpRequest(
            HttpVersion.HTTP_1_1, HttpMethod.valueOf(meta.getMethod()), uri.toASCIIString());
    meta.buildHttpRequestHeader(request);

    ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
    Channel channel = future.getChannel();
    channel.getPipeline().addLast("handler", new DownloaderHandler());
    GlobalVar.metaInfoVar.set(channel, meta);

    future.addListener(new ConnectOk(request));
    channel.getCloseFuture().awaitUninterruptibly().addListener(new ConnectClose());
    System.out.println(Thread.currentThread().getId() + " end sendRequest");
  }
Esempio n. 19
0
  /**
   * Forcefully shuts down the connection to this tablet server and fails all the outstanding RPCs.
   * Only use when shutting down a client.
   *
   * @return deferred object to use to track the shutting down of this connection
   */
  public Deferred<Void> shutdown() {
    // First, check whether we have RPCs in flight and cancel them.
    for (Iterator<KuduRpc<?>> ite = rpcs_inflight.values().iterator(); ite.hasNext(); ) {
      KuduRpc<?> rpc = ite.next();
      rpc.errback(new ConnectionResetException(null));
      ite.remove();
    }

    // Same for the pending RPCs.
    synchronized (this) {
      if (pending_rpcs != null) {
        for (Iterator<KuduRpc<?>> ite = pending_rpcs.iterator(); ite.hasNext(); ) {
          ite.next().errback(new ConnectionResetException(null));
          ite.remove();
        }
      }
    }

    final Channel chancopy = chan;
    if (chancopy == null) {
      return Deferred.fromResult(null);
    }
    if (chancopy.isConnected()) {
      Channels.disconnect(chancopy); // ... this is going to set it to null.
      // At this point, all in-flight RPCs are going to be failed.
    }
    if (chancopy.isBound()) {
      Channels.unbind(chancopy);
    }
    // It's OK to call close() on a Channel if it's already closed.
    final ChannelFuture future = Channels.close(chancopy);
    // Now wrap the ChannelFuture in a Deferred.
    final Deferred<Void> d = new Deferred<Void>();
    // Opportunistically check if it's already completed successfully.
    if (future.isSuccess()) {
      d.callback(null);
    } else {
      // If we get here, either the future failed (yeah, that sounds weird)
      // or the future hasn't completed yet (heh).
      future.addListener(
          new ChannelFutureListener() {
            public void operationComplete(final ChannelFuture future) {
              if (future.isSuccess()) {
                d.callback(null);
                return;
              }
              final Throwable t = future.getCause();
              if (t instanceof Exception) {
                d.callback(t);
              } else {
                // Wrap the Throwable because Deferred doesn't handle Throwables,
                // it only uses Exception.
                d.callback(
                    new NonRecoverableException("Failed to shutdown: " + TabletClient.this, t));
              }
            }
          });
    }
    return d;
  }
Esempio n. 20
0
  @Override
  public void exceptionCaught(final ChannelHandlerContext ctx, final ExceptionEvent event) {
    final Throwable e = event.getCause();
    final Channel c = event.getChannel();

    if (e instanceof RejectedExecutionException) {
      LOG.warn(
          getPeerUuidLoggingString()
              + "RPC rejected by the executor,"
              + " ignore this if we're shutting down",
          e);
    } else if (e instanceof ReadTimeoutException) {
      LOG.debug(getPeerUuidLoggingString() + "Encountered a read timeout");
      // Doing the cleanup here since we want to invalidate all the RPCs right _now_, and not let
      // the ReplayingDecoder continue decoding through Channels.close() below.
      cleanup(c);
    } else {
      LOG.error(getPeerUuidLoggingString() + "Unexpected exception from downstream on " + c, e);
      // For any other exception, likely a connection error, we clear the leader state
      // for those tablets that this TS is the cached leader of.
      kuduClient.demoteAsLeaderForAllTablets(this);
    }
    if (c.isOpen()) {
      Channels.close(c); // Will trigger channelClosed(), which will cleanup()
    } else { // else: presumably a connection timeout.
      cleanup(c); // => need to cleanup() from here directly.
    }
  }
Esempio n. 21
0
 /** Quick and dirty way to close a connection to a tablet server, if it wasn't already closed. */
 @VisibleForTesting
 void disconnect() {
   Channel chancopy = chan;
   if (chancopy != null && chancopy.isConnected()) {
     Channels.disconnect(chancopy);
   }
 }
  protected void sendRequest(
      HttpRequest request,
      SendRequestResultListener listener,
      HttpResponseProcessor responseProcessor) {
    if (isClosingOrClosed()) {
      listener.onSendRequestFailure(request, new ClosedChannelException());
    } else if (!isConnected()) {
      listener.onSendRequestFailure(request, new RuntimeException("unable to send request"));
    } else {
      try {
        setResponseProcessor(responseProcessor, listener);
      } catch (DatabusException e) {
        listener.onSendRequestFailure(request, e.getCause());
        _channel.close();
        return;
      }

      // Send the HTTP request.
      if (_channel.isConnected()) {
        // ChannelFuture future = _channel.write(request);
        // future.addListener(new MySendRequestListener(request, listener));
        _channel.write(request);
      } else {
        _log.error("disconnect on request: " + request.getUri());
        listener.onSendRequestFailure(request, new ClosedChannelException());
      }
    }
  }
  protected void increaseCounter(Runnable task) {
    if (!shouldCount(task)) {
      return;
    }

    Settings settings = this.settings;
    long maxChannelMemorySize = settings.maxChannelMemorySize;

    int increment = settings.objectSizeEstimator.estimateSize(task);

    if (task instanceof ChannelEventRunnable) {
      ChannelEventRunnable eventTask = (ChannelEventRunnable) task;
      eventTask.estimatedSize = increment;
      Channel channel = eventTask.getEvent().getChannel();
      long channelCounter = getChannelCounter(channel).addAndGet(increment);
      // System.out.println("IC: " + channelCounter + ", " + increment);
      if (maxChannelMemorySize != 0 && channelCounter >= maxChannelMemorySize && channel.isOpen()) {
        if (channel.isReadable()) {
          // System.out.println("UNREADABLE");
          ChannelHandlerContext ctx = eventTask.getContext();
          if (ctx.getHandler() instanceof ExecutionHandler) {
            // readSuspended = true;
            ctx.setAttachment(Boolean.TRUE);
          }
          channel.setReadable(false);
        }
      }
    } else {
      ((MemoryAwareRunnable) task).estimatedSize = increment;
    }

    if (totalLimiter != null) {
      totalLimiter.increase(increment);
    }
  }
  @Override
  public AsyncIOWriter write(byte[] data, int offset, int length) throws IOException {

    if (channel.isOpen()) {
      pendingWrite.incrementAndGet();
      final ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();

      ChannelBufferOutputStream c = new ChannelBufferOutputStream(buffer);

      if (headerWritten) {
        c.write(Integer.toHexString(length - offset).getBytes("UTF-8"));
        c.write(CHUNK_DELIMITER);
      }

      c.write(data, offset, length);
      if (headerWritten) {
        c.write(CHUNK_DELIMITER);
      }

      channel.write(c.buffer()).addListener(listener);
      byteWritten = true;
      lastWrite = System.currentTimeMillis();
    } else {
      logger.warn("Trying to write on a closed channel {}", channel);
    }
    headerWritten = true;
    return this;
  }
Esempio n. 25
0
 @Override
 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
   context.getWorkers().put(ctx.getChannel(), new MasterWorkerHolder(ctx.getChannel()));
   Channel channel = ctx.getChannel();
   SocketAddress addr = channel.getRemoteAddress();
   SocketLog.info("worker connected , :" + addr.toString());
   super.channelConnected(ctx, e);
 }
Esempio n. 26
0
 public void ping() {
   if (!channel.isConnected()) {
     System.err.println("MQtt Channel disconnected");
     timer.cancel();
     reconnect();
   }
   channel.write(new PingReqMessage());
 }
Esempio n. 27
0
 /** Close the connection. */
 public synchronized void close() {
   if (!closed && channel != null) {
     ConnectionWatchdog watchdog = channel.getPipeline().get(ConnectionWatchdog.class);
     watchdog.setReconnect(false);
     closed = true;
     channel.close();
   }
 }
Esempio n. 28
0
 protected void setupNewChannel(RpcChannel rpcChannel) {
   Channel channel = rpcChannel.getChannel();
   RpcMessageHandler handler = (RpcMessageHandler) channel.getPipeline().get("handler");
   handler.setChannel(rpcChannel);
   rpcChannel.setServiceMap(Collections.unmodifiableMap(services));
   if (newChannelCallback != null) {
     newChannelCallback.run(rpcChannel);
   }
 }
 @Test
 public void testTimeToSendMessages() throws Exception {
   connectSender();
   senderThread.join();
   reportLatencies();
   listenerChannel.close();
   listenerChannel.unbind();
   bootstrap.releaseExternalResources();
 }
Esempio n. 30
0
  private <T> Response<T> sendRequest(
      RequestType type,
      SlaveContext slaveContext,
      Serializer serializer,
      Deserializer<T> deserializer) {
    // TODO Refactor, break into smaller methods
    Triplet<Channel, ChannelBuffer, ByteBuffer> channelContext = null;
    try {
      // Send 'em over the wire
      channelContext = getChannel();
      Channel channel = channelContext.first();
      ChannelBuffer buffer = channelContext.second();
      buffer.clear();
      buffer = new ChunkingChannelBuffer(buffer, channel, MAX_FRAME_LENGTH);
      buffer.writeByte(type.ordinal());
      if (type.includesSlaveContext()) {
        writeSlaveContext(buffer, slaveContext);
      }
      serializer.write(buffer, channelContext.third());
      if (buffer.writerIndex() > 0) {
        channel.write(buffer);
      }

      // Read the response
      @SuppressWarnings("unchecked")
      BlockingReadHandler<ChannelBuffer> reader =
          (BlockingReadHandler<ChannelBuffer>) channel.getPipeline().get("blockingHandler");
      final Triplet<Channel, ChannelBuffer, ByteBuffer> finalChannelContext = channelContext;
      DechunkingChannelBuffer dechunkingBuffer =
          new DechunkingChannelBuffer(reader) {
            @Override
            protected ChannelBuffer readNext() {
              ChannelBuffer result = super.readNext();
              if (result == null) {
                channelPool.dispose(finalChannelContext);
                throw new HaCommunicationException("Channel has been closed");
              }
              return result;
            }
          };
      T response = deserializer.read(dechunkingBuffer);
      TransactionStream txStreams =
          type.includesSlaveContext()
              ? readTransactionStreams(dechunkingBuffer)
              : TransactionStream.EMPTY;
      return new Response<T>(response, txStreams);
    } catch (ClosedChannelException e) {
      channelPool.dispose(channelContext);
      throw new HaCommunicationException(e);
    } catch (IOException e) {
      throw new HaCommunicationException(e);
    } catch (InterruptedException e) {
      throw new HaCommunicationException(e);
    } catch (Exception e) {
      throw new HaCommunicationException(e);
    }
  }