📄 soa.c
字号:
}void soa_set_activity(soa_session_t *ss, sdp_media_t const *m, enum soa_activity activity){ struct soa_media_activity *ma; sdp_connection_t const *c; int mode, swap; int l_audio = SOA_ACTIVE_DISABLED, r_audio = SOA_ACTIVE_DISABLED; int l_video = SOA_ACTIVE_DISABLED, r_video = SOA_ACTIVE_DISABLED; int l_chat = SOA_ACTIVE_DISABLED, r_chat = SOA_ACTIVE_DISABLED; int l_image = SOA_ACTIVE_DISABLED, r_image = SOA_ACTIVE_DISABLED; int *l, *r; for (; m; m = m->m_next) { if (m->m_type == sdp_media_audio) l = &l_audio, r = &r_audio; else if (m->m_type == sdp_media_video) l = &l_video, r = &r_video; else if (m->m_type == sdp_media_image) l = &l_image, r = &r_image; else if (strcasecmp(m->m_type_name, "message") == 0) l = &l_chat, r = &r_chat; else continue; if (m->m_rejected) { if (*l < 0) *l = SOA_ACTIVE_REJECTED; if (*r < 0) *r = SOA_ACTIVE_REJECTED; continue; } mode = m->m_mode, swap = ((mode << 1) & 2) | ((mode >> 1) & 1); c = sdp_media_connections((sdp_media_t *)m); switch (activity) { case soa_activity_local: *l &= SOA_ACTIVE_SENDRECV; *l |= c && c->c_mcast ? swap : mode; break; case soa_activity_remote: *r &= SOA_ACTIVE_SENDRECV; *r = c && c->c_mcast ? mode : swap; break; case soa_activity_session: *l &= SOA_ACTIVE_SENDRECV; *l |= c && c->c_mcast ? swap : mode; *r &= SOA_ACTIVE_SENDRECV; *r = c && c->c_mcast ? swap : mode; break; } } if (activity == soa_activity_local || activity == soa_activity_session) { ma = ss->ss_local_activity; ma->ma_audio = l_audio; ma->ma_video = l_video; ma->ma_image = l_image; ma->ma_chat = l_chat; } if (activity == soa_activity_remote || activity == soa_activity_session) { ma = ss->ss_remote_activity; ma->ma_audio = r_audio; ma->ma_video = r_video; ma->ma_image = r_image; ma->ma_chat = r_chat; }}/* ----------------------------------------------------------------------*//* Handle SDP *//** * Parses and stores session description * * @param ss instance pointer * @param what caps, local or remote * @param sdp0 new sdp (parsed) * @param sdp_str new sdp (unparsed) * @param str_len length on unparsed data **/staticint soa_set_sdp(soa_session_t *ss, enum soa_sdp_kind what, sdp_session_t const *sdp0, char const *sdp_str, issize_t str_len){ struct soa_description *ssd; int flags, new_version, retval; sdp_parser_t *parser = NULL; sdp_session_t sdp[1]; if (ss == NULL) return -1; switch (what) { case soa_capability_sdp_kind: ssd = ss->ss_caps; flags = sdp_f_config; break; case soa_user_sdp_kind: ssd = ss->ss_user; flags = sdp_f_config; break; case soa_remote_sdp_kind: ssd = ss->ss_remote; flags = sdp_f_mode_0000; break; default: return -1; } if (sdp0) { new_version = sdp_session_cmp(sdp0, ssd->ssd_sdp) != 0; sdp_str = NULL, str_len = -1; } else if (sdp_str) { if (str_len == -1) str_len = strlen(sdp_str); new_version = !ssd->ssd_unparsed || str0ncmp(sdp_str, ssd->ssd_unparsed, str_len + 1) != 0; } else return (void)su_seterrno(EINVAL), -1; if (!new_version) { if (what == soa_remote_sdp_kind) { *sdp = *ssd->ssd_sdp; /* XXX - should check changes by soa_set_remote_sdp */ return ss->ss_actions->soa_set_remote_sdp(ss, new_version, sdp, sdp_str, str_len); } return 0; } if (sdp0) { /* note: case 1 - src in parsed form */ *sdp = *sdp0; } else /* if (sdp_str) */ { /* note: case 2 - src in unparsed form */ parser = sdp_parse(ss->ss_home, sdp_str, str_len, flags | sdp_f_anynet); if (sdp_parsing_error(parser)) { sdp_parser_free(parser); return soa_set_status(ss, 400, "Bad Session Description"); } *sdp = *sdp_session(parser); } switch (what) { case soa_capability_sdp_kind: retval = ss->ss_actions->soa_set_capability_sdp(ss, sdp, sdp_str, str_len); break; case soa_user_sdp_kind: retval = ss->ss_actions->soa_set_user_sdp(ss, sdp, sdp_str, str_len); break; case soa_remote_sdp_kind: retval = ss->ss_actions->soa_set_remote_sdp(ss, 1, sdp, sdp_str, str_len); break; default: retval = soa_set_status(ss, 500, "Internal Error"); break; } if (parser) sdp_parser_free(parser); return retval;}/** Set session descriptions. */int soa_description_set(soa_session_t *ss, struct soa_description *ssd, sdp_session_t *sdp, char const *sdp_str, isize_t str_len){ int retval = -1; sdp_printer_t *printer = NULL; sdp_session_t *sdp_new; char *sdp_str_new; char *sdp_str0_new; void *tbf1, *tbf2, *tbf3, *tbf4; /* Store description in three forms: unparsed, parsed and reprinted */ sdp_new = sdp_session_dup(ss->ss_home, sdp); printer = sdp_print(ss->ss_home, sdp, NULL, 0, 0); sdp_str_new = (char *)sdp_message(printer); if (sdp_str) sdp_str0_new = su_strndup(ss->ss_home, sdp_str, str_len); else sdp_str0_new = sdp_str_new; if (sdp_new && printer && sdp_str_new && sdp_str0_new) { tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer; tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed; ssd->ssd_sdp = sdp_new; ssd->ssd_printer = printer; ssd->ssd_str = sdp_str_new; ssd->ssd_unparsed = sdp_str0_new; retval = 1; } else { tbf1 = sdp_new, tbf2 = printer, tbf3 = sdp_str_new, tbf4 = sdp_str0_new; } su_free(ss->ss_home, tbf1); sdp_printer_free(tbf2); if (tbf3 != tbf4) su_free(ss->ss_home, tbf4); return retval;}/** Duplicate a session descriptions. */int soa_description_dup(su_home_t *home, struct soa_description *ssd, struct soa_description const *ssd0){ if (ssd0->ssd_sdp) { ssd->ssd_sdp = sdp_session_dup(home, ssd0->ssd_sdp); ssd->ssd_printer = sdp_print(home, ssd->ssd_sdp, NULL, 0, 0); ssd->ssd_str = (char *)sdp_message(ssd->ssd_printer); if (ssd0->ssd_str != ssd0->ssd_unparsed) ssd->ssd_unparsed = su_strdup(home, ssd0->ssd_unparsed); else ssd->ssd_unparsed = ssd->ssd_str; } return 0;}/** Free session descriptions. */void soa_description_free(soa_session_t *ss, struct soa_description *ssd){ void *tbf1, *tbf2, *tbf3, *tbf4; tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer; tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed; memset(ssd, 0, sizeof *ssd); su_free(ss->ss_home, tbf1); sdp_printer_free(tbf2); if (tbf3 != tbf4) su_free(ss->ss_home, tbf4);}/** Initialize SDP o= line */intsoa_init_sdp_origin(soa_session_t *ss, sdp_origin_t *o, char buffer[64]){ sdp_connection_t *c; if (ss == NULL || o == NULL) return su_seterrno(EFAULT), -1; assert(o->o_address); if (!o->o_username) o->o_username = "-"; if (o->o_id == 0) su_randmem(&o->o_id, sizeof o->o_id); o->o_id &= ((unsigned longlong)1 << 63) - 1; if (o->o_version == 0) su_randmem(&o->o_version, sizeof o->o_version); o->o_version &= ((unsigned longlong)1 << 63) - 1; c = o->o_address; if (!c->c_nettype || !c->c_address || strcmp(c->c_address, "") == 0 || strcmp(c->c_address, "0.0.0.0") == 0 || strcmp(c->c_address, "::") == 0 || !host_is_local(c->c_address)) { return soa_init_sdp_connection(ss, c, buffer); } return 0;}/** Search for an local address item from string provided by user */staticsu_localinfo_t *li_in_list(su_localinfo_t *li0, char const **llist){ char const *list = *llist; size_t n; if (!list) return NULL; while ((n = strcspn(list, ", "))) { su_localinfo_t *li; for (li = li0; li; li = li->li_next) { if (strncasecmp(li->li_canonname, list, n) == 0 && li->li_canonname[n] == '\0') break; } list += n; while (list[0] == ' ' || list[0] == ',') list++; *llist = list; if (li) return li; } return NULL;}/** Obtain a local address for SDP connection structure */intsoa_init_sdp_connection(soa_session_t *ss, sdp_connection_t *c, char buffer[64]){ su_localinfo_t *res, hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}; su_localinfo_t *li, *li4, *li6; char const *address; int ip4, ip6, error; if (ss == NULL || c == NULL) return su_seterrno(EFAULT), -1; address = ss->ss_address; if (host_is_ip_address(address)) { /* Use the application-specified address - * do not check that it is found from the local address list */ c->c_nettype = sdp_net_in; if (host_is_ip4_address(address)) c->c_addrtype = sdp_addr_ip4; else c->c_addrtype = sdp_addr_ip6; if (!host_is_ip6_reference(address)) { c->c_address = strcpy(buffer, address); } else { /* Remove brackets [] around the reference */ size_t len = strlen(address + 1); c->c_address = memcpy(buffer, address + 1, len - 1); buffer[len - 1] = '\0'; } return 0; } /* XXX - using LI_SCOPE_LINK requires some tweaking */ hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE /* | LI_SCOPE_LINK */; switch (ss->ss_af) { case SOA_AF_IP4_ONLY: hints->li_family = AF_INET, ip4 = 1, ip6 = 0; break;#if HAVE_SIN6 case SOA_AF_IP6_ONLY: hints->li_family = AF_INET6, ip6 = 1, ip4 = 0; break; case SOA_AF_IP4_IP6: ip4 = 2, ip6 = 1; break; case SOA_AF_IP6_IP4: ip4 = 1, ip6 = 2; break;#endif default: ip4 = ip6 = 1; } for (res = NULL; res == NULL;) { if ((error = su_getlocalinfo(hints, &res)) < 0 && error != ELI_NOADDRESS) { SU_DEBUG_1(("%s: su_localinfo: %s\n", __func__, su_gli_strerror(error))); return -1; } if (hints->li_scope & LI_SCOPE_HOST) break; hints->li_scope |= LI_SCOPE_HOST; } if (!(ip4 & ip6 && c->c_nettype == sdp_net_in)) /* Use ss_af preference */; else if (c->c_addrtype == sdp_addr_ip4) ip4 = 2, ip6 = 1; else if (c->c_addrtype == sdp_addr_ip6) ip6 = 2, ip4 = 1; if (address) SU_DEBUG_3(("%s: searching for %s from list \"%s\"\n", __func__, ip6 && !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : "", address)); li = res, li4 = NULL, li6 = NULL; for (;;) { if (address) li = li_in_list(li, &address); if (!li) break;#if HAVE_SIN6 else if (li->li_family == AF_INET6) { if (ip6 >= ip4) break; else if (!li6) li6 = li; /* Best IP6 address */ }#endif else if (li->li_family == AF_INET) { if (ip4 > ip6) break; else if (!li4) li4 = li; /* Best IP4 address */ } if (!address) li = li->li_next; } if (li == NULL) li = li4; if (li == NULL) li = li6; if (li == NULL) ; else if (li->li_family == AF_INET) c->c_nettype = sdp_net_in, c->c_addrtype = sdp_addr_ip4;#if HAVE_SIN6 else if (li->li_family == AF_INET6) c->c_nettype = sdp_net_in, c->c_addrtype = sdp_addr_ip6;#endif if (li) { assert(strlen(li->li_canonname) < 64); c->c_address = strcpy(buffer, li->li_canonname); } su_freelocalinfo(res); if (!li) return -1; else return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -