Example #1
0
void rfraginfo_delete (CCREF *refp)
{
    FragInfo_t	*fip;

    if ((fip = refp->fragments) == NULL)
        return;

    refp->fragments = NULL;
    rcl_access (fip);
    fip->nrefs--;
    rcl_done (fip);
    if (fip->nrefs > 0)
        return;

    db_free_data (fip->data);
    tmr_stop (&fip->timer);
    if (fip->key && fip->key != fip->hash.hash)
        xfree (fip->key);
    xfree (fip);
}
Example #2
0
void reader_add_fragment (READER       *rp,
			  Change_t     *cp,
			  KeyHash_t    *hp,
			  DataFragSMsg *fragp)
{
	Reader_t	*r = (Reader_t *) rp->endpoint.endpoint;
	RemWriter_t	*rwp, *fwp;
	CCREF		*refp;
	FragInfo_t	*fip;
	Change_t	*ncp;
	unsigned	max_frags;

	/*log_printf (RTPS_ID, 0, "reader_add_fragment: snr:%u, start:%u, num:%u, fsize:%u, tsize:%u\r\n",
				fragp->writer_sn.low, 
				fragp->frag_start, fragp->num_fragments,
				fragp->frag_size, fragp->sample_size);*/
	/* Check if we already got fragments from writer. */
	fwp = NULL;
	LIST_FOREACH (rp->rem_writers, rwp)
		if ((refp = LIST_HEAD (rwp->rw_changes)) != NULL &&
		    refp->u.c.change->c_writer == cp->c_writer) {
			fwp = rwp;
			break;
		}

	/* If this is the first, add a new RemWriter for the fragment,
	   allocate all relevant data, and start the fragment timer. */
	if (!fwp) {
		max_frags = (fragp->sample_size + fragp->frag_size - 1) / fragp->frag_size;
		if (fragp->frag_start + fragp->num_fragments - 1 > max_frags)
			return;

		if ((rwp = mds_pool_alloc (&rtps_mem_blocks [MB_REM_WRITER])) == NULL) {
			warn_printf ("reader_add_fragment: no memory for fragment!");
			return;
		}
		memset (rwp, 0, sizeof (RemWriter_t));
		rwp->rw_reader = rp;
		LIST_INIT (rwp->rw_changes);
		rp->rem_writers.count++;
		fwp = rwp;
		LIST_ADD_TAIL (rp->rem_writers, *rwp);
		ncp = hc_change_new ();
		if (!ncp) {
			warn_printf ("reader_add_fragment: no memory for change!");
			goto no_change_mem;
		}
		ncp->c_kind = cp->c_kind;
		ncp->c_writer = cp->c_writer;
		ncp->c_time = cp->c_time;
		ncp->c_seqnr = cp->c_seqnr;
		refp = ccref_add (&rwp->rw_changes, ncp, 0, 1, CS_RECEIVED);
		if (!refp) {
			warn_printf ("reader_add_fragment: no memory for list element!");
			goto no_ref_mem;
		}
		fip = rfraginfo_create (refp, fragp, max_frags);
		if (!fip) {
			warn_printf ("reader_add_fragment: no memory for fragment info!");
			goto no_frag_mem;
		}
	}
	else {
		refp = LIST_HEAD (rwp->rw_changes);
		fip = refp->fragments;
		ncp = refp->u.c.change;
		if (fip->fsize != fragp->frag_size ||
		    fip->length != fragp->sample_size ||
		    !SEQNR_EQ (ncp->c_seqnr, fragp->writer_sn)) {

			/* Incorrect fragment context: reset it. */
			fip = rfraginfo_update (refp, fragp);
			if (!fip)
				goto cleanup;
		}
		else if (fragp->frag_start + fragp->num_fragments - 1 > fip->total)
			return;
	}

	/* Update key info if present. */
	if (hp) {
		fip->hash = *hp;
		fip->hp = &fip->hash;
		fip->key = fip->hash.hash;
		fip->keylen = 12;
	}

	/* Mark the fragment as correctly received. */
	mark_fragment (fip, fragp, cp);

	/* If all fragments received correctly, cleanup the context. */
	if (!fip->num_na) {
		ncp->c_db = fip->data;
		ncp->c_length = fip->length;
		ncp->c_data = fip->data->data;
		rcl_access (fip->data);
		fip->data->nrefs++;
		rcl_done (fip->data);
		rfraginfo_delete (refp);
		reader_cache_add_key (rp, ncp, &fip->hash, fip->key, fip->keylen);

	    cleanup:

		if (fip) {		
			FRAGSC_TMR_STOP (rwp, &fip->timer);
			rfraginfo_delete (refp);
		}
		mds_pool_free (&rtps_mem_blocks [MB_CCREF], refp);
		remote_writer_remove (rp, rwp);
		mds_pool_free (&rtps_mem_blocks [MB_REM_WRITER], rwp);
	}
	else {
		FRAGSC_TMR_START (rwp,
				  &fip->timer,
				  TICKS_PER_SEC * 2,
				  (uintptr_t) rwp,
				  reader_frag_to,
				  &r->r_lock);
	}
	return;

    no_frag_mem:
	mds_pool_free (&rtps_mem_blocks [MB_CCREF], refp);
    no_ref_mem:
    	hc_change_free (ncp);
    no_change_mem:
	mds_pool_free (&rtps_mem_blocks [MB_REM_WRITER], rwp);
	return;
}
Example #3
0
static void sfr_be_data (RemWriter_t         *rwp,
			 Change_t            *cp,
			 SequenceNumber_t    *cpsnr,
			 const KeyHash_t     *hp,
			 const unsigned char *key,
			 size_t              keylen,
#ifdef RTPS_FRAGMENTS
			 DataFragSMsg        *fragp,
			 FragInfo_t	     **finfo,
#endif
			 int                 ignore)
{
	Change_t	*ncp;
	READER		*rp = rwp->rw_reader;
	Reader_t	*r = (Reader_t *) rp->endpoint.endpoint;
#ifdef RTPS_FRAGMENTS
	CCREF		*refp;
	FragInfo_t	*fip;
	unsigned	max_frags = 0;
#if defined (DDS_SECURITY) && defined (DDS_NATIVE_SECURITY)
	DB		*dbp;
	DBW		walk;
	int		error;
#endif
	size_t		ofs;
#endif

	ctrc_printd (RTPS_ID, RTPS_SFR_BE_DATA, &rwp, sizeof (rwp));
	prof_start (rtps_br_data);
#ifdef RTPS_FRAGMENTS
	if (rwp->rw_changes.nchanges) {	/* Lingering fragment? */
		refp = LIST_HEAD (rwp->rw_changes);
		fip = refp->fragments;
	}
	else {
		refp = NULL;
		fip = NULL;
	}
	if (fragp) {
		STATS_INC (rwp->rw_ndatafrags);
		if (!fip) {
			max_frags = (fragp->sample_size + fragp->frag_size - 1) / fragp->frag_size;
			if (fragp->frag_start != 1 ||
			    fragp->frag_start + fragp->num_fragments - 1 > max_frags)
				return;

			ncp = hc_change_new ();
			if (!ncp) {
				warn_printf ("sfr_be_data: no memory for change!");
				return;
			}
			ncp->c_kind = cp->c_kind;
			ncp->c_writer = cp->c_writer;
			ncp->c_time = cp->c_time;
			ncp->c_seqnr = cp->c_seqnr;
			refp = ccref_add (&rwp->rw_changes, ncp, 0, 1, CS_RECEIVED);
			if (!refp) {
				warn_printf ("sfr_be_data: no memory for list element!");
				goto no_ref_mem;
			}

		    new_finfo:

			if (*finfo) {
				fip = *finfo;
				rcl_access (fip);
				fip->nrefs++;
				rcl_done (fip);
			}
			else {
				fip = *finfo = rfraginfo_create (refp, fragp, max_frags);
				if (!fip) {
					goto no_frag_mem;
				}
			}
		}
		else {
			ncp = refp->u.c.change;
			if (fip->fsize != fragp->frag_size ||
			    fip->length != fragp->sample_size ||
			    !SEQNR_EQ (ncp->c_seqnr, fragp->writer_sn)) {

				if (fragp->frag_start != 1)
					return;

				/* Incorrect fragment context: reset it. */
				if (fip->nrefs == 1) {
					fip = rfraginfo_update (refp, fragp);
					if (!fip)
						goto no_frag_mem;
				}
				else {
					rfraginfo_delete (refp);
					goto new_finfo;
				}
			}
			else if (fragp->frag_start != fip->first_na + 1 ||
				 fragp->frag_start + fragp->num_fragments - 1 >
								fip->total)
				return;
		}

		/* Update key info if present. */
		if (hp) {
			fip->hash = *hp;
			fip->hp = &fip->hash;
			fip->key = fip->hash.hash;
			fip->keylen = 12;
		}

		/* Mark the fragment as correctly received. */
		mark_fragment (fip, fragp, cp);
		fip->first_na++;

		/* Check if all fragments are received correctly. */
		if (fip->num_na) {
			FRAGSC_TMR_START (rwp,
					  &fip->timer,
					  TICKS_PER_SEC * 2,
					  (uintptr_t) rwp,
					  sfr_be_frag_to,
					  &r->r_lock);
			return;
		}

#if defined (DDS_SECURITY) && defined (DDS_NATIVE_SECURITY)

		/* Decrypt payload data if an encrypted payload is present. */
		if (rwp->rw_endpoint &&
		    rwp->rw_crypto &&
		    fip->length) {
			walk.dbp = fip->data;
			walk.data = fip->data->data;
			walk.length = walk.left = fip->length;
			dbp = sec_decode_serialized_data (&walk,
							  0,
							  rwp->rw_crypto,
							  &fip->length,
							  &ofs,
							  (DDS_ReturnCode_t *) &error);
			if (!dbp)
				return;

			fip->data = dbp;
		}
		else
#endif
			ofs = 0;

		/* Cleanup the context. */
		ncp->c_db = fip->data;
		ncp->c_length = fip->length;
		ncp->c_data = fip->data->data + ofs;
		rcl_access (fip->data);
		fip->data->nrefs++;
		rcl_done (fip->data);
		cp = ncp;
		FRAGSC_TMR_STOP (rwp, &fip->timer);
		rfraginfo_delete (refp);
		mds_pool_free (&rtps_mem_blocks [MB_CCREF], refp);
		LIST_INIT (rwp->rw_changes);
		rwp->rw_changes.nchanges = 0;
	}
	else {
#endif
		STATS_INC (rwp->rw_ndata);

#ifdef RTPS_FRAGMENTS
		if (fip) { /* Lingering fragment?  Cleanup context. */
			FRAGSC_TMR_STOP (rwp, &fip->timer);
			rfraginfo_delete (refp);
			mds_pool_free (&rtps_mem_blocks [MB_CCREF], refp);
			LIST_INIT (rwp->rw_changes);
			rwp->rw_changes.nchanges = 0;
		}
	}
#endif
	RW_SIGNAL (rwp, "BE-Data");

#ifdef RTPS_MARKERS
	if (rp->endpoint.mark_data)
		rtps_marker_notify (r, EM_DATA, "sfr_be_data");
#endif
	if (SEQNR_LT (*cpsnr, rwp->rw_seqnr_next))
		return;

	if (!SEQNR_EQ (*cpsnr, rwp->rw_seqnr_next))
		dcps_samples_lost (r, SEQNR_DELTA (rwp->rw_seqnr_next, *cpsnr));

	if (!ignore) {
		if (cp->c_nrefs > 1) {
			ncp = hc_change_clone (cp);
			if (!ncp) {
				warn_printf ("sfr_be_data: out of memory for change clone!\r\n");
				return;
			}
		}
		else {
			rcl_access (cp);
			cp->c_nrefs++;
			rcl_done (cp);
			ncp = cp;
		}
		ncp->c_seqnr = *cpsnr;
		reader_cache_add_key (rp, ncp, hp, key, keylen);
	}
	rwp->rw_seqnr_next = cp->c_seqnr;
	SEQNR_INC (rwp->rw_seqnr_next);
	prof_stop (rtps_br_data, 1);
	RW_SNR_TRACE (rwp, "BE-data: update");

#ifdef RTPS_FRAGMENTS
	return;

    no_frag_mem:
	warn_printf ("sfr_be_data: no memory for fragment info!");
	LIST_INIT (rwp->rw_changes);
	rwp->rw_changes.nchanges = 0;
	hc_change_free (refp->u.c.change);
	mds_pool_free (&rtps_mem_blocks [MB_CCREF], refp);
    no_ref_mem:
    	hc_change_free (ncp);
#endif
}
Example #4
0
static void sfr_rel_data (RemWriter_t         *rwp,
			  Change_t            *cp,
			  SequenceNumber_t    *cpsnr,
			  const KeyHash_t     *hp,
			  const unsigned char *key,
			  size_t              keylen,
#ifdef RTPS_FRAGMENTS
			  DataFragSMsg        *fragp,
			  FragInfo_t	      **finfo,
#endif
			  int                 ignore)
{
	ENDPOINT	*ep = &rwp->rw_reader->endpoint;
	CCREF		*rp, *gap_rp;
	HCI		hci;
	Change_t	*ncp;
	InstanceHandle	h;
	SequenceNumber_t gap_first, gap_last, seqnr_first, seqnr_last;
	RejectCause_t	cause;
	/*unsigned	max;*/
	int		error, ooo;

	ctrc_printd (RTPS_ID, RTPS_SFR_REL_DATA, &rwp, sizeof (rwp));
	prof_start (rtps_rr_data);
#if defined (RTPS_FRAGMENTS) && defined (EXTRA_STATS)
	if (fragp)
		STATS_INC (rwp->rw_ndatafrags);
	else
#endif
		STATS_INC (rwp->rw_ndata);

	RW_SIGNAL (rwp, "REL-Data");

#ifdef RTPS_MARKERS
	if (rwp->rw_reader->endpoint.mark_data)
		rtps_marker_notify (rwp->rw_reader->endpoint.endpoint, EM_DATA, "sfr_rel_data");
#endif
#ifdef RTPS_INIT_ACKNACK

	/* If first Data: accept it and become alive. */
	if (!rwp->rw_peer_alive)
		sfr_rel_alive (rwp);
#endif
	rwp->rw_hb_no_data = 0;

	/* If seqnr already in cache: ignore sample. */
	if (SEQNR_LT (*cpsnr, rwp->rw_seqnr_next)) {
		RW_SIGNAL (rwp, "REL-Data: ignore (SNR < hcache.SNR)");
		return;
	}
	ooo = !SEQNR_EQ (rwp->rw_seqnr_next, *cpsnr);

	/* Create a new instance already, if possible. */
	if (ignore
#ifdef RTPS_FRAGMENTS
	           || fragp
#endif
		           )
		hci = NULL;
	else if (ep->multi_inst) {
		hci = hc_lookup_hash (ep->endpoint->cache, hp, key, keylen,
					  &h, 1, ooo, &cause);
		if (!hci) {
			/* Don't see this as rejected -- since there is no ack
			   given, sample will be retransmitted!
			dcps_sample_rejected ((Reader_t *) ep->endpoint,
					      (DDS_SampleRejectedStatusKind) cause,
					      h);*/
			if (!ooo)
				rwp->rw_blocked = 1;
			return;
		}
	}
	else {
		if (!hc_accepts (ep->endpoint->cache, ooo)) {
			/* Don't see this as rejected -- since there is no ack
			   given, sample will be retransmitted!
			dcps_sample_rejected ((Reader_t *) ep->endpoint,
					      DDS_REJECTED_BY_SAMPLES_LIMIT, 0);*/
			if (!ooo)
				rwp->rw_blocked = 1;
			return;
		}
		h = 0;
		hci = NULL;
	}

	/* Add to changes list of proxy writer context. */
	if (LIST_NONEMPTY (rwp->rw_changes)) { /* Already some samples queued. */

		RW_SIGNAL (rwp, "REL-Data: changes-queued");

		if (hci)
			hc_inst_inform (ep->endpoint->cache, hci);

		if (rwp->rw_changes.head->relevant)
			seqnr_first = rwp->rw_changes.head->u.c.change->c_seqnr;
		else
			seqnr_first = rwp->rw_changes.head->u.range.first;
		if (rwp->rw_changes.tail->relevant)
			seqnr_last = rwp->rw_changes.tail->u.c.change->c_seqnr;
		else
			seqnr_last = rwp->rw_changes.tail->u.range.last;

		if (SEQNR_GT (*cpsnr, seqnr_last)) { /* Seqnr > last in list! */

			/* Add new data sample node after tail of list. */
			RW_SIGNAL (rwp, "REL-Data: add-missing>last");
			gap_first = seqnr_last;
			SEQNR_INC (gap_first);
			if (!SEQNR_EQ (gap_first, *cpsnr)) {

				/* Gap between tail and data: add MISSING sample
				   node between current tail of list and to be
				   added data sample node. */
				gap_last = *cpsnr;
				SEQNR_DEC (gap_last);
				if (!rwp->rw_changes.tail->relevant &&
				    rwp->rw_changes.tail->state == CS_MISSING) {

					/* Extend previous gap node. */
					rwp->rw_changes.tail->u.range.last = gap_last;
					RW_SIGNAL (rwp, "REL-Data: extend-gap");
				}
				else {	/* Add new gap node. */
					gap_rp = ccref_add_gap (&rwp->rw_changes,
							        &gap_first,
							        &gap_last,
							        1,
								CS_MISSING);
					if (!gap_rp)
						return;

					RW_SIGNAL (rwp, "REL-Data: add-gap");
				}
			}

			/* Append data sample node. */
			if (ignore)
				rp = ccref_add_gap (&rwp->rw_changes, cpsnr,
						    cpsnr, 1, CS_RECEIVED);
			else
				rp = ccref_add_received (&rwp->rw_changes, cp,
							 cpsnr, hci, h, 1);
			if (!rp)
				return;

			rwp->rw_reader->data_queued++;
#ifdef RTPS_FRAGMENTS
			if (fragp) {
				sfr_fragment (rwp, rp, fragp, finfo, hp, cp, ooo, ignore);
				return;
			}
#endif
			RANGE_CHECK (&rwp->rw_changes, "REL-Data: >last");
		}
		else if (SEQNR_LT (*cpsnr, seqnr_first)) { /* Seqnr < first! */

			/* Add new data sample node before head of list. */
			RW_SIGNAL (rwp, "REL-Data: add-missing<first");
			gap_last = seqnr_first;
			SEQNR_DEC (gap_last);
			if (!SEQNR_EQ (gap_last, *cpsnr)) {

				/* Gap between data and head: add MISSING sample
				   node between to be added data sample and
				   current head of list. */
				gap_first = *cpsnr;
				SEQNR_INC (gap_first);
				if (!rwp->rw_changes.head->relevant &&
				    rwp->rw_changes.tail->state == CS_MISSING) {

					/* Extended following gap node. */
					rwp->rw_changes.head->u.range.first = gap_first;
					RW_SIGNAL (rwp, "REL-Data: extend-gap");
				}
				else {	/* Add new gap node. */
					gap_rp = ccref_add_gap (&rwp->rw_changes,
							        &gap_first,
							        &gap_last,
							        0,
								CS_MISSING);
					if (!gap_rp)
						return;

					RW_SIGNAL (rwp, "REL-Data: add-gap");
				}
			}

			/* Prepend data sample node. */
			if (ignore)
				rp = ccref_add_gap (&rwp->rw_changes, cpsnr,
							 cpsnr, 0, CS_RECEIVED);
			else
				rp = ccref_add_received (&rwp->rw_changes, cp,
							 cpsnr, hci, h, 0);
			if (!rp)
				return;

			rwp->rw_reader->data_queued++;
#ifdef RTPS_FRAGMENTS
			if (fragp) {
				sfr_fragment (rwp, rp, fragp, finfo, hp, cp, ooo, ignore);
				return;
			}
#endif
			RANGE_CHECK (&rwp->rw_changes, "REL-Data: <first");
		}
		else {	/* Seqnr somewhere in list - lets find it. */
			LIST_FOREACH (rwp->rw_changes, rp)
				if (rp->relevant) {
					if (SEQNR_EQ (rp->u.c.change->c_seqnr, *cpsnr))
						break;
				}
				else if (!SEQNR_LT (*cpsnr, rp->u.range.first) &&
					 !SEQNR_GT (*cpsnr, rp->u.range.last))
					break;

			if (LIST_END (rwp->rw_changes, rp) ||
			    (rp->state != CS_MISSING 
#ifdef RTPS_FRAGMENTS
			       && !rp->fragments
#endif
			       			))
				return;
#ifdef RTPS_FRAGMENTS
			if (rp->fragments) {
				sfr_fragment (rwp, rp, fragp, finfo, hp, cp, ooo, ignore);
				return;
			}
#endif
			RW_SIGNAL (rwp, "REL-Data: in-range");
			RANGE_CHECK (&rwp->rw_changes, "REL-Data: in-range");
			if (SEQNR_GT (*cpsnr, rp->u.range.first)) {

				/* Prepend gap node: range.first .. *cpsnr -1 */
				gap_first = rp->u.range.first;
				gap_last = *cpsnr;
				SEQNR_DEC (gap_last);
				gap_rp = ccref_insert_gap (&rwp->rw_changes,
						           rp->prev,
						           &gap_first,
						           &gap_last,
							   CS_MISSING);
				if (!gap_rp)
					return;

				RW_SIGNAL (rwp, "REL-Data: prepend-gap");
			}
			if (SEQNR_LT (*cpsnr, rp->u.range.last)) {

				/* Append gap node: *cpsnr + 1 .. range.last */
				gap_first = *cpsnr;
				SEQNR_INC (gap_first);
				gap_last = rp->u.range.last;
				gap_rp = ccref_insert_gap (&rwp->rw_changes,
						           rp,
						           &gap_first,
						           &gap_last,
							   CS_MISSING);
				if (!gap_rp)
					return;

				RW_SIGNAL (rwp, "REL-Data: append-gap");
			}

			/* Reuse gap node for data. */
#ifdef RTPS_FRAGMENTS
			rp->fragments = NULL;
#endif
			if (ignore) {
				rp->relevant = 0;
				rp->u.range.first = *cpsnr;
				rp->u.range.last = *cpsnr;
			}
			else {
				if (cp->c_nrefs > 1) {
					ncp = hc_change_clone (cp);
					if (!ncp) {
						warn_printf ("sfr_rel_data (): out of memory for change clone!\r\n");
						return;
					}
				}
				else {
					rcl_access (cp);
					cp->c_nrefs++;
					rcl_done (cp);
					ncp = cp;
				}
				ncp->c_handle = h;
				ncp->c_seqnr = *cpsnr;
				rp->relevant = 1;
				rp->u.c.hci = hci;
				rp->u.c.change = ncp;
				rwp->rw_reader->data_queued++;
			}
			rp->state = CS_RECEIVED;
#ifdef RTPS_FRAGMENTS
			if (fragp) {
				sfr_fragment (rwp, rp, fragp, finfo, hp, cp, ooo, ignore);
				return;
			}
#endif
			RW_SIGNAL (rwp, "REL-Data: missing::received");
			RANGE_CHECK (&rwp->rw_changes, "REL-Data: missing::received");
		}

		/* If the received data sample caused some samples to be valid,
		   add these samples to the history cache and remove them from
		   the changes list. */
		rp = LIST_HEAD (rwp->rw_changes);
		if (rp &&
		    (rp->state == CS_RECEIVED || rp->state == CS_LOST) &&
#ifdef RTPS_FRAGMENTS
		    !rp->fragments &&
#endif
		    rwp->rw_heartbeats) {
			RW_SIGNAL (rwp, "REL-Data: process-samples");
			RANGE_CHECK (&rwp->rw_changes, "REL-Data: process-samples");
			sfr_process_samples (rwp);
		}
	}
Example #5
0
static void sfr_fragment (RemWriter_t     *rwp,
			  CCREF           *refp,
			  DataFragSMsg    *fragp,
			  FragInfo_t      **finfo,
			  const KeyHash_t *hp,
			  Change_t        *cp,
			  int             ooo,
			  int             ignore)
{
	Change_t		*xcp, *ncp;
	FragInfo_t		*fip;
	Reader_t		*rp;
	const TypeSupport_t	*ts;
	unsigned		max_frags, size;
	int			all_key, error;
	HCI			hci;
	InstanceHandle		h;
	RejectCause_t		cause;
	DBW			walk;
	size_t			ofs = 0;
#if defined (DDS_SECURITY) && defined (DDS_NATIVE_SECURITY)
	DB			*dbp;
#endif

	/* If this is the first fragment, create the fragments context. */
	fip = refp->fragments;
	if (!fip) {
		if (refp->relevant) {

			/* Replace change with empty one. */
			ncp = hc_change_new ();
			if (!ncp) {
				refp->state = CS_MISSING;
				return;
			}
			xcp = refp->u.c.change;
			ncp->c_kind = xcp->c_kind;
			ncp->c_writer = xcp->c_writer;
			ncp->c_time = xcp->c_time;
			ncp->c_seqnr = xcp->c_seqnr;
			hc_change_free (xcp);
			refp->u.c.change = ncp;
		}
		else {
			refp->state = CS_RECEIVED;
			goto done;
		}
		fip = *finfo;
		if (fip) {
			rcl_access (fip);
			fip->nrefs++;
			rcl_done (fip);
			refp->fragments = fip;
		}
		else {
			max_frags = (fragp->sample_size + fragp->frag_size - 1) / fragp->frag_size;
			if (fragp->frag_start + fragp->num_fragments - 1 > max_frags) {

			    no_frag_mem:

				refp->state = CS_MISSING;
				if (refp->u.c.change)
					hc_change_free (refp->u.c.change);
				return;
			}

			*finfo = fip = rfraginfo_create (refp, fragp, max_frags);
			if (!fip)
				goto no_frag_mem;
		}
	}

	/* If this is the first fragment and we already have a fragmentation
	   context, and the data needs to be ignored, we abort reception. */
	else if (refp->relevant && fragp->frag_start == 1 && ignore) {
		xcp = refp->u.c.change;
		refp->state = CS_RECEIVED;
		refp->relevant = 0;
		refp->u.range.first = refp->u.range.last = xcp->c_seqnr;
		hc_change_free (xcp);
		goto done_clean_fip;
	}

	/* Update key info if present. */
	if (hp) {
		fip->hash = *hp;
		fip->hp = &fip->hash;
	}

	/* Mark the fragment as correctly received. */
	mark_fragment (fip, fragp, cp);

	/* If more fragments pending, simply exit, waiting for the next. */
	if (fip->num_na)
		return;

	/* Data complete! Derive key info and get a new instance if possible. */
	/* If data type indicates multi-instance data, we need the actual keys
	   in order to lookup instances properly. */
	/*log_printf (RTPS_ID, 0, "sfr_fragment: complete!\r\n");*/
	rp = (Reader_t *) rwp->rw_reader->endpoint.endpoint;
	ts = rp->r_topic->type->type_support;
	if (!refp->relevant || !ts->ts_keys) {
		if (!hc_accepts (rp->r_cache, ooo)) {

			/* Don't see this as rejected -- since there is no ack
			   given, last fragment will simply be retransmitted!
			dcps_sample_rejected ((Reader_t *) ep->endpoint,
					      DDS_REJECTED_BY_SAMPLES_LIMIT, 0);*/
			if (!ooo)
				rwp->rw_blocked = 1;

		    ignore_last_fragment:

			fip->num_na = 1;
			fip->first_na = fragp->frag_start + fragp->num_fragments - 2;
			SET_REM (fip->bitmap, fip->first_na);
			return;
		}
		else
			goto no_keys;
	}

#if defined (DDS_SECURITY) && defined (DDS_NATIVE_SECURITY)

	/* Decrypt payload data if an encrypted payload is present. */
	if (rwp->rw_crypto &&
	    fip->length) {
		walk.dbp = fip->data;
		walk.data = fip->data->data;
		walk.length = walk.left = fip->length;
		dbp = sec_decode_serialized_data (&walk,
						  0,
						  rwp->rw_crypto,
						  &fip->length,
						  &ofs,
						  (DDS_ReturnCode_t *) &error);
		if (!dbp)
			goto cleanup;

		fip->data = dbp;
	}
#endif

	/* Key somewhere in either marshalled data or marshalled key.
	   Derive key information if not yet done. */
	if (!fip->key) {
		if (fip->length) {
			walk.dbp = fip->data;
			walk.data = fip->data->data + ofs;
			walk.left = walk.length = fip->length;
		}
		all_key = cp->c_kind != ALIVE;
		size = ts->ts_mkeysize;
		if (!size || !ts->ts_fksize) {
			size = DDS_KeySizeFromMarshalled (walk, ts,
							all_key, NULL);
			if (!size)
				goto cleanup;
		}
		fip->keylen = size;
		if (ts->ts_mkeysize &&
		    ts->ts_fksize &&
		    size <= sizeof (KeyHash_t) &&
		    !ENC_DATA (&rp->r_lep)) {
			if (fip->hp) {
				fip->key = fip->hash.hash;
				goto got_keys;
			}
			if (size < sizeof (KeyHash_t))
				memset (fip->hash.hash + size, 0,
						     sizeof (KeyHash_t) - size);
		}
		else {
			fip->key = xmalloc (size);
			if (!fip->key)
				goto ignore_last_fragment;
		}
		error = DDS_KeyFromMarshalled (fip->key, walk, ts, all_key,
							ENC_DATA (&rp->r_lep));
		if (error) {
			if (fip->key != fip->hash.hash)
				xfree (fip->key);

			fip->key = NULL;
			goto cleanup;
		}
		if (!fip->hp) {
			error = DDS_HashFromKey (fip->hash.hash, fip->key, size,
						    ENC_DATA (&rp->r_lep), ts);
			if (error) {
				if (fip->key != fip->hash.hash)
					xfree (fip->key);

				fip->key = NULL;
				goto cleanup;
			}
			fip->hp = &fip->hash;
		}
	}

    got_keys:

	/* Key information is present in the fragment context now.
	   Derive a new or existing cache instance context. */
	hci = hc_lookup_hash (rp->r_cache,
			      fip->hp, fip->key, fip->keylen,
			      &h, 1, ooo, &cause);
	if (!hci) {

		/* Don't see this as rejected -- since there is no ack
		   given, last fragment will simply be retransmitted!
		dcps_sample_rejected ((Reader_t *) ep->endpoint,
				      (DDS_SampleRejectedStatusKind) cause,
				      h);*/
		if (!ooo)
			rwp->rw_blocked = 1;
		goto ignore_last_fragment;
	}
	refp->u.c.hci = hci;
	refp->u.c.change->c_handle = h;
	hc_inst_inform (rp->r_cache, hci);

    no_keys:

	/* Transform to a valid received sample, as if this was a normal DATA
	   submessage. */
	if (refp->relevant) {
		xcp = refp->u.c.change;
		xcp->c_db = fip->data;
		xcp->c_data = fip->data->data + ofs;
		xcp->c_length = fip->length;
		rcl_access (xcp);
		xcp->c_db->nrefs++;
		rcl_done (xcp);
	}

    done_clean_fip:

    	/* Cleanup fragmentation context. */
	if (fip->nrefs == 1)
		*finfo = NULL;
	rfraginfo_delete (refp);

    done:

	/* If received sample is first, add samples to history cache. */
	sfr_process_samples (rwp);
	return;

    cleanup:
	refp->state = CS_MISSING;
	xcp = refp->u.c.change;
	refp->relevant = 0;
	refp->fragments = NULL;
	refp->u.range.first = refp->u.range.last = xcp->c_seqnr;
	hc_change_free (xcp);
	rfraginfo_delete (refp);
}
Example #6
0
void sfr_process_samples (RemWriter_t *rwp)
{
	Change_t	*cp;
	CCREF		*rp;
	ChangeState_t	state;
	SequenceNumber_t snr;
	int		error;
	PROF_ITER	(n);

	ctrc_printd (RTPS_ID, RTPS_SFR_PROCESS, &rwp, sizeof (rwp));
	prof_start (rtps_rr_proc);

	/* Remove valid entries from the changes list and if relevant, store
	   them in the history cache. */
	while ((rp = LIST_HEAD (rwp->rw_changes)) != NULL &&
	       ((state = rp->state) == CS_LOST || 
	        (state == CS_RECEIVED
#ifdef RTPS_FRAGMENTS
			&& !rp->fragments
#endif
					 ))) {
		PROF_INC (n);

		snr = (rp->relevant) ? rp->u.c.change->c_seqnr : rp->u.range.first;
		if (!SEQNR_EQ (snr, rwp->rw_seqnr_next))
			break;

		/* Check if we can add the sample to the cache. */
		if (rp->relevant) {
			cp = rp->u.c.change;
			snr = cp->c_seqnr;
			if (state == CS_RECEIVED) {
				if (rwp->rw_reader->endpoint.cache_acks)  {
					rcl_access (rp->u.c.change);
					rp->u.c.change->c_nrefs++;
					rcl_done (rp->u.c.change);
				}
				error = reader_cache_add_inst (rwp->rw_reader, 
						               rp->u.c.change,
							       rp->u.c.hci,
							       1);

				/* If cache is full, try again later. */
				if (error == DDS_RETCODE_NO_DATA) {
					rwp->rw_blocked = 1;
					break;
				}
				else if (rwp->rw_reader->endpoint.cache_acks)
					hc_change_free (rp->u.c.change);
			}
			rwp->rw_reader->data_queued--;
		}
		else
			snr = rp->u.range.last;

		/* Remove change from changes list. */
		LIST_REMOVE (rwp->rw_changes, *rp);
		rwp->rw_changes.nchanges--;

		/* Free the reference. */
		mds_pool_free (&rtps_mem_blocks [MB_CCREF], rp);

		/* Update the sequence number. */
		SEQNR_INC (snr);
		rwp->rw_seqnr_next = snr;

		RW_SNR_TRACE (rwp, "process_samples");
	}
	prof_stop (rtps_rr_proc, n);
	RANGE_CHECK (&rwp->rw_changes, "sfr_process_samples");
}