struct rtpp_stream * rtpp_stream_ctor(struct rtpp_log *log, struct rtpp_weakref_obj *servers_wrt, struct rtpp_stats *rtpp_stats, enum rtpp_stream_side side, int session_type, uint64_t seuid) { struct rtpp_stream_priv *pvt; struct rtpp_refcnt *rcnt; pvt = rtpp_rzmalloc(sizeof(struct rtpp_stream_priv), &rcnt); if (pvt == NULL) { goto e0; } pvt->pub.rcnt = rcnt; if (pthread_mutex_init(&pvt->lock, NULL) != 0) { goto e1; } if (session_type == SESS_RTP) { pvt->pub.analyzer = rtpp_analyzer_ctor(log); if (pvt->pub.analyzer == NULL) { goto e3; } } pvt->pub.pcnt_strm = rtpp_pcnt_strm_ctor(); if (pvt->pub.pcnt_strm == NULL) { goto e4; } pvt->servers_wrt = servers_wrt; pvt->rtpp_stats = rtpp_stats; pvt->pub.log = log; CALL_METHOD(log->rcnt, incref); pvt->side = side; pvt->pub.session_type = session_type; pvt->pub.handle_play = &rtpp_stream_handle_play; pvt->pub.handle_noplay = &rtpp_stream_handle_noplay; pvt->pub.isplayer_active = &rtpp_stream_isplayer_active; pvt->pub.finish_playback = &rtpp_stream_finish_playback; pvt->pub.get_actor = &rtpp_stream_get_actor; pvt->pub.get_proto = &rtpp_stream_get_proto; pvt->pub.latch = &rtpp_stream_latch; pvt->pub.check_latch_override = &rtpp_stream_check_latch_override; pvt->pub.fill_addr = &rtpp_stream_fill_addr; pvt->pub.prefill_addr = &rtpp_stream_prefill_addr; pvt->pub.get_rtps = &rtpp_stream_get_rtps; pvt->pub.replace_rtps = &rtpp_stream_replace_rtps; if (session_type == SESS_RTCP) { pvt->pub.guess_addr = &rtpp_stream_guess_addr; } rtpp_gen_uid(&pvt->pub.stuid); pvt->pub.seuid = seuid; CALL_METHOD(pvt->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_stream_dtor, pvt); return (&pvt->pub); e4: if (session_type == SESS_RTP) { CALL_METHOD(pvt->pub.analyzer->rcnt, decref); } e3: pthread_mutex_destroy(&pvt->lock); e1: CALL_METHOD(pvt->pub.rcnt, decref); free(pvt); e0: return (NULL); }
int rtpp_command_ul_handle(struct cfg *cf, struct rtpp_command *cmd, struct ul_opts *ulop, struct rtpp_session *sp, int sidx) { int pidx, lport, i; int fds[2]; char *cp; struct rtpp_session *spa, *spb; pidx = 1; lport = 0; spa = spb = NULL; fds[0] = fds[1] = -1; if (sidx != -1) { assert(cmd->cca.op == UPDATE || cmd->cca.op == LOOKUP); spa = sp; if (spa->fds[sidx] == -1 || ulop->new_port != 0) { if (ulop->local_addr != NULL) { spa->laddr[sidx] = ulop->local_addr; } if (rtpp_create_listener(cf, spa->laddr[sidx], &lport, fds) == -1) { rtpp_log_write(RTPP_LOG_ERR, spa->log, "can't create listener"); reply_error(cf, cmd, ECODE_LSTFAIL_1); goto err_undo_0; } if (spa->fds[sidx] != -1 && ulop->new_port != 0) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "new port requested, releasing %d/%d, replacing with %d/%d", spa->ports[sidx], spa->rtcp->ports[sidx], lport, lport + 1); update_sessions(cf, spa, sidx, fds); } else { assert(spa->fds[sidx] == -1); spa->fds[sidx] = fds[0]; assert(spa->rtcp->fds[sidx] == -1); spa->rtcp->fds[sidx] = fds[1]; append_session(cf, spa, sidx); } spa->ports[sidx] = lport; spa->rtcp->ports[sidx] = lport + 1; if (spa->complete == 0) { cmd->csp->nsess_complete.cnt++; } spa->complete = spa->rtcp->complete = 1; } if (ulop->weak) spa->weak[sidx] = 1; else if (cmd->cca.op == UPDATE) spa->strong = 1; lport = spa->ports[sidx]; ulop->lia[0] = spa->laddr[sidx]; pidx = (sidx == 0) ? 1 : 0; spa->ttl_mode = cf->stable->ttl_mode; if (cmd->cca.op == UPDATE) { spa->ttl[0] = cf->stable->max_setup_ttl; spa->ttl[1] = cf->stable->max_setup_ttl; rtpp_log_write(RTPP_LOG_INFO, spa->log, "adding %s flag to existing session, new=%d/%d/%d", ulop->weak ? ( sidx ? "weak[1]" : "weak[0]" ) : "strong", spa->strong, spa->weak[0], spa->weak[1]); } else { spa->ttl[0] = cf->stable->max_ttl; spa->ttl[1] = cf->stable->max_ttl; } rtpp_log_write(RTPP_LOG_INFO, spa->log, "lookup on ports %d/%d, session timer restarted", spa->ports[0], spa->ports[1]); } else { assert(cmd->cca.op == UPDATE); rtpp_log_write(RTPP_LOG_INFO, cf->stable->glog, "new session %s, tag %s requested, type %s", cmd->cca.call_id, cmd->cca.from_tag, ulop->weak ? "weak" : "strong"); if (cf->stable->slowshutdown != 0) { rtpp_log_write(RTPP_LOG_INFO, cf->stable->glog, "proxy is in the deorbiting-burn mode, new session rejected"); reply_error(cf, cmd, ECODE_SLOWSHTDN); goto err_undo_0; } if (ulop->local_addr != NULL) { ulop->lia[0] = ulop->lia[1] = ulop->local_addr; } if (rtpp_create_listener(cf, ulop->lia[0], &lport, fds) == -1) { rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "can't create listener"); reply_error(cf, cmd, ECODE_LSTFAIL_2); goto err_undo_0; } /* * Session creation. If creation is requested with weak flag, * set weak[0]. */ spa = malloc(sizeof(*spa)); if (spa == NULL) { handle_nomem(cf, cmd, ECODE_NOMEM_4, ulop, fds, spa, spb); return (-1); } /* spb is RTCP twin session for this one. */ spb = malloc(sizeof(*spb)); if (spb == NULL) { handle_nomem(cf, cmd, ECODE_NOMEM_5, ulop, fds, spa, spb); return (-1); } memset(spa, 0, sizeof(*spa)); memset(spb, 0, sizeof(*spb)); spa->init_ts = cmd->dtime; spb->init_ts = cmd->dtime; for (i = 0; i < 2; i++) { spa->fds[i] = spb->fds[i] = -1; spa->last_update[i] = 0; spb->last_update[i] = 0; } spa->call_id = strdup(cmd->cca.call_id); if (spa->call_id == NULL) { handle_nomem(cf, cmd, ECODE_NOMEM_6, ulop, fds, spa, spb); return (-1); } spb->call_id = spa->call_id; spa->tag = strdup(cmd->cca.from_tag); spa->tag_nomedianum = strdup(cmd->cca.from_tag); if (spa->tag == NULL) { handle_nomem(cf, cmd, ECODE_NOMEM_7, ulop, fds, spa, spb); return (-1); } cp = strrchr(spa->tag_nomedianum, ';'); if (cp != NULL) *cp = '\0'; spb->tag = spa->tag; spb->tag_nomedianum = spa->tag_nomedianum; for (i = 0; i < 2; i++) { spa->rrcs[i] = NULL; spb->rrcs[i] = NULL; spa->laddr[i] = ulop->lia[i]; spb->laddr[i] = ulop->lia[i]; } spa->strong = spa->weak[0] = spa->weak[1] = 0; if (ulop->weak) spa->weak[0] = 1; else spa->strong = 1; assert(spa->fds[0] == -1); spa->fds[0] = fds[0]; assert(spb->fds[0] == -1); spb->fds[0] = fds[1]; spa->ports[0] = lport; spb->ports[0] = lport + 1; spa->ttl[0] = cf->stable->max_setup_ttl; spa->ttl[1] = cf->stable->max_setup_ttl; spb->ttl[0] = -1; spb->ttl[1] = -1; spa->log = rtpp_log_open(cf->stable, "rtpproxy", spa->call_id, 0); rtpp_log_setlevel(spa->log, cf->stable->log_level); spb->log = spa->log; spa->rtcp = spb; spb->rtcp = NULL; spa->rtp = NULL; spb->rtp = spa; spa->sridx = spb->sridx = -1; spa->analyzers[0] = rtpp_analyzer_ctor(); spa->analyzers[1] = rtpp_analyzer_ctor(); append_session(cf, spa, 0); append_session(cf, spa, 1); spa->hte = CALL_METHOD(cf->stable->sessions_ht, append, spa->call_id, spa); if (spa->hte == NULL) { remove_session(cf, spa); remove_session(cf, spb); handle_nomem(cf, cmd, ECODE_NOMEM_8, ulop, fds, spa, spb); return (-1); } cf->sessions_created++; cf->sessions_active++; cmd->csp->nsess_created.cnt++; /* * Each session can consume up to 5 open file descriptors (2 RTP, * 2 RTCP and 1 logging) so that warn user when he is likely to * exceed 80% mark on hard limit. */ if (cf->sessions_active > (rtpp_rlim_max(cf) * 80 / (100 * 5)) && cf->nofile_limit_warned == 0) { cf->nofile_limit_warned = 1; rtpp_log_write(RTPP_LOG_WARN, cf->stable->glog, "passed 80%% " "threshold on the open file descriptors limit (%d), " "consider increasing the limit using -L command line " "option", (int)rtpp_rlim_max(cf)); } rtpp_log_write(RTPP_LOG_INFO, spa->log, "new session on a port %d created, " "tag %s", lport, cmd->cca.from_tag); if (cf->stable->record_all != 0) { handle_copy(cf, spa, 0, NULL, 0); handle_copy(cf, spa, 1, NULL, 0); } } if (cmd->cca.op == UPDATE) { if (rtpp_th_get_sn(cf->timeout_handler) == NULL && ulop->socket_name_u != NULL) rtpp_log_write(RTPP_LOG_ERR, spa->log, "must permit notification socket with -n"); if (spa->timeout_data.notify_tag != NULL) { free(spa->timeout_data.notify_tag); spa->timeout_data.notify_tag = NULL; } if (rtpp_th_get_sn(cf->timeout_handler) != NULL && ulop->socket_name_u != NULL) { if (strcmp(rtpp_th_get_sn(cf->timeout_handler), ulop->socket_name_u) != 0) { rtpp_log_write(RTPP_LOG_ERR, spa->log, "invalid socket name %s", ulop->socket_name_u); ulop->socket_name_u = NULL; } else { rtpp_log_write(RTPP_LOG_INFO, spa->log, "setting timeout handler"); spa->timeout_data.handler = cf->timeout_handler; spa->timeout_data.notify_tag = strdup(ulop->notify_tag); } } else if (ulop->socket_name_u == NULL && spa->timeout_data.handler != NULL) { spa->timeout_data.handler = NULL; rtpp_log_write(RTPP_LOG_INFO, spa->log, "disabling timeout handler"); } } if (ulop->ia[0] != NULL && ulop->ia[1] != NULL) { if (spa->addr[pidx] != NULL) spa->last_update[pidx] = cmd->dtime; if (spa->rtcp->addr[pidx] != NULL) spa->rtcp->last_update[pidx] = cmd->dtime; /* * Unless the address provided by client historically * cannot be trusted and address is different from one * that we recorded update it. */ if (spa->untrusted_addr[pidx] == 0 && !(spa->addr[pidx] != NULL && SA_LEN(ulop->ia[0]) == SA_LEN(spa->addr[pidx]) && memcmp(ulop->ia[0], spa->addr[pidx], SA_LEN(ulop->ia[0])) == 0)) { const char *obr, *cbr; if (ulop->pf == AF_INET) { obr = ""; cbr = ""; } else { obr = "["; cbr = "]"; } rtpp_log_write(RTPP_LOG_INFO, spa->log, "pre-filling %s's address " "with %s%s%s:%s", (pidx == 0) ? "callee" : "caller", obr, ulop->addr, cbr, ulop->port); if (spa->addr[pidx] != NULL) { if (spa->latch_info[pidx].latched != 0) { if (spa->prev_addr[pidx] != NULL) free(spa->prev_addr[pidx]); spa->prev_addr[pidx] = spa->addr[pidx]; } else { free(spa->addr[pidx]); } } spa->addr[pidx] = ulop->ia[0]; ulop->ia[0] = NULL; } if (spa->rtcp->untrusted_addr[pidx] == 0 && !(spa->rtcp->addr[pidx] != NULL && SA_LEN(ulop->ia[1]) == SA_LEN(spa->rtcp->addr[pidx]) && memcmp(ulop->ia[1], spa->rtcp->addr[pidx], SA_LEN(ulop->ia[1])) == 0)) { if (spa->rtcp->addr[pidx] != NULL) { if (spa->rtcp->latch_info[pidx].latched != 0) { if (spa->rtcp->prev_addr[pidx] != NULL) free(spa->rtcp->prev_addr[pidx]); spa->rtcp->prev_addr[pidx] = spa->rtcp->addr[pidx]; } else { free(spa->rtcp->addr[pidx]); } } spa->rtcp->addr[pidx] = ulop->ia[1]; ulop->ia[1] = NULL; } } spa->asymmetric[pidx] = spa->rtcp->asymmetric[pidx] = ulop->asymmetric; spa->latch_info[pidx].latched = spa->rtcp->latch_info[pidx].latched = ulop->asymmetric; if (spa->codecs[pidx] != NULL) { free(spa->codecs[pidx]); spa->codecs[pidx] = NULL; } if (ulop->codecs != NULL) { spa->codecs[pidx] = ulop->codecs; ulop->codecs = NULL; } if (ulop->requested_nsamples > 0) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "RTP packets from %s " "will be resized to %d milliseconds", (pidx == 0) ? "callee" : "caller", ulop->requested_nsamples / 8); } else if (spa->resizers[pidx] != NULL) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "Resizing of RTP " "packets from %s has been disabled", (pidx == 0) ? "callee" : "caller"); } if (ulop->requested_nsamples > 0) { if (spa->resizers[pidx] != NULL) { rtp_resizer_set_onsamples(spa->resizers[pidx], ulop->requested_nsamples); } else { spa->resizers[pidx] = rtp_resizer_new(ulop->requested_nsamples); } } else if (spa->resizers[pidx] != NULL) { rtp_resizer_free(cf->stable->rtpp_stats, spa->resizers[pidx]); spa->resizers[pidx] = NULL; } assert(lport != 0); ulop->reply.port = lport; ulop->reply.ia = ulop->lia[0]; if (cf->stable->advaddr[0] != NULL) { if (cf->stable->bmode != 0 && cf->stable->advaddr[1] != NULL && ulop->lia[0] == cf->stable->bindaddr[1]) { ulop->reply.ia_ov = cf->stable->advaddr[1]; } else { ulop->reply.ia_ov = cf->stable->advaddr[0]; } } ul_reply_port(cf, cmd, &ulop->reply); rtpp_command_ul_opts_free(ulop); return (0); err_undo_0: rtpp_command_ul_opts_free(ulop); return (-1); }