示例#1
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);
}
示例#2
0
static void
rtpp_cmd_queue_run(void *arg)
{
    struct rtpp_cmd_async_cf *cmd_cf;
    struct rtpp_cmd_pollset *psp;
    int i, nready, rval;
    double sptime;
#if 0
    double eptime, tused;
#endif
    struct rtpp_command_stats *csp;
    struct rtpp_stats_obj *rtpp_stats_cf;

    cmd_cf = (struct rtpp_cmd_async_cf *)arg;
    rtpp_stats_cf = cmd_cf->cf_save->stable->rtpp_stats;
    csp = &cmd_cf->cstats;

    psp = &cmd_cf->pset;

    for (;;) {
        sptime = getdtime();

        pthread_mutex_lock(&psp->pfds_mutex);
        if (psp->pfds_used == 0) {
            pthread_mutex_unlock(&psp->pfds_mutex);
            if (wait_next_clock(cmd_cf) == TSTATE_CEASE) {
                break;
            }
            continue;
        }
        nready = poll(psp->pfds, psp->pfds_used, 2);
        if (nready == 0) {
            pthread_mutex_unlock(&psp->pfds_mutex);
            if (wait_next_clock(cmd_cf) == TSTATE_CEASE) {
                break;
            }
            continue;
        }
        if (nready < 0 && errno == EINTR) {
            pthread_mutex_unlock(&psp->pfds_mutex);
            continue;
        }
        if (nready > 0) {
            for (i = 0; i < psp->pfds_used; i++) {
                if ((psp->pfds[i].revents & (POLLERR | POLLHUP)) != 0) {
                    if (RTPP_CTRL_ACCEPTABLE(psp->rccs[i]->csock)) {
                        goto closefd;
                    }
                    if (psp->rccs[i]->csock->type == RTPC_STDIO && (psp->pfds[i].revents & POLLIN) == 0) {
                        goto closefd;
                    }
                }
                if ((psp->pfds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (RTPP_CTRL_ISSTREAM(psp->rccs[i]->csock)) {
                    rval = process_commands_stream(cmd_cf->cf_save, psp->rccs[i], sptime, csp, rtpp_stats_cf);
                } else {
                    rval = process_commands(psp->rccs[i]->csock, cmd_cf->cf_save, psp->pfds[i].fd,
                      sptime, csp, rtpp_stats_cf, cmd_cf->rcache);
                }
                /*
                 * Shut down non-datagram sockets that got I/O error
                 * and also all non-continuous UNIX sockets are recycled
                 * after each use.
                 */
                if (!RTPP_CTRL_ISDG(psp->rccs[i]->csock) && (rval == -1 || !RTPP_CTRL_ISSTREAM(psp->rccs[i]->csock))) {
closefd:
                    if (psp->rccs[i]->csock->type == RTPC_STDIO && psp->rccs[i]->csock->exit_on_close != 0) {
                        cmd_cf->cf_save->stable->slowshutdown = 1;
                    }
                    rtpp_cmd_connection_dtor(psp->rccs[i]);
                    psp->pfds_used--;
                    if (psp->pfds_used > 0 && i < psp->pfds_used) {
                        memcpy(&psp->pfds[i], &psp->pfds[i + 1],
                          (psp->pfds_used - i) * sizeof(struct pollfd));
                        memcpy(&psp->rccs[i], &psp->rccs[i + 1],
                          (psp->pfds_used - i) * sizeof(struct rtpp_ctrl_connection *));
                    }
                }
            }
        }
        pthread_mutex_unlock(&psp->pfds_mutex);
        if (nready > 0) {
            rtpp_anetio_pump(cmd_cf->cf_save->stable->rtpp_netio_cf);
        }
#if 0
        eptime = getdtime();
        pthread_mutex_lock(&cmd_cf->cmd_mutex);
        recfilter_apply(&cmd_cf->average_load, (eptime - sptime + tused) * cmd_cf->cf_save->stable->target_pfreq);
        pthread_mutex_unlock(&cmd_cf->cmd_mutex);
#endif
        flush_cstats(rtpp_stats_cf, csp);
#if 0
#if RTPP_DEBUG
        if (last_ctick % (unsigned int)cmd_cf->cf_save->stable->target_pfreq == 0 || last_ctick < 1000) {
            rtpp_log_write(RTPP_LOG_DBUG, cmd_cf->cf_save->stable->glog, "rtpp_cmd_queue_run %lld sptime %f eptime %f, CSV: %f,%f,%f,%f,%f", \
              last_ctick, sptime, eptime, (double)last_ctick / cmd_cf->cf_save->stable->target_pfreq, \
              eptime - sptime + tused, eptime, sptime, tused);
            rtpp_log_write(RTPP_LOG_DBUG, cmd_cf->cf_save->stable->glog, "run %lld average load %f, CSV: %f,%f", last_ctick, \
              cmd_cf->average_load.lastval * 100.0, (double)last_ctick / cmd_cf->cf_save->stable->target_pfreq, cmd_cf->average_load.lastval);
        }
#endif
#endif
    }
}
示例#3
0
void
remove_session(struct cfg *cf, struct rtpp_session *sp)
{
    int i;

    /* Make sure structure is properly locked */
    assert(pthread_mutex_islocked(&cf->glock) == 1);
    assert(pthread_mutex_islocked(&cf->sessinfo.lock) == 1);

    rtpp_log_write(RTPP_LOG_INFO, sp->log, "RTP stats: %lu in from callee, %lu "
                   "in from caller, %lu relayed, %lu dropped", sp->pcount[0], sp->pcount[1],
                   sp->pcount[2], sp->pcount[3]);
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "RTCP stats: %lu in from callee, %lu "
                   "in from caller, %lu relayed, %lu dropped", sp->rtcp->pcount[0],
                   sp->rtcp->pcount[1], sp->rtcp->pcount[2], sp->rtcp->pcount[3]);
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "session on ports %d/%d is cleaned up",
                   sp->ports[0], sp->ports[1]);

    for (i = 0; i < 2; i++) {
        if (sp->addr[i] != NULL)
            free(sp->addr[i]);

        if (sp->prev_addr[i] != NULL)
            free(sp->prev_addr[i]);

        if (sp->rtcp->addr[i] != NULL)
            free(sp->rtcp->addr[i]);

        if (sp->rtcp->prev_addr[i] != NULL)
            free(sp->rtcp->prev_addr[i]);

        if (sp->fds[i] != -1) {
            close(sp->fds[i]);
            assert(cf->sessinfo.sessions[sp->sidx[i]] == sp);
            cf->sessinfo.sessions[sp->sidx[i]] = NULL;
            assert(cf->sessinfo.pfds[sp->sidx[i]].fd == sp->fds[i]);
            cf->sessinfo.pfds[sp->sidx[i]].fd = -1;
            cf->sessinfo.pfds[sp->sidx[i]].events = 0;
        }

        if (sp->rtcp->fds[i] != -1) {
            close(sp->rtcp->fds[i]);
            assert(cf->sessinfo.sessions[sp->rtcp->sidx[i]] == sp->rtcp);
            cf->sessinfo.sessions[sp->rtcp->sidx[i]] = NULL;
            assert(cf->sessinfo.pfds[sp->rtcp->sidx[i]].fd == sp->rtcp->fds[i]);
            cf->sessinfo.pfds[sp->rtcp->sidx[i]].fd = -1;
            cf->sessinfo.pfds[sp->rtcp->sidx[i]].events = 0;
        }

        if (sp->rrcs[i] != NULL)
            rclose(sp, sp->rrcs[i], 1);

        if (sp->rtcp->rrcs[i] != NULL)
            rclose(sp, sp->rtcp->rrcs[i], 1);

        if (sp->rtps[i] != NULL) {
            cf->rtp_servers[sp->sridx] = NULL;
            rtp_server_free(sp->rtps[i]);
        }

        if (sp->codecs[i] != NULL)
            free(sp->codecs[i]);

        if (sp->rtcp->codecs[i] != NULL)
            free(sp->rtcp->codecs[i]);
    }

    if (sp->timeout_data.notify_tag != NULL)
        free(sp->timeout_data.notify_tag);

    hash_table_remove(cf, sp);

    if (sp->call_id != NULL)
        free(sp->call_id);

    if (sp->tag != NULL)
        free(sp->tag);

    rtpp_log_close(sp->log);
    free(sp->rtcp);
    rtp_resizer_free(&sp->resizers[0]);
    rtp_resizer_free(&sp->resizers[1]);
    free(sp);
    cf->sessions_active--;
}
示例#4
0
struct ul_opts *
rtpp_command_ul_opts_parse(struct cfg *cf, struct rtpp_command *cmd,
  struct common_cmd_args *ccap)
{
    int len, tpf, n, i;
    char c;
    char *cp, *t;
    const char *errmsg;
    struct sockaddr_storage tia;
    struct ul_opts *ulop;

    ulop = malloc(sizeof(struct ul_opts));
    if (ulop == NULL) {
        reply_error(cf, cmd, ECODE_NOMEM_1);
        goto err_undo_0;
    }
    memset(ulop, '\0', sizeof(struct ul_opts));
    ul_opts_init(cf, ulop);
    if (ccap->op == UPDATE && cmd->argc > 6) {
        if (cmd->argc == 8) {
            ulop->socket_name_u = cmd->argv[6];
            ulop->notify_tag = cmd->argv[7];
        } else {
            ulop->socket_name_u = cmd->argv[5];
            ulop->notify_tag = cmd->argv[6];
            ccap->to_tag = NULL;
        }
        if (strncmp("unix:", ulop->socket_name_u, 5) == 0)
            ulop->socket_name_u += 5;
        len = url_unquote((uint8_t *)ulop->notify_tag, strlen(ulop->notify_tag));
        if (len == -1) {
            rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
              "command syntax error - invalid URL encoding");
            reply_error(cf, cmd, ECODE_PARSE_10);
            goto err_undo_1;
        }
        ulop->notify_tag[len] = '\0';
    }
    ulop->addr = cmd->argv[2];
    ulop->port = cmd->argv[3];
    /* Process additional command modifiers */
    for (cp = cmd->argv[0] + 1; *cp != '\0'; cp++) {
        switch (*cp) {
        case 'a':
        case 'A':
            ulop->asymmetric = 1;
            break;

        case 'e':
        case 'E':
            if (ulop->lidx < 0) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_11);
                goto err_undo_1;
            }
            ulop->lia[ulop->lidx] = cf->stable->bindaddr[1];
            ulop->lidx--;
            break;

        case 'i':
        case 'I':
            if (ulop->lidx < 0) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_12);
                goto err_undo_1;
            }
            ulop->lia[ulop->lidx] = cf->stable->bindaddr[0];
            ulop->lidx--;
            break;

        case '6':
            ulop->pf = AF_INET6;
            break;

        case 's':
        case 'S':
            ulop->asymmetric = 0;
            break;

        case 'w':
        case 'W':
            ulop->weak = 1;
            break;

        case 'z':
        case 'Z':
            ulop->requested_nsamples = (strtol(cp + 1, &cp, 10) / 10) * 80;
            if (ulop->requested_nsamples <= 0) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_13);
                goto err_undo_1;
            }
            cp--;
            break;

        case 'c':
        case 'C':
            cp += 1;
            for (t = cp; *cp != '\0'; cp++) {
                if (!isdigit(*cp) && *cp != ',')
                    break;
            }
            if (t == cp) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_14);
                goto err_undo_1;
            }
            ulop->codecs = malloc(cp - t + 1);
            if (ulop->codecs == NULL) {
                reply_error(cf, cmd, ECODE_NOMEM_2);
                goto err_undo_1;
            }
            memcpy(ulop->codecs, t, cp - t);
            ulop->codecs[cp - t] = '\0';
            cp--;
            break;

        case 'l':
        case 'L':
            len = extractaddr(cp + 1, &t, &cp, &tpf);
            if (len == -1) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_15);
                goto err_undo_1;
            }
            c = t[len];
            t[len] = '\0';
            pthread_mutex_unlock(&cf->glock);
            ulop->local_addr = host2bindaddr(cf, t, tpf, &errmsg);
            pthread_mutex_lock(&cf->glock);
            if (ulop->local_addr == NULL) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
                  "invalid local address: %s: %s", t, errmsg);
                reply_error(cf, cmd, ECODE_INVLARG_1);
                goto err_undo_1;
            }
            t[len] = c;
            cp--;
            break;

        case 'r':
        case 'R':
            len = extractaddr(cp + 1, &t, &cp, &tpf);
            if (len == -1) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_16);
                goto err_undo_1;
            }
            c = t[len];
            t[len] = '\0';
            ulop->local_addr = alloca(sizeof(struct sockaddr_storage));
            pthread_mutex_unlock(&cf->glock);
            n = resolve(ulop->local_addr, tpf, t, SERVICE, AI_PASSIVE);
            pthread_mutex_lock(&cf->glock);
            if (n != 0) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
                  "invalid remote address: %s: %s", t, gai_strerror(n));
                reply_error(cf, cmd, ECODE_INVLARG_2);
                goto err_undo_1;
            }
            if (local4remote(ulop->local_addr, satoss(ulop->local_addr)) == -1) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
                  "can't find local address for remote address: %s", t);
                reply_error(cf, cmd, ECODE_INVLARG_3);
                goto err_undo_1;
            }
            ulop->local_addr = addr2bindaddr(cf, ulop->local_addr, &errmsg);
            if (ulop->local_addr == NULL) {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
                  "invalid local address: %s", errmsg);
                reply_error(cf, cmd, ECODE_INVLARG_4);
                goto err_undo_1;
            }
            t[len] = c;
            cp--;
            break;

        default:
            rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "unknown command modifier `%c'",
              *cp);
            break;
        }
    }
    if (ulop->addr != NULL && ulop->port != NULL && strlen(ulop->addr) >= 7) {
        pthread_mutex_unlock(&cf->glock);
        n = resolve(sstosa(&tia), ulop-> pf, ulop->addr, ulop->port, AI_NUMERICHOST);
        pthread_mutex_lock(&cf->glock);
        if (n == 0) {
            if (!ishostnull(sstosa(&tia))) {
                for (i = 0; i < 2; i++) {
                    ulop->ia[i] = malloc(SS_LEN(&tia));
                    if (ulop->ia[i] == NULL) {
                        reply_error(cf, cmd, ECODE_NOMEM_3);
                        goto err_undo_1;
                    }
                    memcpy(ulop->ia[i], &tia, SS_LEN(&tia));
                }
                /* Set port for RTCP, will work both for IPv4 and IPv6 */
                n = ntohs(satosin(ulop->ia[1])->sin_port);
                satosin(ulop->ia[1])->sin_port = htons(n + 1);
            }
        } else {
            rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "getaddrinfo: %s",
              gai_strerror(n));
        }
    }
    return (ulop);

err_undo_1:
    rtpp_command_ul_opts_free(ulop);
err_undo_0:
    return (NULL);
}
示例#5
0
static void
process_rtp(struct cfg *cf, double dtime, int alarm_tick)
{
    int readyfd, skipfd, ridx;
    struct rtpp_session *sp;
    struct rtp_packet *packet;

    /* Relay RTP/RTCP */
    skipfd = 0;
    pthread_mutex_lock(&cf->sessinfo.lock);
    for (readyfd = 0; readyfd < cf->sessinfo.nsessions; readyfd++) {
	sp = cf->sessinfo.sessions[readyfd];

	if (alarm_tick != 0 && sp != NULL && sp->rtcp != NULL &&
	  sp->sidx[0] == readyfd) {
	    if (get_ttl(sp) == 0) {
		rtpp_log_write(RTPP_LOG_INFO, sp->log, "session timeout");
		rtpp_notify_schedule(cf, sp);
		remove_session(cf, sp);
	    } else {
		if (sp->ttl[0] != 0)
		    sp->ttl[0]--;
		if (sp->ttl[1] != 0)
		    sp->ttl[1]--;
	    }
	}

	if (cf->sessinfo.pfds[readyfd].fd == -1) {
	    /* Deleted session, count and move one */
	    skipfd++;
	    continue;
	}

	/* Find index of the call leg within a session */
	for (ridx = 0; ridx < 2; ridx++)
	    if (cf->sessinfo.pfds[readyfd].fd == sp->fds[ridx])
		break;
	/*
	 * Can't happen.
	 */
	assert(ridx != 2);

	/* Compact pfds[] and sessions[] by eliminating removed sessions */
	if (skipfd > 0) {
	    cf->sessinfo.pfds[readyfd - skipfd] = cf->sessinfo.pfds[readyfd];
	    cf->sessinfo.sessions[readyfd - skipfd] = cf->sessinfo.sessions[readyfd];
	    sp->sidx[ridx] = readyfd - skipfd;
	}

	if (sp->complete != 0) {
	    if ((cf->sessinfo.pfds[readyfd].revents & POLLIN) != 0)
		rxmit_packets(cf, sp, ridx, dtime);
	    if (sp->resizers[ridx].output_nsamples > 0) {
		while ((packet = rtp_resizer_get(&sp->resizers[ridx], dtime)) != NULL) {
		    send_packet(cf, sp, ridx, packet);
		    rtp_packet_free(packet);
		}
	    }
	}
    }
    /* Trim any deleted sessions at the end */
    cf->sessinfo.nsessions -= skipfd;
    pthread_mutex_unlock(&cf->sessinfo.lock);
}
示例#6
0
void
remove_session(struct cfg *cf, struct rtpp_session *sp)
{
    int i;
    double session_time;

    session_time = getdtime() - sp->init_ts;
    /* Make sure structure is properly locked */
    assert(pthread_mutex_islocked(&cf->glock) == 1);
    assert(pthread_mutex_islocked(&cf->sessinfo.lock) == 1);

    rtpp_log_write(RTPP_LOG_INFO, sp->log, "RTP stats: %lu in from callee, %lu "
      "in from caller, %lu relayed, %lu dropped", sp->pcount[0], sp->pcount[1],
      sp->pcount[2], sp->pcount[3]);
    if (sp->pcount[0] == 0 && sp->pcount[1] == 0) {
        CALL_METHOD(cf->stable->rtpp_stats, updatebyname, "nsess_nortp", 1);
    } else if (sp->pcount[0] == 0 || sp->pcount[1] == 0) {
        CALL_METHOD(cf->stable->rtpp_stats, updatebyname, "nsess_owrtp", 1);
    }
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "RTCP stats: %lu in from callee, %lu "
      "in from caller, %lu relayed, %lu dropped", sp->rtcp->pcount[0],
      sp->rtcp->pcount[1], sp->rtcp->pcount[2], sp->rtcp->pcount[3]);
    if (sp->rtcp->pcount[0] == 0 && sp->rtcp->pcount[1] == 0) {
        CALL_METHOD(cf->stable->rtpp_stats, updatebyname, "nsess_nortcp", 1);
    } else if (sp->rtcp->pcount[0] == 0 || sp->rtcp->pcount[1] == 0) {
        CALL_METHOD(cf->stable->rtpp_stats, updatebyname, "nsess_owrtcp", 1);
    }
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "session on ports %d/%d is cleaned up",
      sp->ports[0], sp->ports[1]);
    for (i = 0; i < 2; i++) {
	if (sp->addr[i] != NULL)
	    free(sp->addr[i]);
	if (sp->prev_addr[i] != NULL)
	    free(sp->prev_addr[i]);
	if (sp->rtcp->addr[i] != NULL)
	    free(sp->rtcp->addr[i]);
	if (sp->rtcp->prev_addr[i] != NULL)
	    free(sp->rtcp->prev_addr[i]);
	if (sp->fds[i] != -1) {
	    shutdown(sp->fds[i], SHUT_RDWR);
	    close(sp->fds[i]);
	    assert(cf->sessinfo.sessions[sp->sidx[i]] == sp);
	    cf->sessinfo.sessions[sp->sidx[i]] = NULL;
	    assert(cf->sessinfo.pfds_rtp[sp->sidx[i]].fd == sp->fds[i]);
	    cf->sessinfo.pfds_rtp[sp->sidx[i]].fd = -1;
	    cf->sessinfo.pfds_rtp[sp->sidx[i]].events = 0;
	}
	if (sp->rtcp->fds[i] != -1) {
	    shutdown(sp->rtcp->fds[i], SHUT_RDWR);
	    close(sp->rtcp->fds[i]);
	    assert(cf->sessinfo.pfds_rtcp[sp->rtcp->sidx[i]].fd == sp->rtcp->fds[i]);
	    cf->sessinfo.pfds_rtcp[sp->rtcp->sidx[i]].fd = -1;
	    cf->sessinfo.pfds_rtcp[sp->rtcp->sidx[i]].events = 0;
	}
	if (sp->rrcs[i] != NULL) {
	    rclose(sp, sp->rrcs[i], 1);
            if (sp->record_single_file != 0) {
                sp->rtcp->rrcs[i] = NULL;
                sp->rrcs[NOT(i)] = NULL;
                sp->rtcp->rrcs[NOT(i)] = NULL;
            }
        }
	if (sp->rtcp->rrcs[i] != NULL)
	    rclose(sp, sp->rtcp->rrcs[i], 1);
	if (sp->rtps[i] != NULL) {
	    cf->rtp_servers[sp->sridx] = NULL;
	    rtp_server_free(sp->rtps[i]);
	}
	if (sp->codecs[i] != NULL)
	    free(sp->codecs[i]);
	if (sp->rtcp->codecs[i] != NULL)
	    free(sp->rtcp->codecs[i]);
        if (sp->resizers[i] != NULL)
             rtp_resizer_free(sp->resizers[i]);
    }
    if (sp->timeout_data.notify_tag != NULL)
	free(sp->timeout_data.notify_tag);
    if (sp->hte != NULL)
        CALL_METHOD(cf->stable->sessions_ht, remove, sp->call_id, sp->hte);
    if (sp->call_id != NULL)
	free(sp->call_id);
    if (sp->tag != NULL)
	free(sp->tag);
    if (sp->tag_nomedianum != NULL)
	free(sp->tag_nomedianum);
    rtpp_log_close(sp->log);
    free(sp->rtcp);
    free(sp);
    cf->sessions_active--;
    CALL_METHOD(cf->stable->rtpp_stats, updatebyname, "nsess_destroyed", 1);
    CALL_METHOD(cf->stable->rtpp_stats, updatebyname_d, "total_duration",
      session_time);
}
示例#7
0
int
handle_command(struct cfg *cf, struct rtpp_command *cmd)
{
    int i, verbose, rval;
    int playcount;
    char *cp, *tcp;
    char *pname, *codecs, *recording_name;
    struct rtpp_session *spa;
    int record_single_file;
    struct ul_opts *ulop;
    struct d_opts dopt;

    spa = NULL;
    recording_name = NULL;
    codecs = NULL;

    /* Step II: parse parameters that are specific to a particular op and run simple ops */
    switch (cmd->cca.op) {
    case VER_FEATURE:
        handle_ver_feature(cf, cmd);
        return 0;

    case GET_VER:
        /* This returns base version. */
        reply_number(cf, cmd, CPROTOVER);
        return 0;

    case DELETE_ALL:
        /* Delete all active sessions */
        rtpp_log_write(RTPP_LOG_INFO, cf->stable->glog, "deleting all active sessions");
        pthread_mutex_lock(&cf->sessinfo.lock);
        for (i = 0; i < cf->sessinfo.nsessions; i++) {
            spa = cf->sessinfo.sessions[i];
            if (spa == NULL || spa->sidx[0] != i)
                continue;
            remove_session(cf, spa);
        }
        pthread_mutex_unlock(&cf->sessinfo.lock);
        reply_ok(cf, cmd);
        return 0;

    case INFO:
        handle_info(cf, cmd, &cmd->argv[0][1]);
        return 0;

    case PLAY:
        /*
         * P callid pname codecs from_tag to_tag
         *
         *   <codecs> could be either comma-separated list of supported
         *   payload types or word "session" (without quotes), in which
         *   case list saved on last session update will be used instead.
         */
        playcount = 1;
        pname = cmd->argv[2];
        codecs = cmd->argv[3];
        tcp = &(cmd->argv[0][1]);
	if (*tcp != '\0') {
	    playcount = strtol(tcp, &cp, 10);
            if (cp == tcp || *cp != '\0') {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_6);
                return 0;
            }
        }
        break;

    case COPY:
        recording_name = cmd->argv[2];
        /* Fallthrough */
    case RECORD:
        if (cmd->argv[0][1] == 'S' || cmd->argv[0][1] == 's') {
            if (cmd->argv[0][2] != '\0') {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_2);
                return 0;
            }
            record_single_file = (cf->stable->record_pcap == 0) ? 0 : 1;
        } else {
            if (cmd->argv[0][1] != '\0') {
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
                reply_error(cf, cmd, ECODE_PARSE_3);
                return 0;
            }
            record_single_file = 0;
        }
        break;

    case DELETE:
        /* D[w] call_id from_tag [to_tag] */
        dopt.weak = 0;
        for (cp = cmd->argv[0] + 1; *cp != '\0'; cp++) {
            switch (*cp) {
            case 'w':
            case 'W':
                dopt.weak = 1;
                break;

            default:
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
                  "DELETE: unknown command modifier `%c'", *cp);
                reply_error(cf, cmd, ECODE_PARSE_4);
                return 0;
            }
        }
        break;

    case UPDATE:
    case LOOKUP:
        ulop = rtpp_command_ul_opts_parse(cf, cmd);
        if (ulop == NULL) {
            return 0;
        }
	break;

    case GET_STATS:
        verbose = 0;
        for (cp = cmd->argv[0] + 1; *cp != '\0'; cp++) {
            switch (*cp) {
            case 'v':
            case 'V':
                verbose = 1;
                break;

            default:
                rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog,
                  "STATS: unknown command modifier `%c'", *cp);
                reply_error(cf, cmd, ECODE_PARSE_5);
                return 0;
            }
        }
        i = handle_get_stats(cf, cmd, verbose);
        if (i != 0) {
            reply_error(cf, cmd, i);
        }
        return 0;

    default:
        break;
    }

    /*
     * Record and delete need special handling since they apply to all
     * streams in the session.
     */
    switch (cmd->cca.op) {
    case DELETE:
	i = handle_delete(cf, &cmd->cca, dopt.weak);
	break;

    case RECORD:
	i = handle_record(cf, &cmd->cca, record_single_file);
	break;

    default:
	i = find_stream(cf, cmd->cca.call_id, cmd->cca.from_tag, cmd->cca.to_tag, &spa);
	if (i != -1 && cmd->cca.op != UPDATE)
	    i = NOT(i);
	break;
    }

    if (i == -1 && cmd->cca.op != UPDATE) {
	rtpp_log_write(RTPP_LOG_INFO, cf->stable->glog,
	  "%s request failed: session %s, tags %s/%s not found", cmd->cca.rname,
	  cmd->cca.call_id, cmd->cca.from_tag, cmd->cca.to_tag != NULL ? cmd->cca.to_tag : "NONE");
	if (cmd->cca.op == LOOKUP) {
            rtpp_command_ul_opts_free(ulop);
	    ul_reply_port(cf, cmd, NULL);
	    return 0;
	}
	reply_error(cf, cmd, ECODE_SESUNKN);
	return 0;
    }

    switch (cmd->cca.op) {
    case DELETE:
    case RECORD:
	reply_ok(cf, cmd);
	break;

    case NOPLAY:
	handle_noplay(cf, spa, i, cmd);
	reply_ok(cf, cmd);
	break;

    case PLAY:
	handle_noplay(cf, spa, i, cmd);
	if (strcmp(codecs, "session") == 0) {
	    if (spa->codecs[i] == NULL) {
		reply_error(cf, cmd, ECODE_INVLARG_5);
		return 0;
	    }
	    codecs = spa->codecs[i];
	}
	if (playcount != 0 && handle_play(cf, spa, i, codecs, pname, playcount, cmd) != 0) {
	    reply_error(cf, cmd, ECODE_PLRFAIL);
	    return 0;
	}
	reply_ok(cf, cmd);
	break;

    case COPY:
	if (handle_copy(cf, spa, i, recording_name, record_single_file) != 0) {
            reply_error(cf, cmd, ECODE_CPYFAIL);
            return 0;
        }
	reply_ok(cf, cmd);
	break;

    case QUERY:
	rval = handle_query(cf, cmd, spa, i);
	if (rval != 0) {
	    reply_error(cf, cmd, rval);
	}
	break;

    case LOOKUP:
    case UPDATE:
        rtpp_command_ul_handle(cf, cmd, ulop, spa, i);
	break;

    default:
	/* Programmatic error, should not happen */
	abort();
    }

    return 0;
}
示例#8
0
void *
ropen(struct cfg *cf, struct rtpp_session *sp, char *rname, int orig)
{
    struct rtpp_record_channel *rrc;
    const char *sdir, *suffix1, *suffix2;
    char *cp, *tmp;
    int n, port, rval, remote;
    struct sockaddr_storage raddr;
    pcap_hdr_t pcap_hdr;

    remote = (rname != NULL && strncmp("udp:", rname, 4) == 0) ? 1 : 0;

    rrc = malloc(sizeof(*rrc));
    if (rrc == NULL) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't allocate memory");
	return NULL;
    }
    memset(rrc, 0, sizeof(*rrc));

    if (remote) {
	tmp = strdup(rname + 4);
	if (tmp == NULL) {
	    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't allocate memory");
	    return NULL;
	}
	rrc->mode = MODE_REMOTE_RTP;
	rrc->needspool = 0;
	cp = strrchr(tmp, ':');
	if (cp == NULL) {
	    rtpp_log_write(RTPP_LOG_ERR, sp->log, "remote recording target specification should include port number");
	    free(rrc);
	    free(tmp);
	    return NULL;
	}
	*cp = '\0';
	cp++;

	if (sp->rtcp == NULL) {
	    /* Handle RTCP (increase target port by 1) */
	    port = atoi(cp);
	    if (port <= 0 || port > ((sp->rtcp != NULL) ? 65534 : 65535)) {
		rtpp_log_write(RTPP_LOG_ERR, sp->log, "invalid port in the remote recording target specification");
		free(rrc);
		free(tmp);
		return NULL;
	    }
	    sprintf(cp, "%d", port + 1);
	}

	n = resolve(sstosa(&raddr), AF_INET, tmp, cp, AI_PASSIVE);
	if (n != 0) {
	    rtpp_log_write(RTPP_LOG_ERR, sp->log, "ropen: getaddrinfo: %s", gai_strerror(n));
	    free(rrc);
	    free(tmp);
	    return NULL;
	}
	rrc->fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (rrc->fd == -1) {
	    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "ropen: can't create socket");
	    free(rrc);
	    free(tmp);
	    return NULL;
	}
	if (connect(rrc->fd, sstosa(&raddr), SA_LEN(sstosa(&raddr))) == -1) {
	    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "ropen: can't connect socket");
	    close(rrc->fd);
	    free(rrc);
	    free(tmp);
	    return NULL;
	}
	free(tmp);
	return (void *)(rrc);
    }

    if (cf->stable.rdir == NULL) {
	rtpp_log_write(RTPP_LOG_ERR, sp->log, "directory for saving local recordings is not configured");
	free(rrc);
	return NULL;
    }

    if (cf->stable.record_pcap != 0) {
	rrc->mode = MODE_LOCAL_PCAP;
    } else {
	rrc->mode = MODE_LOCAL_PKT;
    }

    if (sp->record_single_file != 0) {
        suffix1 = suffix2 = "";
    } else {
        suffix1 = (orig != 0) ? ".o" : ".a";
        suffix2 = (sp->rtcp != NULL) ? ".rtp" : ".rtcp";
    }
    if (cf->stable.sdir == NULL) {
	sdir = cf->stable.rdir;
	rrc->needspool = 0;
    } else {
	sdir = cf->stable.sdir;
	rrc->needspool = 1;
	if (rname == NULL) {
	    sprintf(rrc->rpath, "%s/%s=%s%s%s", cf->stable.rdir, sp->call_id, sp->tag_nomedianum,
	      suffix1, suffix2);
	} else {
	    sprintf(rrc->rpath, "%s/%s%s", cf->stable.rdir, rname, suffix2);
	}
    }
    if (rname == NULL) {
	sprintf(rrc->spath, "%s/%s=%s%s%s", sdir, sp->call_id, sp->tag_nomedianum,
	  suffix1, suffix2);
    } else {
	sprintf(rrc->spath, "%s/%s%s", sdir, rname, suffix2);
    }
    rrc->fd = open(rrc->spath, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
    if (rrc->fd == -1) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't open file %s for writing",
	  rrc->spath);
	free(rrc);
	return NULL;
    }

    if (rrc->mode == MODE_LOCAL_PCAP) {
	pcap_hdr.magic_number = PCAP_MAGIC;
	pcap_hdr.version_major = PCAP_VER_MAJR;
	pcap_hdr.version_minor = PCAP_VER_MINR;
	pcap_hdr.thiszone = 0;
	pcap_hdr.sigfigs = 0;
	pcap_hdr.snaplen = 65535;
	pcap_hdr.network = PCAP_FORMAT;
	rval = write(rrc->fd, &pcap_hdr, sizeof(pcap_hdr));
	if (rval == -1) {
	    close(rrc->fd);
	    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "%s: error writing header",
	      rrc->spath);
	    free(rrc);
	    return NULL;
	}
	if (rval < sizeof(pcap_hdr)) {
	    close(rrc->fd);
	    rtpp_log_write(RTPP_LOG_ERR, sp->log, "%s: short write writing header",
	      rrc->spath);
	    free(rrc);
	    return NULL;
	}
    }

    return (void *)(rrc);
}
示例#9
0
int
get_command(struct cfg_stable *cfs, int controlfd, struct rtpp_command *cmd)
{
    char **ap;
    char *cp;
    int len, i;

    if (cfs->umode == 0) {
        for (;;) {
            len = read(controlfd, cmd->buf, sizeof(cmd->buf) - 1);

            if (len != -1 || (errno != EAGAIN && errno != EINTR))
                break;

            sched_yield();
        }
    } else {
        cmd->rlen = sizeof(cmd->raddr);
        len = recvfrom(controlfd, cmd->buf, sizeof(cmd->buf) - 1, 0,
                       sstosa(&cmd->raddr), &cmd->rlen);
    }

    if (len == -1) {
        if (errno != EAGAIN && errno != EINTR)
            rtpp_log_ewrite(RTPP_LOG_ERR, cfs->glog, "can't read from control socket");

        return (-1);
    }

    cmd->buf[len] = '\0';

    rtpp_log_write(RTPP_LOG_DBUG, cfs->glog, "received command \"%s\"", cmd->buf);

    cp = cmd->buf;
    cmd->argc = 0;
    memset(cmd->argv, 0, sizeof(cmd->argv));

    for (ap = cmd->argv; (*ap = rtpp_strsep(&cp, "\r\n\t ")) != NULL;)
        if (**ap != '\0') {
            cmd->argc++;

            if (++ap >= &cmd->argv[10])
                break;
        }

    cmd->cookie = NULL;

    if (cmd->argc < 1 || (cfs->umode != 0 && cmd->argc < 2)) {
        rtpp_log_write(RTPP_LOG_ERR, cfs->glog, "command syntax error");
        reply_error(cfs, controlfd, cmd, 0);
        return (0);
    }

    /* Stream communication mode doesn't use cookie */
    if (cfs->umode != 0) {
        cmd->cookie = cmd->argv[0];

        for (i = 1; i < cmd->argc; i++)
            cmd->argv[i - 1] = cmd->argv[i];

        cmd->argc--;
        cmd->argv[cmd->argc] = NULL;
    } else {
        cmd->cookie = NULL;
    }

    return (cmd->argc);
}
示例#10
0
struct rtpp_command *
get_command(struct cfg *cf, int controlfd, int *rval, double dtime,
  struct rtpp_command_stats *csp, int umode,
  struct rtpp_cmd_rcache_obj *rcache_obj)
{
    char **ap;
    char *cp;
    int len, i;
    struct rtpp_command *cmd;

    cmd = malloc(sizeof(struct rtpp_command));
    if (cmd == NULL) {
        *rval = ENOMEM;
        return (NULL);
    }
    memset(cmd, 0, sizeof(struct rtpp_command));
    cmd->controlfd = controlfd;
    cmd->dtime = dtime;
    cmd->csp = csp;
    cmd->umode = umode;
    if (umode == 0) {
        for (;;) {
            len = read(controlfd, cmd->buf, sizeof(cmd->buf) - 1);
            if (len != -1 || (errno != EAGAIN && errno != EINTR))
                break;
        }
    } else {
        cmd->rlen = sizeof(cmd->raddr);
        len = recvfrom(controlfd, cmd->buf, sizeof(cmd->buf) - 1, 0,
          sstosa(&cmd->raddr), &cmd->rlen);
    }
    if (len == -1) {
        if (errno != EAGAIN && errno != EINTR)
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable->glog, "can't read from control socket");
        free(cmd);
        *rval = -1;
        return (NULL);
    }
    cmd->buf[len] = '\0';

    rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "received command \"%s\"", cmd->buf);
    csp->ncmds_rcvd.cnt++;

    cp = cmd->buf;
    for (ap = cmd->argv; (*ap = rtpp_strsep(&cp, "\r\n\t ")) != NULL;) {
        if (**ap != '\0') {
            cmd->argc++;
            if (++ap >= &cmd->argv[RTPC_MAX_ARGC])
                break;
        }
    }
    if (cmd->argc < 1 || (umode != 0 && cmd->argc < 2)) {
        rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
        reply_error(cf, cmd, ECODE_PARSE_1);
        *rval = 0;
        free(cmd);
        return (NULL);
    }

    /* Stream communication mode doesn't use cookie */
    if (umode != 0) {
        cmd->cookie = cmd->argv[0];
        if (CALL_METHOD(rcache_obj, lookup, cmd->cookie, cmd->buf_r, sizeof(cmd->buf_r)) == 1) {
            len = strlen(cmd->buf_r);
            rtpp_anetio_sendto(cf->stable->rtpp_netio_cf, cmd->controlfd, cmd->buf_r, len, 0,
              sstosa(&cmd->raddr), cmd->rlen);
            csp->ncmds_rcvd.cnt--;
            csp->ncmds_rcvd_ndups.cnt++;
            *rval = 0;
            free(cmd);
            return (NULL);
        }
        cmd->rcache_obj = rcache_obj;
        for (i = 1; i < cmd->argc; i++)
            cmd->argv[i - 1] = cmd->argv[i];
        cmd->argc--;
        cmd->argv[cmd->argc] = NULL;
    }

    /* Step I: parse parameters that are common to all ops */
    if (rtpp_command_pre_parse(cf, cmd) != 0) {
        /* Error reply is handled by the rtpp_command_pre_parse() */
        *rval = 0;
        free(cmd);
        return (NULL);
    }

    return (cmd);
}
示例#11
0
void
remove_session(struct cfg *cf, struct rtpp_session *sp)
{

    int i;

    rtpp_log_write(RTPP_LOG_INFO, sp->log, "RTP stats: %lu in from callee, %lu "
                   "in from caller, %lu relayed, %lu dropped", sp->pcount[0], sp->pcount[1],
                   sp->pcount[2], sp->pcount[3]);
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "RTCP stats: %lu in from callee, %lu "
                   "in from caller, %lu relayed, %lu dropped", sp->rtcp->pcount[0],
                   sp->rtcp->pcount[1], sp->rtcp->pcount[2], sp->rtcp->pcount[3]);
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "session on ports %d/%d is cleaned up",
                   sp->ports[0], sp->ports[1]);

    for (i = 0; i < 2; i++)
    {
        if (sp->addr[i] != NULL)
            free(sp->addr[i]);
        if (sp->prev_addr[i] != NULL)
            free(sp->prev_addr[i]);
        if (sp->rtcp->addr[i] != NULL)
            free(sp->rtcp->addr[i]);
        if (sp->rtcp->prev_addr[i] != NULL)
            free(sp->rtcp->prev_addr[i]);
        //if(sp->stream[i]->bio != NULL) {
        //    BIO_free(sp->stream[i]->bio);
        //}
        if (sp->stream[i] != NULL)
        {
            rtpp_dtls_free_stream(sp->stream[i]);
        }
        if (sp->rtcp->stream[i] != NULL)
        {
            rtpp_dtls_free_stream(sp->rtcp->stream[i]);
        }
        if (sp->fds[i] != -1)
        {
            close(sp->fds[i]);
            assert(cf->sessions[sp->sidx[i]] == sp);
            cf->sessions[sp->sidx[i]] = NULL;
            assert(cf->pfds[sp->sidx[i]].fd == sp->fds[i]);
            cf->pfds[sp->sidx[i]].fd = -1;
            cf->pfds[sp->sidx[i]].events = 0;
        }
        if (sp->rtcp->fds[i] != -1)
        {
            close(sp->rtcp->fds[i]);
            assert(cf->sessions[sp->rtcp->sidx[i]] == sp->rtcp);
            cf->sessions[sp->rtcp->sidx[i]] = NULL;
            assert(cf->pfds[sp->rtcp->sidx[i]].fd == sp->rtcp->fds[i]);
            cf->pfds[sp->rtcp->sidx[i]].fd = -1;
            cf->pfds[sp->rtcp->sidx[i]].events = 0;
        }
        if (sp->rrcs[i] != NULL)
            rclose(sp, sp->rrcs[i], 1);
        if (sp->rtcp->rrcs[i] != NULL)
            rclose(sp, sp->rtcp->rrcs[i], 1);
        if (sp->rtps[i] != NULL)
        {
            cf->rtp_servers[sp->sridx] = NULL;
            rtp_server_free(sp->rtps[i]);
        }
        if (sp->codecs[i] != NULL)
            free(sp->codecs[i]);
        if (sp->rtcp->codecs[i] != NULL)
            free(sp->rtcp->codecs[i]);
        if (sp->bridgeBindAddr[i] != NULL) // VLAN Support (FRN4811)
            free(sp->bridgeBindAddr[i]);

        if (sp->ice_u[i] != NULL)
        {
            if (sp->ice_u[i]->local_user_name != NULL)
                free(sp->ice_u[i]->local_user_name);
            if (sp->ice_u[i]->local_password != NULL)
                free(sp->ice_u[i]->local_password);

            if (sp->ice_u[i]->remote_user_name != NULL)
                free(sp->ice_u[i]->remote_user_name);
            if (sp->ice_u[i]->remote_password != NULL)
                free(sp->ice_u[i]->remote_password);

            free(sp->ice_u[i]); 
        }

        if (sp->ice_candidate_list[i] != NULL) // ICE remote candidate support
            delete_ice_candidate(sp, i);
        if (sp->rtcp->ice_candidate_list[i] != NULL)
            delete_ice_candidate(sp->rtcp, i);
        if (sp->transcode)
            rtp_transcoder_free(&sp->trans[i],cf);
        if (sp->secure)
        {
            rtpp_srtp_free_context(&sp->srtp[i]);
            rtpp_srtp_free_context(&sp->rtcp->srtp[i]);
        }
        rtp_resizer_free(&sp->resizers[i]);

    }// for
    rtpp_stun_agent_remove(sp); //Remove stun agent Context.

    remove_session_frm_active_rsz_lst(sp);
    rtpp_log_write(RTPP_LOG_INFO, sp->log, "timed resizer lists cleaned up");


    if (sp->timeout_data.notify_tag != NULL)
        free(sp->timeout_data.notify_tag);
    hash_table_remove(cf, sp);
    if (sp->call_id != NULL)
        free(sp->call_id);
    if (sp->tag != NULL)
        free(sp->tag);
    rtpp_log_close(sp->log);

    free(sp->rtcp);
    free(sp);
    cf->sessions_active--;

}
示例#12
0
/* Call Backs */
int dtls_verify_cb(int ok, X509_STORE_CTX* store) {

    SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
    rtpp_stream *st = (rtpp_stream*)SSL_get_app_data(ssl);
    int depth = X509_STORE_CTX_get_error_depth(store);
    X509* cert = X509_STORE_CTX_get_current_cert(store);
    int override = 1;
    char buf[512];
    int err = X509_STORE_CTX_get_error(store);

    bzero(buf, 512);
    X509_NAME_oneline(X509_get_subject_name(cert),buf,sizeof(buf));
    rtpp_log_write(RTPP_LOG_INFO, glog, "depth[%d] subject = %s\n", depth, buf);
    bzero(buf, 512);
    X509_NAME_oneline(X509_get_issuer_name(cert),buf,sizeof(buf));
    rtpp_log_write(RTPP_LOG_INFO, glog, "depth[%d] issuer = %s\n", depth, buf);
    rtpp_log_write(RTPP_LOG_INFO, glog, "verify error:ok=%d num=%d:%s\n", ok,err, X509_verify_cert_error_string(err));  
    rtpp_log_write(RTPP_LOG_INFO, glog, "depth:%d, error code is %d\n", depth,store->error);

    switch (err)
    {
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
        rtpp_log_write(RTPP_LOG_INFO, glog, "issuer= %s\n",buf);
        break;

    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
    case X509_V_ERR_CERT_NOT_YET_VALID:
        rtpp_log_write(RTPP_LOG_INFO, glog, "notBefore\n");
        break;

    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
    case X509_V_ERR_CERT_HAS_EXPIRED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "notAfter\n");
        break;

    case X509_V_ERR_CERT_SIGNATURE_FAILURE:
    case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
        rtpp_log_write(RTPP_LOG_INFO, glog, "unable to decrypt cert signature\n");
        break;

    case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
        rtpp_log_write(RTPP_LOG_INFO, glog, "Critical Extension\n");
        break;
    case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
        rtpp_log_write(RTPP_LOG_INFO, glog, "unable to decode issuer public key\n");
        break;

    case X509_V_ERR_OUT_OF_MEM:
        rtpp_log_write(RTPP_LOG_ERR, glog, "Out of memory \n");
        break;
    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
         if (st->remote_fp_algorithm && st->remote_fp_value)
         { 
            ok = 1;
            rtpp_log_write(RTPP_LOG_INFO, glog,"{%d}fingerprint verification st:%p fd:%d ssl:%p\n",depth, st, st->fd, ssl);
            if(!dtls_verify_digest(st,cert))
            {
                //override = 0;/* should be Zero*/
                ok = 0;
            }
                
        }
        rtpp_log_write(RTPP_LOG_INFO, glog, "Self signed certificate issue\n");
        break;
    case X509_V_ERR_CERT_REVOKED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "certitifcate revoked\n");
        break;
    case X509_V_ERR_INVALID_CA:
        rtpp_log_write(RTPP_LOG_INFO, glog, "invalid CA\n");
        break;
    case X509_V_ERR_PATH_LENGTH_EXCEEDED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "path length exceeded\n");
        break;
    case X509_V_ERR_INVALID_PURPOSE:
        rtpp_log_write(RTPP_LOG_INFO, glog, "invalid purpose\n");
        break;
    case X509_V_ERR_CERT_UNTRUSTED:
    case X509_V_ERR_CERT_REJECTED:
        rtpp_log_write(RTPP_LOG_INFO, glog, "certificate untrusted/rejected\n");
        break;
    default:
        rtpp_log_write(RTPP_LOG_INFO, glog, "default: error code is %d (check x509_vfy.h)\n", store->error);
        break;
    }
    if (!ok)
    {
        if (override)
        {
            rtpp_log_write(RTPP_LOG_INFO, glog, "something wrong with the cert[%d]!!! error code:%d (x509_vfy.h) Ignoring for Now\n",depth, store->error);
            ok=1;
        }
        else
            rtpp_log_write(RTPP_LOG_INFO, glog, "verify error:num=%d:%s depth:%d\n", err, X509_verify_cert_error_string(err),depth);  
    }
示例#13
0
struct rtpp_command *
rtpp_command_stream_get(struct cfg *cf, struct rtpp_cmd_connection *rcs,
  int *rval, double dtime, struct rtpp_command_stats *csp)
{
    char **ap;
    char *cp, *cp1;
    int len;
    struct rtpp_command *cmd;

    if (rcs->inbuf_epos == rcs->inbuf_ppos) {
        *rval = EAGAIN;
        return (NULL);
    }
    cp = &(rcs->inbuf[rcs->inbuf_ppos]);
    len = rcs->inbuf_epos - rcs->inbuf_ppos;
    cp1 = memchr(cp, '\n', len);
    if (cp1 == NULL) {
        *rval = EAGAIN;
        return (NULL);
    }

    cmd = rtpp_zmalloc(sizeof(struct rtpp_command));
    if (cmd == NULL) {
        *rval = ENOMEM;
        return (NULL);
    }

    cmd->controlfd = rcs->controlfd_out;
    cmd->dtime = dtime;
    cmd->csp = csp;
    cmd->umode = 0;
    if (rcs->rlen > 0) {
        cmd->rlen = rcs->rlen;
        memcpy(&cmd->raddr, &rcs->raddr, rcs->rlen);
    }

    len = cp1 - cp;
    memcpy(cmd->buf, cp, len);
    cmd->buf[len] = '\0';
    rcs->inbuf_ppos += len + 1;

    rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "received command \"%s\"", cmd->buf);
    csp->ncmds_rcvd.cnt++;

    cp = cmd->buf;
    for (ap = cmd->argv; (*ap = rtpp_strsep(&cp, "\r\n\t ")) != NULL;) {
        if (**ap != '\0') {
            cmd->argc++;
            if (++ap >= &cmd->argv[RTPC_MAX_ARGC])
                break;
        }
    }

    if (cmd->argc < 1) {
        rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
        reply_error(cf, cmd, ECODE_PARSE_1);
        *rval = EINVAL;
        free(cmd);
        return (NULL);
    }

    /* Step I: parse parameters that are common to all ops */
    if (rtpp_command_pre_parse(cf, cmd) != 0) {
        /* Error reply is handled by the rtpp_command_pre_parse() */
        *rval = 0;
        free(cmd);
        return (NULL);
    }

    return (cmd);
}
示例#14
0
/**
 * rtpp_parse_bridge_modifier - Handles the bridge modifier "B/b" in UPDATE and LOOKUP commands
 *                         Argument format: ip4/6:netId-ipAddr
 *
 * @param[in] cf      - Config
 * @param[in] arg     - Bridge modifier argument (from the command)
 *
 * @param[out] isIpV6 - 1 if IPV6
 * @param[out] netId  - Network Id (if name)
 * @param[out] ipAddr - IP address
 *
 * @return 0 (success), -1 (failure)
 *
 * Notes: Added for FRN4811
 */
int rtpp_parse_bridge_modifier(struct cfg *cf, char *arg, int *isIpV6, char *netId, char *ipAddr)
{
    if (arg == NULL)
    {
        rtpp_log_write(RTPP_LOG_ERR, cf->glog, "Bridge modifier argument is NULL");
        return -1;
    }

    rtpp_log_write(RTPP_LOG_DBUG, cf->glog, "Bridge modifier argument = %s", arg);

    // Get IP ver (ip4 or ip6)
    char *pColon = strchr(arg, ':');
    if (pColon == NULL)
    {
        rtpp_log_write(RTPP_LOG_ERR, cf->glog, "IP addr version not present");
        return -1;
    }

    char ipVer[4];
    strncpy(ipVer, arg, 3);
    ipVer[3] = '\0';

    if (strcasecmp(ipVer, IPV4_TYPE_IN_CMD) == 0)
    {
        *isIpV6 = 0;
    }
    else if (strcasecmp(ipVer, IPV6_TYPE_IN_CMD) == 0)
    {
        *isIpV6 = 1;
    }
    else
    {
        rtpp_log_write(RTPP_LOG_ERR, cf->glog, "IP version (%s) invalid", ipVer);
        return -1;
    }

    // Get network id
    char *pHyphen = strchr(pColon, '-');
    if (pHyphen == NULL)
    {
        rtpp_log_write(RTPP_LOG_ERR, cf->glog, "Network Id not present");
        return -1;
    }

    // Copy network id
    char *netIdStart = pColon + 1;  // Exclude :
    int len = pHyphen - netIdStart;

    if (len <= 0 || len > MAX_NETWORK_ID_LEN)
    {
        rtpp_log_write(RTPP_LOG_ERR, cf->glog, "Invalid network Id length (%d)", len);
        return -1;
    }

    // Copy network id
    strncpy(netId, netIdStart, len);
    *(netId+len) = '\0';

    // Get IP address
    char *ipAddrStart = pHyphen + 1;     // Exclude -
    len = strlen(ipAddrStart);

    if (len <= 0 || len > MAX_IP_ADDR_LEN)
    {
        rtpp_log_write(RTPP_LOG_ERR, cf->glog, "IP address not present");
        return -1;
    }

    // Copy IP address
    strncpy(ipAddr, ipAddrStart, len);
    *(ipAddr+len) = '\0';

    rtpp_log_write(RTPP_LOG_DBUG, cf->glog, "Ver: %s, NetworkId: %s, IP address: %s", ipVer, netId, ipAddr);

    return 0;
}
示例#15
0
static void
handle_info(struct cfg *cf, struct rtpp_command *cmd,
  const char *opts)
{
#if 0
    struct rtpp_session *spa, *spb;
    char addrs[4][256];
#endif
    int len, i, brief, load;
    char buf[1024 * 8];
    unsigned long long packets_in, packets_out;

    brief = 0;
    load = 0;
    for (i = 0; opts[i] != '\0'; i++) {
        switch (opts[i]) {
        case 'b':
        case 'B':
            brief = 1;
            break;

        case 'l':
        case 'L':
            load = 1;
            break;

        default:
            rtpp_log_write(RTPP_LOG_ERR, cf->stable->glog, "command syntax error");
            reply_error(cf, cmd, ECODE_PARSE_7);
            return;
        }
    }

    packets_in = CALL_METHOD(cf->stable->rtpp_stats, getlvalbyname, "npkts_rcvd");
    packets_out = CALL_METHOD(cf->stable->rtpp_stats, getlvalbyname, "npkts_relayed") +
      CALL_METHOD(cf->stable->rtpp_stats, getlvalbyname, "npkts_played");
    pthread_mutex_lock(&cf->sessinfo.lock);
    len = snprintf(buf, sizeof(buf), "sessions created: %llu\nactive sessions: %d\n"
      "active streams: %d\npackets received: %llu\npackets transmitted: %llu\n",
      cf->sessions_created, cf->sessions_active, cf->sessinfo.nsessions,
      packets_in, packets_out);
    if (load != 0) {
          len += snprintf(buf + len, sizeof(buf) - len, "average load: %f\n",
            CALL_METHOD(cf->stable->rtpp_cmd_cf, get_aload));
    }
#if 0
XXX this needs work to fix it after rtp/rtcp split 
    for (i = 0; i < cf->sessinfo.nsessions && brief == 0; i++) {
        spa = cf->sessinfo.sessions[i];
        if (spa == NULL || spa->sidx[0] != i)
            continue;
        /* RTCP twin session */
        if (spa->rtcp == NULL) {
            spb = spa->rtp;
            buf[len++] = '\t';
        } else {
            spb = spa->rtcp;
            buf[len++] = '\t';
            buf[len++] = 'C';
            buf[len++] = ' ';
        }

        addr2char_r(spb->laddr[1], addrs[0], sizeof(addrs[0]));
        if (spb->addr[1] == NULL) {
            strcpy(addrs[1], "NONE");
        } else {
            sprintf(addrs[1], "%s:%d", addr2char(spb->addr[1]),
              addr2port(spb->addr[1]));
        }
        addr2char_r(spb->laddr[0], addrs[2], sizeof(addrs[2]));
        if (spb->addr[0] == NULL) {
            strcpy(addrs[3], "NONE");
        } else {
            sprintf(addrs[3], "%s:%d", addr2char(spb->addr[0]),
              addr2port(spb->addr[0]));
        }

        len += snprintf(buf + len, sizeof(buf) - len,
          "%s/%s: caller = %s:%d/%s, callee = %s:%d/%s, "
          "stats = %lu/%lu/%lu/%lu, ttl = %d/%d\n",
          spb->call_id, spb->tag, addrs[0], spb->ports[1], addrs[1],
          addrs[2], spb->ports[0], addrs[3], spa->pcount[0], spa->pcount[1],
          spa->pcount[2], spa->pcount[3], spb->ttl[0], spb->ttl[1]);
        if (len + 512 > sizeof(buf)) {
            rtpc_doreply(cf, buf, len, cmd);
            len = 0;
        }
    }
#endif
    pthread_mutex_unlock(&cf->sessinfo.lock);
    if (len > 0) {
        rtpc_doreply(cf, buf, len, cmd, 0);
    }
}
static void
rtpp_proc_async_run(void *arg)
{
    struct cfg *cf;
    double last_tick_time;
    int alarm_tick, i, ndrain, rtp_only;
    struct rtpp_proc_async_cf *proc_cf;
    long long ncycles_ref;
#ifdef RTPP_DEBUG
    int ncycles_ref_pre, last_ctick;
#endif
    struct sign_arg *s_a;
    struct rtpp_wi *wi, *wis[10];
    struct sthread_args *sender;
    double tp[4];
    struct rtpp_proc_rstats *rstats;
    struct rtpp_stats_obj *stats_cf;

    cf = (struct cfg *)arg;
    proc_cf = cf->stable->rtpp_proc_cf;
    stats_cf = cf->stable->rtpp_stats;
    rstats = &proc_cf->rstats;

    last_tick_time = 0;
    wi = rtpp_queue_get_item(proc_cf->time_q, 0);
    s_a = (struct sign_arg *)rtpp_wi_sgnl_get_data(wi, NULL);
#ifdef RTPP_DEBUG
    last_ctick = s_a->clock_tick;
    ncycles_ref_pre = s_a->ncycles_ref;
#endif
    rtpp_wi_free(wi);

    tp[0] = getdtime();
    for (;;) {
        i = rtpp_queue_get_items(proc_cf->time_q, wis, 10, 0);
        if (i <= 0) {
            continue;
        }
        i -= 1;
        s_a = (struct sign_arg *)rtpp_wi_sgnl_get_data(wis[i], NULL);
        ndrain = (s_a->ncycles_ref - ncycles_ref) / (cf->stable->target_pfreq / MAX_RTP_RATE);
#ifdef RTPP_DEBUG
        last_ctick = s_a->clock_tick;
        ncycles_ref_pre = ncycles_ref;
#endif
        ncycles_ref = s_a->ncycles_ref;
        for(; i > -1; i--) {
            rtpp_wi_free(wis[i]);
        }

        tp[1] = getdtime();
#if RTPP_DEBUG
        if (last_ctick % (unsigned int)cf->stable->target_pfreq == 0 || last_ctick < 1000) {
            rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld sptime %f, CSV: %f,%f,%f", \
              last_ctick, tp[1], (double)last_ctick / cf->stable->target_pfreq, \
              ((double)ncycles_ref / cf->stable->target_pfreq) - tp[1], tp[1]);
        }
#endif

        if (ndrain < 1) {
            ndrain = 1;
        }

#if RTPP_DEBUG
        if (ndrain > 1) {
            rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld " \
              "ncycles_ref %lld, ncycles_ref_pre %lld, ndrain %d CSV: %f,%f,%d", \
              last_ctick, ncycles_ref, ncycles_ref_pre, ndrain, \
              (double)last_ctick / cf->stable->target_pfreq, ndrain);
        }
#endif

        alarm_tick = 0;
        if (last_tick_time == 0 || last_tick_time > tp[1]) {
            last_tick_time = tp[1];
        } else if (last_tick_time + (double)TIMETICK < tp[1]) {
            alarm_tick = 1;
            last_tick_time = tp[1];
        }

        if (alarm_tick || (ncycles_ref % 7) == 0) {
            rtp_only = 0;
        } else {
            rtp_only = 1;
        }

        pthread_mutex_lock(&cf->sessinfo.lock);
        if (cf->sessinfo.nsessions > 0) {
            if (rtp_only == 0) {
                i = poll(cf->sessinfo.pfds_rtcp, cf->sessinfo.nsessions, 0);
            }
            i = poll(cf->sessinfo.pfds_rtp, cf->sessinfo.nsessions, 0);
            pthread_mutex_unlock(&cf->sessinfo.lock);
            if (i < 0 && errno == EINTR) {
                rtpp_command_async_wakeup(cf->stable->rtpp_cmd_cf);
                tp[0] = getdtime();
                continue;
            }
        } else {
            pthread_mutex_unlock(&cf->sessinfo.lock);
        }

        tp[2] = getdtime();

        sender = rtpp_anetio_pick_sender(proc_cf->op);
        if (rtp_only == 0) {
            pthread_mutex_lock(&cf->glock);
            process_rtp(cf, tp[2], alarm_tick, ndrain, sender, rstats);
        } else {
            process_rtp_only(cf, tp[2], ndrain, sender, rstats);
            pthread_mutex_lock(&cf->glock);
        }

        if (cf->rtp_nsessions > 0) {
            process_rtp_servers(cf, tp[2], sender, rstats);
        }
        pthread_mutex_unlock(&cf->glock);
        rtpp_anetio_pump_q(sender);
        rtpp_command_async_wakeup(cf->stable->rtpp_cmd_cf);
        tp[3] = getdtime();
        flush_rstats(stats_cf, rstats);

#if RTPP_DEBUG
        recfilter_apply(&proc_cf->sleep_time, tp[1] - tp[0]);
        recfilter_apply(&proc_cf->poll_time, tp[2] - tp[1]);
        recfilter_apply(&proc_cf->proc_time, tp[3] - tp[2]);
#endif
        tp[0] = tp[3];
#if RTPP_DEBUG
        if (last_ctick % (unsigned int)cf->stable->target_pfreq == 0 || last_ctick < 1000) {
#if 0
            rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld eptime %f, CSV: %f,%f,%f", \
              last_ctick, tp[3], (double)last_ctick / cf->stable->target_pfreq, tp[3] - tp[1], tp[3]);
#endif
            rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld eptime %f sleep_time %f poll_time %f proc_time %f CSV: %f,%f,%f,%f", \
              last_ctick, tp[3], proc_cf->sleep_time.lastval, proc_cf->poll_time.lastval, proc_cf->proc_time.lastval, \
              (double)last_ctick / cf->stable->target_pfreq, proc_cf->sleep_time.lastval, proc_cf->poll_time.lastval, proc_cf->proc_time.lastval);
        }
#endif
    }

}
示例#17
0
int
handle_command(struct cfg *cf, int controlfd, double dtime)
{
    int len, argc, i, j, pidx, asymmetric;
    int external, pf, lidx, playcount, weak;
    int fds[2], lport, n;
    socklen_t rlen;
    char buf[1024 * 8];
    char *cp, *call_id, *from_tag, *to_tag, *addr, *port, *cookie;
    char *pname, *codecs, *recording_name, *t;
    struct rtpp_session *spa, *spb;
    char **ap, *argv[10];
    const char *rname;
    struct sockaddr *ia[2], *lia[2];
    struct sockaddr_storage raddr;
    int requested_nsamples;
    enum {DELETE, RECORD, PLAY, NOPLAY, COPY, UPDATE, LOOKUP, QUERY} op;
    int max_argc;
    char *socket_name_u, *notify_tag;

    requested_nsamples = -1;
    ia[0] = ia[1] = NULL;
    spa = spb = NULL;
    lia[0] = lia[1] = cf->bindaddr[0];
    lidx = 1;
    fds[0] = fds[1] = -1;
    recording_name = NULL;
    socket_name_u = notify_tag = NULL;

    if (cf->umode == 0) {
	for (;;) {
	    len = read(controlfd, buf, sizeof(buf) - 1);
	    if (len != -1 || (errno != EAGAIN && errno != EINTR))
		break;
	    sched_yield();
	}
    } else {
	rlen = sizeof(raddr);
	len = recvfrom(controlfd, buf, sizeof(buf) - 1, 0,
	  sstosa(&raddr), &rlen);
    }
    if (len == -1) {
	if (errno != EAGAIN && errno != EINTR)
	    rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "can't read from control socket");
	return -1;
    }
    buf[len] = '\0';

    rtpp_log_write(RTPP_LOG_DBUG, cf->glog, "received command \"%s\"", buf);

    cp = buf;
    argc = 0;
    memset(argv, 0, sizeof(argv));
    for (ap = argv; (*ap = rtpp_strsep(&cp, "\r\n\t ")) != NULL;)
	if (**ap != '\0') {
	    argc++;
	    if (++ap >= &argv[10])
		break;
	}
    cookie = NULL;
    if (argc < 1 || (cf->umode != 0 && argc < 2)) {
	rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
	reply_error(cf, controlfd, &raddr, rlen, cookie, 0);
	return 0;
    }

    /* Stream communication mode doesn't use cookie */
    if (cf->umode != 0) {
	cookie = argv[0];
	for (i = 1; i < argc; i++)
	    argv[i - 1] = argv[i];
	argc--;
	argv[argc] = NULL;
    } else {
	cookie = NULL;
    }

    addr = port = NULL;
    switch (argv[0][0]) {
    case 'u':
    case 'U':
	/* U[opts] callid remote_ip remote_port from_tag [to_tag] */
	op = UPDATE;
	rname = "update/create";
	break;

    case 'l':
    case 'L':
	op = LOOKUP;
	rname = "lookup";
	break;

    case 'd':
    case 'D':
	op = DELETE;
	rname = "delete";
	break;

    case 'p':
    case 'P':
	/*
	 * P callid pname codecs from_tag to_tag
	 *
	 *   <codecs> could be either comma-separated list of supported
	 *   payload types or word "session" (without quotes), in which
	 *   case list saved on last session update will be used instead.
	 */
	op = PLAY;
	rname = "play";
	playcount = 1;
	pname = argv[2];
	codecs = argv[3];
	break;

    case 'r':
    case 'R':
	op = RECORD;
	rname = "record";
	break;

    case 'c':
    case 'C':
	op = COPY;
	rname = "copy";
	break;

    case 's':
    case 'S':
	op = NOPLAY;
	rname = "noplay";
	break;

    case 'v':
    case 'V':
	if (argv[0][1] == 'F' || argv[0][1] == 'f') {
	    int i, known;
	    /*
	     * Wait for protocol version datestamp and check whether we
	     * know it.
	     */
	    if (argc != 2 && argc != 3) {
		rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
		reply_error(cf, controlfd, &raddr, rlen, cookie, 2);
		return 0;
	    }
	    for (known = i = 0; proto_caps[i].pc_id != NULL; ++i) {
		if (!strcmp(argv[1], proto_caps[i].pc_id)) {
		    known = 1;
		    break;
		}
	    }
	    reply_number(cf, controlfd, &raddr, rlen, cookie, known);
	    return 0;
	}
	if (argc != 1 && argc != 2) {
	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 2);
	    return 0;
	}
	/* This returns base version. */
	reply_number(cf, controlfd, &raddr, rlen, cookie, CPROTOVER);
	return 0;

    case 'i':
    case 'I':
	if (cookie == NULL)
	    len = sprintf(buf, "sessions created: %llu\nactive sessions: %d\n"
	      "active streams: %d\n", cf->sessions_created,
	      cf->sessions_active, cf->nsessions / 2);
	else
	    len = sprintf(buf, "%s sessions created: %llu\nactive sessions: %d\n"
	      "active streams: %d\n", cookie, cf->sessions_created,
	      cf->sessions_active, cf->nsessions / 2);
	for (i = 1; i < cf->nsessions; i++) {
	    char addrs[4][256];

	    spa = cf->sessions[i];
	    if (spa == NULL || spa->sidx[0] != i)
		continue;
	    /* RTCP twin session */
	    if (spa->rtcp == NULL) {
		spb = spa->rtp;
		buf[len++] = '\t';
	    } else {
		spb = spa->rtcp;
		buf[len++] = '\t';
		buf[len++] = 'C';
		buf[len++] = ' ';
	    }

	    addr2char_r(spb->laddr[1], addrs[0], sizeof(addrs[0]));
	    if (spb->addr[1] == NULL) {
		strcpy(addrs[1], "NONE");
	    } else {
		sprintf(addrs[1], "%s:%d", addr2char(spb->addr[1]),
		  addr2port(spb->addr[1]));
	    }
	    addr2char_r(spb->laddr[0], addrs[2], sizeof(addrs[2]));
	    if (spb->addr[0] == NULL) {
		strcpy(addrs[3], "NONE");
	    } else {
		sprintf(addrs[3], "%s:%d", addr2char(spb->addr[0]),
		  addr2port(spb->addr[0]));
	    }

	    len += sprintf(buf + len,
	      "%s/%s: caller = %s:%d/%s, callee = %s:%d/%s, "
	      "stats = %lu/%lu/%lu/%lu, ttl = %d/%d\n",
	      spb->call_id, spb->tag, addrs[0], spb->ports[1], addrs[1],
	      addrs[2], spb->ports[0], addrs[3], spa->pcount[0], spa->pcount[1],
	      spa->pcount[2], spa->pcount[3], spb->ttl[0], spb->ttl[1]);
	    if (len + 512 > sizeof(buf)) {
		doreply(cf, controlfd, buf, len, &raddr, rlen);
		len = 0;
	    }
	}
	if (len > 0)
	    doreply(cf, controlfd, buf, len, &raddr, rlen);;
	return 0;
	break;

    case 'q':
    case 'Q':
	op = QUERY;
	rname = "query";
	break;

    case 'x':
    case 'X':
        /* Delete all active sessions */
        rtpp_log_write(RTPP_LOG_INFO, cf->glog, "deleting all active sessions");
        for (i = 1; i < cf->nsessions; i++) {
	    spa = cf->sessions[i];
	    if (spa == NULL || spa->sidx[0] != i)
		continue;
	    /* Skip RTCP twin session */
	    if (spa->rtcp != NULL) {
		remove_session(cf, spa);
	    }
        }
        reply_ok(cf, controlfd, &raddr, rlen, cookie);
        return 0;
        break;

    default:
	rtpp_log_write(RTPP_LOG_ERR, cf->glog, "unknown command");
	reply_error(cf, controlfd, &raddr, rlen, cookie, 3);
	return 0;
    }
    call_id = argv[1];
    if (op == UPDATE || op == LOOKUP || op == PLAY) {
	max_argc = (op == UPDATE ? 8 : 6);
	if (argc < 5 || argc > max_argc) {
	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 4);
	    return 0;
	}
	from_tag = argv[4];
	to_tag = argv[5];
	if (op == PLAY && argv[0][1] != '\0')
	    playcount = atoi(argv[0] + 1);
	if (op == UPDATE && argc > 6) {
	    socket_name_u = argv[6];
	    if (strncmp("unix:", socket_name_u, 5) == 0)
		socket_name_u += 5;
	    if (argc == 8) {
		notify_tag = argv[7];
		len = url_unquote((uint8_t *)notify_tag, strlen(notify_tag));
		if (len == -1) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog,
		      "command syntax error - invalid URL encoding");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 4);
		    return 0;
		}
		notify_tag[len] = '\0';
	    }
	}
    }
    if (op == COPY) {
	if (argc < 4 || argc > 5) {
	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
	    return 0;
	}
	recording_name = argv[2];
	from_tag = argv[3];
	to_tag = argv[4];
    }
    if (op == DELETE || op == RECORD || op == NOPLAY || op == QUERY) {
	if (argc < 3 || argc > 4) {
	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
	    return 0;
	}
	from_tag = argv[2];
	to_tag = argv[3];
    }
    if (op == DELETE || op == RECORD || op == COPY || op == NOPLAY) {
	/* D, R and S commands don't take any modifiers */
	if (argv[0][1] != '\0') {
	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
	    return 0;
	}
    }
    if (op == UPDATE || op == LOOKUP || op == DELETE) {
	addr = argv[2];
	port = argv[3];
	/* Process additional command modifiers */
	external = 1;
	/* In bridge mode all clients are assumed to be asymmetric */
	asymmetric = (cf->bmode != 0) ? 1 : 0;
	pf = AF_INET;
	weak = 0;
	for (cp = argv[0] + 1; *cp != '\0'; cp++) {
	    switch (*cp) {
	    case 'a':
	    case 'A':
		asymmetric = 1;
		break;

	    case 'e':
	    case 'E':
		if (lidx < 0) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		lia[lidx] = cf->bindaddr[1];
		lidx--;
		break;

	    case 'i':
	    case 'I':
		if (lidx < 0) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		lia[lidx] = cf->bindaddr[0];
		lidx--;
		break;

	    case '6':
		pf = AF_INET6;
		break;

	    case 's':
	    case 'S':
		asymmetric = 0;
		break;

	    case 'w':
	    case 'W':
		weak = 1;
		break;

	    case 'z':
	    case 'Z':
		requested_nsamples = (strtol(cp + 1, &cp, 10) / 10) * 80;
		if (requested_nsamples <= 0) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		cp--;
		break;

	    case 'c':
	    case 'C':
		cp += 1;
		for (t = cp; *cp != '\0'; cp++) {
		    if (!isdigit(*cp) && *cp != ',')
			break;
		}
		if (t == cp) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		codecs = alloca(cp - t + 1);
		memcpy(codecs, t, cp - t);
		codecs[cp - t] = '\0';
		cp--;
		break;

	    default:
		rtpp_log_write(RTPP_LOG_ERR, cf->glog, "unknown command modifier `%c'",
		  *cp);
		break;
	    }
	}
	if (op != DELETE && addr != NULL && port != NULL && strlen(addr) >= 7) {
	    struct sockaddr_storage tia;

	    if ((n = resolve(sstosa(&tia), pf, addr, port,
	      AI_NUMERICHOST)) == 0) {
		if (!ishostnull(sstosa(&tia))) {
		    for (i = 0; i < 2; i++) {
			ia[i] = malloc(SS_LEN(&tia));
			if (ia[i] == NULL) {
			    handle_nomem(cf, controlfd, &raddr, rlen, cookie,
			      5, ia, fds, spa, spb);
			    return 0;
			}
			memcpy(ia[i], &tia, SS_LEN(&tia));
		    }
		    /* Set port for RTCP, will work both for IPv4 and IPv6 */
		    n = ntohs(satosin(ia[1])->sin_port);
		    satosin(ia[1])->sin_port = htons(n + 1);
		}
	    } else {
		rtpp_log_write(RTPP_LOG_ERR, cf->glog, "getaddrinfo: %s",
		  gai_strerror(n));
	    }
	}
    }

    /*
     * Record and delete need special handling since they apply to all
     * streams in the session.
     */
    switch (op) {
    case DELETE:
	i = handle_delete(cf, call_id, from_tag, to_tag, weak);
	break;

    case RECORD:
	i = handle_record(cf, call_id, from_tag, to_tag);
	break;

    default:
	i = find_stream(cf, call_id, from_tag, to_tag, &spa);
	if (i != -1 && op != UPDATE)
	    i = NOT(i);
	break;
    }

    if (i == -1 && op != UPDATE) {
	rtpp_log_write(RTPP_LOG_INFO, cf->glog,
	  "%s request failed: session %s, tags %s/%s not found", rname,
	  call_id, from_tag, to_tag != NULL ? to_tag : "NONE");
	if (op == LOOKUP) {
	    for (i = 0; i < 2; i++)
		if (ia[i] != NULL)
		    free(ia[i]);
	    reply_port(cf, controlfd, &raddr, rlen, cookie, 0, lia);
	    return 0;
	}
	reply_error(cf, controlfd, &raddr, rlen, cookie, 8);
	return 0;
    }

    switch (op) {
    case DELETE:
    case RECORD:
	reply_ok(cf, controlfd, &raddr, rlen, cookie);
	return 0;

    case NOPLAY:
	handle_noplay(cf, spa, i);
	reply_ok(cf, controlfd, &raddr, rlen, cookie);
	return 0;

    case PLAY:
	handle_noplay(cf, spa, i);
	if (strcmp(codecs, "session") == 0) {
	    if (spa->codecs[i] == NULL) {
		reply_error(cf, controlfd, &raddr, rlen, cookie, 6);
		return 0;
	    }
	    codecs = spa->codecs[i];
	}
	if (playcount != 0 && handle_play(cf, spa, i, codecs, pname, playcount) != 0) {
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 6);
	    return 0;
	}
	reply_ok(cf, controlfd, &raddr, rlen, cookie);
	return 0;

    case COPY:
	handle_copy(cf, spa, i, recording_name);
	reply_ok(cf, controlfd, &raddr, rlen, cookie);
	return 0;

    case QUERY:
	handle_query(cf, controlfd, &raddr, rlen, cookie, spa, i);
	return 0;

    case LOOKUP:
    case UPDATE:
	/* those are handled below */
	break;

    default:
	/* Programmatic error, should not happen */
	abort();
    }

    pidx = 1;
    lport = 0;
    if (i != -1) {
	assert(op == UPDATE || op == LOOKUP);
	if (spa->fds[i] == -1) {
	    j = ishostseq(cf->bindaddr[0], spa->laddr[i]) ? 0 : 1;
	    if (create_listener(cf, spa->laddr[i], &lport, fds) == -1) {
		rtpp_log_write(RTPP_LOG_ERR, spa->log, "can't create listener");
		reply_error(cf, controlfd, &raddr, rlen, cookie, 7);
		return 0;
	    }
	    assert(spa->fds[i] == -1);
	    spa->fds[i] = fds[0];
	    assert(spa->rtcp->fds[i] == -1);
	    spa->rtcp->fds[i] = fds[1];
	    spa->ports[i] = lport;
	    spa->rtcp->ports[i] = lport + 1;
	    spa->complete = spa->rtcp->complete = 1;
	    append_session(cf, spa, i);
	    append_session(cf, spa->rtcp, i);
	}
	if (weak)
	    spa->weak[i] = 1;
	else if (op == UPDATE)
	    spa->strong = 1;
	lport = spa->ports[i];
	lia[0] = spa->laddr[i];
	pidx = (i == 0) ? 1 : 0;
	spa->ttl_mode = cf->ttl_mode;
	spa->ttl[0] = cf->max_ttl;
	spa->ttl[1] = cf->max_ttl;
	if (op == UPDATE) {
	    rtpp_log_write(RTPP_LOG_INFO, spa->log,
	      "adding %s flag to existing session, new=%d/%d/%d",
	      weak ? ( i ? "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(op == UPDATE);
	rtpp_log_write(RTPP_LOG_INFO, cf->glog,
	  "new session %s, tag %s requested, type %s",
	  call_id, from_tag, weak ? "weak" : "strong");

	j = ishostseq(cf->bindaddr[0], lia[0]) ? 0 : 1;
	if (create_listener(cf, cf->bindaddr[j], &lport, fds) == -1) {
	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "can't create listener");
	    reply_error(cf, controlfd, &raddr, rlen, cookie, 10);
	    return 0;
	}

	/*
	 * Session creation. If creation is requested with weak flag,
	 * set weak[0].
	 */
	spa = malloc(sizeof(*spa));
	if (spa == NULL) {
	    handle_nomem(cf, controlfd, &raddr, rlen, cookie, 11, ia,
	      fds, spa, spb);
	    return 0;
	}
	/* spb is RTCP twin session for this one. */
	spb = malloc(sizeof(*spb));
	if (spb == NULL) {
	    handle_nomem(cf, controlfd, &raddr, rlen, cookie, 12, ia,
	      fds, spa, spb);
	    return 0;
	}
	memset(spa, 0, sizeof(*spa));
	memset(spb, 0, sizeof(*spb));
	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(call_id);
	if (spa->call_id == NULL) {
	    handle_nomem(cf, controlfd, &raddr, rlen, cookie, 13, ia,
	      fds, spa, spb);
	    return 0;
	}
	spb->call_id = spa->call_id;
	spa->tag = strdup(from_tag);
	if (spa->tag == NULL) {
	    handle_nomem(cf, controlfd, &raddr, rlen, cookie, 14, ia,
	      fds, spa, spb);
	    return 0;
	}
	spb->tag = spa->tag;
	for (i = 0; i < 2; i++) {
	    spa->rrcs[i] = NULL;
	    spb->rrcs[i] = NULL;
	    spa->laddr[i] = lia[i];
	    spb->laddr[i] = lia[i];
	}
	spa->strong = spa->weak[0] = spa->weak[1] = 0;
	if (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->max_ttl;
	spa->ttl[1] = cf->max_ttl;
	spb->ttl[0] = -1;
	spb->ttl[1] = -1;
	spa->log = rtpp_log_open(cf, "rtpproxy", spa->call_id, 0);
	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);
	append_session(cf, spb, 0);
	append_session(cf, spb, 1);

	hash_table_append(cf, spa);

	cf->sessions_created++;
	cf->sessions_active++;
	/*
	 * 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 > (cf->nofile_limit.rlim_max * 80 / (100 * 5)) &&
	  cf->nofile_limit_warned == 0) {
	    cf->nofile_limit_warned = 1;
	    rtpp_log_write(RTPP_LOG_WARN, cf->glog, "passed 80%% "
	      "threshold on the open file descriptors limit (%d), "
	      "consider increasing the limit using -L command line "
	      "option", (int)cf->nofile_limit.rlim_max);
	}

	rtpp_log_write(RTPP_LOG_INFO, spa->log, "new session on a port %d created, "
	  "tag %s", lport, from_tag);
	if (cf->record_all != 0) {
	    handle_copy(cf, spa, 0, NULL);
	    handle_copy(cf, spa, 1, NULL);
	}
    }

    if (op == UPDATE) {
	if (cf->timeout_handler.socket_name == NULL && 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 (cf->timeout_handler.socket_name != NULL && socket_name_u != NULL) {
	    if (strcmp(cf->timeout_handler.socket_name, socket_name_u) != 0) {
		rtpp_log_write(RTPP_LOG_ERR, spa->log, "invalid socket name %s", socket_name_u);
		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(notify_tag);
	    }
	} else if (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 (ia[0] != NULL && ia[1] != NULL) {
        if (spa->addr[pidx] != NULL)
            spa->last_update[pidx] = dtime;
        if (spa->rtcp->addr[pidx] != NULL)
            spa->rtcp->last_update[pidx] = 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(ia[0]) == SA_LEN(spa->addr[pidx]) &&
	  memcmp(ia[0], spa->addr[pidx], SA_LEN(ia[0])) == 0)) {
	    rtpp_log_write(RTPP_LOG_INFO, spa->log, "pre-filling %s's address "
	      "with %s:%s", (pidx == 0) ? "callee" : "caller", addr, 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] = ia[0];
	    ia[0] = NULL;
	}
	if (spa->rtcp->untrusted_addr[pidx] == 0 && !(spa->rtcp->addr[pidx] != NULL &&
	  SA_LEN(ia[1]) == SA_LEN(spa->rtcp->addr[pidx]) &&
	  memcmp(ia[1], spa->rtcp->addr[pidx], SA_LEN(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] = ia[1];
	    ia[1] = NULL;
	}
    }
    spa->asymmetric[pidx] = spa->rtcp->asymmetric[pidx] = asymmetric;
    spa->canupdate[pidx] = spa->rtcp->canupdate[pidx] = NOT(asymmetric);
    if (spa->codecs[pidx] != NULL) {
	free(spa->codecs[pidx]);
	spa->codecs[pidx] = NULL;
    }
    if (codecs != NULL)
	spa->codecs[pidx] = strdup(codecs);
    if (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", requested_nsamples / 8);
    } else if (spa->resizers[pidx].output_nsamples > 0) {
	  rtpp_log_write(RTPP_LOG_INFO, spa->log, "Resizing of RTP "
	  "packets from %s has been disabled",
	  (pidx == 0) ? "callee" : "caller");
    }
    spa->resizers[pidx].output_nsamples = requested_nsamples;

    for (i = 0; i < 2; i++)
	if (ia[i] != NULL)
	    free(ia[i]);

    assert(lport != 0);
    reply_port(cf, controlfd, &raddr, rlen, cookie, lport, lia);
    return 0;
}
示例#18
0
static void
rxmit_packets(struct cfg *cf, struct rtpp_session *sp, int ridx,
  double dtime)
{
    int ndrain, i, port;
    struct rtp_packet *packet = NULL;

    /* Repeat since we may have several packets queued on the same socket */
    for (ndrain = 0; ndrain < 5; ndrain++) {
	if (packet != NULL)
	    rtp_packet_free(packet);

	packet = rtp_recv(sp->fds[ridx]);
	if (packet == NULL)
	    break;
	packet->laddr = sp->laddr[ridx];
	packet->rport = sp->ports[ridx];
	packet->rtime = dtime;

	i = 0;
	if (sp->addr[ridx] != NULL) {
	    /* Check that the packet is authentic, drop if it isn't */
	    if (sp->asymmetric[ridx] == 0) {
		if (memcmp(sp->addr[ridx], &packet->raddr, packet->rlen) != 0) {
		    if (sp->canupdate[ridx] == 0) {
			/*
			 * Continue, since there could be good packets in
			 * queue.
			 */
			continue;
		    }
		    /* Signal that an address has to be updated */
		    i = 1;
		} else if (sp->canupdate[ridx] != 0 &&
		  sp->last_update[ridx] != 0 &&
		  dtime - sp->last_update[ridx] > UPDATE_WINDOW) {
		    sp->canupdate[ridx] = 0;
		}
	    } else {
		/*
		 * For asymmetric clients don't check
		 * source port since it may be different.
		 */
		if (!ishostseq(sp->addr[ridx], sstosa(&packet->raddr)))
		    /*
		     * Continue, since there could be good packets in
		     * queue.
		     */
		    continue;
	    }
	    sp->pcount[ridx]++;
	} else {
	    sp->pcount[ridx]++;
	    sp->addr[ridx] = malloc(packet->rlen);
	    if (sp->addr[ridx] == NULL) {
		sp->pcount[3]++;
		rtpp_log_write(RTPP_LOG_ERR, sp->log,
		  "can't allocate memory for remote address - "
		  "removing session");
		remove_session(cf, GET_RTP(sp));
		/* Break, sp is invalid now */
		break;
	    }
	    /* Signal that an address have to be updated. */
	    i = 1;
	}

	/*
	 * Update recorded address if it's necessary. Set "untrusted address"
	 * flag in the session state, so that possible future address updates
	 * from that client won't get address changed immediately to some
	 * bogus one.
	 */
	if (i != 0) {
	    sp->untrusted_addr[ridx] = 1;
	    memcpy(sp->addr[ridx], &packet->raddr, packet->rlen);
	    if (sp->prev_addr[ridx] == NULL || memcmp(sp->prev_addr[ridx],
	      &packet->raddr, packet->rlen) != 0) {
	        sp->canupdate[ridx] = 0;
	    }

	    port = ntohs(satosin(&packet->raddr)->sin_port);

	    rtpp_log_write(RTPP_LOG_INFO, sp->log,
	      "%s's address filled in: %s:%d (%s)",
	      (ridx == 0) ? "callee" : "caller",
	      addr2char(sstosa(&packet->raddr)), port,
	      (sp->rtp == NULL) ? "RTP" : "RTCP");

	    /*
	     * Check if we have updated RTP while RTCP is still
	     * empty or contains address that differs from one we
	     * used when updating RTP. Try to guess RTCP if so,
	     * should be handy for non-NAT'ed clients, and some
	     * NATed as well.
	     */
	    if (sp->rtcp != NULL && (sp->rtcp->addr[ridx] == NULL ||
	      !ishostseq(sp->rtcp->addr[ridx], sstosa(&packet->raddr)))) {
		if (sp->rtcp->addr[ridx] == NULL) {
		    sp->rtcp->addr[ridx] = malloc(packet->rlen);
		    if (sp->rtcp->addr[ridx] == NULL) {
			sp->pcount[3]++;
			rtpp_log_write(RTPP_LOG_ERR, sp->log,
			  "can't allocate memory for remote address - "
			  "removing session");
			remove_session(cf, sp);
			/* Break, sp is invalid now */
			break;
		    }
		}
		memcpy(sp->rtcp->addr[ridx], &packet->raddr, packet->rlen);
		satosin(sp->rtcp->addr[ridx])->sin_port = htons(port + 1);
		/* Use guessed value as the only true one for asymmetric clients */
		sp->rtcp->canupdate[ridx] = NOT(sp->rtcp->asymmetric[ridx]);
		rtpp_log_write(RTPP_LOG_INFO, sp->log, "guessing RTCP port "
		  "for %s to be %d",
		  (ridx == 0) ? "callee" : "caller", port + 1);
	    }
	}

	if (sp->resizers[ridx].output_nsamples > 0)
	    rtp_resizer_enqueue(&sp->resizers[ridx], &packet);
	if (packet != NULL)
	    send_packet(cf, sp, ridx, packet);
    }

    if (packet != NULL)
	rtp_packet_free(packet);
}
示例#19
0
static int
handle_delete(struct cfg *cf, char *call_id, char *from_tag, char *to_tag, int weak)
{
    int ndeleted;
    unsigned int medianum;
    struct rtpp_session *spa, *spb;
    int cmpr, cmpr1, idx;

    ndeleted = 0;
    for (spa = session_findfirst(cf, call_id); spa != NULL;) {
	medianum = 0;
	if ((cmpr1 = compare_session_tags(spa->tag, from_tag, &medianum)) != 0) {
	    idx = 1;
	    cmpr = cmpr1;
	} else if (to_tag != NULL &&
	  (cmpr1 = compare_session_tags(spa->tag, to_tag, &medianum)) != 0) {
	    idx = 0;
	    cmpr = cmpr1;
	} else {
	    spa = session_findnext(spa);
	    continue;
	}

	if (weak)
	    spa->weak[idx] = 0;
	else
	    spa->strong = 0;

	/*
	 * This seems to be stable from reiterations, the only side
	 * effect is less efficient work.
	 */
	if (spa->strong || spa->weak[0] || spa->weak[1]) {
	    rtpp_log_write(RTPP_LOG_INFO, spa->log,
	      "delete: medianum=%u: removing %s flag, seeing flags to"
	      " continue session (strong=%d, weak=%d/%d)",
	      medianum,
	      weak ? ( idx ? "weak[1]" : "weak[0]" ) : "strong",
	      spa->strong, spa->weak[0], spa->weak[1]);
	    /* Skipping to next possible stream for this call */
	    ++ndeleted;
	    spa = session_findnext(spa);
	    continue;
	}
	rtpp_log_write(RTPP_LOG_INFO, spa->log,
	  "forcefully deleting session %u on ports %d/%d",
	   medianum, spa->ports[0], spa->ports[1]);
	/* Search forward before we do removal */
	spb = spa;
	spa = session_findnext(spa);
	remove_session(cf, spb);
	++ndeleted;
	if (cmpr != 2) {
	    break;
	}
    }
    if (ndeleted == 0) {
	return -1;
    }
    return 0;
}
示例#20
0
int
main(int argc, char **argv)
{
    int i, len, timeout, controlfd, alarm_tick;
    double sptime, eptime, last_tick_time;
    unsigned long delay;
    struct cfg cf;
    char buf[256];

    memset(&cf, 0, sizeof(cf));

    init_config(&cf, argc, argv);

    seedrandom();

    init_hash_table(&cf.stable);
    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 */
    }

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

    if (cf.timeout_socket != NULL) {
	cf.timeout_handler = rtpp_notify_init(glog, cf.timeout_socket);
	if (cf.timeout_handler == NULL) {
	    rtpp_log_ewrite(RTPP_LOG_ERR, glog, "can't start notification thread");
	    exit(1);
	}
    }

    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, fatsignal);
    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.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);
	}
    }

    cf.stable.controlfd = controlfd;

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

    rtpp_command_async_init(&cf);

    sptime = 0;
    last_tick_time = 0;
    for (;;) {
        pthread_mutex_lock(&cf.glock);
        pthread_mutex_lock(&cf.sessinfo.lock);
	if (cf.rtp_nsessions > 0 || cf.sessinfo.nsessions > 0) {
	    timeout = RTPS_TICKS_MIN;
	} else {
	    timeout = TIMETICK * 1000;
        }
        pthread_mutex_unlock(&cf.sessinfo.lock);
        pthread_mutex_unlock(&cf.glock);
	eptime = getdtime();
	delay = (eptime - sptime) * 1000000.0;
	if (delay < (1000000 / POLL_LIMIT)) {
	    usleep((1000000 / POLL_LIMIT) - delay);
	    sptime = getdtime();
	} else {
	    sptime = eptime;
	}
        pthread_mutex_lock(&cf.sessinfo.lock);
        if (cf.sessinfo.nsessions > 0) {
	    i = poll(cf.sessinfo.pfds, cf.sessinfo.nsessions, timeout);
            pthread_mutex_unlock(&cf.sessinfo.lock);
	    if (i < 0 && errno == EINTR)
	        continue;
        } else {
            pthread_mutex_unlock(&cf.sessinfo.lock);
            usleep(timeout * 1000);
        }
	eptime = getdtime();
        pthread_mutex_lock(&cf.glock);
	if (cf.rtp_nsessions > 0) {
	    process_rtp_servers(&cf, eptime);
	}
        pthread_mutex_unlock(&cf.glock);
	if (eptime > last_tick_time + TIMETICK) {
	    alarm_tick = 1;
	    last_tick_time = eptime;
	} else {
	    alarm_tick = 0;
	}
        pthread_mutex_lock(&cf.glock);
	process_rtp(&cf, eptime, alarm_tick);
        pthread_mutex_unlock(&cf.glock);
    }

    exit(0);
}
示例#21
0
文件: main.c 项目: yzy5768/rtpproxy
int
main(int argc, char **argv)
{
    int i, len;
    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));
    cf.stable->ctrl_socks = malloc(sizeof(struct rtpp_list));
    if (cf.stable->ctrl_socks == NULL) {
         err(1, "can't allocate memory for the struct rtpp_cfg_stable");
         /* NOTREACHED */
    }
    memset(cf.stable->ctrl_socks, '\0', sizeof(struct rtpp_list));
    RTPP_LIST_RESET(cf.stable->ctrl_socks);    

    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);

    if (rtpp_controlfd_init(&cf) != 0) {
        err(1, "can't inilialize control socket%s",
          cf.stable->ctrl_socks->len > 1 ? "s" : "");
    }

    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(cf.stable->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.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);
#ifdef HAVE_SYSTEMD_SD_DAEMON_H
    sd_notify(0, "READY=1");
#endif
#ifdef RTPP_CHECK_LEAKS
    rtpp_memdeb_setbaseln();
#endif
    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);
        }
    }

#ifdef HAVE_SYSTEMD_SD_DAEMON_H
    sd_notify(0, "STATUS=Exited");
#endif

#ifdef RTPP_CHECK_LEAKS
    exit(rtpp_memdeb_dumpstats(&cf) == 0 ? 0 : 1);
#else
    exit(0);
#endif
}