Esempio n. 1
0
/** Compare two session descriptions
 */
int sdp_session_cmp(sdp_session_t const *a, sdp_session_t const *b)
{
  int rv;
  sdp_bandwidth_t const *ab, *bb;
  sdp_attribute_t const *aa, *ba;
  sdp_media_t const *am, *bm;

  if ((rv = (a != NULL) - (b != NULL)))
    return rv;
  if (a == b)
    return 0;
  if ((rv = (a->sdp_version[0] - b->sdp_version[0])))
    return rv;
  if ((rv = sdp_origin_cmp(a->sdp_origin, b->sdp_origin)))
    return rv;
  if ((rv = su_strcmp(a->sdp_subject, b->sdp_subject)))
    return rv;
  if ((rv = su_strcmp(a->sdp_information, b->sdp_information)))
    return rv;
  if ((rv = su_strcmp(a->sdp_uri, b->sdp_uri)))
    return rv;
  if ((rv = sdp_list_cmp(a->sdp_emails, b->sdp_emails)))
    return rv;
  if ((rv = sdp_list_cmp(a->sdp_phones, b->sdp_phones)))
    return rv;
  if ((rv = sdp_connection_cmp(a->sdp_connection, b->sdp_connection)))
    return rv;

  for (ab = a->sdp_bandwidths, bb = b->sdp_bandwidths;
       ab || bb;
       ab = ab->b_next, bb = bb->b_next)
    if ((rv = sdp_bandwidth_cmp(a->sdp_bandwidths, b->sdp_bandwidths)))
      return rv;

  if ((rv = sdp_time_cmp(a->sdp_time, b->sdp_time)))
    return rv;
  if ((rv = sdp_key_cmp(a->sdp_key, b->sdp_key)))
    return rv;

  for (aa = a->sdp_attributes, ba = b->sdp_attributes;
       aa || bb;
       aa = aa->a_next, ba = ba->a_next)
    if ((rv = sdp_attribute_cmp(aa, ba)))
      return rv;

  for (am = a->sdp_media, bm = b->sdp_media;
       am || bm;
       am = am->m_next, bm = bm->m_next)
    if ((rv = sdp_media_cmp(am, bm)))
      return rv;

  return 0;
}
Esempio n. 2
0
/**
 * Updates the modified copy of local SDP based
 * on application provided local SDP and remote SDP.
 */
static int offer_answer_step(soa_session_t *ss,
			     enum offer_answer_action action,
			     char const *by)
{
  soa_static_session_t *sss = (soa_static_session_t *)ss;

  sdp_session_t *local = ss->ss_local->ssd_sdp;
  sdp_session_t local0[1];

  sdp_session_t *user = ss->ss_user->ssd_sdp;
  unsigned user_version = ss->ss_user_version;

  sdp_session_t *remote = ss->ss_remote->ssd_sdp;
  unsigned remote_version = ss->ss_remote_version;

  int fresh = 0;

  sdp_origin_t o[1] = {{ sizeof(o) }};
  sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
  char c0_buffer[64];

  sdp_time_t t[1] = {{ sizeof(t) }};

  int *u2s = NULL, *s2u = NULL, *tbf;

  sdp_session_t *latest = NULL, *previous = NULL;

  char const *phrase = "Internal Media Error";

  su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)];

  su_home_auto(tmphome, sizeof tmphome);

  SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n",
	      (void *)ss, by));

  if (user == NULL)
    return soa_set_status(ss, 500, "No session set by user");

  if (action == generate_offer)
    remote = NULL;
  else if (remote == NULL)
    return soa_set_status(ss, 500, "No remote SDP");

  /* Pre-negotiation Step: Expand truncated remote SDP */
  if (local && remote) switch (action) {
  case generate_answer:
  case process_answer:
    if (sdp_media_count(remote, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0) <
	sdp_media_count(local, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0)) {
      SU_DEBUG_5(("%s: remote %s is truncated: expanding\n",
		  by, action == generate_answer ? "offer" : "answer"));
      remote = soa_sdp_expand_media(tmphome, remote, local);
      if (remote == NULL)
	return soa_set_status(ss, 500, "Cannot expand remote session");
    }
  default:
    break;
  }

  /* Step A: Create local SDP session (based on user-supplied SDP) */
  if (local == NULL) switch (action) {
  case generate_offer:
  case generate_answer:
    SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		"generating local description"));

    fresh = 1;
    local = local0;
    *local = *user, local->sdp_media = NULL;

    o->o_username = "******";
    o->o_address = c0;
    c0->c_address = c0_buffer;

    if (!local->sdp_origin)
      local->sdp_origin = o;
    break;

  case process_answer:
  default:
    goto internal_error;
  }

  /* Step B: upgrade local SDP (add m= lines to it)  */
  switch (action) {
  case generate_offer:
    /* Upgrade local SDP based on user SDP */
    if (local != local0 && ss->ss_local_user_version == user_version)
      break;
    if (local != local0)
      *local0 = *local, local = local0;
    SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		"upgrade with local description"));
    if (soa_sdp_upgrade(ss, tmphome, local, user, NULL, &u2s, &s2u) < 0)
      goto internal_error;
    break;
  case generate_answer:
    /* Upgrade local SDP based on remote SDP */
    if (ss->ss_local_user_version == user_version &&
	ss->ss_local_remote_version == remote_version)
      break;
    if (1) {
      if (local != local0)
	*local0 = *local, local = local0;
      SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		  "upgrade with remote description"));
      if (soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u) < 0)
	goto internal_error;
    }
    break;
  case process_answer:
  default:
    break;
  }


  /* Step C: reject media */
  switch (action) {
  case generate_offer:
    /* Local media is marked as rejected already in upgrade phase */
    break;
  case generate_answer:
  case process_answer:
    if (ss->ss_local_remote_version == remote_version)
      break;
    if (soa_sdp_reject_is_needed(local, remote)) {
      if (local != local0) {
	*local0 = *local, local = local0;
#define DUP_LOCAL(local)					 \
	do {							 \
	  if (!local->sdp_media) break;				 \
	  local->sdp_media =					 \
	    sdp_media_dup_all(tmphome, local->sdp_media, local); \
	  if (!local->sdp_media)				 \
	    goto internal_error;				 \
	} while (0)
	DUP_LOCAL(local);
      }
      SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		  "marking rejected media"));
      soa_sdp_reject(tmphome, local, remote);
    }
    break;
  default:
    break;
  }

  /* Step D: Set media mode bits */
  switch (action) {
    int const *s2u_;

  case generate_offer:
  case generate_answer:
  case process_answer:
    s2u_ = s2u;

    if (!s2u_) s2u_ = sss->sss_s2u;

    if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) {
      if (local != local0) {
	*local0 = *local, local = local0;
	DUP_LOCAL(local);
      }

      soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0);
    }
    break;
  default:
    break;
  }

  /* Step E: Upgrade codecs by answer. */
  switch (action) {
  case process_answer:
    /* Upgrade local SDP based on remote SDP */
    if (ss->ss_local_remote_version == remote_version)
      break;
    if (1 /* We don't have good test for codecs */) {
      SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		  "upgrade codecs with remote description"));
      if (local != local0) {
	*local0 = *local, local = local0;
	DUP_LOCAL(local);
      }
      soa_sdp_session_upgrade_rtpmaps(ss, local, remote);
    }
    break;
  case generate_offer:
  case generate_answer:
  default:
    break;
  }

  /* Step F0: Initialize o= line */
  if (fresh) {
	if (user->sdp_origin) {
      o->o_username = user->sdp_origin->o_username;

	  if (user->sdp_origin->o_address)
	    o->o_address = user->sdp_origin->o_address;

      if (user->sdp_origin->o_id)
		  o->o_id = user->sdp_origin->o_id;

	  if (user->sdp_origin->o_version && user->sdp_origin->o_version != o->o_version) {
		  o->o_version = user->sdp_origin->o_version;
		  o->o_version--;
	  }
	}

    if (soa_init_sdp_origin_with_session(ss, o, c0_buffer, local) < 0) {
      phrase = "Cannot Get IP Address for Session Description";
      goto internal_error;
    }

    local->sdp_origin = o;
  }

  /* Step F: Update c= line(s) */
  switch (action) {
    sdp_connection_t *user_c, *local_c;

  case generate_offer:
  case generate_answer:
    user_c = user->sdp_connection;
    if (!soa_check_sdp_connection(user_c))
      user_c = NULL;

    local_c = local->sdp_connection;
    if (!soa_check_sdp_connection(local_c))
      local_c = NULL;

    if (ss->ss_local_user_version != user_version ||
	local_c == NULL ||
	(user_c != NULL && sdp_connection_cmp(local_c, user_c))) {
      sdp_media_t *m;

      if (user_c)
	c = user_c;
      else
	c = local->sdp_origin->o_address;

      /* Every m= line (even rejected one) must have a c= line
       * or there must be a c= line at session level
       */
      for (m = local->sdp_media; m; m = m->m_next)
	if (m->m_connections == NULL)
	  break;

      if (m) {
	if (local != local0) {
	  *local0 = *local, local = local0;
	  DUP_LOCAL(local);
	}
	local->sdp_connection = c;
      }
    }
    break;

  default:
    break;
  }

  soa_description_free(ss, ss->ss_previous);
  su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL;
  su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL;

  if (u2s) {
    u2s = u2s_alloc(ss->ss_home, u2s);
    s2u = u2s_alloc(ss->ss_home, s2u);
    if (!u2s || !s2u)
      goto internal_error;
  }

  if (ss->ss_local->ssd_sdp != local &&
      sdp_session_cmp(ss->ss_local->ssd_sdp, local)) {
    int bump;

    switch (action) {
    case generate_offer:
      bump = sdp_session_cmp(local, sss->sss_latest);
      break;
    case generate_answer:
      bump = 1;
      break;
    case process_answer:
    default:
      bump = 0;
      break;
    }

    if (bump) {
      /* Upgrade the version number */
      if (local->sdp_origin != o)
	*o = *local->sdp_origin, local->sdp_origin = o;
      o->o_version++;
    }

    /* Do sanity checks for the created SDP */
    if (!local->sdp_subject)	/* s= is mandatory */
      local->sdp_subject = "-";
    if (!local->sdp_time)	/* t= is mandatory */
      local->sdp_time = t;

    if (action == generate_offer) {
      /* Keep a copy of previous session state */
      int *previous_u2s = u2s_alloc(ss->ss_home, sss->sss_u2s);
      int *previous_s2u = u2s_alloc(ss->ss_home, sss->sss_s2u);

      if ((sss->sss_u2s && !previous_u2s) || (sss->sss_s2u && !previous_s2u))
	goto internal_error;

      *ss->ss_previous = *ss->ss_local;
      memset(ss->ss_local, 0, (sizeof *ss->ss_local));
      ss->ss_previous_user_version = ss->ss_local_user_version;
      ss->ss_previous_remote_version = ss->ss_local_remote_version;
      sss->sss_previous.u2s = previous_u2s;
      sss->sss_previous.s2u = previous_s2u;
    }

    SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		"storing local description"));

    /* Update the unparsed and pretty-printed descriptions  */
    if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) {
      if (action == generate_offer) {
	/* Remove 2nd reference to local session state */
	memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
	ss->ss_previous_user_version = 0;
	ss->ss_previous_remote_version = 0;
	su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL;
	su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL;
      }

      su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u);

      goto internal_error;
    }

    if (bump) {
      latest = sdp_session_dup(ss->ss_home, ss->ss_local->ssd_sdp);
      previous = sss->sss_latest;
    }
  }

  if (u2s) {
    tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf);
    tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf);
  }

  /* Update version numbers */
  switch (action) {
  case generate_offer:
    ss->ss_local_user_version = user_version;
    sss->sss_latest = latest;
    break;
  case generate_answer:
    ss->ss_local_user_version = user_version;
    ss->ss_local_remote_version = remote_version;
    sss->sss_latest = latest;
    break;
  case process_answer:
    ss->ss_local_remote_version = remote_version;
  default:
    break;
  }

  if (previous)
    su_free(ss->ss_home, previous);

  su_home_deinit(tmphome);
  return 0;

 internal_error:
  su_home_deinit(tmphome);
  return soa_set_status(ss, 500, phrase);
}
Esempio n. 3
0
/** Compare two media (m=) fields */
int sdp_media_cmp(sdp_media_t const *a, sdp_media_t const *b)
{
  int rv;

  sdp_connection_t const *ac, *bc;
  sdp_bandwidth_t const *ab, *bb;
  sdp_rtpmap_t const *arm, *brm;
  sdp_attribute_t const *aa, *ba;

  if (a == b)
    return 0;
  if ((rv = (a != NULL) - (b != NULL)))
    return rv;

  if (a->m_type != b->m_type)
    return a->m_type < b->m_type ? -1 : 1;
  if (a->m_type == sdp_media_x)
    if ((rv = su_strcmp(a->m_type_name, b->m_type_name)))
      return rv;
  if (a->m_port != b->m_port)
    return a->m_port < b->m_port ? -1 : 1;

  if (a->m_port == 0 /* && b->m_port == 0 */)
    /* Ignore transport protocol and media list if media has been rejected */
    return 0;

  if (a->m_number_of_ports != b->m_number_of_ports)
    return a->m_number_of_ports < b->m_number_of_ports ? -1 : 1;

  if (a->m_proto != b->m_proto)
    return a->m_proto < b->m_proto ? -1 : 1;
  if (a->m_proto == sdp_proto_x)
    if ((rv = su_strcmp(a->m_proto_name, b->m_proto_name)))
      return rv;

  if (a->m_mode != b->m_mode)
    return a->m_mode < b->m_mode ? -1 : 1;

  for (arm = a->m_rtpmaps, brm = b->m_rtpmaps;
       arm || brm;
       arm = arm->rm_next, brm = brm->rm_next)
    if ((rv = sdp_rtpmap_cmp(arm, brm)))
      return rv;

  if ((rv = sdp_list_cmp(a->m_format, b->m_format)))
    return rv;

  if ((rv = su_strcmp(a->m_information, b->m_information)))
    return rv;

  for (ac = a->m_connections, bc = b->m_connections;
       ac || bc;
       ac = ac->c_next, bc = bc->c_next)
  if ((rv = sdp_connection_cmp(ac, bc)))
    return rv;

  for (ab = a->m_bandwidths, bb = b->m_bandwidths;
       ab || bb;
       ab = ab->b_next, bb = bb->b_next)
    if ((rv = sdp_bandwidth_cmp(a->m_bandwidths, b->m_bandwidths)))
      return rv;

  if ((rv = sdp_key_cmp(a->m_key, b->m_key)))
    return rv;

  for (aa = a->m_attributes, ba = b->m_attributes;
       aa || bb;
       aa = aa->a_next, ba = ba->a_next)
    if ((rv = sdp_attribute_cmp(aa, ba)))
      return rv;

  return 0;
}