Beispiel #1
0
static void
rtpp_log_obj_setlevel(struct rtpp_log *self, int log_level)
{
    struct rtpp_log_priv *pvt;

    pvt = PUB2PVT(self);
    if (log_level != -1) {
        rtpp_log_setlevel(pvt->log, log_level);
    } else {
        rtpp_log_setlevel(pvt->log, RTPP_LOG_ERR);
    }
}
Beispiel #2
0
int
main(int argc, char **argv)
{
    int i, len, controlfd;
    double eval, clk;
    long long ncycles_ref, counter;
    double eptime;
    double add_delay;
    struct cfg cf;
    char buf[256];
    struct recfilter loop_error;
    struct PFD phase_detector;
    useconds_t usleep_time;
    struct sched_param sparam;
#if RTPP_DEBUG
    double sleep_time, filter_lastval;
#endif
    memset(&cf, 0, sizeof(cf));

    cf.stable = malloc(sizeof(struct rtpp_cfg_stable));
    if (cf.stable == NULL) {
         err(1, "can't allocate memory for the struct rtpp_cfg_stable");
         /* NOTREACHED */
    }
    memset(cf.stable, '\0', sizeof(struct rtpp_cfg_stable));

    init_config(&cf, argc, argv);

    seedrandom();

    cf.stable->sessions_ht = rtpp_hash_table_ctor();
    if (cf.stable->sessions_ht == NULL) {
        err(1, "can't allocate memory for the hash table");
         /* NOTREACHED */
    }
    cf.stable->rtpp_stats = rtpp_stats_ctor();
    if (cf.stable->rtpp_stats == NULL) {
        err(1, "can't allocate memory for the stats data");
         /* NOTREACHED */
    }
    init_port_table(&cf);

    controlfd = init_controlfd(&cf);

    if (cf.stable->nodaemon == 0) {
	if (rtpp_daemon(0, 0) == -1)
	    err(1, "can't switch into daemon mode");
	    /* NOTREACHED */
    }

    if (rtpp_notify_init() != 0)
        errx(1, "can't start notification thread");

    cf.stable->glog = rtpp_log_open(cf.stable, "rtpproxy", NULL, LF_REOPEN);
    rtpp_log_setlevel(cf.stable->glog, cf.stable->log_level);
    _sig_cf = &cf;
    atexit(ehandler);
    rtpp_log_write(RTPP_LOG_INFO, cf.stable->glog, "rtpproxy started, pid %d", getpid());

    i = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
    if (i >= 0) {
	len = sprintf(buf, "%u\n", (unsigned int)getpid());
	write(i, buf, len);
	close(i);
    } else {
	rtpp_log_ewrite(RTPP_LOG_ERR, cf.stable->glog, "can't open pidfile for writing");
    }

    signal(SIGHUP, sighup);
    signal(SIGINT, fatsignal);
    signal(SIGKILL, fatsignal);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGTERM, fatsignal);
    signal(SIGXCPU, fatsignal);
    signal(SIGXFSZ, fatsignal);
    signal(SIGVTALRM, fatsignal);
    signal(SIGPROF, fatsignal);
    signal(SIGUSR1, fatsignal);
    signal(SIGUSR2, fatsignal);

    if (cf.stable->sched_policy != SCHED_OTHER) {
        sparam.sched_priority = sched_get_priority_max(cf.stable->sched_policy);
        if (sched_setscheduler(0, cf.stable->sched_policy, &sparam) == -1) {
            rtpp_log_ewrite(RTPP_LOG_ERR, cf.stable->glog, "sched_setscheduler(SCHED_%s, %d)",
              (cf.stable->sched_policy == SCHED_FIFO) ? "FIFO" : "RR", sparam.sched_priority);
        }
    }

    if (cf.stable->run_uname != NULL || cf.stable->run_gname != NULL) {
	if (drop_privileges(&cf) != 0) {
	    rtpp_log_ewrite(RTPP_LOG_ERR, cf.stable->glog,
	      "can't switch to requested user/group");
	    exit(1);
	}
    }
    set_rlimits(&cf);

    cf.stable->controlfd = controlfd;

    cf.sessinfo.sessions[0] = NULL;
    cf.sessinfo.nsessions = 0;
    cf.rtp_nsessions = 0;

    rtpp_command_async_init(&cf);
    rtpp_proc_async_init(&cf);

    counter = 0;
    recfilter_init(&loop_error, 0.96, 0.0, 0);
    PFD_init(&phase_detector, 2.0);
    for (;;) {
	eptime = getdtime();

        clk = (eptime + cf.stable->sched_offset) * cf.stable->target_pfreq;

        ncycles_ref = llrint(clk);

        eval = PFD_get_error(&phase_detector, clk);

#if RTPP_DEBUG
        filter_lastval = loop_error.lastval;
#endif

        if (eval != 0.0) {
            recfilter_apply(&loop_error, sigmoid(eval));
        }

#if RTPP_DEBUG
        if (counter % (unsigned int)cf.stable->target_pfreq == 0 || counter < 1000) {
          rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld ncycles %f raw error1 %f, filter lastval %f, filter nextval %f",
            counter, clk, eval, filter_lastval, loop_error.lastval);
        }
#endif
        add_delay = freqoff_to_period(cf.stable->target_pfreq, 1.0, loop_error.lastval);
        usleep_time = add_delay * 1000000.0;
#if RTPP_DEBUG
        if (counter % (unsigned int)cf.stable->target_pfreq == 0 || counter < 1000) {
            rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld filter lastval %f, filter nextval %f, error %f",
              counter, filter_lastval, loop_error.lastval, sigmoid(eval));
            rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld extra sleeping time %llu", counter, usleep_time);
        }
        sleep_time = getdtime();
#endif
        rtpp_proc_async_wakeup(cf.stable->rtpp_proc_cf, counter, ncycles_ref);
        usleep(usleep_time);
#if RTPP_DEBUG
        sleep_time = getdtime() - sleep_time;
        if (counter % (unsigned int)cf.stable->target_pfreq == 0 || counter < 1000 || sleep_time > add_delay * 2.0) {
            rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld sleeping time required %llu sleeping time actual %f, CSV: %f,%f,%f", \
              counter, usleep_time, sleep_time, (double)counter / cf.stable->target_pfreq, ((double)usleep_time) / 1000.0, sleep_time * 1000.0);
        }
#endif
        counter += 1;
        if (cf.stable->slowshutdown != 0) {
            pthread_mutex_lock(&cf.sessinfo.lock);
            if (cf.sessinfo.nsessions == 0) {
                /* The below unlock is not necessary, but does not hurt either */
                pthread_mutex_unlock(&cf.sessinfo.lock);
                rtpp_log_write(RTPP_LOG_INFO, cf.stable->glog,
                  "deorbiting-burn sequence completed, exiting");
                break;
            }
            pthread_mutex_unlock(&cf.sessinfo.lock);
        }
    }

    exit(0);
}
Beispiel #3
0
int
rtpp_command_ul_handle(struct cfg *cf, struct rtpp_command *cmd,
  struct common_cmd_args *ccap, 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(ccap->op == UPDATE || ccap->op == LOOKUP);
        spa = sp;
        if (spa->fds[sidx] == -1) {
            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;
            }
            assert(spa->fds[sidx] == -1);
            spa->fds[sidx] = fds[0];
            assert(spa->rtcp->fds[sidx] == -1);
            spa->rtcp->fds[sidx] = fds[1];
            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;
            append_session(cf, spa, sidx);
        }
        if (ulop->weak)
            spa->weak[sidx] = 1;
        else if (ccap->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;
        spa->ttl[0] = cf->stable->max_ttl;
        spa->ttl[1] = cf->stable->max_ttl;
        if (ccap->op == UPDATE) {
            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]);
        }
        rtpp_log_write(RTPP_LOG_INFO, spa->log,
          "lookup on ports %d/%d, session timer restarted", spa->ports[0],
          spa->ports[1]);
    } else {
        assert(ccap->op == UPDATE);
        rtpp_log_write(RTPP_LOG_INFO, cf->stable->glog,
          "new session %s, tag %s requested, type %s",
          ccap->call_id, ccap->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(ccap->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(ccap->from_tag);
        spa->tag_nomedianum = strdup(ccap->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_ttl;
        spa->ttl[1] = cf->stable->max_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;

        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, ccap->from_tag);
        if (cf->stable->record_all != 0) {
            handle_copy(cf, spa, 0, NULL, 0);
            handle_copy(cf, spa, 1, NULL, 0);
        }
    }

    if (ccap->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)) {
            rtpp_log_write(RTPP_LOG_INFO, spa->log, "pre-filling %s's address "
              "with %s:%s", (pidx == 0) ? "callee" : "caller", ulop->addr, ulop->port);
            if (spa->addr[pidx] != NULL) {
                if (spa->canupdate[pidx] == 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->canupdate[pidx] == 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->canupdate[pidx] = spa->rtcp->canupdate[pidx] = NOT(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(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);
}