/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.distributed.internal; import org.apache.geode.DataSerializer; import org.apache.geode.Instantiator; import org.apache.geode.SystemConnectException; import org.apache.geode.internal.*; import org.apache.geode.internal.InternalDataSerializer.SerializerAttributesHolder; import org.apache.geode.internal.InternalInstantiator.InstantiatorAttributesHolder; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.net.SocketCreator; import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.Logger; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.net.InetAddress; import java.util.Collection; import java.util.Collections; import java.util.Set; /** * A message that is sent to all other distribution manager when a distribution manager starts up. */ public final class StartupMessage extends HighPriorityDistributionMessage implements AdminMessageType { private static final Logger logger = LogService.getLogger(); private String version = GemFireVersion.getGemFireVersion(); // added for bug 29005 private int replyProcessorId; private boolean isMcastEnabled; private boolean isTcpDisabled; private Set interfaces; private int distributedSystemId; private String redundancyZone; private boolean enforceUniqueZone; // additional fields using StartupMessageData below here... private Collection<String> hostedLocatorsAll; boolean isSharedConfigurationEnabled; private int mcastPort; private String mcastHostAddress; // see InetAddress.getHostAddress() for the format of this string /** * Determine all of the addresses that this host represents. An empty list will be regarded as an * error by all who see it. * * @return list of addresses for this host * @since GemFire 5.7 */ public static Set getMyAddresses(DistributionManager dm) { try { Set addresses = SocketCreator.getMyAddresses(); return addresses; } catch (IllegalArgumentException e) { logger.fatal(e.getMessage(), e); return Collections.EMPTY_SET; } } /** * A list of errors that occurs while deserializing this message. See bug 31573. */ private transient StringBuffer fromDataProblems; /** * Creates new instance for DataSerializer. */ public StartupMessage() {} /** * Creates new instance for StartupOperation. * * @param hostedLocators * @param isSharedConfigurationEnabled true if cluster configuration is enabled */ StartupMessage(Collection<String> hostedLocators, boolean isSharedConfigurationEnabled) { this.hostedLocatorsAll = hostedLocators; this.isSharedConfigurationEnabled = isSharedConfigurationEnabled; } /////////////////////// Instance Methods /////////////////////// /** * Sets the reply processor for this message */ void setReplyProcessorId(int proc) { this.replyProcessorId = proc; } /** * Sets the mcastEnabled flag for this message * * @since GemFire 5.0 */ void setMcastEnabled(boolean flag) { isMcastEnabled = flag; } int getMcastPort() { return this.mcastPort; } void setMcastPort(int port) { this.mcastPort = port; } String getMcastHostAddress() { return this.mcastHostAddress; } void setMcastHostAddress(InetAddress addr) { String hostAddr = null; if (addr != null) { hostAddr = addr.getHostAddress(); } this.mcastHostAddress = hostAddr; } @Override public boolean sendViaUDP() { return true; } // void setHostedLocatorsWithSharedConfiguration(Collection<String> // hostedLocatorsWithSharedConfiguration) { // this.hostedLocatorsWithSharedConfiguration = hostedLocatorsWithSharedConfiguration; // } /** * Sets the tcpDisabled flag for this message * * @since GemFire 5.0 */ void setTcpDisabled(boolean flag) { isTcpDisabled = flag; } void setInterfaces(Set interfaces) { this.interfaces = interfaces; if (interfaces == null || interfaces.size() == 0) { throw new SystemConnectException("Unable to examine network card"); } } public void setDistributedSystemId(int distributedSystemId) { this.distributedSystemId = distributedSystemId; } public void setRedundancyZone(String redundancyZone) { this.redundancyZone = redundancyZone; } public void setEnforceUniqueZone(boolean enforceUniqueZone) { this.enforceUniqueZone = enforceUniqueZone; } /** * Adds the distribution manager that is started up to the current DM's list of members. * * This method is invoked on the receiver side */ @Override protected void process(DistributionManager dm) { String rejectionMessage = null; final boolean isAdminDM = dm.getId().getVmKind() == DistributionManager.ADMIN_ONLY_DM_TYPE || dm.getId().getVmKind() == DistributionManager.LOCATOR_DM_TYPE; String myVersion = GemFireVersion.getGemFireVersion(); String theirVersion = this.version; if (dm.getTransport().isMcastEnabled() != isMcastEnabled) { rejectionMessage = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_ISMCASTENABLED_1_DOES_NOT_MATCH_THE_DISTRIBUTED_SYSTEM_IT_IS_ATTEMPTING_TO_JOIN .toLocalizedString( new Object[] {getSender(), isMcastEnabled ? "enabled" : "disabled"}); } else if (isMcastEnabled && dm.getSystem().getOriginalConfig().getMcastPort() != getMcastPort()) { rejectionMessage = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_MCAST_PORT_1_DOES_NOT_MATCH_THE_DISTRIBUTED_SYSTEM_2_IT_IS_ATTEMPTING_TO_JOIN .toLocalizedString(new Object[] {getSender(), getMcastPort(), dm.getSystem().getOriginalConfig().getMcastPort()}); } else if (isMcastEnabled && !checkMcastAddress(dm.getSystem().getOriginalConfig().getMcastAddress(), getMcastHostAddress())) { rejectionMessage = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_MCAST_ADDRESS_1_DOES_NOT_MATCH_THE_DISTRIBUTED_SYSTEM_2_IT_IS_ATTEMPTING_TO_JOIN .toLocalizedString(new Object[] {getSender(), getMcastHostAddress(), dm.getSystem().getOriginalConfig().getMcastAddress()}); } else if (dm.getTransport().isTcpDisabled() != isTcpDisabled) { rejectionMessage = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_ISTCPDISABLED_1_DOES_NOT_MATCH_THE_DISTRIBUTED_SYSTEM_IT_IS_ATTEMPTING_TO_JOIN .toLocalizedString(new Object[] {getSender(), Boolean.valueOf(isTcpDisabled)}); } else if (dm.getDistributedSystemId() != DistributionConfig.DEFAULT_DISTRIBUTED_SYSTEM_ID && distributedSystemId != DistributionConfig.DEFAULT_DISTRIBUTED_SYSTEM_ID && distributedSystemId != dm.getDistributedSystemId()) { String distributedSystemListener = System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "DistributedSystemListener"); // this check is specific for Jayesh's use case of WAN BootStraping if (distributedSystemListener != null) { if (-distributedSystemId != dm.getDistributedSystemId()) { rejectionMessage = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_DISTRIBUTED_SYSTEM_ID_1_DOES_NOT_MATCH_THE_DISTRIBUTED_SYSTEM_2_IT_IS_ATTEMPTING_TO_JOIN .toLocalizedString(new Object[] {getSender(), Integer.valueOf(distributedSystemId), dm.getDistributedSystemId()}); } } else { rejectionMessage = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_DISTRIBUTED_SYSTEM_ID_1_DOES_NOT_MATCH_THE_DISTRIBUTED_SYSTEM_2_IT_IS_ATTEMPTING_TO_JOIN .toLocalizedString(new Object[] {getSender(), Integer.valueOf(distributedSystemId), dm.getDistributedSystemId()}); } } if (this.fromDataProblems != null) { if (logger.isDebugEnabled()) { logger.debug(this.fromDataProblems); } } if (rejectionMessage == null) { // change state only if there's no rejectionMessage yet if (this.interfaces == null || this.interfaces.size() == 0) { final org.apache.geode.i18n.StringId msg = LocalizedStrings.StartupMessage_REJECTED_NEW_SYSTEM_NODE_0_BECAUSE_PEER_HAS_NO_NETWORK_INTERFACES; rejectionMessage = msg.toLocalizedString(getSender()); } else { dm.setEquivalentHosts(this.interfaces); } } if (rejectionMessage != null) { logger.warn(rejectionMessage); } if (rejectionMessage == null) { // change state only if there's no rejectionMessage yet dm.setRedundancyZone(getSender(), this.redundancyZone); dm.setEnforceUniqueZone(this.enforceUniqueZone); if (this.hostedLocatorsAll != null) { // boolean isSharedConfigurationEnabled = false; // if (this.hostedLocatorsWithSharedConfiguration != null) { // isSharedConfigurationEnabled = true; // } dm.addHostedLocators(getSender(), this.hostedLocatorsAll, this.isSharedConfigurationEnabled); } } StartupResponseMessage m = null; // Commenting out. See Bruces note in the StartupMessageData constructor. // Comparisons should use the functionality described in SerializationVersions // if (GemFireVersion.compareVersions(theirVersion,"6.6.2") >= 0) { m = new StartupResponseWithVersionMessage(dm, replyProcessorId, getSender(), rejectionMessage, isAdminDM); // } else { // m = new StartupResponseMessage(dm, replyProcessorId, getSender(), rejectionMessage, // isAdminDM); // } if (logger.isDebugEnabled()) { logger.debug("Received StartupMessage from a member with version: {}, my version is:{}", theirVersion, myVersion); } dm.putOutgoing(m); if (rejectionMessage != null) { dm.getMembershipManager().startupMessageFailed(getSender(), rejectionMessage); } // bug33638: we need to discard this member if they aren't a peer. if (rejectionMessage != null) dm.handleManagerDeparture(getSender(), false, rejectionMessage); } private static boolean checkMcastAddress(InetAddress myMcastAddr, String otherMcastHostAddr) { String myMcastHostAddr = null; if (myMcastAddr != null) { myMcastHostAddr = myMcastAddr.getHostAddress(); } if (StringUtils.equals(myMcastHostAddr, otherMcastHostAddr)) return true; if (myMcastHostAddr == null) return false; return myMcastHostAddr.equals(otherMcastHostAddr); } public int getDSFID() { return STARTUP_MESSAGE; } @Override public Version[] getSerializationVersions() { return null; } @Override public void toData(DataOutput out) throws IOException { super.toData(out); DataSerializer.writeString(this.version, out); out.writeInt(this.replyProcessorId); out.writeBoolean(this.isMcastEnabled); out.writeBoolean(this.isTcpDisabled); // Send a description of all of the DataSerializers and // Instantiators that have been registered SerializerAttributesHolder[] sahs = InternalDataSerializer.getSerializersForDistribution(); out.writeInt(sahs.length); for (int i = 0; i < sahs.length; i++) { DataSerializer.writeNonPrimitiveClassName(sahs[i].getClassName(), out); out.writeInt(sahs[i].getId()); } Object[] insts = InternalInstantiator.getInstantiatorsForSerialization(); out.writeInt(insts.length); for (int i = 0; i < insts.length; i++) { String instantiatorClassName, instantiatedClassName; int id; if (insts[i] instanceof Instantiator) { instantiatorClassName = ((Instantiator) insts[i]).getClass().getName(); instantiatedClassName = ((Instantiator) insts[i]).getInstantiatedClass().getName(); id = ((Instantiator) insts[i]).getId(); } else { instantiatorClassName = ((InstantiatorAttributesHolder) insts[i]).getInstantiatorClassName(); instantiatedClassName = ((InstantiatorAttributesHolder) insts[i]).getInstantiatedClassName(); id = ((InstantiatorAttributesHolder) insts[i]).getId(); } DataSerializer.writeNonPrimitiveClassName(instantiatorClassName, out); DataSerializer.writeNonPrimitiveClassName(instantiatedClassName, out); out.writeInt(id); } DataSerializer.writeObject(interfaces, out); out.writeInt(distributedSystemId); DataSerializer.writeString(redundancyZone, out); out.writeBoolean(enforceUniqueZone); StartupMessageData data = new StartupMessageData(); data.writeHostedLocators(this.hostedLocatorsAll); data.writeIsSharedConfigurationEnabled(this.isSharedConfigurationEnabled); data.writeMcastPort(this.mcastPort); data.writeMcastHostAddress(this.mcastHostAddress); data.writeTo(out); } /** * Notes a problem that occurs while invoking {@link #fromData}. */ private void fromDataProblem(String s) { if (this.fromDataProblems == null) { this.fromDataProblems = new StringBuffer(); } this.fromDataProblems.append(s); this.fromDataProblems.append("\n\n"); } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { super.fromData(in); this.version = DataSerializer.readString(in); this.replyProcessorId = in.readInt(); this.isMcastEnabled = in.readBoolean(); this.isTcpDisabled = in.readBoolean(); int serializerCount = in.readInt(); for (int i = 0; i < serializerCount; i++) { String cName = DataSerializer.readNonPrimitiveClassName(in); int id = in.readInt(); // id try { if (cName != null) { InternalDataSerializer.register(cName, false, null, null, id); } } catch (IllegalArgumentException ex) { fromDataProblem( LocalizedStrings.StartupMessage_ILLEGALARGUMENTEXCEPTION_WHILE_REGISTERING_A_DATASERIALIZER_0 .toLocalizedString(ex)); } } int instantiatorCount = in.readInt(); for (int i = 0; i < instantiatorCount; i++) { String instantiatorClassName = DataSerializer.readNonPrimitiveClassName(in); String instantiatedClassName = DataSerializer.readNonPrimitiveClassName(in); int id = in.readInt(); try { if (instantiatorClassName != null && instantiatedClassName != null) { InternalInstantiator.register(instantiatorClassName, instantiatedClassName, id, false); } } catch (IllegalArgumentException ex) { fromDataProblem( LocalizedStrings.StartupMessage_ILLEGALARGUMENTEXCEPTION_WHILE_REGISTERING_AN_INSTANTIATOR_0 .toLocalizedString(ex)); } } // for this.interfaces = (Set) DataSerializer.readObject(in); this.distributedSystemId = in.readInt(); this.redundancyZone = DataSerializer.readString(in); this.enforceUniqueZone = in.readBoolean(); StartupMessageData data = new StartupMessageData(); data.readFrom(in); this.hostedLocatorsAll = data.readHostedLocators(); this.isSharedConfigurationEnabled = data.readIsSharedConfigurationEnabled(); this.mcastPort = data.readMcastPort(); this.mcastHostAddress = data.readMcastHostAddress(); } @Override public String toString() { return LocalizedStrings.StartupMessage_STARTUPMESSAGE_DM_0_HAS_STARTED_PROCESSOR_1_WITH_DISTRIBUTED_SYSTEM_ID_2 .toLocalizedString(new Object[] {getSender(), Integer.valueOf(replyProcessorId), this.distributedSystemId}); } }