/* * Copyright 2014 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.navercorp.pinpoint.collector.receiver.udp; import com.navercorp.pinpoint.collector.receiver.DispatchHandler; import com.navercorp.pinpoint.thrift.dto.TSpan; import com.navercorp.pinpoint.thrift.dto.TSpanChunk; import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import com.navercorp.pinpoint.thrift.io.*; import org.apache.commons.collections.CollectionUtils; import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * @author Taejin Koo */ public class SpanStreamUDPPacketHandlerFactory<T extends DatagramPacket> implements PacketHandlerFactory<T> { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final DeserializerFactory<HeaderTBaseDeserializer> deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory()); private final DispatchHandler dispatchHandler; @SuppressWarnings("unused") private final TBaseFilter<SocketAddress> filter; private final PacketHandler<T> dispatchPacket = new DispatchPacket(); public SpanStreamUDPPacketHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter<SocketAddress> filter) { if (dispatchHandler == null) { throw new NullPointerException("dispatchHandler must not be null"); } if (filter == null) { throw new NullPointerException("filter must not be null"); } this.dispatchHandler = dispatchHandler; this.filter = filter; } @Override public PacketHandler<T> createPacketHandler() { return this.dispatchPacket; } // stateless private class DispatchPacket implements PacketHandler<T> { private DispatchPacket() { } @Override public void receive(DatagramSocket localSocket, DatagramPacket packet) { final HeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); ByteBuffer requestBuffer = ByteBuffer.wrap(packet.getData()); if (requestBuffer.remaining() < SpanStreamConstants.START_PROTOCOL_BUFFER_SIZE) { return; } byte signature = requestBuffer.get(); if (signature != SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE) { logger.warn("Wrong signature: 0x" + Integer.toHexString(signature & 0xFF) + " (expected: 0x" + Integer.toHexString(SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE & 0xFF) + ')'); return; } byte version = requestBuffer.get(); int chunkSize = 0xff & requestBuffer.get(); SocketAddress socketAddress = packet.getSocketAddress(); try { for (int i = 0; i < chunkSize; i++) { byte[] componentData = getComponentData(requestBuffer, deserializer); if (componentData == null) { logger.warn("Buffer Wrong signature: 0x{} (expected: 0x{})", Integer.toHexString(signature & 0xFF), Integer.toHexString(SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE & 0xFF)); break; } List<TBase<?, ?>> tbaseList = deserializer.deserializeList(componentData); if (CollectionUtils.isEmpty(tbaseList)) { continue; } if (tbaseList.size() == 1) { if (filter.filter(localSocket, tbaseList.get(0), socketAddress) == TBaseFilter.BREAK) { continue; } } List<TSpanEvent> spanEventList = getSpanEventList(tbaseList); TBase<?, ?> tBase = tbaseList.get(tbaseList.size() - 1); if (tBase instanceof TSpan) { ((TSpan) tBase).setSpanEventList(spanEventList); } else if (tBase instanceof TSpanChunk) { ((TSpanChunk) tBase).setSpanEventList(spanEventList); } dispatchHandler.dispatchRequestMessage(tBase); } } catch (Exception e) { logger.warn("Failed to handle receive packet.", e); } } } private byte[] getComponentData(ByteBuffer buffer, HeaderTBaseDeserializer deserializer) { if (buffer.remaining() < 2) { logger.warn("Can't available {} fixed buffer.", 2); return null; } int componentSize = 0xffff & buffer.getShort(); if (buffer.remaining() < componentSize) { logger.warn("Can't available {} fixed buffer.", buffer.remaining()); return null; } byte[] componentData = new byte[componentSize]; buffer.get(componentData); return componentData; } private List<TSpanEvent> getSpanEventList(List<TBase<?, ?>> tbaseList) { if (CollectionUtils.isEmpty(tbaseList)) { return new ArrayList<>(0); } int spanEventListSize = tbaseList.size() - 1; List<TSpanEvent> spanEventList = new ArrayList<>(spanEventListSize); for (int i = 0; i < spanEventListSize; i++) { TBase<?, ?> tBase = tbaseList.get(i); if (tBase instanceof TSpanEvent) { spanEventList.add((TSpanEvent) tBase); } } return spanEventList; } }