ignore all-zero durability service QoS in SEDP
For compatibility with TwinOaks CoreDX, ignore an all-zero durability service QoS received over SEDP for volatile and transient-local endpoints. Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
bd3188af5b
commit
638cab9291
2 changed files with 100 additions and 22 deletions
|
@ -593,6 +593,11 @@ static void bswap_history_qospolicy (nn_history_qospolicy_t *q)
|
|||
q->depth = bswap4 (q->depth);
|
||||
}
|
||||
|
||||
static int history_qospolicy_allzero (const nn_history_qospolicy_t *q)
|
||||
{
|
||||
return q->kind == NN_KEEP_LAST_HISTORY_QOS && q->depth == 0;
|
||||
}
|
||||
|
||||
int validate_history_qospolicy (const nn_history_qospolicy_t *q)
|
||||
{
|
||||
/* Validity of history setting and of resource limits are dependent,
|
||||
|
@ -630,6 +635,11 @@ static void bswap_resource_limits_qospolicy (nn_resource_limits_qospolicy_t *q)
|
|||
q->max_samples_per_instance = bswap4 (q->max_samples_per_instance);
|
||||
}
|
||||
|
||||
static int resource_limits_qospolicy_allzero (const nn_resource_limits_qospolicy_t *q)
|
||||
{
|
||||
return q->max_samples == 0 && q->max_instances == 0 && q->max_samples_per_instance == 0;
|
||||
}
|
||||
|
||||
int validate_resource_limits_qospolicy (const nn_resource_limits_qospolicy_t *q)
|
||||
{
|
||||
const int unlimited = NN_DDS_LENGTH_UNLIMITED;
|
||||
|
@ -707,9 +717,18 @@ static void bswap_durability_service_qospolicy (nn_durability_service_qospolicy_
|
|||
bswap_resource_limits_qospolicy (&q->resource_limits);
|
||||
}
|
||||
|
||||
int validate_durability_service_qospolicy (const nn_durability_service_qospolicy_t *q)
|
||||
static int durability_service_qospolicy_allzero (const nn_durability_service_qospolicy_t *q)
|
||||
{
|
||||
return (history_qospolicy_allzero (&q->history) &&
|
||||
resource_limits_qospolicy_allzero (&q->resource_limits) &&
|
||||
q->service_cleanup_delay.seconds == 0 && q->service_cleanup_delay.fraction == 0);
|
||||
}
|
||||
|
||||
static int validate_durability_service_qospolicy_acceptzero (const nn_durability_service_qospolicy_t *q, bool acceptzero)
|
||||
{
|
||||
int res;
|
||||
if (acceptzero && durability_service_qospolicy_allzero (q))
|
||||
return 0;
|
||||
if ((res = validate_duration (&q->service_cleanup_delay)) < 0)
|
||||
{
|
||||
DDS_TRACE("plist/validate_durability_service_qospolicy: duration invalid\n");
|
||||
|
@ -723,6 +742,11 @@ int validate_durability_service_qospolicy (const nn_durability_service_qospolicy
|
|||
return 0;
|
||||
}
|
||||
|
||||
int validate_durability_service_qospolicy (const nn_durability_service_qospolicy_t *q)
|
||||
{
|
||||
return validate_durability_service_qospolicy_acceptzero (q, false);
|
||||
}
|
||||
|
||||
static void bswap_liveliness_qospolicy (nn_liveliness_qospolicy_t *q)
|
||||
{
|
||||
q->kind = bswap4u (q->kind);
|
||||
|
@ -1300,8 +1324,9 @@ static int do_guid (nn_guid_t *dst, uint64_t *present, uint64_t fl, int (*valid)
|
|||
*dst = nn_ntoh_guid (*dst);
|
||||
if (valid (dst, dd) < 0)
|
||||
{
|
||||
if (fl == PP_PARTICIPANT_GUID && vendor_is_twinoaks (dd->vendorid) &&
|
||||
dst->entityid.u == 0 && ! NN_STRICT_P)
|
||||
/* CoreDX once upon a time used to send out PARTICIPANT_GUID parameters with a 0 entity id, but it
|
||||
that has long since changed (even if I don't know exactly when) */
|
||||
if (fl == PP_PARTICIPANT_GUID && vendor_is_twinoaks (dd->vendorid) && dst->entityid.u == 0 && ! NN_STRICT_P)
|
||||
{
|
||||
DDS_LOG(DDS_LC_DISCOVERY, "plist(vendor %u.%u): rewriting invalid participant guid %x:%x:%x:%x\n",
|
||||
dd->vendorid.id[0], dd->vendorid.id[1], PGUID (*dst));
|
||||
|
@ -1523,7 +1548,6 @@ static int init_one_parameter
|
|||
} \
|
||||
return 0
|
||||
Q (DURABILITY, durability);
|
||||
Q (DURABILITY_SERVICE, durability_service);
|
||||
Q (LIVELINESS, liveliness);
|
||||
Q (DESTINATION_ORDER, destination_order);
|
||||
Q (HISTORY, history);
|
||||
|
@ -1534,6 +1558,27 @@ static int init_one_parameter
|
|||
Q (TRANSPORT_PRIORITY, transport_priority);
|
||||
#undef Q
|
||||
|
||||
case PID_DURABILITY_SERVICE:
|
||||
if (dd->bufsz < sizeof (nn_durability_service_qospolicy_t))
|
||||
{
|
||||
DDS_TRACE("plist/init_one_parameter[pid=DURABILITY_SERVICE]: buffer too small\n");
|
||||
return ERR_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
nn_durability_service_qospolicy_t *q = &dest->qos.durability_service;
|
||||
/* All-zero durability service is illegal, but at least CoreDX sometimes advertises
|
||||
it in some harmless cases. So accept all-zero durability service, then handle it
|
||||
in final_validation, where we can determine whether it really is harmless or not */
|
||||
memcpy (q, dd->buf, sizeof (*q));
|
||||
if (dd->bswap)
|
||||
bswap_durability_service_qospolicy (q);
|
||||
if ((res = validate_durability_service_qospolicy_acceptzero (q, true)) < 0)
|
||||
return res;
|
||||
dest->qos.present |= QP_DURABILITY_SERVICE;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* PID_RELIABILITY handled differently because it (formally, for
|
||||
static typing reasons) has a different type on the network
|
||||
than internally, with the transformation between the two
|
||||
|
@ -2253,9 +2298,9 @@ nn_plist_t *nn_plist_dup (const nn_plist_t *src)
|
|||
return dst;
|
||||
}
|
||||
|
||||
static int final_validation (nn_plist_t *dest)
|
||||
static int final_validation (nn_plist_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid)
|
||||
{
|
||||
/* Resource limits & history are related, so if only one is given,
|
||||
/* Resource limits & history are related, so if only one is given,
|
||||
set the other to the default, claim it has been provided &
|
||||
validate the combination. They can't be changed afterward, so
|
||||
this is a reasonable interpretation. */
|
||||
|
@ -2276,6 +2321,46 @@ static int final_validation (nn_plist_t *dest)
|
|||
if ((res = validate_history_and_resource_limits (&dest->qos.history, &dest->qos.resource_limits)) < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Durability service is sort-of accepted if all zeros, but only
|
||||
for some protocol versions and vendors. We don't handle want
|
||||
to deal with that case internally. Now that all QoS have been
|
||||
parsed we know the setting of the durability QoS (the default
|
||||
is always VOLATILE), and hence we can verify that the setting
|
||||
is valid or delete it if irrelevant. */
|
||||
if (dest->qos.present & QP_DURABILITY_SERVICE)
|
||||
{
|
||||
const nn_durability_kind_t durkind = (dest->qos.present & QP_DURABILITY) ? dest->qos.durability.kind : NN_VOLATILE_DURABILITY_QOS;
|
||||
bool acceptzero;
|
||||
/* Use a somewhat convoluted rule to decide whether or not to
|
||||
"accept" an all-zero durability service setting, to find a
|
||||
reasonable mix of strictness and compatibility */
|
||||
if (protocol_version_is_newer (protocol_version))
|
||||
acceptzero = true;
|
||||
else if (NN_STRICT_P)
|
||||
acceptzero = vendor_is_twinoaks (vendorid);
|
||||
else
|
||||
acceptzero = !vendor_is_eclipse (vendorid);
|
||||
switch (durkind)
|
||||
{
|
||||
case NN_VOLATILE_DURABILITY_QOS:
|
||||
case NN_TRANSIENT_LOCAL_DURABILITY_QOS:
|
||||
/* pretend we never saw it if it is all zero */
|
||||
if (acceptzero && durability_service_qospolicy_allzero (&dest->qos.durability_service))
|
||||
dest->qos.present &= ~QP_DURABILITY_SERVICE;
|
||||
break;
|
||||
case NN_TRANSIENT_DURABILITY_QOS:
|
||||
case NN_PERSISTENT_DURABILITY_QOS:
|
||||
break;
|
||||
}
|
||||
/* if it is still present, it must be valid */
|
||||
if (dest->qos.present & QP_DURABILITY_SERVICE)
|
||||
{
|
||||
int res;
|
||||
if ((res = validate_durability_service_qospolicy (&dest->qos.durability_service)) < 0)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2341,10 +2426,9 @@ int nn_plist_init_frommsg
|
|||
length = (unsigned short) (dd.bswap ? bswap2u (par->length) : par->length);
|
||||
if (pid == PID_SENTINEL)
|
||||
{
|
||||
/* Sentinel terminates list, the length is ignored, DDSI
|
||||
9.4.2.11. */
|
||||
/* Sentinel terminates list, the length is ignored, DDSI 9.4.2.11. */
|
||||
DDS_LOG(DDS_LC_PLIST, "%4x PID %x\n", (unsigned) (pl - src->buf), pid);
|
||||
if ((res = final_validation (dest)) < 0)
|
||||
if ((res = final_validation (dest, src->protocol_version, src->vendorid)) < 0)
|
||||
{
|
||||
nn_plist_fini (dest);
|
||||
return ERR_INVALID;
|
||||
|
|
|
@ -1117,20 +1117,14 @@ OpenSplice.
|
|||
Compatibility issues with TwinOaks
|
||||
----------------------------------
|
||||
|
||||
Interoperability with TwinOaks CoreDX require (or used to require at some point in the
|
||||
past):
|
||||
In the default configuration there should be no interoperability issues with TwinOaks CoreDX,
|
||||
although there is the aforementioned difference in interpretation of the meaning of the
|
||||
‘autodispose_unregistered_instances’ QoS on the writer.
|
||||
|
||||
Interoperability with very old versions of CoreDX may require setting:
|
||||
|
||||
+ ``Compatibility/ManySocketsMode``: *true*
|
||||
+ ``Compatibility/StandardsConformance``: *lax*
|
||||
+ ``Compatibility/AckNackNumbitsEmptySet``: *0*
|
||||
+ ``Compatibility/ExplicitlyPublishQosSetToDefault``: *true*
|
||||
|
||||
The ``ManySocketsMode`` option needed to be changed from the default, to ensure that
|
||||
each domain participant has a unique locator; this was needed because TwinOaks CoreDX
|
||||
DDS did not include the full GUID of a reader or writer if it needs to address just one,
|
||||
but this is probably no longer the case. Note that the (old) behaviour of TwinOaks
|
||||
CoreDX DDS has always been allowed by the specification.
|
||||
|
||||
The ``Compatibility/ExplicitlyPublishQosSetToDefault`` settings work around TwinOaks
|
||||
CoreDX DDS’ use of incorrect default values for some of the QoS settings if they are not
|
||||
explicitly supplied during discovery. It may be that this is no longer the case.
|
||||
The exact version number of CoreDX starting with which these settings are no longer needed is
|
||||
unknown, but it has certainly not been needed for several years.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue