/* * Copyright 2017 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 io.aeron.driver; import io.aeron.command.*; import io.aeron.driver.exceptions.ControlProtocolException; import org.agrona.MutableDirectBuffer; import org.agrona.concurrent.MessageHandler; import org.agrona.concurrent.errors.DistinctErrorLog; import org.agrona.concurrent.ringbuffer.RingBuffer; import org.agrona.concurrent.status.AtomicCounter; import static io.aeron.CommonContext.IPC_CHANNEL; import static io.aeron.CommonContext.SPY_PREFIX; import static io.aeron.ErrorCode.GENERIC_ERROR; import static io.aeron.command.ControlProtocolEvents.*; /** * Receives commands from Aeron clients and dispatches them to the {@link DriverConductor} for processing. */ class DriverAdapter implements MessageHandler { /** * Limit for the number of messages to be read in each receive. */ public static final int MESSAGE_COUNT_LIMIT = 10; private final PublicationMessageFlyweight publicationMsgFlyweight = new PublicationMessageFlyweight(); private final SubscriptionMessageFlyweight subscriptionMsgFlyweight = new SubscriptionMessageFlyweight(); private final CorrelatedMessageFlyweight correlatedMsgFlyweight = new CorrelatedMessageFlyweight(); private final RemoveMessageFlyweight removeMsgFlyweight = new RemoveMessageFlyweight(); private final DestinationMessageFlyweight destinationMsgFlyweight = new DestinationMessageFlyweight(); private final DriverConductor conductor; private final RingBuffer toDriverCommands; private final ClientProxy clientProxy; private final AtomicCounter errors; private final DistinctErrorLog errorLog; DriverAdapter( final AtomicCounter errors, final DistinctErrorLog errorLog, final RingBuffer toDriverCommands, final ClientProxy clientProxy, final DriverConductor driverConductor) { this.errors = errors; this.errorLog = errorLog; this.toDriverCommands = toDriverCommands; this.clientProxy = clientProxy; this.conductor = driverConductor; } public int receive() { return toDriverCommands.read(this, MESSAGE_COUNT_LIMIT); } @SuppressWarnings("MethodLength") public void onMessage( final int msgTypeId, final MutableDirectBuffer buffer, final int index, @SuppressWarnings("unused") final int length) { long correlationId = 0; try { switch (msgTypeId) { case ADD_PUBLICATION: { publicationMsgFlyweight.wrap(buffer, index); correlationId = publicationMsgFlyweight.correlationId(); addPublication(correlationId, false); break; } case REMOVE_PUBLICATION: { removeMsgFlyweight.wrap(buffer, index); correlationId = removeMsgFlyweight.correlationId(); conductor.onRemovePublication(removeMsgFlyweight.registrationId(), correlationId); break; } case ADD_EXCLUSIVE_PUBLICATION: { publicationMsgFlyweight.wrap(buffer, index); correlationId = publicationMsgFlyweight.correlationId(); addPublication(correlationId, true); break; } case ADD_SUBSCRIPTION: { subscriptionMsgFlyweight.wrap(buffer, index); correlationId = subscriptionMsgFlyweight.correlationId(); final int streamId = subscriptionMsgFlyweight.streamId(); final long clientId = subscriptionMsgFlyweight.clientId(); final String channel = subscriptionMsgFlyweight.channel(); if (channel.startsWith(IPC_CHANNEL)) { conductor.onAddIpcSubscription(channel, streamId, correlationId, clientId); } else if (channel.startsWith(SPY_PREFIX)) { conductor.onAddSpySubscription( channel.substring(SPY_PREFIX.length()), streamId, correlationId, clientId); } else { conductor.onAddNetworkSubscription(channel, streamId, correlationId, clientId); } break; } case REMOVE_SUBSCRIPTION: { removeMsgFlyweight.wrap(buffer, index); correlationId = removeMsgFlyweight.correlationId(); conductor.onRemoveSubscription(removeMsgFlyweight.registrationId(), correlationId); break; } case ADD_DESTINATION: { destinationMsgFlyweight.wrap(buffer, index); correlationId = destinationMsgFlyweight.correlationId(); final long channelRegistrationId = destinationMsgFlyweight.registrationCorrelationId(); final String channel = destinationMsgFlyweight.channel(); conductor.onAddDestination(channelRegistrationId, channel, correlationId); break; } case REMOVE_DESTINATION: { destinationMsgFlyweight.wrap(buffer, index); correlationId = destinationMsgFlyweight.correlationId(); final long channelRegistrationId = destinationMsgFlyweight.registrationCorrelationId(); final String channel = destinationMsgFlyweight.channel(); conductor.onRemoveDestination(channelRegistrationId, channel, correlationId); break; } case CLIENT_KEEPALIVE: { correlatedMsgFlyweight.wrap(buffer, index); conductor.onClientKeepalive(correlatedMsgFlyweight.clientId()); break; } } } catch (final ControlProtocolException ex) { clientProxy.onError(ex.errorCode(), ex.getMessage(), correlationId); recordError(ex); } catch (final Exception ex) { clientProxy.onError(GENERIC_ERROR, ex.getMessage(), correlationId); recordError(ex); } } public void addPublication(final long correlationId, final boolean isExclusive) { final int streamId = publicationMsgFlyweight.streamId(); final long clientId = publicationMsgFlyweight.clientId(); final String channel = publicationMsgFlyweight.channel(); if (channel.startsWith(IPC_CHANNEL)) { conductor.onAddIpcPublication(channel, streamId, correlationId, clientId, isExclusive); } else { conductor.onAddNetworkPublication(channel, streamId, correlationId, clientId, isExclusive); } } private void recordError(final Exception ex) { errors.increment(); errorLog.record(ex); } }