@Override public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception { if (!chunked) { final HttpRequest request = (HttpRequest) e.getMessage(); final ChannelBuffer buffer = request.getContent(); receivedData.write(buffer.array()); // System.out.println("received "+buffer.array() ); // System.out.println(buffer.array().length); if (!request.isChunked()) { processRequest(e); } else { chunked = true; } // final boolean keepAlive = isKeepAlive(request); } else { final HttpChunk chunk = (HttpChunk) e.getMessage(); final ChannelBuffer buffer = chunk.getContent(); receivedData.write(buffer.array()); if (chunk.isLast()) { processRequest(e); } } }
@Override protected Object decode( final ChannelHandlerContext ctx, final Channel channel, final ChannelBuffer buffer) throws Exception { while (buffer.readable()) { byte c = buffer.readByte(); // check if last character read was DLE if (foundDLE) { foundDLE = false; if (c == DleStxEtxConstants.STX && !foundPacket) { foundPacket = true; } else if (c == DleStxEtxConstants.ETX && foundPacket) { ChannelBuffer packetRead = packet; resetDecodingState(); return packetRead; } else if (c == DleStxEtxConstants.DLE && foundPacket) { // Stuffed DLE found packet.writeByte(DleStxEtxConstants.DLE); } else { if (log.isWarnEnabled()) { log.warn( "Incomplete packet received: {}", StringUtils.toHexString( packet.array(), packet.readerIndex(), packet.readableBytes())); } resetDecodingState(); } } else { if (c == DleStxEtxConstants.DLE) { // log.trace("Plain DLE received"); foundDLE = true; } else if (foundPacket) { packet.writeByte(c); } } } // decoding is not yet complete, we'll need more bytes until we find DLE // ETX return null; }
/* (non-Javadoc) * @see com.e9.framework.channel.i.Message#decode(com.e9.framework.channel.i.IoBuffer) */ @Override public void decode(IoBuffer arg0) throws Exception { // TODO Auto-generated method stub ChannelBuffer buffer = null; try { buffer = beginDecode(arg0); // buffer.skipBytes(GwLength.STATUS); } catch (Exception e) { // TODO: handle exception throw new Exception(buffer == null ? "" : Common.toHex(buffer.array()), e); } }
public static void send(MessageEvent event, Integer transactionId, Long connectionId) throws Exception { logger.debug("ConnectionResponse::send to " + event.getRemoteAddress()); ChannelBuffer responseBuffer = ChannelBuffers.buffer(4 + 4 + 8); responseBuffer.writeInt(Action.CONNECT.getId()); responseBuffer.writeInt(transactionId); responseBuffer.writeLong(connectionId); logger.debug("ConnectionResponse DUMP: " + Utils.getHexString(responseBuffer.array())); event.getChannel().write(responseBuffer, event.getRemoteAddress()); }
/** * Read a PeerAddress from a Netty buffer. I did not want to include ChannelBuffer in the class * PeerAddress * * @param buffer The Netty buffer * @return A PeerAddress created from the buffer (deserialized) */ private static PeerAddress readPeerAddress(final ChannelBuffer buffer) { if (buffer.readableBytes() < 21) return null; Number160 id = readID(buffer); // peek int type = buffer.getUnsignedByte(buffer.readerIndex()); // now we know the length int len = PeerAddress.expectedSocketLength(type); if (buffer.readableBytes() < len) return null; PeerAddress peerAddress = new PeerAddress(id, buffer.array(), buffer.arrayOffset() + buffer.readerIndex()); buffer.skipBytes(len); return peerAddress; }
/* * Each ControlMessage is encoded as: * code (<0) ... short(2) * Each TaskMessage is encoded as: * task (>=0) ... short(2) * len ... int(4) * payload ... byte[] * */ protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { // Make sure that we have received at least a short if (buf.readableBytes() < 2) { // need more data return null; } // Mark the current buffer position before reading task/len field // because the whole frame might not be in the buffer yet. // We will reset the buffer position to the marked position if // there's not enough bytes in the buffer. buf.markReaderIndex(); // read the short field short code = buf.readShort(); // case 1: Control message ControlMessage ctrl_msg = ControlMessage.mkMessage(code); if (ctrl_msg != null) return ctrl_msg; // case 2: task Message short task = code; // Make sure that we have received at least an integer (length) if (buf.readableBytes() < 4) { // need more data buf.resetReaderIndex(); return null; } // Read the length field. int length = buf.readInt(); if (length <= 0) { return new TaskMessage(task, null); } // Make sure if there's enough bytes in the buffer. if (buf.readableBytes() < length) { // The whole bytes were not received yet - return null. buf.resetReaderIndex(); return null; } // There's enough bytes in the buffer. Read it. ChannelBuffer payload = buf.readBytes(length); // Successfully decoded a frame. // Return a TaskMessage object return new TaskMessage(task, payload.array()); }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { ChannelBuffer buf; PaxosMessage msg; buf = (ChannelBuffer) e.getMessage(); // Read in the message string. msg = new PaxosMessage(); msg.unSerialize(buf.array()); // Send the message upstream to the server handler. Channels.fireMessageReceived(ctx, msg); }
public static void send( MessageEvent event, Integer transactionId, List<TorrentStats> torrentStatsList) throws Exception { logger.debug("ScrapeResponse::send to " + event.getRemoteAddress()); ChannelBuffer responseBuffer = ChannelBuffers.buffer(4 + 4 + torrentStatsList.size() * 12); responseBuffer.writeInt(Action.SCRAPE.getId()); responseBuffer.writeInt(transactionId); for (TorrentStats torrentStats : torrentStatsList) { responseBuffer.writeInt(torrentStats.seeders); responseBuffer.writeInt(torrentStats.completed); responseBuffer.writeInt(torrentStats.leechers); } logger.debug("ScrapeResponse DUMP: " + Utils.getHexString(responseBuffer.array())); event.getChannel().write(responseBuffer, event.getRemoteAddress()); }
/** * Decodes bytes from a channel buffer * * @param ctx a channel handler context * @param channel a channel * @param msg a message * @return a byte array */ @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!(msg instanceof ChannelBuffer)) { return msg; } ChannelBuffer buf = (ChannelBuffer) msg; byte[] array; if (buf.hasArray()) { if (buf.arrayOffset() == 0 && buf.readableBytes() == buf.capacity()) { array = buf.array(); } else { array = new byte[buf.readableBytes()]; buf.getBytes(0, array); } } else { array = new byte[buf.readableBytes()]; buf.getBytes(0, array); } return array; }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ResultCode success; ChannelBuffer buf = (ChannelBuffer) e.getMessage(); TMemoryInputTransport trans = new TMemoryInputTransport(buf.array()); TBinaryProtocol proto = new TBinaryProtocol(trans); TMessage msg = proto.readMessageBegin(); if (msg.type == TMessageType.EXCEPTION) { proto.readMessageEnd(); } TField field; proto.readStructBegin(); while (true) { field = proto.readFieldBegin(); if (field.type == TType.STOP) { break; } switch (field.id) { case 0: // SUCCESS if (field.type == TType.I32) { success = ResultCode.findByValue(proto.readI32()); stats.accumulateOutcomeWithDelta( success.getValue() == 0 ? Outcome.SUCCESS : Outcome.GRACEFUL_FAILURE, 0); } else { TProtocolUtil.skip(proto, field.type); } break; default: TProtocolUtil.skip(proto, field.type); } proto.readFieldEnd(); } proto.readStructEnd(); proto.readMessageEnd(); }
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page. if (req.getUri().equals("/")) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); setContentLength(res, content.readableBytes()); res.setContent(content); sendHttpResponse(ctx, req, res); return; } // Serve the WebSocket handshake request. if (req.getUri().equals(WEBSOCKET_PATH) && Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION)) && WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) { // Create the WebSocket handshake response. HttpResponse res = new DefaultHttpResponse( HTTP_1_1, new HttpResponseStatus(101, "Web Socket Protocol Handshake")); res.addHeader(Names.UPGRADE, WEBSOCKET); res.addHeader(CONNECTION, Values.UPGRADE); // Fill in the headers and contents depending on handshake method. if (req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2)) { // New handshake method with a challenge: res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req)); String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(SEC_WEBSOCKET_PROTOCOL, protocol); } // Calculate the answer of the challenge. String key1 = req.getHeader(SEC_WEBSOCKET_KEY1); String key2 = req.getHeader(SEC_WEBSOCKET_KEY2); int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length()); int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length()); long c = req.getContent().readLong(); ChannelBuffer input = ChannelBuffers.buffer(16); input.writeInt(a); input.writeInt(b); input.writeLong(c); ChannelBuffer output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array())); res.setContent(output); } else { // Old handshake method with no challenge: res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req)); String protocol = req.getHeader(WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(WEBSOCKET_PROTOCOL, protocol); } } // Upgrade the connection and send the handshake response. ChannelPipeline p = ctx.getChannel().getPipeline(); p.remove("aggregator"); p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder()); ctx.getChannel().write(res); p.replace("encoder", "wsencoder", new WebSocketFrameEncoder()); return; } // Send an error page otherwise. sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); }
@Override public byte[] array() { return buffer.array(); }
private void websocketHandshake(final ChannelHandlerContext ctx, HttpRequest req, MessageEvent e) throws Exception { // Create the WebSocket handshake response. HttpResponse res = new DefaultHttpResponse( HttpVersion.HTTP_1_1, new HttpResponseStatus(101, "Web Socket Protocol Handshake")); res.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); res.addHeader(CONNECTION, HttpHeaders.Values.UPGRADE); // Fill in the headers and contents depending on handshake method. if (req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2)) { // New handshake method with a challenge: res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader( SEC_WEBSOCKET_LOCATION, "ws://" + req.getHeader(HttpHeaders.Names.HOST) + req.getUri()); String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(SEC_WEBSOCKET_PROTOCOL, protocol); } // Calculate the answer of the challenge. String key1 = req.getHeader(SEC_WEBSOCKET_KEY1); String key2 = req.getHeader(SEC_WEBSOCKET_KEY2); int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length()); int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length()); long c = req.getContent().readLong(); ChannelBuffer input = ChannelBuffers.buffer(16); input.writeInt(a); input.writeInt(b); input.writeLong(c); try { ChannelBuffer output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array())); res.setContent(output); } catch (NoSuchAlgorithmException ex) { throw new UnexpectedException(ex); } } else { // Old handshake method with no challenge: res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); res.addHeader( WEBSOCKET_LOCATION, "ws://" + req.getHeader(HttpHeaders.Names.HOST) + req.getUri()); String protocol = req.getHeader(WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(WEBSOCKET_PROTOCOL, protocol); } } // Keep the original request Http.Request request = parseRequest(ctx, req); // Route the websocket request request.method = "WS"; Map<String, String> route = Router.route(request.method, request.path); if (!route.containsKey("action")) { // No route found to handle this websocket connection ctx.getChannel() .write(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND)); return; } // Upgrade the connection and send the handshake response. ChannelPipeline p = ctx.getChannel().getPipeline(); p.remove("aggregator"); p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder()); // Connect ctx.getChannel().write(res); p.replace("encoder", "wsencoder", new WebSocketFrameEncoder()); req.setMethod(new HttpMethod("WEBSOCKET")); // Inbound Http.Inbound inbound = new Http.Inbound() { @Override public boolean isOpen() { return ctx.getChannel().isOpen(); } }; channels.put(ctx, inbound); // Outbound Http.Outbound outbound = new Http.Outbound() { final List<ChannelFuture> writeFutures = Collections.synchronizedList(new ArrayList<ChannelFuture>()); Promise<Void> closeTask; synchronized void writeAndClose(ChannelFuture writeFuture) { if (!writeFuture.isDone()) { writeFutures.add(writeFuture); writeFuture.addListener( new ChannelFutureListener() { public void operationComplete(ChannelFuture cf) throws Exception { writeFutures.remove(cf); futureClose(); } }); } } void futureClose() { if (closeTask != null && writeFutures.isEmpty()) { closeTask.invoke(null); } } @Override public void send(String data) { if (!isOpen()) { throw new IllegalStateException("The outbound channel is closed"); } writeAndClose(ctx.getChannel().write(new DefaultWebSocketFrame(data))); } @Override public void send(byte opcode, byte[] data, int offset, int length) { if (!isOpen()) { throw new IllegalStateException("The outbound channel is closed"); } writeAndClose( ctx.getChannel() .write(new DefaultWebSocketFrame(opcode, wrappedBuffer(data, offset, length)))); } @Override public synchronized boolean isOpen() { return ctx.getChannel().isOpen() && closeTask == null; } @Override public synchronized void close() { closeTask = new Promise<Void>(); closeTask.onRedeem( new Action<Promise<Void>>() { public void invoke(Promise<Void> completed) { writeFutures.clear(); ctx.getChannel().disconnect(); closeTask = null; } }); futureClose(); } }; Invoker.invoke(new WebSocketInvocation(route, request, inbound, outbound, ctx, e)); }
/* * Each ControlMessage is encoded as: code (<0) ... short(2) Each * TaskMessage is encoded as: task (>=0) ... short(2) len ... int(4) payload * ... byte[] * */ protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { // Make sure that we have received at least a short long available = buf.readableBytes(); // Length of control message is 10. // Minimum length of a task message is 6(short taskId, int length). if (available < 10) { // need more data return null; } Long startTime = null; if (isServer) { startTime = System.nanoTime(); } try { // Mark the current buffer position before reading task/len field // because the whole frame might not be in the buffer yet. // We will reset the buffer position to the marked position if // there's not enough bytes in the buffer. buf.markReaderIndex(); // read the short field short code = buf.readShort(); available -= 2; // case 1: Control message ControlMessage ctrl_msg = ControlMessage.mkMessage(code); if (ctrl_msg != null) { if (available < 12) { // The time stamp bytes were not received yet - return null. buf.resetReaderIndex(); return null; } long timeStamp = buf.readLong(); int clientPort = buf.readInt(); available -= 12; if (ctrl_msg == ControlMessage.EOB_MESSAGE) { long interval = System.currentTimeMillis() - timeStamp; if (interval > 0) { Histogram netTransTime = getTransmitHistogram(channel, clientPort); if (netTransTime != null) { netTransTime.update(interval); } } recvSpeed.update(Double.valueOf(ControlMessage.encodeLength())); } return ctrl_msg; } // case 2: task Message short task = code; // Make sure that we have received at least an integer (length) if (available < 8) { // need more data buf.resetReaderIndex(); return null; } // Read the length field. int length = buf.readInt(); if (length <= 0) { LOG.info("Receive one message whose TaskMessage's message length is {}", length); return new TaskMessage(task, null); } int headerLength = buf.readInt(); if (headerLength <= 0) { LOG.info("Receive one message whose TaskMessage's message header length is {}", length); } // Make sure if there's enough bytes in the buffer. available -= 8; if (available < length + headerLength) { // The whole bytes were not received yet - return null. buf.resetReaderIndex(); return null; } String component = null; String stream = null; if (headerLength > 0) { ChannelBuffer header = buf.readBytes(headerLength); String headerValue = new String(header.array()); String splits[] = headerValue.split(" "); stream = splits[0]; component = splits[1]; } // There's enough bytes in the buffer. Read it. ChannelBuffer payload = buf.readBytes(length); // Successfully decoded a frame. // Return a TaskMessage object byte[] rawBytes = payload.array(); // @@@ TESTING CODE // LOG.info("Receive task:{}, length: {}, data:{}", // task, length, JStormUtils.toPrintableString(rawBytes)); TaskMessage ret = new TaskMessage(task, rawBytes, component, stream); recvSpeed.update(Double.valueOf(rawBytes.length + 6)); return ret; } finally { if (isServer) { Long endTime = System.nanoTime(); timer.update((endTime - startTime) / 1000000.0d); } } }