Remove non-standard "CM" discovery topics
These topics are non-standard and not actually used anywhere in Cyclone, so it is rather silly to keep them. Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
		
							parent
							
								
									a6dc93ac03
								
							
						
					
					
						commit
						a41a615999
					
				
					 10 changed files with 49 additions and 339 deletions
				
			
		| 
						 | 
				
			
			@ -138,20 +138,9 @@ static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
 | 
			
		|||
  /* Set additional default participant properties */
 | 
			
		||||
 | 
			
		||||
  char progname[50] = "UNKNOWN"; /* FIXME: once retrieving process names is back in */
 | 
			
		||||
  char hostname[64];
 | 
			
		||||
  domain->gv.default_local_plist_pp.process_id = (unsigned) ddsrt_getpid();
 | 
			
		||||
  domain->gv.default_local_plist_pp.present |= PP_PRISMTECH_PROCESS_ID;
 | 
			
		||||
  domain->gv.default_local_plist_pp.exec_name = dds_string_alloc(32);
 | 
			
		||||
  (void) snprintf (domain->gv.default_local_plist_pp.exec_name, 32, "CycloneDDS: %u", domain->gv.default_local_plist_pp.process_id);
 | 
			
		||||
  len = (uint32_t) (13 + strlen (domain->gv.default_local_plist_pp.exec_name));
 | 
			
		||||
  domain->gv.default_local_plist_pp.present |= PP_PRISMTECH_EXEC_NAME;
 | 
			
		||||
  if (ddsrt_gethostname (hostname, sizeof (hostname)) == DDS_RETCODE_OK)
 | 
			
		||||
  {
 | 
			
		||||
    domain->gv.default_local_plist_pp.node_name = dds_string_dup (hostname);
 | 
			
		||||
    domain->gv.default_local_plist_pp.present |= PP_PRISMTECH_NODE_NAME;
 | 
			
		||||
  }
 | 
			
		||||
  len = (uint32_t) (strlen (progname) + 13);
 | 
			
		||||
  domain->gv.default_local_plist_pp.entity_name = dds_alloc (len);
 | 
			
		||||
  (void) snprintf (domain->gv.default_local_plist_pp.entity_name, len, "%s<%u>", progname, domain->gv.default_local_plist_pp.process_id);
 | 
			
		||||
  (void) snprintf (domain->gv.default_local_plist_pp.entity_name, len, "%s<%u>", progname, (unsigned) ddsrt_getpid ());
 | 
			
		||||
  domain->gv.default_local_plist_pp.present |= PP_ENTITY_NAME;
 | 
			
		||||
 | 
			
		||||
  if (rtps_start (&domain->gv) < 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -161,4 +161,4 @@ CU_Test(ddsc_lifespan, basic, .init=lifespan_init, .fini=lifespan_fini)
 | 
			
		|||
  check_whc_state(g_writer, -1, -1);
 | 
			
		||||
 | 
			
		||||
  dds_delete_qos(qos);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,6 @@ int sedp_dispose_unregister_writer (struct writer *wr);
 | 
			
		|||
int sedp_dispose_unregister_reader (struct reader *rd);
 | 
			
		||||
 | 
			
		||||
int sedp_write_topic (struct participant *pp, const struct nn_plist *datap);
 | 
			
		||||
int sedp_write_cm_participant (struct participant *pp, int alive);
 | 
			
		||||
 | 
			
		||||
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -196,7 +196,6 @@ struct participant
 | 
			
		|||
  struct entity_common e;
 | 
			
		||||
  dds_duration_t lease_duration; /* constant */
 | 
			
		||||
  uint32_t bes; /* built-in endpoint set */
 | 
			
		||||
  uint32_t prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
 | 
			
		||||
  unsigned is_ddsi2_pp: 1; /* true for the "federation leader", the ddsi2 participant itself in OSPL; FIXME: probably should use this for broker mode as well ... */
 | 
			
		||||
  struct nn_plist *plist; /* settings/QoS for this participant */
 | 
			
		||||
  struct xevent *spdp_xevent; /* timed event for periodically publishing SPDP */
 | 
			
		||||
| 
						 | 
				
			
			@ -347,7 +346,6 @@ struct proxy_participant
 | 
			
		|||
  unsigned lease_expired: 1;
 | 
			
		||||
  unsigned deleting: 1;
 | 
			
		||||
  unsigned proxypp_have_spdp: 1;
 | 
			
		||||
  unsigned proxypp_have_cm: 1;
 | 
			
		||||
  unsigned owns_lease: 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -645,16 +643,11 @@ void delete_local_orphan_writer (struct local_orphan_writer *wr);
 | 
			
		|||
/* Set when this proxy participant is not to be announced on the built-in topics yet */
 | 
			
		||||
#define CF_PROXYPP_NO_SPDP                     (1 << 3)
 | 
			
		||||
 | 
			
		||||
void new_proxy_participant (struct q_globals *gv, const struct ddsi_guid *guid, unsigned bes, unsigned prismtech_bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq);
 | 
			
		||||
void new_proxy_participant (struct q_globals *gv, const struct ddsi_guid *guid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq);
 | 
			
		||||
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
 | 
			
		||||
 | 
			
		||||
enum update_proxy_participant_source {
 | 
			
		||||
  UPD_PROXYPP_SPDP,
 | 
			
		||||
  UPD_PROXYPP_CM
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp);
 | 
			
		||||
int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp);
 | 
			
		||||
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, nn_wctime_t timestamp);
 | 
			
		||||
int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, nn_wctime_t timestamp);
 | 
			
		||||
void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease);
 | 
			
		||||
 | 
			
		||||
void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,20 +47,16 @@ extern "C" {
 | 
			
		|||
#define PP_ORIGINAL_WRITER_INFO                 ((uint64_t)1 << 23)
 | 
			
		||||
#define PP_ENDPOINT_GUID                        ((uint64_t)1 << 24)
 | 
			
		||||
#define PP_PRISMTECH_PARTICIPANT_VERSION_INFO   ((uint64_t)1 << 26)
 | 
			
		||||
#define PP_PRISMTECH_NODE_NAME                  ((uint64_t)1 << 27)
 | 
			
		||||
#define PP_PRISMTECH_EXEC_NAME                  ((uint64_t)1 << 28)
 | 
			
		||||
#define PP_PRISMTECH_PROCESS_ID                 ((uint64_t)1 << 29)
 | 
			
		||||
#define PP_PRISMTECH_BUILTIN_ENDPOINT_SET       ((uint64_t)1 << 33)
 | 
			
		||||
#define PP_PRISMTECH_TYPE_DESCRIPTION           ((uint64_t)1 << 34)
 | 
			
		||||
#define PP_COHERENT_SET                         ((uint64_t)1 << 37)
 | 
			
		||||
#define PP_PRISMTECH_TYPE_DESCRIPTION           ((uint64_t)1 << 27)
 | 
			
		||||
#define PP_COHERENT_SET                         ((uint64_t)1 << 28)
 | 
			
		||||
#ifdef DDSI_INCLUDE_SSM
 | 
			
		||||
#define PP_READER_FAVOURS_SSM                   ((uint64_t)1 << 39)
 | 
			
		||||
#define PP_READER_FAVOURS_SSM                   ((uint64_t)1 << 29)
 | 
			
		||||
#endif
 | 
			
		||||
/* Security extensions. */
 | 
			
		||||
#define PP_IDENTITY_TOKEN                       ((uint64_t)1 << 41)
 | 
			
		||||
#define PP_PERMISSIONS_TOKEN                    ((uint64_t)1 << 42)
 | 
			
		||||
#define PP_DOMAIN_ID                            ((uint64_t)1 << 43)
 | 
			
		||||
#define PP_DOMAIN_TAG                           ((uint64_t)1 << 44)
 | 
			
		||||
#define PP_IDENTITY_TOKEN                       ((uint64_t)1 << 30)
 | 
			
		||||
#define PP_PERMISSIONS_TOKEN                    ((uint64_t)1 << 31)
 | 
			
		||||
#define PP_DOMAIN_ID                            ((uint64_t)1 << 32)
 | 
			
		||||
#define PP_DOMAIN_TAG                           ((uint64_t)1 << 33)
 | 
			
		||||
/* Set for unrecognized parameters that are in the reserved space or
 | 
			
		||||
   in our own vendor-specific space that have the
 | 
			
		||||
   PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */
 | 
			
		||||
| 
						 | 
				
			
			@ -150,15 +146,11 @@ typedef struct nn_plist {
 | 
			
		|||
  nn_entityid_t group_entityid;
 | 
			
		||||
#endif
 | 
			
		||||
  uint32_t builtin_endpoint_set;
 | 
			
		||||
  uint32_t prismtech_builtin_endpoint_set;
 | 
			
		||||
  /* int type_max_size_serialized; */
 | 
			
		||||
  char *entity_name;
 | 
			
		||||
  nn_keyhash_t keyhash;
 | 
			
		||||
  uint32_t statusinfo;
 | 
			
		||||
  nn_prismtech_participant_version_info_t prismtech_participant_version_info;
 | 
			
		||||
  char *node_name;
 | 
			
		||||
  char *exec_name;
 | 
			
		||||
  uint32_t process_id;
 | 
			
		||||
  char *type_description;
 | 
			
		||||
  nn_sequence_number_t coherent_set_seqno;
 | 
			
		||||
#ifdef DDSI_INCLUDE_SSM
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,12 +44,6 @@ typedef int64_t seqno_t;
 | 
			
		|||
#define NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER 0x100c7
 | 
			
		||||
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER 0x200c2
 | 
			
		||||
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER 0x200c7
 | 
			
		||||
#define NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER 0x142
 | 
			
		||||
#define NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER 0x147
 | 
			
		||||
#define NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER 0x242
 | 
			
		||||
#define NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER 0x247
 | 
			
		||||
#define NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER 0x342
 | 
			
		||||
#define NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER 0x347
 | 
			
		||||
#define NN_ENTITYID_SOURCE_MASK 0xc0
 | 
			
		||||
#define NN_ENTITYID_SOURCE_USER 0x00
 | 
			
		||||
#define NN_ENTITYID_SOURCE_BUILTIN 0xc0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -236,11 +236,6 @@ int spdp_write (struct participant *pp)
 | 
			
		|||
    ps.aliased |= PP_DOMAIN_TAG;
 | 
			
		||||
    ps.domain_tag = pp->e.gv->config.domainTag;
 | 
			
		||||
  }
 | 
			
		||||
  if (pp->prismtech_bes)
 | 
			
		||||
  {
 | 
			
		||||
    ps.present |= PP_PRISMTECH_BUILTIN_ENDPOINT_SET;
 | 
			
		||||
    ps.prismtech_builtin_endpoint_set = pp->prismtech_bes;
 | 
			
		||||
  }
 | 
			
		||||
  ps.default_unicast_locators.n = 1;
 | 
			
		||||
  ps.default_unicast_locators.first =
 | 
			
		||||
    ps.default_unicast_locators.last = &def_uni_loc_one;
 | 
			
		||||
| 
						 | 
				
			
			@ -526,8 +521,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
    NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER |
 | 
			
		||||
    NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER;
 | 
			
		||||
  struct addrset *as_meta, *as_default;
 | 
			
		||||
  unsigned builtin_endpoint_set;
 | 
			
		||||
  unsigned prismtech_builtin_endpoint_set;
 | 
			
		||||
  uint32_t builtin_endpoint_set;
 | 
			
		||||
  ddsi_guid_t privileged_pp_guid;
 | 
			
		||||
  dds_duration_t lease_duration;
 | 
			
		||||
  unsigned custom_flags = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -555,7 +549,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
     so it seemed; and yet they are necessary for correct operation,
 | 
			
		||||
     so add them. */
 | 
			
		||||
  builtin_endpoint_set = datap->builtin_endpoint_set;
 | 
			
		||||
  prismtech_builtin_endpoint_set = (datap->present & PP_PRISMTECH_BUILTIN_ENDPOINT_SET) ? datap->prismtech_builtin_endpoint_set : 0;
 | 
			
		||||
  if (vendor_is_rti (rst->vendor) &&
 | 
			
		||||
      ((builtin_endpoint_set &
 | 
			
		||||
        (NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER |
 | 
			
		||||
| 
						 | 
				
			
			@ -570,21 +563,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
      NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER |
 | 
			
		||||
      NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER;
 | 
			
		||||
  }
 | 
			
		||||
  if ((datap->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) &&
 | 
			
		||||
      (datap->present & PP_PRISMTECH_BUILTIN_ENDPOINT_SET) &&
 | 
			
		||||
      !(datap->prismtech_participant_version_info.flags & NN_PRISMTECH_FL_PTBES_FIXED_0))
 | 
			
		||||
  {
 | 
			
		||||
    /* FIXED_0 (bug 0) indicates that this is an updated version that advertises
 | 
			
		||||
       CM readers/writers correctly (without it, we could make a reasonable guess,
 | 
			
		||||
       but it would cause problems with cases where we would be happy with only
 | 
			
		||||
       (say) CM participant. Have to do a backwards-compatible fix because it has
 | 
			
		||||
       already been released with the flags all aliased to bits 0 and 1 ... */
 | 
			
		||||
      GVLOGDISC (" (ptbes_fixed_0 %x)", prismtech_builtin_endpoint_set);
 | 
			
		||||
      if (prismtech_builtin_endpoint_set & NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER)
 | 
			
		||||
        prismtech_builtin_endpoint_set |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER;
 | 
			
		||||
      if (prismtech_builtin_endpoint_set & NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER)
 | 
			
		||||
        prismtech_builtin_endpoint_set |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Do we know this GUID already? */
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -627,7 +605,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
          GVLOGDISC ("SPDP ST0 "PGUIDFMT, PGUID (datap->participant_guid));
 | 
			
		||||
        GVLOGDISC (proxypp->implicitly_created ? " (NEW was-implicitly-created)" : " (update)");
 | 
			
		||||
        proxypp->implicitly_created = 0;
 | 
			
		||||
        update_proxy_participant_plist_locked (proxypp, seq, datap, UPD_PROXYPP_SPDP, timestamp);
 | 
			
		||||
        update_proxy_participant_plist_locked (proxypp, seq, datap, timestamp);
 | 
			
		||||
      }
 | 
			
		||||
      ddsrt_mutex_unlock (&proxypp->e.lock);
 | 
			
		||||
      return interesting;
 | 
			
		||||
| 
						 | 
				
			
			@ -641,7 +619,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x ptbes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set, prismtech_builtin_endpoint_set);
 | 
			
		||||
  GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set);
 | 
			
		||||
 | 
			
		||||
  if (datap->present & PP_PARTICIPANT_LEASE_DURATION)
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -770,7 +748,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
 | 
			
		|||
    gv,
 | 
			
		||||
    &datap->participant_guid,
 | 
			
		||||
    builtin_endpoint_set,
 | 
			
		||||
    prismtech_builtin_endpoint_set,
 | 
			
		||||
    &privileged_pp_guid,
 | 
			
		||||
    as_default,
 | 
			
		||||
    as_meta,
 | 
			
		||||
| 
						 | 
				
			
			@ -1109,7 +1086,7 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv
 | 
			
		|||
       doing anything about (1).  That means we fall back to the legacy mode of locally generating
 | 
			
		||||
       GIDs but leaving the system id unchanged if the remote is OSPL.  */
 | 
			
		||||
    actual_vendorid = (datap->present & PP_VENDORID) ?  datap->vendorid : vendorid;
 | 
			
		||||
    new_proxy_participant(gv, ppguid, 0, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, T_NEVER, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp, seq);
 | 
			
		||||
    new_proxy_participant(gv, ppguid, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, T_NEVER, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp, seq);
 | 
			
		||||
  }
 | 
			
		||||
  else if (ppguid->prefix.u[0] == src_guid_prefix->u[0] && vendor_is_eclipse_or_opensplice (vendorid))
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -1143,7 +1120,7 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv
 | 
			
		|||
      ddsrt_mutex_unlock (&privpp->e.lock);
 | 
			
		||||
 | 
			
		||||
      pp_plist.prismtech_participant_version_info.flags &= ~NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2;
 | 
			
		||||
      new_proxy_participant (gv, ppguid, 0, 0, &privguid, as_default, as_meta, &pp_plist, T_NEVER, vendorid, CF_IMPLICITLY_CREATED_PROXYPP | CF_PROXYPP_NO_SPDP, timestamp, seq);
 | 
			
		||||
      new_proxy_participant (gv, ppguid, 0, &privguid, as_default, as_meta, &pp_plist, T_NEVER, vendorid, CF_IMPLICITLY_CREATED_PROXYPP | CF_PROXYPP_NO_SPDP, timestamp, seq);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1447,104 +1424,6 @@ int sedp_write_topic (struct participant *pp, const struct nn_plist *datap)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 ***
 | 
			
		||||
 *** PrismTech CM data
 | 
			
		||||
 ***
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
int sedp_write_cm_participant (struct participant *pp, int alive)
 | 
			
		||||
{
 | 
			
		||||
  struct writer * sedp_wr;
 | 
			
		||||
  struct nn_xmsg *mpayload;
 | 
			
		||||
  nn_plist_t ps;
 | 
			
		||||
  int ret;
 | 
			
		||||
 | 
			
		||||
  if (pp->e.onlylocal) {
 | 
			
		||||
      /* This topic is only locally available. */
 | 
			
		||||
      return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sedp_wr = get_sedp_writer (pp, NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER);
 | 
			
		||||
 | 
			
		||||
  /* The message is only a temporary thing, used only for encoding
 | 
			
		||||
   the QoS and other settings. So the header fields aren't really
 | 
			
		||||
   important, except that they need to be set to reasonable things
 | 
			
		||||
   or it'll crash */
 | 
			
		||||
  mpayload = nn_xmsg_new (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA);
 | 
			
		||||
  nn_plist_init_empty (&ps);
 | 
			
		||||
  ps.present = PP_PARTICIPANT_GUID;
 | 
			
		||||
  ps.participant_guid = pp->e.guid;
 | 
			
		||||
  nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0);
 | 
			
		||||
  nn_plist_fini (&ps);
 | 
			
		||||
  if (alive)
 | 
			
		||||
  {
 | 
			
		||||
    nn_plist_addtomsg (mpayload, pp->plist,
 | 
			
		||||
                       PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID |
 | 
			
		||||
                       PP_ENTITY_NAME,
 | 
			
		||||
                       QP_PRISMTECH_ENTITY_FACTORY);
 | 
			
		||||
  }
 | 
			
		||||
  nn_xmsg_addpar_sentinel (mpayload);
 | 
			
		||||
 | 
			
		||||
  ETRACE (pp, "sedp: write CMParticipant ST%x for "PGUIDFMT" via "PGUIDFMT"\n",
 | 
			
		||||
          alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER, PGUID (pp->e.guid), PGUID (sedp_wr->e.guid));
 | 
			
		||||
  ret = write_mpayload (sedp_wr, alive, PID_PARTICIPANT_GUID, mpayload);
 | 
			
		||||
  nn_xmsg_free (mpayload);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_SEDP_CM (const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
  struct q_globals * const gv = rst->gv;
 | 
			
		||||
  const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
 | 
			
		||||
  GVLOGDISC ("SEDP_CM ST%x", statusinfo);
 | 
			
		||||
  assert (wr_entity_id.u == NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER);
 | 
			
		||||
  (void) wr_entity_id;
 | 
			
		||||
  if (data == NULL)
 | 
			
		||||
  {
 | 
			
		||||
    GVLOGDISC (" no payload?\n");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    nn_plist_t decoded_data;
 | 
			
		||||
    nn_plist_src_t src;
 | 
			
		||||
    dds_return_t plist_ret;
 | 
			
		||||
    src.protocol_version = rst->protocol_version;
 | 
			
		||||
    src.vendorid = rst->vendor;
 | 
			
		||||
    src.encoding = data->identifier;
 | 
			
		||||
    src.buf = (unsigned char *) data + 4;
 | 
			
		||||
    src.bufsz = len - 4;
 | 
			
		||||
    src.strict = NN_STRICT_P (gv->config);
 | 
			
		||||
    src.factory = gv->m_factory;
 | 
			
		||||
    src.logconfig = &gv->logconfig;
 | 
			
		||||
    if ((plist_ret = nn_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (plist_ret != DDS_RETCODE_UNSUPPORTED)
 | 
			
		||||
        GVWARNING ("SEDP_CM (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* ignore: dispose/unregister is tied to deleting the participant, which will take care of the dispose/unregister for us */;
 | 
			
		||||
    if ((statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      struct proxy_participant *proxypp;
 | 
			
		||||
      if (!(decoded_data.present & PP_PARTICIPANT_GUID))
 | 
			
		||||
        GVWARNING ("SEDP_CM (vendor %u.%u): missing participant GUID\n", src.vendorid.id[0], src.vendorid.id[1]);
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        if ((proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, &decoded_data.participant_guid)) == NULL)
 | 
			
		||||
          proxypp = implicitly_create_proxypp (gv, &decoded_data.participant_guid, &decoded_data, &rst->src_guid_prefix, rst->vendor, timestamp, 0);
 | 
			
		||||
        if (proxypp != NULL)
 | 
			
		||||
          update_proxy_participant_plist (proxypp, 0, &decoded_data, UPD_PROXYPP_CM, timestamp);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    nn_plist_fini (&decoded_data);
 | 
			
		||||
  }
 | 
			
		||||
  GVLOGDISC ("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1711,13 +1590,8 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
 | 
			
		|||
      switch (srcguid.entityid.u)
 | 
			
		||||
      {
 | 
			
		||||
        case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER:
 | 
			
		||||
        case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER:
 | 
			
		||||
          pid = PID_PARTICIPANT_GUID;
 | 
			
		||||
          break;
 | 
			
		||||
        case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER:
 | 
			
		||||
        case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER:
 | 
			
		||||
          pid = PID_GROUP_GUID;
 | 
			
		||||
          break;
 | 
			
		||||
        case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER:
 | 
			
		||||
        case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER:
 | 
			
		||||
          pid = PID_ENDPOINT_GUID;
 | 
			
		||||
| 
						 | 
				
			
			@ -1767,9 +1641,6 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
 | 
			
		|||
    case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
 | 
			
		||||
      handle_pmd_message (sampleinfo->rst, timestamp, statusinfo, datap, datasz);
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER:
 | 
			
		||||
      handle_SEDP_CM (sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      GVLOGDISC ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": not handled\n",
 | 
			
		||||
                 sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,10 +94,6 @@ static const unsigned builtin_writers_besmask =
 | 
			
		|||
  NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER |
 | 
			
		||||
  NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER |
 | 
			
		||||
  NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER;
 | 
			
		||||
static const unsigned prismtech_builtin_writers_besmask =
 | 
			
		||||
  NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER |
 | 
			
		||||
  NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER |
 | 
			
		||||
  NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
 | 
			
		||||
static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg);
 | 
			
		||||
static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, void *status_cbarg);
 | 
			
		||||
| 
						 | 
				
			
			@ -570,18 +566,16 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
 | 
			
		|||
 | 
			
		||||
  /* Create built-in endpoints (note: these have no GID, and no group GUID). */
 | 
			
		||||
  pp->bes = 0;
 | 
			
		||||
  pp->prismtech_bes = 0;
 | 
			
		||||
  subguid.prefix = pp->e.guid.prefix;
 | 
			
		||||
  memset (&group_guid, 0, sizeof (group_guid));
 | 
			
		||||
  /* SPDP writer */
 | 
			
		||||
#define LAST_WR_PARAMS NULL, NULL
 | 
			
		||||
 | 
			
		||||
  /* SPDP writer */
 | 
			
		||||
  /* Note: skip SEDP <=> skip SPDP because of the way ddsi_discovery.c does things
 | 
			
		||||
     currently.  */
 | 
			
		||||
  if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS))
 | 
			
		||||
  {
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, whc_new(gv, 1, 1, 1), NULL, NULL);
 | 
			
		||||
    /* But we need the as_disc address set for SPDP, because we need to
 | 
			
		||||
       send it to everyone regardless of the existence of readers. */
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -604,31 +598,19 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
 | 
			
		|||
  if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS))
 | 
			
		||||
  {
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL);
 | 
			
		||||
    pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL);
 | 
			
		||||
    pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (gv->config.do_topic_discovery)
 | 
			
		||||
  {
 | 
			
		||||
    /* TODO: make this one configurable, we don't want all participants to publish all topics (or even just those that they use themselves) */
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL);
 | 
			
		||||
    pp->bes |= NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -636,7 +618,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
 | 
			
		|||
  if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS))
 | 
			
		||||
  {
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS);
 | 
			
		||||
    new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL);
 | 
			
		||||
    pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -658,21 +640,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
 | 
			
		|||
    subguid.entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER);
 | 
			
		||||
    new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL);
 | 
			
		||||
    pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER);
 | 
			
		||||
    new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL);
 | 
			
		||||
    pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER);
 | 
			
		||||
    new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL);
 | 
			
		||||
    pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER;
 | 
			
		||||
 | 
			
		||||
    subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER);
 | 
			
		||||
    new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL);
 | 
			
		||||
    pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER;
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
#undef LAST_WR_PARAMS
 | 
			
		||||
 | 
			
		||||
  /* If the participant doesn't have the full set of builtin writers
 | 
			
		||||
     it depends on the privileged participant, which must exist, hence
 | 
			
		||||
| 
						 | 
				
			
			@ -682,8 +650,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
 | 
			
		|||
     Except when the participant is only locally available. */
 | 
			
		||||
  if (!(flags & RTPS_PF_ONLY_LOCAL)) {
 | 
			
		||||
    ddsrt_mutex_lock (&gv->privileged_pp_lock);
 | 
			
		||||
    if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask ||
 | 
			
		||||
        (pp->prismtech_bes & prismtech_builtin_writers_besmask) != prismtech_builtin_writers_besmask)
 | 
			
		||||
    if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask)
 | 
			
		||||
    {
 | 
			
		||||
      /* Simply crash when the privileged participant doesn't exist when
 | 
			
		||||
         it is needed.  Its existence is a precondition, and this is not
 | 
			
		||||
| 
						 | 
				
			
			@ -731,10 +698,6 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
 | 
			
		|||
    pp->spdp_xevent = qxev_spdp (gv->xevents, add_duration_to_mtime (now_mt (), 100 * T_MILLISECOND), &pp->e.guid, NULL);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Also write the CM data - this one being transient local, we only
 | 
			
		||||
   need to write it once (or when it changes, I suppose) */
 | 
			
		||||
  sedp_write_cm_participant (pp, 1);
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    nn_mtime_t tsched;
 | 
			
		||||
    tsched.v = (pp->lease_duration == T_NEVER) ? T_NEVER : 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -808,13 +771,6 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g
 | 
			
		|||
    NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER,
 | 
			
		||||
    NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER,
 | 
			
		||||
    /* PrismTech ones: */
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER,
 | 
			
		||||
    NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER
 | 
			
		||||
  };
 | 
			
		||||
  ddsi_guid_t stguid;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -833,7 +789,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g
 | 
			
		|||
  ELOGDISC (pp, "unref_participant("PGUIDFMT" @ %p <- "PGUIDFMT" @ %p) user %"PRId32" builtin %"PRId32"\n",
 | 
			
		||||
            PGUID (pp->e.guid), (void*)pp, PGUID (stguid), (void*)guid_of_refing_entity, pp->user_refc, pp->builtin_refc);
 | 
			
		||||
 | 
			
		||||
  if (pp->user_refc == 0 && (pp->bes != 0 || pp->prismtech_bes != 0) && !pp->builtins_deleted)
 | 
			
		||||
  if (pp->user_refc == 0 && pp->bes != 0 && !pp->builtins_deleted)
 | 
			
		||||
  {
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -869,9 +825,6 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g
 | 
			
		|||
       scheduled for deletion when it runs into an empty WHC */
 | 
			
		||||
    spdp_dispose_unregister (pp);
 | 
			
		||||
 | 
			
		||||
    /* We don't care, but other implementations might: */
 | 
			
		||||
    sedp_write_cm_participant (pp, 0);
 | 
			
		||||
 | 
			
		||||
    /* If this happens to be the privileged_pp, clear it */
 | 
			
		||||
    ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock);
 | 
			
		||||
    if (pp == pp->e.gv->privileged_pp)
 | 
			
		||||
| 
						 | 
				
			
			@ -887,8 +840,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g
 | 
			
		|||
 | 
			
		||||
    if (!(pp->e.onlylocal))
 | 
			
		||||
    {
 | 
			
		||||
      if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask ||
 | 
			
		||||
          (pp->prismtech_bes & prismtech_builtin_writers_besmask) != prismtech_builtin_writers_besmask)
 | 
			
		||||
      if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask)
 | 
			
		||||
      {
 | 
			
		||||
        /* Participant doesn't have a full complement of built-in
 | 
			
		||||
           writers, therefore, it relies on gv.privileged_pp, and
 | 
			
		||||
| 
						 | 
				
			
			@ -963,7 +915,7 @@ dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *p
 | 
			
		|||
struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid)
 | 
			
		||||
{
 | 
			
		||||
  ddsi_guid_t bwr_guid;
 | 
			
		||||
  unsigned bes_mask = 0, prismtech_bes_mask = 0;
 | 
			
		||||
  uint32_t bes_mask = 0;
 | 
			
		||||
 | 
			
		||||
  if (pp->e.onlylocal) {
 | 
			
		||||
      return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -986,15 +938,6 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity
 | 
			
		|||
    case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
 | 
			
		||||
      bes_mask = NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER:
 | 
			
		||||
      prismtech_bes_mask = NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER:
 | 
			
		||||
      prismtech_bes_mask = NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER:
 | 
			
		||||
      prismtech_bes_mask = NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER:
 | 
			
		||||
      bes_mask = NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER;
 | 
			
		||||
      break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1003,7 +946,7 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity
 | 
			
		|||
      return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((pp->bes & bes_mask) || (pp->prismtech_bes & prismtech_bes_mask))
 | 
			
		||||
  if (pp->bes & bes_mask)
 | 
			
		||||
  {
 | 
			
		||||
    /* Participant has this SEDP writer => use it. */
 | 
			
		||||
    bwr_guid.prefix = pp->e.guid.prefix;
 | 
			
		||||
| 
						 | 
				
			
			@ -2165,25 +2108,6 @@ static ddsi_entityid_t builtin_entityid_match (ddsi_entityid_t x)
 | 
			
		|||
      res.u = NN_ENTITYID_UNKNOWN;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER:
 | 
			
		||||
      res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER:
 | 
			
		||||
      res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER:
 | 
			
		||||
      res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER:
 | 
			
		||||
      res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER:
 | 
			
		||||
      res.u = NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER;
 | 
			
		||||
      break;
 | 
			
		||||
    case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER:
 | 
			
		||||
      res.u = NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      assert (0);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -3732,22 +3656,7 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void new_proxy_participant
 | 
			
		||||
(
 | 
			
		||||
  struct q_globals *gv,
 | 
			
		||||
  const struct ddsi_guid *ppguid,
 | 
			
		||||
  unsigned bes,
 | 
			
		||||
  unsigned prismtech_bes,
 | 
			
		||||
  const struct ddsi_guid *privileged_pp_guid,
 | 
			
		||||
  struct addrset *as_default,
 | 
			
		||||
  struct addrset *as_meta,
 | 
			
		||||
  const nn_plist_t *plist,
 | 
			
		||||
  dds_duration_t tlease_dur,
 | 
			
		||||
  nn_vendorid_t vendor,
 | 
			
		||||
  unsigned custom_flags,
 | 
			
		||||
  nn_wctime_t timestamp,
 | 
			
		||||
  seqno_t seq
 | 
			
		||||
)
 | 
			
		||||
void new_proxy_participant (struct q_globals *gv, const struct ddsi_guid *ppguid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const nn_plist_t *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq)
 | 
			
		||||
{
 | 
			
		||||
  /* No locking => iff all participants use unique guids, and sedp
 | 
			
		||||
     runs on a single thread, it can't go wrong. FIXME, maybe? The
 | 
			
		||||
| 
						 | 
				
			
			@ -3768,7 +3677,6 @@ void new_proxy_participant
 | 
			
		|||
  proxypp->deleting = 0;
 | 
			
		||||
  proxypp->vendor = vendor;
 | 
			
		||||
  proxypp->bes = bes;
 | 
			
		||||
  proxypp->prismtech_bes = prismtech_bes;
 | 
			
		||||
  proxypp->seq = seq;
 | 
			
		||||
  if (privileged_pp_guid) {
 | 
			
		||||
    proxypp->privileged_pp_guid = *privileged_pp_guid;
 | 
			
		||||
| 
						 | 
				
			
			@ -3850,14 +3758,6 @@ void new_proxy_participant
 | 
			
		|||
    proxypp->proxypp_have_spdp = 0;
 | 
			
		||||
  else
 | 
			
		||||
    proxypp->proxypp_have_spdp = 1;
 | 
			
		||||
  /* Non-PrismTech doesn't implement the PT extensions and therefore won't generate
 | 
			
		||||
     a CMParticipant; if a PT peer does not implement a CMParticipant writer, then it
 | 
			
		||||
     presumably also is a handicapped implementation (perhaps simply an old one) */
 | 
			
		||||
  if (!vendor_is_eclipse_or_prismtech(proxypp->vendor) ||
 | 
			
		||||
      (proxypp->bes != 0 && !(proxypp->prismtech_bes & NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER)))
 | 
			
		||||
    proxypp->proxypp_have_cm = 1;
 | 
			
		||||
  else
 | 
			
		||||
    proxypp->proxypp_have_cm = 0;
 | 
			
		||||
 | 
			
		||||
  /* Proxy participant must be in the hash tables for
 | 
			
		||||
     new_proxy_{writer,reader} to work */
 | 
			
		||||
| 
						 | 
				
			
			@ -3887,13 +3787,7 @@ void new_proxy_participant
 | 
			
		|||
      LTE (PARTICIPANT_MESSAGE_DATA_WRITER, P2P, PARTICIPANT_MESSAGE_WRITER),
 | 
			
		||||
      LTE (PARTICIPANT_MESSAGE_DATA_READER, P2P, PARTICIPANT_MESSAGE_READER),
 | 
			
		||||
      TE (DISC_, TOPIC_ANNOUNCER, SEDP, TOPIC_WRITER),
 | 
			
		||||
      TE (DISC_, TOPIC_DETECTOR, SEDP, TOPIC_READER),
 | 
			
		||||
      PT_TE (DISC_, CM_PARTICIPANT_READER, SEDP, CM_PARTICIPANT_READER),
 | 
			
		||||
      PT_TE (DISC_, CM_PARTICIPANT_WRITER, SEDP, CM_PARTICIPANT_WRITER),
 | 
			
		||||
      PT_TE (DISC_, CM_PUBLISHER_READER, SEDP, CM_PUBLISHER_READER),
 | 
			
		||||
      PT_TE (DISC_, CM_PUBLISHER_WRITER, SEDP, CM_PUBLISHER_WRITER),
 | 
			
		||||
      PT_TE (DISC_, CM_SUBSCRIBER_READER, SEDP, CM_SUBSCRIBER_READER),
 | 
			
		||||
      PT_TE (DISC_, CM_SUBSCRIBER_WRITER, SEDP, CM_SUBSCRIBER_WRITER)
 | 
			
		||||
      TE (DISC_, TOPIC_DETECTOR, SEDP, TOPIC_READER)
 | 
			
		||||
    };
 | 
			
		||||
#undef PT_TE
 | 
			
		||||
#undef TE
 | 
			
		||||
| 
						 | 
				
			
			@ -3945,39 +3839,31 @@ void new_proxy_participant
 | 
			
		|||
  ddsrt_mutex_unlock (&proxypp->e.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp)
 | 
			
		||||
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, nn_wctime_t timestamp)
 | 
			
		||||
{
 | 
			
		||||
  nn_plist_t *new_plist = ddsrt_malloc (sizeof (*new_plist));
 | 
			
		||||
  nn_plist_init_empty (new_plist);
 | 
			
		||||
  nn_plist_mergein_missing (new_plist, datap, PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | PP_ENTITY_NAME, QP_USER_DATA);
 | 
			
		||||
  nn_plist_mergein_missing (new_plist, &proxypp->e.gv->default_plist_pp, ~(uint64_t)0, ~(uint64_t)0);
 | 
			
		||||
 | 
			
		||||
  if (seq > proxypp->seq)
 | 
			
		||||
  {
 | 
			
		||||
    proxypp->seq = seq;
 | 
			
		||||
 | 
			
		||||
  switch (source)
 | 
			
		||||
  {
 | 
			
		||||
    case UPD_PROXYPP_SPDP:
 | 
			
		||||
      (void) update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp);
 | 
			
		||||
      nn_plist_fini (new_plist);
 | 
			
		||||
      ddsrt_free (new_plist);
 | 
			
		||||
      proxypp->proxypp_have_spdp = 1;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case UPD_PROXYPP_CM:
 | 
			
		||||
      nn_plist_fini (proxypp->plist);
 | 
			
		||||
      ddsrt_free (proxypp->plist);
 | 
			
		||||
      proxypp->plist = new_plist;
 | 
			
		||||
      proxypp->proxypp_have_cm = 1;
 | 
			
		||||
      break;
 | 
			
		||||
    struct q_globals * const gv = proxypp->e.gv;
 | 
			
		||||
    const uint64_t pmask = PP_ENTITY_NAME;
 | 
			
		||||
    const uint64_t qmask = QP_USER_DATA;
 | 
			
		||||
    nn_plist_t *new_plist = ddsrt_malloc (sizeof (*new_plist));
 | 
			
		||||
    nn_plist_init_empty (new_plist);
 | 
			
		||||
    nn_plist_mergein_missing (new_plist, datap, pmask, qmask);
 | 
			
		||||
    nn_plist_mergein_missing (new_plist, &gv->default_plist_pp, ~(uint64_t)0, ~(uint64_t)0);
 | 
			
		||||
    (void) update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp);
 | 
			
		||||
    nn_plist_fini (new_plist);
 | 
			
		||||
    ddsrt_free (new_plist);
 | 
			
		||||
    proxypp->proxypp_have_spdp = 1;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp)
 | 
			
		||||
int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, nn_wctime_t timestamp)
 | 
			
		||||
{
 | 
			
		||||
  ddsrt_mutex_lock (&proxypp->e.lock);
 | 
			
		||||
  update_proxy_participant_plist_locked (proxypp, seq, datap, source, timestamp);
 | 
			
		||||
  update_proxy_participant_plist_locked (proxypp, seq, datap, timestamp);
 | 
			
		||||
  ddsrt_mutex_unlock (&proxypp->e.lock);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1221,11 +1221,7 @@ static const struct piddesc piddesc_eclipse[] = {
 | 
			
		|||
  { PID_PAD, PDF_QOS, QP_CYCLONE_IGNORELOCAL, "CYCLONE_IGNORELOCAL",
 | 
			
		||||
    offsetof (struct nn_plist, qos.ignorelocal), membersize (struct nn_plist, qos.ignorelocal),
 | 
			
		||||
    { .desc = { XE2, XSTOP } }, 0 },
 | 
			
		||||
  PP  (PRISMTECH_BUILTIN_ENDPOINT_SET,      prismtech_builtin_endpoint_set, Xu),
 | 
			
		||||
  PP  (PRISMTECH_PARTICIPANT_VERSION_INFO,  prismtech_participant_version_info, Xux5, XS),
 | 
			
		||||
  PP  (PRISMTECH_EXEC_NAME,                 exec_name, XS),
 | 
			
		||||
  PP  (PRISMTECH_PROCESS_ID,                process_id, Xu),
 | 
			
		||||
  PP  (PRISMTECH_NODE_NAME,                 node_name, XS),
 | 
			
		||||
  PP  (PRISMTECH_TYPE_DESCRIPTION,          type_description, XS),
 | 
			
		||||
  { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1237,11 +1233,7 @@ static const struct piddesc piddesc_prismtech[] = {
 | 
			
		|||
  QP  (PRISMTECH_WRITER_DATA_LIFECYCLE,     writer_data_lifecycle, Xb),
 | 
			
		||||
  QP  (PRISMTECH_READER_DATA_LIFECYCLE,     reader_data_lifecycle, XDx2),
 | 
			
		||||
  QP  (PRISMTECH_SUBSCRIPTION_KEYS,         subscription_keys, XbCOND, XQ, XS, XSTOP),
 | 
			
		||||
  PP  (PRISMTECH_BUILTIN_ENDPOINT_SET,      prismtech_builtin_endpoint_set, Xu),
 | 
			
		||||
  PP  (PRISMTECH_PARTICIPANT_VERSION_INFO,  prismtech_participant_version_info, Xux5, XS),
 | 
			
		||||
  PP  (PRISMTECH_EXEC_NAME,                 exec_name, XS),
 | 
			
		||||
  PP  (PRISMTECH_PROCESS_ID,                process_id, Xu),
 | 
			
		||||
  PP  (PRISMTECH_NODE_NAME,                 node_name, XS),
 | 
			
		||||
  PP  (PRISMTECH_TYPE_DESCRIPTION,          type_description, XS),
 | 
			
		||||
  { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1320,8 +1312,8 @@ static const struct piddesc_index piddesc_vendor_index[] = {
 | 
			
		|||
/* List of entries that require unalias, fini processing;
 | 
			
		||||
   initialized by nn_plist_init_tables; will assert when
 | 
			
		||||
   table too small or too large */
 | 
			
		||||
static const struct piddesc *piddesc_unalias[20];
 | 
			
		||||
static const struct piddesc *piddesc_fini[20];
 | 
			
		||||
static const struct piddesc *piddesc_unalias[18];
 | 
			
		||||
static const struct piddesc *piddesc_fini[18];
 | 
			
		||||
static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT;
 | 
			
		||||
 | 
			
		||||
static nn_parameterid_t pid_without_flags (nn_parameterid_t pid)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,8 @@ CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		|||
  nn_plist_t p0, p0memcpy;
 | 
			
		||||
  char *p0strs[3];
 | 
			
		||||
  nn_plist_init_empty (&p0);
 | 
			
		||||
  p0.present = PP_PRISMTECH_PROCESS_ID | PP_ENTITY_NAME;
 | 
			
		||||
  p0.present = PP_ENTITY_NAME;
 | 
			
		||||
  p0.aliased = PP_ENTITY_NAME;
 | 
			
		||||
  p0.process_id = 0x12345678;
 | 
			
		||||
  p0.entity_name = "nemo";
 | 
			
		||||
  p0.qos.present = QP_PARTITION;
 | 
			
		||||
  p0.qos.aliased = QP_PARTITION;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +55,6 @@ CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		|||
  CU_ASSERT (p1.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p1.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p1.qos.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p1.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p1.entity_name != p0.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p1.entity_name, p0.entity_name);
 | 
			
		||||
  CU_ASSERT (p1.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +81,6 @@ CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		|||
  CU_ASSERT (p2.aliased == p2memcpy.aliased);
 | 
			
		||||
  CU_ASSERT (p2.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p2.qos.aliased == p2memcpy.qos.aliased);
 | 
			
		||||
  CU_ASSERT (p2.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p2.entity_name == p2memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p2.entity_name, "omen");
 | 
			
		||||
  CU_ASSERT (p2.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +98,6 @@ CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		|||
  CU_ASSERT (p0.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p0.qos.present == p0memcpy.qos.present);
 | 
			
		||||
  CU_ASSERT (p0.qos.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p0.process_id == p0memcpy.process_id);
 | 
			
		||||
  CU_ASSERT (p0.entity_name != p0memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p0.entity_name, p0memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT (p0.qos.partition.n == p0memcpy.qos.partition.n);
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +119,6 @@ CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		|||
  CU_ASSERT (p3.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p3.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p3.qos.aliased == 0);
 | 
			
		||||
  CU_ASSERT (p3.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p3.entity_name != p0.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p3.entity_name, p0.entity_name);
 | 
			
		||||
  CU_ASSERT (p3.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +145,6 @@ CU_Test (ddsi_plist, unalias_copy_merge)
 | 
			
		|||
  CU_ASSERT (p4.aliased == p4memcpy.aliased);
 | 
			
		||||
  CU_ASSERT (p4.qos.present == p0.qos.present);
 | 
			
		||||
  CU_ASSERT (p4.qos.aliased == p4memcpy.qos.aliased);
 | 
			
		||||
  CU_ASSERT (p4.process_id == p0.process_id);
 | 
			
		||||
  CU_ASSERT (p4.entity_name == p4memcpy.entity_name);
 | 
			
		||||
  CU_ASSERT_STRING_EQUAL (p4.entity_name, "omen");
 | 
			
		||||
  CU_ASSERT (p4.qos.partition.n == p0.qos.partition.n);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue