📄 soa.c
字号:
soa_set_activity(ss, r_sdp->sdp_media, 1); ss->ss_answer_recv = 1; ss->ss_complete = 1; ss->ss_unprocessed_remote = 0; return 0;}/** Process rejection of offer */int soa_process_reject(soa_session_t *ss, soa_callback_f *completed){ SU_DEBUG_9(("soa_process_reject(%s::%p, %p) called\n", ss ? ss->ss_actions->soa_name : "", ss, completed)); /** @ERROR EFAULT Bad address as @a ss. */ if (ss == NULL) return su_seterrno(EFAULT), -1; /** @ERROR An operation is already in progress. */ if (ss->ss_in_progress) return su_seterrno(EALREADY), -1; /** @ERROR EPROTO We have not sent an offer or already have received answer. */ if (!ss->ss_offer_sent || ss->ss_answer_recv) return su_seterrno(EPROTO), -1; return ss->ss_actions->soa_process_reject(ss, completed);}/** * Process reject from remote end. */int soa_base_process_reject(soa_session_t *ss, soa_callback_f *completed){ sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp; (void)completed; if (!l_sdp) return -1; soa_set_activity(ss, l_sdp->sdp_media, 0); ss->ss_offer_sent = 0; return 0;}/** Activate session */int soa_activate(soa_session_t *ss, char const *option){ SU_DEBUG_9(("soa_activate(%s::%p, %s%s%s) called\n", ss ? ss->ss_actions->soa_name : "", ss, NICE(option))); /** @ERROR EFAULT Bad address as @a ss. */ if (ss == NULL) return -1; ss->ss_active = 1; return ss->ss_actions->soa_activate_session(ss, option);}int soa_base_activate(soa_session_t *ss, char const *option){ (void)ss; (void)option; return 0;}/** Deactivate session */int soa_deactivate(soa_session_t *ss, char const *option){ SU_DEBUG_9(("soa_deactivate(%s::%p, %s%s%s) called\n", ss ? ss->ss_actions->soa_name : "", ss, NICE(option))); /** @ERROR EFAULT Bad address as @a ss. */ if (ss == NULL) return -1; ss->ss_active = 0; return ss->ss_actions->soa_deactivate_session(ss, option);}int soa_base_deactivate(soa_session_t *ss, char const *option){ (void)ss; (void)option; return 0;}/** Terminate session */void soa_terminate(soa_session_t *ss, char const *option){ SU_DEBUG_9(("soa_terminate(%s::%p) called\n", ss ? ss->ss_actions->soa_name : "", ss)); /** @ERROR EFAULT Bad address as @a ss. */ if (ss == NULL) return; ss->ss_active = 0; ss->ss_terminated++; ss->ss_actions->soa_terminate_session(ss, option);}void soa_base_terminate(soa_session_t *ss, char const *option){ (void)option; soa_init_offer_answer(ss); ss->ss_oa_rounds = 0; soa_description_free(ss, ss->ss_remote); soa_set_activity(ss, NULL, 0); soa_set_activity(ss, NULL, 1);}int soa_has_received_sdp(soa_session_t const *ss){ return ss && ss->ss_unprocessed_remote;}int soa_is_complete(soa_session_t const *ss){ return ss && ss->ss_complete;}int soa_is_audio_active(soa_session_t const *ss){ return ss ? ss->ss_local_activity->ma_audio : SOA_ACTIVE_DISABLED;}int soa_is_video_active(soa_session_t const *ss){ return ss ? ss->ss_local_activity->ma_video : SOA_ACTIVE_DISABLED;}int soa_is_image_active(soa_session_t const *ss){ return ss ? ss->ss_local_activity->ma_image : SOA_ACTIVE_DISABLED;}int soa_is_chat_active(soa_session_t const *ss){ return ss ? ss->ss_local_activity->ma_chat : SOA_ACTIVE_DISABLED;}int soa_is_remote_audio_active(soa_session_t const *ss){ return ss ? ss->ss_remote_activity->ma_audio : SOA_ACTIVE_DISABLED;}int soa_is_remote_video_active(soa_session_t const *ss){ return ss ? ss->ss_remote_activity->ma_video : SOA_ACTIVE_DISABLED;}int soa_is_remote_image_active(soa_session_t const *ss){ return ss ? ss->ss_remote_activity->ma_image : SOA_ACTIVE_DISABLED;}int soa_is_remote_chat_active(soa_session_t const *ss){ return ss ? ss->ss_remote_activity->ma_chat : SOA_ACTIVE_DISABLED;}/* ======================================================================== */int soa_set_status(soa_session_t *ss, int status, char const *phrase){ if (ss) { ss->ss_status = status, ss->ss_phrase = phrase; ss->ss_wcode = 0, ss->ss_warning = NULL; } return -1;}int soa_set_warning(soa_session_t *ss, int code, char const *text){ if (ss) ss->ss_wcode = code, ss->ss_warning = text; return -1;}static inlineint soa_media_is_ready(soa_session_t const *ss){ XXX; return 0; /* return ss && ss->ss_session != NULL; */}void soa_set_activity(soa_session_t *ss, sdp_media_t const *m, int remote){ struct soa_media_activity *ma; sdp_connection_t const *c; int mode; int ma_audio = SOA_ACTIVE_DISABLED; int ma_video = SOA_ACTIVE_DISABLED; int ma_chat = SOA_ACTIVE_DISABLED; int ma_image = SOA_ACTIVE_DISABLED; int *p; remote = !!remote; ma = remote ? ss->ss_remote_activity : ss->ss_local_activity; for (; m; m = m->m_next) { if (m->m_type == sdp_media_audio) p = &ma_audio; else if (m->m_type == sdp_media_video) p = &ma_video; else if (m->m_type == sdp_media_image) p = &ma_image; else if (strcasecmp(m->m_type_name, "message") == 0) p = &ma_chat; else continue; if (m->m_rejected) { if (*p < 0) *p = SOA_ACTIVE_REJECTED; continue; } mode = m->m_mode; c = sdp_media_connections((sdp_media_t *)m); if (remote != (c && c->c_mcast)) mode = ((mode << 1) & 2) | ((mode >> 1) & 1); if (*p < 0) *p = mode; else *p |= mode; } ma->ma_audio = ma_audio; ma->ma_video = ma_video; ma->ma_image = ma_image; ma->ma_chat = ma_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, int str_len){ struct soa_description *ssd; int flags, new_version, retval; sdp_parser_t *parser = NULL; sdp_session_t sdp[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; else if (sdp_str) new_version = str0cmp(sdp_str, ssd->ssd_unparsed) != 0; else return (void)su_seterrno(EINVAL), -1; if (sdp_str && str_len == -1) str_len = strlen(sdp_str); 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, int 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 || strcasecmp(c->c_address, "localhost") == 0 || strcasecmp(c->c_address, "localhost.localdomain") == 0 || strcmp(c->c_address, "0.0.0.0") == 0 || strcmp(c->c_address, "127.0.0.1") == 0 || strcmp(c->c_address, "::") == 0 || strcmp(c->c_address, "::1") == 0) { 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; int 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; /* 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; address = ss->ss_address; 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 + -