const char *call_delete_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { str fromtag, totag, viabranch, callid; bencode_item_t *flags, *it; int fatal = 0; if (!bencode_dictionary_get_str(input, "call-id", &callid)) return "No call-id in message"; if (!bencode_dictionary_get_str(input, "from-tag", &fromtag)) return "No from-tag in message"; bencode_dictionary_get_str(input, "to-tag", &totag); bencode_dictionary_get_str(input, "via-branch", &viabranch); flags = bencode_dictionary_get_expect(input, "flags", BENCODE_LIST); if (flags) { for (it = flags->child; it; it = it->sibling) { if (!bencode_strcmp(it, "fatal")) fatal = 1; } } if (call_delete_branch(m, &callid, &viabranch, &fromtag, &totag, output)) { if (fatal) return "Call-ID not found or tags didn't match"; bencode_dictionary_add_string(output, "warning", "Call-ID not found or tags didn't match"); } bencode_dictionary_add_string(output, "result", "ok"); return NULL; }
const char *call_query_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { str callid, fromtag, totag; struct call *call; if (!bencode_dictionary_get_str(input, "call-id", &callid)) return "No call-id in message"; call = call_get_opmode(&callid, m, OP_OTHER); if (!call) return "Unknown call-id"; bencode_dictionary_get_str(input, "from-tag", &fromtag); bencode_dictionary_get_str(input, "to-tag", &totag); bencode_dictionary_add_string(output, "result", "ok"); ng_call_stats(call, &fromtag, &totag, output, NULL); rwlock_unlock_w(&call->master_lock); obj_put(call); return NULL; }
static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, enum call_opmode opmode) { str sdp, fromtag, totag = STR_NULL, callid; char *errstr; GQueue parsed = G_QUEUE_INIT; GQueue streams = G_QUEUE_INIT; struct call *call; struct call_monologue *monologue; int ret; struct sdp_ng_flags flags; struct sdp_chopper *chopper; if (!bencode_dictionary_get_str(input, "sdp", &sdp)) return "No SDP body in message"; if (!bencode_dictionary_get_str(input, "call-id", &callid)) return "No call-id in message"; if (!bencode_dictionary_get_str(input, "from-tag", &fromtag)) return "No from-tag in message"; if (opmode == OP_ANSWER) { if (!bencode_dictionary_get_str(input, "to-tag", &totag)) return "No to-tag in message"; } //bencode_dictionary_get_str(input, "via-branch", &viabranch); if (sdp_parse(&sdp, &parsed)) return "Failed to parse SDP"; call_ng_process_flags(&flags, input); flags.opmode = opmode; errstr = "Incomplete SDP specification"; if (sdp_streams(&parsed, &streams, &flags)) goto out; call = call_get_opmode(&callid, m, opmode); errstr = "Unknown call-id"; if (!call) goto out; /* At least the random ICE strings are contained within the call struct, so we * need to hold a ref until we're done sending the reply */ call_bencode_hold_ref(call, output); monologue = call_get_mono_dialogue(call, &fromtag, &totag); errstr = "Invalid dialogue association"; if (!monologue) { rwlock_unlock_w(&call->master_lock); obj_put(call); goto out; } chopper = sdp_chopper_new(&sdp); bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper); ret = monologue_offer_answer(monologue, &streams, &flags); if (!ret) ret = sdp_replace(chopper, &parsed, monologue->active_dialogue, &flags); rwlock_unlock_w(&call->master_lock); redis_update(call, m->conf.redis); obj_put(call); errstr = "Error rewriting SDP"; if (ret) goto out; bencode_dictionary_add_iovec(output, "sdp", &g_array_index(chopper->iov, struct iovec, 0), chopper->iov_num, chopper->str_len); bencode_dictionary_add_string(output, "result", "ok"); errstr = NULL; out: sdp_free(&parsed); streams_free(&streams); return errstr; }
static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *input) { bencode_item_t *list, *it; int diridx; str s; ZERO(*out); if ((list = bencode_dictionary_get_expect(input, "flags", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { str_hyphenate(it); if (!bencode_strcmp(it, "trust-address")) out->trust_address = 1; else if (!bencode_strcmp(it, "asymmetric")) out->asymmetric = 1; else if (!bencode_strcmp(it, "strict-source")) out->strict_source = 1; else if (!bencode_strcmp(it, "media-handover")) out->media_handover = 1; else ilog(LOG_WARN, "Unknown flag encountered: '"BENCODE_FORMAT"'", BENCODE_FMT(it)); } } if ((list = bencode_dictionary_get_expect(input, "replace", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { str_hyphenate(it); if (!bencode_strcmp(it, "origin")) out->replace_origin = 1; else if (!bencode_strcmp(it, "session-connection")) out->replace_sess_conn = 1; else ilog(LOG_WARN, "Unknown 'replace' flag encountered: '"BENCODE_FORMAT"'", BENCODE_FMT(it)); } } diridx = 0; if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) { for (it = list->child; it && diridx < 2; it = it->sibling) bencode_get_str(it, &out->direction[diridx++]); } list = bencode_dictionary_get_expect(input, "received from", BENCODE_LIST); if (!list) list = bencode_dictionary_get_expect(input, "received-from", BENCODE_LIST); if (list && (it = list->child)) { bencode_get_str(it, &out->received_from_family); bencode_get_str(it->sibling, &out->received_from_address); } if (bencode_dictionary_get_str(input, "ICE", &s)) { if (!str_cmp(&s, "remove")) out->ice_remove = 1; else if (!str_cmp(&s, "force")) out->ice_force = 1; else if (!str_cmp(&s, "force_relay") || !str_cmp(&s, "force-relay")) out->ice_force_relay = 1; else ilog(LOG_WARN, "Unknown 'ICE' flag encountered: '"STR_FORMAT"'", STR_FMT(&s)); } if ((list = bencode_dictionary_get_expect(input, "rtcp-mux", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { if (!bencode_strcmp(it, "offer")) out->rtcp_mux_offer = 1; else if (!bencode_strcmp(it, "demux")) out->rtcp_mux_demux = 1; else if (!bencode_strcmp(it, "accept")) out->rtcp_mux_accept = 1; else if (!bencode_strcmp(it, "reject")) out->rtcp_mux_reject = 1; else ilog(LOG_WARN, "Unknown 'rtcp-mux' flag encountered: '"BENCODE_FORMAT"'", BENCODE_FMT(it)); } } bencode_get_alt(input, "transport-protocol", "transport protocol", &out->transport_protocol_str); out->transport_protocol = transport_protocol(&out->transport_protocol_str); bencode_get_alt(input, "media-address", "media address", &out->media_address); if (bencode_get_alt(input, "address-family", "address family", &out->address_family_str)) out->address_family = address_family(&out->address_family_str); out->tos = bencode_dictionary_get_integer(input, "TOS", 256); }
INLINE char *bencode_get_alt(bencode_item_t *i, const char *one, const char *two, str *out) { char *o; if ((o = bencode_dictionary_get_str(i, one, out))) return o; return bencode_dictionary_get_str(i, two, out); }
static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin, char *addr, struct udp_listener *ul) { struct control_ng *c = (void *) obj; bencode_buffer_t bencbuf; bencode_item_t *dict, *resp; str cmd, cookie, data, reply, *to_send, callid; const char *errstr; struct iovec iov[3]; unsigned int iovlen; GString *log_str; struct control_ng_stats* cur = get_control_ng_stats(c,&sin->address); str_chr_str(&data, buf, ' '); if (!data.s || data.s == buf->s) { ilog(LOG_WARNING, "Received invalid data on NG port (no cookie) from %s: "STR_FORMAT, addr, STR_FMT(buf)); return; } bencode_buffer_init(&bencbuf); resp = bencode_dictionary(&bencbuf); cookie = *buf; cookie.len -= data.len; *data.s++ = '\0'; data.len--; errstr = "Invalid data (no payload)"; if (data.len <= 0) goto err_send; to_send = cookie_cache_lookup(&c->cookie_cache, &cookie); if (to_send) { ilog(LOG_INFO, "Detected command from %s as a duplicate", addr); resp = NULL; goto send_only; } dict = bencode_decode_expect_str(&bencbuf, &data, BENCODE_DICTIONARY); errstr = "Could not decode dictionary"; if (!dict) goto err_send; bencode_dictionary_get_str(dict, "command", &cmd); errstr = "Dictionary contains no key \"command\""; if (!cmd.s) goto err_send; bencode_dictionary_get_str(dict, "call-id", &callid); log_info_str(&callid); ilog(LOG_INFO, "Received command '"STR_FORMAT"' from %s", STR_FMT(&cmd), addr); if (get_log_level() >= LOG_DEBUG) { log_str = g_string_sized_new(256); g_string_append_printf(log_str, "Dump for '"STR_FORMAT"' from %s: ", STR_FMT(&cmd), addr); pretty_print(dict, log_str); ilog(LOG_DEBUG, "%.*s", (int) log_str->len, log_str->str); g_string_free(log_str, TRUE); } errstr = NULL; if (!str_cmp(&cmd, "ping")) { bencode_dictionary_add_string(resp, "result", "pong"); g_atomic_int_inc(&cur->ping); } else if (!str_cmp(&cmd, "offer")) { errstr = call_offer_ng(dict, c->callmaster, resp, addr, sin); g_atomic_int_inc(&cur->offer); } else if (!str_cmp(&cmd, "answer")) { errstr = call_answer_ng(dict, c->callmaster, resp); g_atomic_int_inc(&cur->answer); } else if (!str_cmp(&cmd, "delete")) { errstr = call_delete_ng(dict, c->callmaster, resp); g_atomic_int_inc(&cur->delete); }
static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *input) { bencode_item_t *list, *it; int diridx; str s; ZERO(*out); if ((list = bencode_dictionary_get_expect(input, "flags", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { if (!bencode_strcmp(it, "trust address")) out->trust_address = 1; else if (!bencode_strcmp(it, "asymmetric")) out->asymmetric = 1; else if (!bencode_strcmp(it, "trust-address")) out->trust_address = 1; else if (!bencode_strcmp(it, "strict source")) out->strict_source = 1; else if (!bencode_strcmp(it, "media handover")) out->media_handover = 1; } } if ((list = bencode_dictionary_get_expect(input, "replace", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { if (!bencode_strcmp(it, "origin")) out->replace_origin = 1; else if (!bencode_strcmp(it, "session connection")) out->replace_sess_conn = 1; else if (!bencode_strcmp(it, "session-connection")) out->replace_sess_conn = 1; } } diridx = 0; if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) { for (it = list->child; it && diridx < 2; it = it->sibling) { if (!bencode_strcmp(it, "internal")) out->directions[diridx++] = DIR_INTERNAL; else if (!bencode_strcmp(it, "external")) out->directions[diridx++] = DIR_EXTERNAL; } } list = bencode_dictionary_get_expect(input, "received from", BENCODE_LIST); if (!list) list = bencode_dictionary_get_expect(input, "received-from", BENCODE_LIST); if (list && (it = list->child)) { bencode_get_str(it, &out->received_from_family); bencode_get_str(it->sibling, &out->received_from_address); } if (bencode_dictionary_get_str(input, "ICE", &s)) { if (!str_cmp(&s, "remove")) out->ice_remove = 1; else if (!str_cmp(&s, "force")) out->ice_force = 1; else if (!str_cmp(&s, "force_relay")) out->ice_force_relay = 1; } if ((list = bencode_dictionary_get_expect(input, "rtcp-mux", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { if (!bencode_strcmp(it, "offer")) out->rtcp_mux_offer = 1; else if (!bencode_strcmp(it, "demux")) out->rtcp_mux_demux = 1; else if (!bencode_strcmp(it, "accept")) out->rtcp_mux_accept = 1; else if (!bencode_strcmp(it, "reject")) out->rtcp_mux_reject = 1; } } bencode_dictionary_get_str(input, "transport protocol", &out->transport_protocol_str); if (!out->transport_protocol_str.s) bencode_dictionary_get_str(input, "transport-protocol", &out->transport_protocol_str); out->transport_protocol = transport_protocol(&out->transport_protocol_str); bencode_dictionary_get_str(input, "media address", &out->media_address); if (bencode_dictionary_get_str(input, "address family", &out->address_family_str)) out->address_family = address_family(&out->address_family_str); }
static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *input) { bencode_item_t *list, *it; int diridx; str s; ZERO(*out); out->trust_address = trust_address_def; out->dtls_passive = dtls_passive_def; if ((list = bencode_dictionary_get_expect(input, "flags", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { if (it->type != BENCODE_STRING) continue; str_hyphenate(it); if (!bencode_strcmp(it, "trust-address")) out->trust_address = 1; else if (!bencode_strcmp(it, "SIP-source-address")) out->trust_address = 0; else if (!bencode_strcmp(it, "asymmetric")) out->asymmetric = 1; else if (!bencode_strcmp(it, "strict-source")) out->strict_source = 1; else if (!bencode_strcmp(it, "media-handover")) out->media_handover = 1; else if (!bencode_strcmp(it, "reset")) out->reset = 1; else if (it->iov[1].iov_len >= 5 && !memcmp(it->iov[1].iov_base, "SDES-", 5)) ng_sdes_option(out, it, 5); else ilog(LOG_WARN, "Unknown flag encountered: '"BENCODE_FORMAT"'", BENCODE_FMT(it)); } } if ((list = bencode_dictionary_get_expect(input, "replace", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { str_hyphenate(it); if (!bencode_strcmp(it, "origin")) out->replace_origin = 1; else if (!bencode_strcmp(it, "session-connection")) out->replace_sess_conn = 1; else ilog(LOG_WARN, "Unknown 'replace' flag encountered: '"BENCODE_FORMAT"'", BENCODE_FMT(it)); } } diridx = 0; if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) { for (it = list->child; it && diridx < 2; it = it->sibling) bencode_get_str(it, &out->direction[diridx++]); } list = bencode_dictionary_get_expect(input, "received from", BENCODE_LIST); if (!list) list = bencode_dictionary_get_expect(input, "received-from", BENCODE_LIST); if (list && (it = list->child)) { bencode_get_str(it, &out->received_from_family); bencode_get_str(it->sibling, &out->received_from_address); } if (bencode_dictionary_get_str(input, "ICE", &s)) { if (!str_cmp(&s, "remove")) out->ice_remove = 1; else if (!str_cmp(&s, "force")) out->ice_force = 1; else if (!str_cmp(&s, "force_relay") || !str_cmp(&s, "force-relay") || !str_cmp(&s, "force relay")) out->ice_force_relay = 1; else ilog(LOG_WARN, "Unknown 'ICE' flag encountered: '"STR_FORMAT"'", STR_FMT(&s)); } if (bencode_dictionary_get_str(input, "DTLS", &s)) { if (!str_cmp(&s, "passive")) out->dtls_passive = 1; else if (!str_cmp(&s, "no") || !str_cmp(&s, "off") || !str_cmp(&s, "disabled") || !str_cmp(&s, "disable")) out->dtls_off = 1; else ilog(LOG_WARN, "Unknown 'DTLS' flag encountered: '"STR_FORMAT"'", STR_FMT(&s)); } if ((list = bencode_dictionary_get_expect(input, "rtcp-mux", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) { if (!bencode_strcmp(it, "offer")) out->rtcp_mux_offer = 1; else if (!bencode_strcmp(it, "demux")) out->rtcp_mux_demux = 1; else if (!bencode_strcmp(it, "accept")) out->rtcp_mux_accept = 1; else if (!bencode_strcmp(it, "reject")) out->rtcp_mux_reject = 1; else ilog(LOG_WARN, "Unknown 'rtcp-mux' flag encountered: '"BENCODE_FORMAT"'", BENCODE_FMT(it)); } } /* XXX abstractize the other list walking functions using callbacks */ /* XXX module still needs to support this list */ if ((list = bencode_dictionary_get_expect(input, "SDES", BENCODE_LIST))) { for (it = list->child; it; it = it->sibling) ng_sdes_option(out, it, 0); } bencode_get_alt(input, "transport-protocol", "transport protocol", &out->transport_protocol_str); out->transport_protocol = transport_protocol(&out->transport_protocol_str); bencode_get_alt(input, "media-address", "media address", &out->media_address); if (bencode_get_alt(input, "address-family", "address family", &out->address_family_str)) out->address_family = address_family(&out->address_family_str); out->tos = bencode_dictionary_get_integer(input, "TOS", 256); }