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; }
static void ng_stats_endpoint(bencode_item_t *dict, const struct endpoint *ep) { char buf[64]; if (IN6_IS_ADDR_V4MAPPED(&ep->ip46)) { bencode_dictionary_add_string(dict, "family", "IPv4"); inet_ntop(AF_INET, &(ep->ip46.s6_addr32[3]), buf, sizeof(buf)); } else { bencode_dictionary_add_string(dict, "family", "IPv6"); inet_ntop(AF_INET6, &ep->ip46, buf, sizeof(buf)); } bencode_dictionary_add_string_dup(dict, "address", buf); bencode_dictionary_add_integer(dict, "port", ep->port); }
static void ng_stats_media(bencode_item_t *list, const struct call_media *m, struct call_stats *totals) { bencode_item_t *dict, *streams = NULL, *flags; GList *l; struct packet_stream *ps; if (!list) goto stats; dict = bencode_list_add_dictionary(list); bencode_dictionary_add_integer(dict, "index", m->index); bencode_dictionary_add_str(dict, "type", &m->type); if (m->protocol) bencode_dictionary_add_string(dict, "protocol", m->protocol->name); streams = bencode_dictionary_add_list(dict, "streams"); flags = bencode_dictionary_add_list(dict, "flags"); BF_M("initialized", INITIALIZED); BF_M("rtcp-mux", RTCP_MUX); BF_M("DTLS-SRTP", DTLS); BF_M("SDES", SDES); BF_M("passthrough", PASSTHRU); BF_M("ICE", ICE); stats: for (l = m->streams.head; l; l = l->next) { ps = l->data; ng_stats_stream(streams, ps, totals); } }
const char *call_list_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { bencode_item_t *calls = NULL; long long int limit; limit = bencode_dictionary_get_integer(input, "limit", 32); if (limit < 0) { return "invalid limit, must be >= 0"; } bencode_dictionary_add_string(output, "result", "ok"); calls = bencode_dictionary_add_list(output, "calls"); ng_list_calls(m, calls, limit); return NULL; }
static void ng_stats_stream(bencode_item_t *list, const struct packet_stream *ps, struct call_stats *totals) { bencode_item_t *dict = NULL, *flags; struct stats *s; if (!list) goto stats; dict = bencode_list_add_dictionary(list); if (ps->sfd) bencode_dictionary_add_integer(dict, "local port", ps->sfd->fd.localport); ng_stats_endpoint(bencode_dictionary_add_dictionary(dict, "endpoint"), &ps->endpoint); ng_stats_endpoint(bencode_dictionary_add_dictionary(dict, "advertised endpoint"), &ps->advertised_endpoint); if (ps->crypto.params.crypto_suite) bencode_dictionary_add_string(dict, "crypto suite", ps->crypto.params.crypto_suite->name); bencode_dictionary_add_integer(dict, "last packet", ps->last_packet); flags = bencode_dictionary_add_list(dict, "flags"); BF_PS("RTP", RTP); BF_PS("RTCP", RTCP); BF_PS("fallback RTCP", FALLBACK_RTCP); BF_PS("filled", FILLED); BF_PS("confirmed", CONFIRMED); BF_PS("kernelized", KERNELIZED); BF_PS("no kernel support", NO_KERNEL_SUPPORT); BF_PS("DTLS fingerprint verified", FINGERPRINT_VERIFIED); BF_PS("strict source address", STRICT_SOURCE); BF_PS("media handover", MEDIA_HANDOVER); stats: if (totals->last_packet < ps->last_packet) totals->last_packet = ps->last_packet; /* XXX distinguish between input and output */ s = &totals->totals[0]; if (!PS_ISSET(ps, RTP)) s = &totals->totals[1]; ng_stats(bencode_dictionary_add_dictionary(dict, "stats"), &ps->stats, s); }
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 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); }