docs: protected void rcvHandshake(CommsByteBuffer request, Conversation conversation, int requestNumber,
                                  boolean allocatedFromBufferPool) {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(this, tc, "rcvHandshake",
                                             new Object[]
                                             {
                                                request,
                                                conversation,
                                                "" + requestNumber,
                                                "" + allocatedFromBufferPool,
                                             });
  
          //How the conversation which performed this handshake is to be used. By default this will be JFAP unless something
          //else is specified as part of the handshake.
          ConversationUsageType usageType = ConversationUsageType.JFAP;
  
          //Create handshake properties here but only set them later if this isn't a WMQRA handshake.
          CATHandshakeProperties catHandshakeProps = new CATHandshakeProperties();
  
          // Ensure we send back a connection type to be consistent with the doc.
          // Just send back what we received...
          CommsByteBuffer reply = poolManager.allocate();
          reply.put(request.get());
  
          // Get the current FAP level, overriding from SIB properties if required
          int currentFapLevel = CommsUtils.getRuntimeIntProperty(CommsConstants.SERVER_FAP_LEVEL_KEY,
                                                                 "" + CommsConstants.CURRENT_FAP_VERSION);
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              SibTr.debug(this, tc, "Server is FAP Level: " + currentFapLevel);
  
          boolean noErrorOccurred = true;
          // These are the mandatory fields we need to check. If any of these are missing on any
          // initial handshake flow, then this is an error.
          boolean rcvFapLevel = false;
          boolean rcvProdVersion = false;
  
          // The Client -> ME initial handshake should always carry the Product Id (not needed for
          // ME-> ME).
          boolean rcvProdId = false;
  
          // Ensure we do checking about the correct FAP level to select.
          boolean rcvSupportedFaps = false;
          boolean[] supportedFaps = null;
          int peerFapLevel = 0;
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              SibTr.debug(this, tc, "----- Received the following handshake data -----");
  
          while (request.hasRemaining() && noErrorOccurred) {
              short fieldId = request.getShort();
  
              switch (fieldId) {
  
                  case CommsConstants.FIELDID_PRODUCT_VERSION:
  
                      short productVersionFieldLength = request.getShort();
  
                      // Ensure the length is 2
                      if (productVersionFieldLength != 2) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Product Version field length", productVersionFieldLength);
                          rejectHandshake(conversation, requestNumber, "ProductVersion length");
                          noErrorOccurred = false;
                      } else {
                          byte upperProductVersion = request.get();
                          byte lowerProductVersion = request.get();
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Product Version   : " + upperProductVersion + "." + lowerProductVersion);
  
                          rcvProdVersion = true;
  
                          catHandshakeProps.setMajorVersion(upperProductVersion);
                          catHandshakeProps.setMinorVersion(lowerProductVersion);
  
                          // Always inform the client what version we are
                          reply.putShort(CommsConstants.FIELDID_PRODUCT_VERSION);
                          reply.putShort(2);
                          reply.put((byte) SIMPConstants.API_MAJOR_VERSION);
                          reply.put((byte) SIMPConstants.API_MINOR_VERSION);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_FAP_LEVEL:
  
                      short fapLevelFieldLength = request.getShort();
  
                      // Ensure the length is 2
                      if (fapLevelFieldLength != 2) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected FAP Level field length", fapLevelFieldLength);
                          rejectHandshake(conversation, requestNumber, "FAPLevel length");
                          noErrorOccurred = false;
                      } else {
                          peerFapLevel = request.getShort();
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " FAP Version       : " + peerFapLevel);
                          rcvFapLevel = true;
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_MAX_MESSAGE_SIZE:
  
                      short maxMessageFieldLength = request.getShort();
  
                      // Ensure the length is 8
                      if (maxMessageFieldLength != 8) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Max Message Size field length", maxMessageFieldLength);
                          rejectHandshake(conversation, requestNumber, "MaxMessageSize length");
                          noErrorOccurred = false;
                      } else {
                          long maxMessageSize = request.getLong();
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Max Msg Size      : " + maxMessageSize);
                          catHandshakeProps.setMaxMessageSize(maxMessageSize);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_MAX_TRANSMISSION_SIZE:
  
                      short maxTransmissionFieldLength = request.getShort();
  
                      // Ensure the length is 4
                      if (maxTransmissionFieldLength != 4) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Max Transmission Size field length", maxTransmissionFieldLength);
                          rejectHandshake(conversation, requestNumber, "MaxTransmissionSize length");
                          noErrorOccurred = false;
                      } else {
                          int maxTransmissionSize = request.getInt();
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Max Tx Size       : " + maxTransmissionSize);
                          catHandshakeProps.setMaxTransmissionSize(maxTransmissionSize);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_HEARTBEAT_INTERVAL:
  
                      short heartbeatFieldLength = request.getShort();
  
                      // Ensure the length is 2
                      if (heartbeatFieldLength != 2) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Heartbeat Interval field length", heartbeatFieldLength);
                          rejectHandshake(conversation, requestNumber, "HeartbeatInterval length");
                          noErrorOccurred = false;
                      } else {
                          short heartbeatInterval = request.getShort();
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Heartbeat Interval: " + heartbeatInterval);
  
                          // Heartbeats are negotiated upwards - so take the maximum of the two values
                          short maxInterval = (short) Math.max(conversation.getHeartbeatInterval(), heartbeatInterval);
  
                          // If we are set to be higher than the client, then we need to reply
                          // and tell the client
                          if (maxInterval > heartbeatInterval) {
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                                  SibTr.debug(this, tc, "> Negotiating Heartbeat Interval to: " + maxInterval);
  
                              reply.putShort(CommsConstants.FIELDID_HEARTBEAT_INTERVAL);
                              reply.putShort(2);
                              reply.putShort(maxInterval);
                          }
                          // Otherwise accept the client values
                          else {
                              conversation.setHeartbeatInterval(maxInterval);
                          }
  
                          catHandshakeProps.setHeartbeatInterval(maxInterval);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_HEARTBEAT_TIMEOUT:
  
                      short heartbeatTimeoutFieldLength = request.getShort();
  
                      // Ensure the length is 2
                      if (heartbeatTimeoutFieldLength != 2) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Heartbeat Timeout field length", heartbeatTimeoutFieldLength);
                          rejectHandshake(conversation, requestNumber, "HeartbeatTimeout length");
                          noErrorOccurred = false;
                      } else {
                          short heartbeatTimeout = request.getShort();
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Heartbeat Timeout : " + heartbeatTimeout);
  
                          // Heartbeats are negotiated upwards - so take the maximum of the two values
                          short maxTimeout = (short) Math.max(conversation.getHeartbeatTimeout(), heartbeatTimeout);
  
                          // If we are set to be higher than the client, then we need to reply
                          // and tell the client
                          if (maxTimeout > heartbeatTimeout) {
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                                  SibTr.debug(this, tc, "> Negotiating Heartbeat Timeout to: " + maxTimeout);
  
                              reply.putShort(CommsConstants.FIELDID_HEARTBEAT_TIMEOUT);
                              reply.putShort(2);
                              reply.putShort(maxTimeout);
                          }
                          // Otherwise accept the client values
                          else {
                              conversation.setHeartbeatTimeout(maxTimeout);
                          }
  
                          catHandshakeProps.setHeartbeatTimeout(maxTimeout);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_CAPABILITIES:
  
                      short capabilityLength = request.getShort();
  
                      if (capabilityLength != 2) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Capability field length", capabilityLength);
                          rejectHandshake(conversation, requestNumber, "Capability length");
                          noErrorOccurred = false;
                      } else {
                          short capability = request.getShort();
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Capabilities      : 0x" + Integer.toHexString(capability));
  
                          if ((capability & CommsConstants.CAPABILITIY_RESERVED_MASK) != 0) {
                              // If we have been presented with capabilities we are unfamiliar with, mask
                              // off the unfamiliar bits and reply stating that we support the capabilities
                              // we are aware of.
                              capability &= ~CommsConstants.CAPABILITIY_RESERVED_MASK;
  
                              reply.putShort(CommsConstants.FIELDID_CAPABILITIES);
                              reply.putShort(2);
                              reply.putShort(capability);
                          }
  
                          catHandshakeProps.setCapabilites(capability);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_PRODUCT_ID:
  
                      short productIdLength = request.getShort();
  
                      if (productIdLength != 2) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Product Id length", productIdLength);
                          rejectHandshake(conversation, requestNumber, "Product Id length");
                          noErrorOccurred = false;
                      } else {
                          short productId = request.getShort();
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Peer Product Id   : 0x" + Integer.toHexString(productId));
  
                          rcvProdId = true;
  
                          catHandshakeProps.setPeerProductId(productId);
  
                          // Reply to the client letting them know who we are
                          reply.putShort(CommsConstants.FIELDID_PRODUCT_ID);
                          reply.putShort(2);
                          reply.putShort(CommsConstants.PRODUCT_ID_JETSTREAM);
                      }
  
                      break;
  
                  case CommsConstants.FIELDID_SUPORTED_FAPS:
  
                      short supportedFapsLength = request.getShort();
                      if (supportedFapsLength != 32) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected Supported FAPs length: " + supportedFapsLength);
                          rejectHandshake(conversation, requestNumber, "Supported FAPs length");
                          noErrorOccurred = false;
                      } else {
                          // If trace is switched on - create a StringBuffer to build up a description
                          // of the supported FAP levels.
                          StringBuffer traceData = null;
  
                          // Read the supported FAP bitmap as an array of 32 bytes.
                          byte[] fapsBitmap = request.get(32);
  
                          // Convert the bitmap into an array of boolean values where
                          // index 0 corresponds to FAP level 1.
                          supportedFaps = new boolean[256];
                          for (int i = 0; i < supportedFaps.length; ++i) {
                              int byteValue = fapsBitmap[(255 - i) / 8];
                              boolean bitOn = ((byteValue >> (i % 8)) & 0x01) == 0x01;
                              supportedFaps[i] = bitOn;
  
                              if (bitOn) {
                                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                      if (traceData == null)
                                          traceData = new StringBuffer().append(i + 1);
                                      else
                                          traceData.append(", ").append(i + 1);
                                  }
                              }
                          }
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, " Supported FAP's   : " + traceData.toString());
  
                          // Note that we found a supported FAPs field.
                          rcvSupportedFaps = true;
                      }
                      break;
  
                  case CommsConstants.FIELDID_CONVERSATION_USAGE_TYPE:
  
                      final short length = request.getShort();
  
                      if (length != 4) {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(this, tc, "Unexpected FIELDID_CONVERSATION_USAGE_TYPE length: " + length);
                          rejectHandshake(conversation, requestNumber, "FIELDID_CONVERSATION_USAGE_TYPE length");
                          noErrorOccurred = false;
                      } else {
                          //Generate ConversationUsageType from buffer.
                          usageType = ConversationUsageType.deserialize(request);
  
                          //We only allow non-JFAP usage types on z/OS in the CRA so check this is the case.
                          if (usageType != ConversationUsageType.JFAP) {
                              //...Romil Liberty change
                              //final PlatformHelper helper = PlatformHelperFactory.getPlatformHelper();
                              //if(!(helper.isZOS() && helper.isCRAJvm()))
                              //{
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                                  SibTr.debug(this, tc, "Not running on z/OS CRA rejecting handshake");
                              rejectHandshake(conversation, requestNumber, "FIELDID_CONVERSATION_USAGE_TYPE platform");
                              noErrorOccurred = false;
  
                              //Venu Liberty COMMS
                              // z/OS specific code has been removed
                          }
                      }
                      break;
  
                  case CommsConstants.FIELDID_CELL_NAME:
                      //Ignore field length.
                      request.getShort();
                      final String remoteCellName = request.getString();
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Remote cell name: " + remoteCellName);
  
                      catHandshakeProps.setRemoteCellName(remoteCellName);
  
                      break;
  
                  case CommsConstants.FIELDID_NODE_NAME:
                      //Ignore field length.
                      request.getShort();
                      final String remoteNodeName = request.getString();
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Remote node name: " + remoteNodeName);
  
                      catHandshakeProps.setRemoteNodeName(remoteNodeName);
  
                      break;
  
                  case CommsConstants.FIELDID_SERVER_NAME:
                      //Ignore field length.
                      request.getShort();
                      final String remoteServerName = request.getString();
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Remote server name: " + remoteServerName);
  
                      catHandshakeProps.setRemoteServerName(remoteServerName);
  
                      break;
  
                  case CommsConstants.FIELDID_CLUSTER_NAME:
                      //Ignore field length.
                      request.getShort();
                      final String remoteClusterName = request.getString();
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Remote cluster name: " + remoteClusterName);
  
                      catHandshakeProps.setRemoteClusterName(remoteClusterName);
  
                      break;
  
                  default:
  
                      // We must ensure that we skip past the data so that we safely ignore the unknown
                      // field. The format will always be the same, i.e. BIT16 length, followed by the data.
                      short fieldLength = request.getShort();
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "* Unknown Field    : Id: " + fieldId + ", Length: " + fieldLength);
  
                      // Now skip the data
                      request.skip(fieldLength);
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              SibTr.debug(this, tc, "----- End of handshake data ---------------------");
  
          if (noErrorOccurred) {
              // Now check we received all the mandatory fields
              if (!rcvFapLevel) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                      SibTr.debug(this, tc, "No FAP level present in handshake");
                  rejectHandshake(conversation, requestNumber, "FAPLevel");
              } else if (!rcvProdVersion) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                      SibTr.debug(this, tc, "No Product Version present in handshake");
                  rejectHandshake(conversation, requestNumber, "ProductVersion");
              } else if (!rcvProdId && clientConnection) // This is only bad if this is a client - ME conn
              {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                      SibTr.debug(this, tc, "No Product Id present in handshake");
                  rejectHandshake(conversation, requestNumber, "ProductId");
              }
              // Otherwise, we can accept the connection
              else {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                      SibTr.debug(this, tc, "Handshake contained enough information to continue");
                  boolean foundSuitableFapLevel = true;
  
                  // Start out by considering using our peer's FAP.
                  int linkFapLevel = peerFapLevel;
  
                  // If the peers FAP level is greater than the level we support
                  // downgrade the support to our level.
                  if (linkFapLevel > currentFapLevel) {
                      linkFapLevel = currentFapLevel;
                  }
  
                  // Did the FAP flow contain a supported FAP versions field? Note we only look at these
                  // fields if we ourselves are at FAP level 3 or above.
                  if (rcvSupportedFaps && currentFapLevel >= JFapChannelConstants.FAP_VERSION_3) {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Examining the peers supported FAP levels");
  
                      // It may be the case that an IFIX has resulted in the client
                      // not understanding the level of FAP that we wish to use.
                      // Consult the set of supported FAP levels that the client
                      // sent to determine a common, supported, FAP level.
                      // Note: that the table of suitable FAP levels uses index zero
                      //       for FAP level 1 - hence the +1 and -1 code.
                      int i = linkFapLevel - 1;
                      boolean suitableLevelFound = false;
                      while ((i >= 0) && !suitableLevelFound) {
                          suitableLevelFound =
                                          supportedFaps[i] &&
                                                          (supportedFaps[i] == CommsConstants.isFapLevelSupported(i + 1));
  
                          if (!suitableLevelFound)
                              i -= 1;
                      }
  
                      if (suitableLevelFound)
                          linkFapLevel = i + 1;
                      else {
                          // There are no mutually agreeable FAP levels.
                          // Fail the handshake.
                          foundSuitableFapLevel = false;
                          rejectHandshake(conversation, requestNumber, "No mutually agreeable FAP level");
                      }
                  } else {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Peer did not supply supported FAP levels " +
                                                                "or SupportedFAPVersions field is not applicable");
  
                      // If the peer did not supply any supported FAP versions then we can only talk
                      // version 1 or 2.
                      if (peerFapLevel == JFapChannelConstants.FAP_VERSION_1) {
                          linkFapLevel = JFapChannelConstants.FAP_VERSION_1;
                      } else {
                          linkFapLevel = JFapChannelConstants.FAP_VERSION_2;
                      }
                  }
  
                  // If we have found a suitable FAP level - complete the handshake.
                  if (foundSuitableFapLevel) {
                      // Add FAP level to reply.
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Informing peer of negotiatied value: " + linkFapLevel);
  
                      reply.putShort(CommsConstants.FIELDID_FAP_LEVEL);
                      reply.putShort(2);
                      reply.putShort(linkFapLevel);
  
                      // Set the FAP level in the handshake properties - so that we can
                      // refer to it later.
                      catHandshakeProps.setFapLevel((short) linkFapLevel);
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Handshake Properties: ", catHandshakeProps);
  
                      //Only set handshake properties on Conversation if usageType requires it.
                      if (usageType.requiresNormalHandshakeProcessing())
                          conversation.setHandshakeProperties(catHandshakeProps);
  
                      // Send the handshake reply to our peer.
                      try {
                          conversation.send(reply,
                                            JFapChannelConstants.SEG_HANDSHAKE,
                                            requestNumber,
                                            JFapChannelConstants.PRIORITY_HANDSHAKE,
                                            true,
                                            ThrottlingPolicy.BLOCK_THREAD,
                                            null);
                      } catch (SIException e) {
                          FFDCFilter.processException(e,
                                                      CLASS_NAME + ".rcvHandshake",
                                                      CommsConstants.COMMONSERVERRECEIVELISTENER_RHSHAKE_01,
                                                      this);
  
                          SibTr.error(tc, "COMMUNICATION_ERROR_SICO2019", e);
                      }
                  }
              }
          }
  
          request.release(allocatedFromBufferPool);
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(this, tc, "rcvHandshake");
      }