
uk.co.real_logic.aeron.driver.media.ReceiveChannelEndpoint Maven / Gradle / Ivy
/*
* Copyright 2014 - 2015 Real Logic Ltd.
*
* 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 uk.co.real_logic.aeron.driver.media;
import uk.co.real_logic.aeron.driver.event.EventLogger;
import uk.co.real_logic.aeron.driver.*;
import uk.co.real_logic.aeron.driver.exceptions.ConfigurationException;
import uk.co.real_logic.aeron.protocol.*;
import uk.co.real_logic.agrona.collections.Int2ObjectHashMap;
import uk.co.real_logic.agrona.collections.MutableInteger;
import uk.co.real_logic.agrona.concurrent.UnsafeBuffer;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import static uk.co.real_logic.aeron.logbuffer.FrameDescriptor.frameType;
import static uk.co.real_logic.aeron.protocol.HeaderFlyweight.HDR_TYPE_DATA;
import static uk.co.real_logic.aeron.protocol.HeaderFlyweight.HDR_TYPE_PAD;
import static uk.co.real_logic.aeron.protocol.HeaderFlyweight.HDR_TYPE_SETUP;
/**
* Aggregator of multiple subscriptions onto a single transport session for processing of data frames.
*/
public class ReceiveChannelEndpoint extends UdpChannelTransport
{
private final DataPacketDispatcher dispatcher;
private final SystemCounters systemCounters;
private final ByteBuffer smBuffer = ByteBuffer.allocateDirect(StatusMessageFlyweight.HEADER_LENGTH);
private final StatusMessageFlyweight smHeader;
private final ByteBuffer nakBuffer = ByteBuffer.allocateDirect(NakFlyweight.HEADER_LENGTH);
private final NakFlyweight nakHeader;
private final SetupFlyweight setupHeader;
private final DataHeaderFlyweight dataHeader;
private final Int2ObjectHashMap refCountByStreamIdMap = new Int2ObjectHashMap<>();
private volatile boolean isClosed = false;
public ReceiveChannelEndpoint(
final UdpChannel udpChannel,
final DataPacketDispatcher dispatcher,
final EventLogger logger,
final SystemCounters systemCounters,
final LossGenerator lossGenerator)
{
super(
udpChannel,
udpChannel.remoteData(),
udpChannel.remoteData(),
null,
lossGenerator,
logger);
smHeader = new StatusMessageFlyweight(smBuffer);
smHeader
.version(HeaderFlyweight.CURRENT_VERSION)
.headerType(HeaderFlyweight.HDR_TYPE_SM)
.frameLength(StatusMessageFlyweight.HEADER_LENGTH);
nakHeader = new NakFlyweight(nakBuffer);
nakHeader
.version(HeaderFlyweight.CURRENT_VERSION)
.headerType(HeaderFlyweight.HDR_TYPE_NAK)
.frameLength(NakFlyweight.HEADER_LENGTH);
dataHeader = new DataHeaderFlyweight(receiveBuffer());
setupHeader = new SetupFlyweight(receiveBuffer());
this.dispatcher = dispatcher;
this.systemCounters = systemCounters;
}
public String originalUriString()
{
return udpChannel().originalUriString();
}
public void close()
{
super.close();
isClosed = true;
}
public boolean isClosed()
{
return isClosed;
}
public void openChannel()
{
openDatagramChannel();
}
public DataPacketDispatcher dispatcher()
{
return dispatcher;
}
public int incRefToStream(final int streamId)
{
MutableInteger count = refCountByStreamIdMap.get(streamId);
if (null == count)
{
count = new MutableInteger();
refCountByStreamIdMap.put(streamId, count);
}
count.value++;
return count.value;
}
public int decRefToStream(final int streamId)
{
final MutableInteger count = refCountByStreamIdMap.get(streamId);
if (null == count)
{
throw new IllegalStateException("Could not find stream Id to decrement: " + streamId);
}
count.value--;
if (0 == count.value)
{
refCountByStreamIdMap.remove(streamId);
}
return count.value;
}
public int streamCount()
{
return refCountByStreamIdMap.size();
}
public int onDataPacket(
final DataHeaderFlyweight header, final UnsafeBuffer buffer, final int length, final InetSocketAddress srcAddress)
{
return dispatcher.onDataPacket(this, header, buffer, length, srcAddress);
}
public void onSetupMessage(final SetupFlyweight header, final UnsafeBuffer buffer, final InetSocketAddress srcAddress)
{
dispatcher.onSetupMessage(this, header, buffer, srcAddress);
}
public void sendSetupElicitingStatusMessage(final InetSocketAddress controlAddress, final int sessionId, final int streamId)
{
sendStatusMessage(controlAddress, sessionId, streamId, 0, 0, 0, StatusMessageFlyweight.SEND_SETUP_FLAG);
}
public void validateWindowMaxLength(final int windowMaxLength)
{
final int soRcvbuf = getOption(StandardSocketOptions.SO_RCVBUF);
if (windowMaxLength > soRcvbuf)
{
throw new ConfigurationException(String.format(
"Max Window length greater than socket SO_RCVBUF, increase %s to match window: windowMaxLength=%d, SO_RCVBUF=%d",
Configuration.INITIAL_WINDOW_LENGTH_PROP_NAME,
windowMaxLength,
soRcvbuf));
}
}
public void validateSenderMtuLength(final int senderMtuLength)
{
final int soRcvbuf = getOption(StandardSocketOptions.SO_RCVBUF);
if (senderMtuLength > soRcvbuf)
{
throw new ConfigurationException(String.format(
"Sender MTU greater than socket SO_RCVBUF, increase %s to match MTU: senderMtuLength=%d, SO_RCVBUF=%d",
Configuration.SOCKET_RCVBUF_LENGTH_PROP_NAME,
senderMtuLength,
soRcvbuf));
}
final int capacity = receiveBufferCapacity();
if (senderMtuLength > capacity)
{
throw new ConfigurationException(String.format(
"Sender MTU greater than receive buffer capacity, increase %s to match MTU: senderMtuLength=%d, capacity=%d",
Configuration.RECEIVE_BUFFER_LENGTH_PROP_NAME,
senderMtuLength,
capacity));
}
}
public void sendStatusMessage(
final InetSocketAddress controlAddress,
final int sessionId,
final int streamId,
final int termId,
final int termOffset,
final int window,
final short flags)
{
if (!isClosed)
{
smBuffer.clear();
smHeader
.sessionId(sessionId)
.streamId(streamId)
.consumptionTermId(termId)
.consumptionTermOffset(termOffset)
.receiverWindowLength(window)
.flags(flags);
final int bytesSent = sendTo(smBuffer, controlAddress);
if (StatusMessageFlyweight.HEADER_LENGTH != bytesSent)
{
systemCounters.statusMessageShortSends().orderedIncrement();
}
}
}
public void sendNakMessage(
final InetSocketAddress controlAddress,
final int sessionId,
final int streamId,
final int termId,
final int termOffset,
final int length)
{
if (!isClosed)
{
nakBuffer.clear();
nakHeader
.streamId(streamId)
.sessionId(sessionId)
.termId(termId)
.termOffset(termOffset)
.length(length);
final int bytesSent = sendTo(nakBuffer, controlAddress);
if (NakFlyweight.HEADER_LENGTH != bytesSent)
{
systemCounters.nakMessageShortSends().orderedIncrement();
}
}
}
public int pollForData()
{
int bytesReceived = 0;
final InetSocketAddress srcAddress = receive();
if (null != srcAddress)
{
final ByteBuffer receiveByteBuffer = receiveByteBuffer();
final int length = receiveByteBuffer.position();
final UnsafeBuffer receiveBuffer = receiveBuffer();
if (lossGenerator().shouldDropFrame(srcAddress, receiveBuffer, length))
{
logger().logFrameInDropped(receiveByteBuffer, 0, length, srcAddress);
}
else
{
logger().logFrameIn(receiveByteBuffer, 0, length, srcAddress);
if (isValidFrame(receiveBuffer, length))
{
bytesReceived = dispatch(receiveBuffer, length, srcAddress);
}
}
}
return bytesReceived;
}
private int dispatch(final UnsafeBuffer buffer, final int length, final InetSocketAddress srcAddress)
{
int bytesReceived = 0;
switch (frameType(buffer, 0))
{
case HDR_TYPE_PAD:
case HDR_TYPE_DATA:
bytesReceived = dispatcher.onDataPacket(this, dataHeader, buffer, length, srcAddress);
break;
case HDR_TYPE_SETUP:
dispatcher.onSetupMessage(this, setupHeader, buffer, srcAddress);
break;
}
return bytesReceived;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy