Example #1
0
rtperror UpdateMemberInfoByBYE(_RTP_CONTEXT *the_context, 
			       rtcp_packet *the_packet,
			       struct sockaddr *fromaddr,
			       int addrlen) {


  member *pkt_origin_member;
  u_int32 cur_ssrc;
  unsigned int ssrc_iter;
  int i;
  rtcp_bye_block bb;


  /* Copy the reason code (non null terminated) from the packet
     into the context variable, so it can be returned to the
     callback */
  for(i = 0; i < the_packet->variant.bye.reason_length; i++) {
    the_context->byereason[i] = the_packet->variant.bye.reason[i];
  }
  the_context->byereason[i] = '\0';

  /* Update info for the various members */
  for (ssrc_iter=0; ssrc_iter < RTCP_RC(*the_packet->common); ssrc_iter++){

    bb = RTPGetByeBlock(the_packet, ssrc_iter);
    cur_ssrc = bb.ssrccsrc;

    pkt_origin_member =
      UpdateTimeOrCreateMember(the_context, cur_ssrc,
			       fromaddr, addrlen, TRUE, 
			       RTP_MEMBER_PENDING);

    /* The member that is about to go BYE has been placed on the
       membership list if it wasn't already there, and timestamped
       with the current time (since we just received a BYE packet
       for it, the current time is appropriate).  We now destroy it
       unless the BYE was (believed to be) due to a collision and the
       CNAME is known.  In such a case, we leave the member on the
       member-list.  Note that the remove will fail if the member is in
       the CSRC list */

    if (!pkt_origin_member->colliding ||
	pkt_origin_member->sdes_info[0] == NULL){

      RemoveMember(the_context, pkt_origin_member);

      if (the_context->UpdateMemberCallBack != NULL){
	the_context->UpdateMemberCallBack(the_context->context_num,
					  pkt_origin_member->unique_id,
					  RTP_FLAG_MEMBER_LEAVES,
					  the_context->byereason);
      }
      DestroyMember(the_context, pkt_origin_member);
    }
  }

  return(RTP_OK);
}
Example #2
0
static int rtcp_parse(struct rtp_context *ctx, const unsigned char* data, size_t bytes)
{
	uint32_t rtcphd;
	rtcp_header_t header;

	assert(bytes >= sizeof(rtcphd));
	rtcphd = nbo_r32(data);

	header.v = RTCP_V(rtcphd);
	header.p = RTCP_P(rtcphd);
	header.rc = RTCP_RC(rtcphd);
	header.pt = RTCP_PT(rtcphd);
	header.length = RTCP_LEN(rtcphd);
	assert((header.length+1)*4 <= bytes);
	assert(2 == header.v); // 1. RTP version field must equal 2 (p69)
	// 2. The payload type filed of the first RTCP packet in a compound packet must be SR or RR (p69)
	// 3. padding only valid at the last packet

	if(1 == header.p)
	{
		assert((header.length+1)*4 + 4 <= bytes);
		header.length -= *(data + header.length - 1) * 4;
	}

	switch(header.pt)
	{
	case RTCP_SR:
		rtcp_sr_unpack(ctx, &header, data+4);
		break;

	case RTCP_RR:
		rtcp_rr_unpack(ctx, &header, data+4);
		break;

	case RTCP_SDES:
		rtcp_sdes_unpack(ctx, &header, data+4);
		break;

	case RTCP_BYE:
		rtcp_bye_unpack(ctx, &header, data+4);
		break;

	case RTCP_APP:
		rtcp_app_unpack(ctx, &header, data+4);
		break;

	default:
		assert(0);
	}

	return (header.length+1)*4;
}
Example #3
0
rtperror UpdateMemberInfoByRR(_RTP_CONTEXT *the_context, 
			      rtcp_packet *the_packet,
			      struct sockaddr *fromaddr,
			      int addrlen) {


  member *pkt_origin_member;
  rtcp_report_block the_block;
  struct timeval tvalptr;
  unsigned int ssrc_iter;

  gettimeofday(&tvalptr, NULL);


  pkt_origin_member =
    UpdateTimeOrCreateMember(the_context,
			     the_packet->variant.rr.rr_fixed->ssrc,
			     fromaddr, addrlen, TRUE, RTP_MEMBER_PENDING);
  pkt_origin_member->recv_rtp_count++;

  /* Now deal with member state changes. The member should move to pending if it has sent two RTP packets */
  if(((pkt_origin_member->recv_rtp_count > 1) &&
      (pkt_origin_member->status == RTP_MEMBER_PENDING)) ||
     (pkt_origin_member->status == RTP_MEMBER_EXPIRED)){
    ChangeMemberStatus(the_context,pkt_origin_member,RTP_MEMBER_CONFIRMED);
  }

  for (ssrc_iter=0; ssrc_iter < RTCP_RC(*the_packet->common); ssrc_iter++){
    member *reported_sender;
    the_block = RTPGetReportBlock(the_packet, ssrc_iter);
    /* NOTE: We don't update sender times based on the
       report block, because 2 receivers could perpetually update
       each other's sender list even after the sender has left. */
    /* We create a member that is on the SSRC list if it is 
       not already part of the session */
    if ((reported_sender = 
	 GetMemberFromSSRCHash(the_context, the_block.ssrc)) == NULL) {
      reported_sender = 
	EstablishNewMember(the_context, the_block.ssrc, NULL,
			     fromaddr, TRUE, RTP_MEMBER_PENDING);
    }
    UpdateSenderTime(the_context, reported_sender, tvalptr, 0);
    Update_RR(pkt_origin_member, reported_sender, &the_block);
  }

  return(RTP_OK);
}
Example #4
0
rtperror UpdateMemberInfoBySDES(_RTP_CONTEXT *the_context, 
				rtcp_packet *the_packet,
				struct sockaddr *fromaddr,
				int addrlen) {


  member *pkt_origin_member = NULL;
  member *prev_member;
  rtcp_sdes_item sdes_item;
  char **member_item;
  char the_item[100];
  u_int32 cur_ssrc, prev_ssrc;
  struct timeval tvalptr;
  unsigned int ssrc_iter;
  gettimeofday(&tvalptr, NULL);

  if (RTCP_RC(*the_packet->common)==0){
    return(RTP_OK);
  }

  ssrc_iter = 0;
  sdes_item = InitSDESItemIter(the_packet);

  /* Make prev_ssrc not match initial ssrc.  This is so the
     member will be retrieved*/
  prev_ssrc = sdes_item.ssrc + 1;

  /* The item pointed to does not represent the end of
     all items in the packet until it's type has
     value 0 and its chunk # = that of the rc field of the
     sdes packet. */
  while (sdes_item.type != 0 || 
	 ssrc_iter < RTCP_RC(*the_packet->common)){
    /* only has stuff worth processing if the time type
       is not 0. */

    if (sdes_item.type > 0 && sdes_item.type < _RTP_NUM_SDES_TYPES + 1){

      cur_ssrc = sdes_item.ssrc;
      if (cur_ssrc != prev_ssrc){
	  /* NOTE: This will update the membership time of every
	     member that contains info in the SDES packet */

	if(ssrc_iter == 0) {
	  pkt_origin_member =
	    UpdateTimeOrCreateMember(the_context, cur_ssrc,
				     fromaddr, addrlen, TRUE, 
				     RTP_MEMBER_PENDING);

	  pkt_origin_member->recv_rtp_count++;

	  /* Now deal with member state changes. The member should
	     move to pending if it has sent two RTP packets */
	  if(((pkt_origin_member->recv_rtp_count > 1) &&
	      (pkt_origin_member->status == RTP_MEMBER_PENDING)) ||
	     (pkt_origin_member->status == RTP_MEMBER_EXPIRED)){
	    ChangeMemberStatus(the_context,pkt_origin_member,RTP_MEMBER_CONFIRMED);
	  }

	} else {
	  pkt_origin_member =
	    UpdateTimeOrCreateMember(the_context, cur_ssrc,
				     fromaddr, addrlen, TRUE, 
				     RTP_MEMBER_PENDING_CONTRIBUTOR);
	  
	  pkt_origin_member->recv_csrc_count++;

	  /* Now deal with member state changes. The member should
	     move to pending if it has sent two RTP packets */
	  if(((pkt_origin_member->recv_csrc_count > 1) &&
	      (pkt_origin_member->status == RTP_MEMBER_PENDING_CONTRIBUTOR)) ||
	     (pkt_origin_member->status == RTP_MEMBER_EXPIRED_CONTRIBUTOR)){
	    ChangeMemberStatus(the_context,pkt_origin_member,RTP_MEMBER_CONFIRMED_CONTRIBUTOR);
	  }


	}

      }

      /* set member_item to point to the location where we 
	 store the SDES item for the member. */
      member_item = pkt_origin_member->sdes_info + sdes_item.type - 1;
      if (*member_item != NULL){
	  
	/* Previous SDES info for this field existed.  If the
	   field remains the same, then do not make a change. */
	if (strncmp(*member_item, sdes_item.description,
		    sdes_item.len) != 0){
	  if (sdes_item.type == 1){
	    /* If we get here, then we found a member with the same
	       SSRC but different CNAME.  We need to
	       search through the rest of the colliding members
	       to see if we can find a member with the same
	       address and CNAME -- i.e. if we've already seen and handled
	       this collision.  If not, handle the collision now.
	       If so, just have pkt_origin_member point to the found
	       member. */

#ifdef _RTP_DEBUG
	    printf("Members with different CNAMEs collide\n");
#endif

	    while (pkt_origin_member->collides_with_next != NULL){
	      if (strncmp(*member_item, sdes_item.description,
			  sdes_item.len) == 0){
		return(RTP_OK);
	      }
	      pkt_origin_member = pkt_origin_member->collides_with_next;
	      member_item = pkt_origin_member->sdes_info +
		sdes_item.type - 1;
	    }


#ifdef _RTP_DEBUG
	    printf("Handle1...\n");
#endif
	    
	    pkt_origin_member =
	      HandleSSRCCollision(the_context, pkt_origin_member,
				  fromaddr, TRUE, the_item,ssrc_iter);
	  }
	  else {
	    /* We are changing an SDES item other than CNAME.  Free the old
	       one here, and put the new one in below. */
	    free(*member_item);
	    *member_item = NULL;
	  }
	} 
	if (sdes_item.type == 1 &&
	    fromaddr->sa_family != _RTP_ADDRESS_NOT_YET_KNOWN) {
	  /* Either we've found the member with this CNAME and SDES, or
	     we've just created a new member.  Check to see if the
	     member's addr is the same as the packet's fromaddr; if not,
	     announce an IP address change for the member. */
	  if (pkt_origin_member->my_addr[1].sa_family ==
	      _RTP_ADDRESS_NOT_YET_KNOWN ||
	      FromDifferentSource(fromaddr, &pkt_origin_member->my_addr[1],
				  addrlen)) {
	    pkt_origin_member->my_addr[1] = *fromaddr;

	    if (the_context->ChangedMemberSockaddrCallBack != NULL &&
		pkt_origin_member->unique_id != 0) {
	      the_context->
		ChangedMemberSockaddrCallBack(the_context->context_num,
					      pkt_origin_member->unique_id,
					      &pkt_origin_member->my_addr[1],
					      TRUE);
	    }
	  }
	}
      }
      else if (sdes_item.type == 1){
	/* CNAME was previously NULL for member, so we must check to
	   see if the CNAME has already been used.  If so, we need
	   to finish up moving a member due to a collision.
	   If not, we note that this is a new member. */
	strncpy(the_item, sdes_item.description, sdes_item.len);
	the_item[sdes_item.len] = '\0';
	prev_member = GetMemberFromCNAMEHash(the_context, the_item);
	if (prev_member != NULL){ /* CNAME already used. */
	  if (prev_member == the_context->my_memberinfo) {
	    /* The already-used CNAME was our own!  Through error or
	       malice or mis-configuration, we've received a packet which
	       didn't come from our IP address or have our ssrc, but which
	       has our CNAME.  Assume this was a looped back packet. */
	    return errordebug(RTP_PACKET_LOOPBACK, "UpdateMemberInfoByRTCP",
			      "context %d, got a foreign packet with our CNAME",
			      (int)the_context->context_num);

	  }
	  /* CNAMEs are unique.  Thus, we can be sure that we
	     have retrieved the sole member with the same CNAME,
	     and that these 2 members should be merged. */

#ifdef _RTP_DEBUG
	  printf ("*** Going to merge members... ***\n");
#endif

	  pkt_origin_member = 
	    MergeMembers(the_context, prev_member, pkt_origin_member);
	  member_item = pkt_origin_member->sdes_info + sdes_item.type - 1;
	}
      }


      /* Whether we just freed memory or it has never been 
	 allocated, now we add the new SDES item */
	
      if (*member_item == NULL){
	*member_item = malloc(sdes_item.len + 1);
	strncpy(*member_item, sdes_item.description, sdes_item.len);
	(*member_item)[sdes_item.len] = '\0';
	if (sdes_item.type == 1){

	  /* Item is a CNAME.  CNAME data has just come in for this
	     member so we add the member to the CNAME hash at this
	     point */
	  EnterCNAMEHashTable(the_context, pkt_origin_member);

	  /* Change status to confirmed since we've got cname */
	  if((ssrc_iter == 0) &&
	     (pkt_origin_member->status != RTP_MEMBER_CONFIRMED)) {
	    ChangeMemberStatus(the_context,pkt_origin_member,RTP_MEMBER_CONFIRMED);
	  } else if(ssrc_iter != 0) {
	    /* This is a CSRC who has a new CNAME. They're now a confirmed contributor */
	    ChangeMemberStatus(the_context,pkt_origin_member,RTP_MEMBER_CONFIRMED_CONTRIBUTOR);
	  }


	}
	if (the_context->ChangedMemberInfoCallBack != NULL) {
	  the_context->
	    ChangedMemberInfoCallBack(the_context->context_num,
				      pkt_origin_member->unique_id,
				      sdes_item.type, *member_item,
				      RTP_FLAG_MEMBER_INFO_CHANGES);
	}
      }
      prev_ssrc = cur_ssrc;
    }
    else (ssrc_iter++);
    if (ssrc_iter < RTCP_RC(*the_packet->common)){
      sdes_item = GetNextItem(&sdes_item);
    }
      
  }

  return(RTP_OK);
}
Example #5
0
rtperror UpdateMemberInfoBySR(_RTP_CONTEXT *the_context, 
			      rtcp_packet *the_packet,
			      struct sockaddr *fromaddr,
			      int addrlen) {
  member *pkt_origin_member;
  rtcp_report_block the_block;
  struct timeval tvalptr;
  unsigned int ssrc_iter;

  gettimeofday(&tvalptr, NULL);

  pkt_origin_member =
    UpdateTimeOrCreateMember(the_context,
			     the_packet->variant.sr.sr_fixed->ssrc,
			     fromaddr, addrlen, TRUE, RTP_MEMBER_PENDING);
  pkt_origin_member->recv_rtp_count++;

  /* Now deal with member state changes. The member should move to pending if it has sent two RT(c)P packets */
  if(((pkt_origin_member->recv_rtp_count > 1) &&
      (pkt_origin_member->status == RTP_MEMBER_PENDING)) ||
     (pkt_origin_member->status == RTP_MEMBER_EXPIRED)){
    ChangeMemberStatus(the_context,pkt_origin_member,RTP_MEMBER_CONFIRMED);
  }

  UpdateSenderTime(the_context, pkt_origin_member, tvalptr, 0);

  /* update remaining fields based on receipt of packet */
  /* NTP timestamp */
  pkt_origin_member->ntp_timestamp.secs =
    the_packet->variant.sr.sr_fixed->ntp_secs;
  pkt_origin_member->ntp_timestamp.frac =
    the_packet->variant.sr.sr_fixed->ntp_frac;
  /* RTP timestamp */
  pkt_origin_member->rtp_timestamp =
    the_packet->variant.sr.sr_fixed->rtp_stamp;
  /* pkt and oct counts */
  pkt_origin_member->pkt_count = 
    the_packet->variant.sr.sr_fixed->pkt_count;
  pkt_origin_member->oct_count =
    the_packet->variant.sr.sr_fixed->oct_count;

  /* For each sender report block, update sender info as held by
     this member */
  for (ssrc_iter=0; ssrc_iter < RTCP_RC(*the_packet->common); ssrc_iter++) {
    member *reported_sender;
    the_block = RTPGetReportBlock(the_packet, ssrc_iter);
    /* NOTE: We don't update sender times based on the
       report block, because 2 receivers could perpetually update
       each other's sender list even after the sender has left. */
    /* We create members from the SSRC list if they are not
       already part of the session */
    if ((reported_sender =
	 GetMemberFromSSRCHash(the_context, the_block.ssrc)) == NULL) {
      reported_sender =
	EstablishNewMember(the_context, the_block.ssrc,
			   NULL, fromaddr, TRUE, RTP_MEMBER_PENDING);
    }
    UpdateSenderTime(the_context, reported_sender, tvalptr, 0);
    Update_RR(pkt_origin_member, reported_sender, &the_block);
  }

  /* update our local info about the member's last SR send time */
  pkt_origin_member->last_sr_receipt_time = tvalptr;

  return(RTP_OK);

}