예제 #1
0
int
rtpp_command_pre_parse(struct cfg *cf, struct rtpp_command *cmd)
{
    struct cmd_props cprops;

    if (fill_cmd_props(cf, cmd, &cprops) != 0) {
        RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "unknown command \"%c\"",
          cmd->argv[0][0]);
        reply_error(cmd, ECODE_CMDUNKN);
        return (-1);
    }
    if (cmd->argc < cprops.min_argc || cmd->argc > cprops.max_argc) {
        RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "%s command syntax error"
          ": invalid number of arguments (%d)", cmd->cca.rname, cmd->argc);
        reply_error(cmd, ECODE_PARSE_NARGS);
        return (-1);
    }
    if (cprops.has_cmods == 0 && cprops.cmods[0] != '\0') {
        RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "%s command syntax error"
          ": modifiers are not supported by the command", cmd->cca.rname);
        reply_error(cmd, ECODE_PARSE_MODS);
        return (-1);
    }
    cmd->cca.call_id = cprops.has_call_id ? cmd->argv[1] : NULL;
    cmd->cca.from_tag = cprops.fpos > 0 ? cmd->argv[cprops.fpos] : NULL;
    cmd->cca.to_tag = cprops.tpos > 0 ? cmd->argv[cprops.tpos] : NULL;
    return (0);
}
예제 #2
0
static int
rtpp_stream_handle_play(struct rtpp_stream *self, char *codecs,
  char *pname, int playcount, struct rtpp_command *cmd, int ptime)
{
    struct rtpp_stream_priv *pvt;
    int n;
    char *cp;
    struct rtpp_server *rsrv;
    uint16_t seq;
    uint32_t ssrc;
    const char *plerror;

    pvt = PUB2PVT(self);
    pthread_mutex_lock(&pvt->lock);
    plerror = "reason unknown";
    while (*codecs != '\0') {
        n = strtol(codecs, &cp, 10);
        if (cp == codecs) {
            plerror = "invalid codecs";
            break;
        }
        codecs = cp;
        if (*codecs != '\0')
            codecs++;
        rsrv = rtpp_server_ctor(pname, n, playcount, cmd->dtime, ptime);
        if (rsrv == NULL) {
            RTPP_LOG(pvt->pub.log, RTPP_LOG_DBUG, "rtpp_server_ctor(\"%s\", %d, %d) failed",
              pname, n, playcount);
            plerror = "rtpp_server_ctor() failed";
            continue;
        }
        rsrv->stuid = self->stuid;
        ssrc = CALL_METHOD(rsrv, get_ssrc);
        seq = CALL_METHOD(rsrv, get_seq);
        if (CALL_METHOD(pvt->servers_wrt, reg, rsrv->rcnt, rsrv->sruid) != 0) {
            CALL_METHOD(rsrv->rcnt, decref);
            plerror = "servers_wrt->reg() method failed";
            break;
        }
        assert(pvt->rtps == RTPP_UID_NONE);
        pvt->rtps = rsrv->sruid;
        pthread_mutex_unlock(&pvt->lock);
        cmd->csp->nplrs_created.cnt++;
        CALL_METHOD(rsrv->rcnt, reg_pd, (rtpp_refcnt_dtor_t)player_predestroy_cb,
          pvt->rtpp_stats);
        CALL_METHOD(rsrv->rcnt, decref);
        RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO,
          "%d times playing prompt %s codec %d: SSRC=" SSRC_FMT ", seq=%u",
          playcount, pname, n, ssrc, seq);
        return 0;
    }
    pthread_mutex_unlock(&pvt->lock);
    RTPP_LOG(pvt->pub.log, RTPP_LOG_ERR, "can't create player: %s", plerror);
    return -1;
}
예제 #3
0
static int
rtpp_proc_ttl_foreach(void *dp, void *ap)
{
    struct foreach_args *fap;
    struct rtpp_session *sp;

    fap = (struct foreach_args *)ap;
    /*
     * This method does not need us to bump ref, since we are in the
     * locked context of the rtpp_hash_table, which holds its own ref.
     */
    sp = (struct rtpp_session *)dp;

    if (CALL_METHOD(sp->rtp, get_ttl) == 0) {
        RTPP_LOG(sp->log, RTPP_LOG_INFO, "session timeout");
        if (sp->timeout_data.notify_target != NULL) {
            CALL_METHOD(fap->rtpp_notify_cf, schedule,
              sp->timeout_data.notify_target, sp->timeout_data.notify_tag);
        }
        CALL_SMETHOD(fap->rtpp_stats, updatebyname, "nsess_timeout", 1);
        CALL_METHOD(fap->sessions_wrt, unreg, sp->seuid);
        return (RTPP_HT_MATCH_DEL);
    } else {
        CALL_METHOD(sp->rtp, decr_ttl);
    }
    return (RTPP_HT_MATCH_CONT);
}
예제 #4
0
static int
rtpp_stream_guess_addr(struct rtpp_stream *self,
  struct rtp_packet *packet)
{
    int rport;
    const char *actor, *ptype;
    struct rtpp_stream_priv *pvt;

    pvt = PUB2PVT(self);

    if (self->addr != NULL && ishostseq(self->addr, sstosa(&packet->raddr))) {
        return (0);
    }
    if (self->addr == NULL) {
        self->addr = malloc(packet->rlen);
        if (self->addr == NULL) {
            return (-1);
        }
    }
    actor = rtpp_stream_get_actor(self);
    ptype =  rtpp_stream_get_proto(self);
    rport = ntohs(satosin(&packet->raddr)->sin_port);
    if (IS_LAST_PORT(rport)) {
        return (-1);
    }
    memcpy(self->addr, &packet->raddr, packet->rlen);
    satosin(self->addr)->sin_port = htons(rport + 1);
    /* Use guessed value as the only true one for asymmetric clients */
    self->latch_info.latched = self->asymmetric;
    RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO, "guessing %s port "
      "for %s to be %d", ptype, actor, rport + 1);

    return (0);
}
예제 #5
0
static void
do_timeout_notification(struct rtpp_notify_wi *wi, int retries,
  struct rtpp_log *log)
{
    int result;

    if (wi->rttp->connected == 0) {
        reconnect_timeout_handler(log, wi->rttp);

        /* If connect fails, no notification will be sent */
        if (wi->rttp->connected == 0) {
            RTPP_LOG(log, RTPP_LOG_ERR, "unable to send timeout notification");
            return;
        }
    }

    do {
        result = send(wi->rttp->fd, wi->notify_buf, wi->len - 1, 0);
    } while (result == -1 && errno == EINTR);

    if (result < 0) {
        wi->rttp->connected = 0;
        RTPP_ELOG(log, RTPP_LOG_ERR, "failed to send timeout notification");
        if (retries > 0)
            do_timeout_notification(wi, retries - 1, log);
    }
}
예제 #6
0
static int
rtpp_stream_check_latch_override(struct rtpp_stream *self,
  struct rtp_packet *packet)
{
    const char *actor;
    struct rtpp_stream_priv *pvt;
    char saddr[MAX_AP_STRBUF];

    pvt = PUB2PVT(self);

    if (self->session_type == SESS_RTCP || self->latch_info.ssrc == 0)
        return (0);
    if (rtp_packet_parse(packet) != RTP_PARSER_OK)
        return (0);
    if (packet->parsed->ssrc != self->latch_info.ssrc)
        return (0);
    if (packet->parsed->seq < self->latch_info.seq && self->latch_info.seq - packet->parsed->seq < 536)
        return (0);

    actor = rtpp_stream_get_actor(self);

    addrport2char_r(sstosa(&packet->raddr), saddr, sizeof(saddr));
    RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO,
      "%s's address re-latched: %s (%s), SSRC=" SSRC_FMT ", Seq=%u->%u", actor,
      saddr, "RTP", self->latch_info.ssrc, self->latch_info.seq,
      packet->parsed->seq);

    self->latch_info.seq = packet->parsed->seq;
    return (1);
}
예제 #7
0
static void
rtpp_mif_dtor(struct rtpp_module_if_priv *pvt)
{

    rtpp_module_if_fin(&(pvt->pub));
    /* First, stop the worker thread and wait for it to terminate */
    rtpp_queue_put_item(pvt->sigterm, pvt->req_q);
    pthread_join(pvt->thread_id, NULL);
    rtpp_queue_destroy(pvt->req_q);

    /* Then run module destructor (if any) */
    if (pvt->mip->dtor != NULL) {
        pvt->mip->dtor(pvt->mpvt);
    }

#if RTPP_CHECK_LEAKS
    /* Check if module leaked any mem */
    if (rtpp_memdeb_dumpstats(pvt->memdeb_p, 1) != 0) {
        RTPP_LOG(pvt->log, RTPP_LOG_ERR, "module '%s' leaked memory after "
          "destruction", pvt->mip->name);
    }
    rtpp_memdeb_dtor(pvt->memdeb_p);
#endif
    /* Unload and free everything */
    dlclose(pvt->dmp);
    CALL_METHOD(pvt->log->rcnt, decref);
    free(pvt);
}
예제 #8
0
static void
rtpp_stream_finish_playback(struct rtpp_stream *self, uint64_t sruid)
{
    struct rtpp_stream_priv *pvt;

    pvt = PUB2PVT(self);
    pthread_mutex_lock(&pvt->lock);
    if (pvt->rtps != RTPP_UID_NONE && pvt->rtps == sruid) {
        pvt->rtps = RTPP_UID_NONE;
        RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO,
          "player at port %d has finished", self->port);
    }
    pthread_mutex_unlock(&pvt->lock);
}
예제 #9
0
int
rtpp_anetio_sendto(struct rtpp_anetio_cf *netio_cf, int sock, const void *msg, \
  size_t msg_len, int flags, const struct sockaddr *sendto, socklen_t tolen)
{
    struct rtpp_wi *wi;

    wi = rtpp_wi_malloc(sock, msg, msg_len, flags, sendto, tolen);
    if (wi == NULL) {
        return (-1);
    }
#if RTPP_DEBUG_netio >= 1
    wi->debug = 1;
    wi->log = netio_cf->args[0].glog;
    CALL_SMETHOD(wi->log->rcnt, incref);
#if RTPP_DEBUG_netio >= 2
    RTPP_LOG(netio_cf->args[0].glog, RTPP_LOG_DBUG, "malloc(%d, %p, %d, %d, %p, %d) = %p",
      sock, msg, msg_len, flags, sendto, tolen, wi);
    RTPP_LOG(netio_cf->args[0].glog, RTPP_LOG_DBUG, "sendto(%d, %p, %d, %d, %p, %d)",
      wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, wi->tolen);
#endif
#endif
    rtpp_queue_put_item(wi, netio_cf->args[0].out_q);
    return (0);
}
예제 #10
0
static void
reconnect_timeout_handler(struct rtpp_log *log, struct rtpp_tnotify_target *rttp)
{

    assert (rttp->connected == 0);

    if (rttp->fd == -1) {
        RTPP_LOG(log, RTPP_LOG_DBUG, "connecting timeout socket");
    } else {
        RTPP_LOG(log, RTPP_LOG_DBUG, "reconnecting timeout socket");
        close(rttp->fd);
    }
    rttp->fd = socket(rttp->socket_type, SOCK_STREAM, 0);
    if (rttp->fd == -1) {
        RTPP_ELOG(log, RTPP_LOG_ERR, "can't create timeout socket");
        return;
    }
    if (rttp->local != NULL) {
        if (bind(rttp->fd, rttp->local, SA_LEN(rttp->local)) < 0) {
            RTPP_ELOG(log, RTPP_LOG_ERR, "can't bind timeout socket");
            goto e0;
        }
    }
    if (connect(rttp->fd, (struct sockaddr *)&(rttp->remote), rttp->remote_len) == -1) {
        RTPP_ELOG(log, RTPP_LOG_ERR, "can't connect to timeout socket");
        goto e0;
    } else {
        rttp->connected = 1;
    }
    return;

e0:
    close(rttp->fd);
    rttp->fd = -1;
    return;
}
예제 #11
0
static void
rtpp_stream_handle_noplay(struct rtpp_stream *self)
{
    struct rtpp_stream_priv *pvt;

    pvt = PUB2PVT(self);
    pthread_mutex_lock(&pvt->lock);
    if (pvt->rtps != RTPP_UID_NONE) {
        if (CALL_METHOD(pvt->servers_wrt, unreg, pvt->rtps) != NULL) {
            pvt->rtps = RTPP_UID_NONE;
        }
        RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO,
          "stopping player at port %d", self->port);
    }
    pthread_mutex_unlock(&pvt->lock);
}
예제 #12
0
static void
rtpp_mif_do_acct(struct rtpp_module_if *self, struct rtpp_acct *acct)
{
    struct rtpp_module_if_priv *pvt;
    struct rtpp_wi *wi;

    pvt = PUB2PVT(self);
    wi = rtpp_wi_malloc_apis(do_acct_aname, &acct, sizeof(acct));
    if (wi == NULL) {
        RTPP_LOG(pvt->log, RTPP_LOG_ERR, "module '%s': cannot allocate "
          "memory", pvt->mip->name);
        return;
    }
    CALL_METHOD(acct->rcnt, incref);
    rtpp_queue_put_item(wi, pvt->req_q);
}
예제 #13
0
static int
rtpp_stream_latch(struct rtpp_stream *self, double dtime,
  struct rtp_packet *packet)
{
    const char *actor, *ptype, *ssrc, *seq, *relatch;
    char ssrc_buf[11], seq_buf[6];
    struct rtpp_stream_priv *pvt;
    char saddr[MAX_AP_STRBUF];

    pvt = PUB2PVT(self);
    if (pvt->last_update != 0 && \
      dtime - pvt->last_update < UPDATE_WINDOW) {
        return (0);
    }

    actor = rtpp_stream_get_actor(self);
    ptype = rtpp_stream_get_proto(self);

    if (self->session_type == SESS_RTP) {
        if (rtp_packet_parse(packet) == RTP_PARSER_OK) {
            self->latch_info.ssrc = packet->parsed->ssrc;
            self->latch_info.seq = packet->parsed->seq;
            snprintf(ssrc_buf, sizeof(ssrc_buf), SSRC_FMT, packet->parsed->ssrc);
            snprintf(seq_buf, sizeof(seq_buf), "%u", packet->parsed->seq);
            ssrc = ssrc_buf;
            seq = seq_buf;
        } else {
            self->latch_info.ssrc = 0;
            ssrc = seq = "INVALID";
        }
    } else {
        self->latch_info.ssrc = 0;
        ssrc = seq = "UNKNOWN";
    }

    addrport2char_r(sstosa(&packet->raddr), saddr, sizeof(saddr));
    if (self->latch_info.latched == 0) {
        relatch = "";
    } else {
        relatch = "re-";
    }
    RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO,
      "%s's address %slatched in: %s (%s), SSRC=%s, Seq=%s", actor, relatch,
      saddr, ptype, ssrc, seq);
    self->latch_info.latched = 1;
    return (1);
}
예제 #14
0
static void
handle_nomem(struct cfg *cf, struct rtpp_command *cmd,
  int ecode, struct ul_opts *ulop, struct rtpp_socket **fds,
  struct rtpp_session *spa)
{
    int i;

    RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "can't allocate memory");
    rtpp_command_ul_opts_free(ulop);
    if (spa != NULL) {
        CALL_METHOD(spa->rcnt, decref);
    }
    if (fds != NULL) {
        for (i = 0; i < 2; i++)
            if (fds[i] != NULL)
                CALL_METHOD(fds[i]->rcnt, decref);
    }
    reply_error(cmd, ecode);
}
예제 #15
0
static void
rtpp_stream_prefill_addr(struct rtpp_stream *self, struct sockaddr **iapp,
  double dtime)
{
    struct rtpp_stream_priv *pvt;
    char saddr[MAX_AP_STRBUF];
    const char *actor, *ptype;

    pvt = PUB2PVT(self);

    if (self->addr != NULL)
        pvt->last_update = dtime;

    /*
     * Unless the address provided by client historically
     * cannot be trusted and address is different from one
     * that we recorded update it.
     */
    if (pvt->untrusted_addr != 0)
        return;
    if (self->addr != NULL && isaddrseq(self->addr, *iapp)) {
        return;
    }

    addrport2char_r(*iapp, saddr, sizeof(saddr));
    actor = rtpp_stream_get_actor(self);
    ptype =  rtpp_stream_get_proto(self);
    RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO, "pre-filling %s's %s address "
      "with %s", actor, ptype, saddr);
    if (self->addr != NULL) {
        if (self->latch_info.latched != 0) {
            if (pvt->prev_addr != NULL)
                 free(pvt->prev_addr);
            pvt->prev_addr = self->addr;
        } else {
            free(self->addr);
        }
    }
    self->addr = *iapp;
    *iapp = NULL;
}
예제 #16
0
int
rtpp_anetio_send_pkt_na(struct sthread_args *sender, int sock, \
  struct rtpp_netaddr *sendto, struct rtp_packet *pkt,
  struct rtpp_refcnt *sock_rcnt, struct rtpp_log *plog)
{
    struct rtpp_wi *wi;
    int nsend;

    if (sender->dmode != 0 && pkt->size < LBR_THRS) {
        nsend = 2;
    } else {
        nsend = 1;
    }

    wi = rtpp_wi_malloc_pkt_na(sock, pkt, sendto, nsend, sock_rcnt);
    if (wi == NULL) {
        rtp_packet_free(pkt);
        return (-1);
    }
    /*
     * rtpp_wi_malloc_pkt() consumes pkt and returns wi, so no need to
     * call rtp_packet_free() here.
     */
#if RTPP_DEBUG_netio >= 2
    wi->debug = 1;
    if (plog == NULL) {
        plog = sender->glog;
    }
    CALL_SMETHOD(plog->rcnt, incref);
    wi->log = plog;
    RTPP_LOG(plog, RTPP_LOG_DBUG, "send_pkt(%d, %p, %d, %d, %p, %d)",
      wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, wi->tolen);
#endif
    rtpp_queue_put_item(wi, sender->out_q);
    return (0);
}
예제 #17
0
static void
rtpp_stream_fill_addr(struct rtpp_stream *self,
  struct rtp_packet *packet)
{
    const char *actor, *ptype;
    struct rtpp_stream_priv *pvt;
    char saddr[MAX_AP_STRBUF];

    pvt = PUB2PVT(self);

    pvt->untrusted_addr = 1;
    memcpy(self->addr, &packet->raddr, packet->rlen);
    if (pvt->prev_addr == NULL || memcmp(pvt->prev_addr,
      &packet->raddr, packet->rlen) != 0) {
        self->latch_info.latched = 1;
    }

    actor = rtpp_stream_get_actor(self);
    ptype =  rtpp_stream_get_proto(self);
    addrport2char_r(sstosa(&packet->raddr), saddr, sizeof(saddr));
    RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO,
      "%s's address filled in: %s (%s)", actor, saddr, ptype);
    return;
}
예제 #18
0
static void
rtpp_stream_dtor(struct rtpp_stream_priv *pvt)
{
    struct rtpp_stream *pub;

    pub = &(pvt->pub);
    rtpp_stream_fin(pub);
    if (pub->analyzer != NULL) {
         struct rtpa_stats rst;
         char ssrc_buf[11];
         const char *actor, *ssrc;

         actor = rtpp_stream_get_actor(pub);
         CALL_METHOD(pub->analyzer, get_stats, &rst);
         if (rst.ssrc_changes != 0) {
             snprintf(ssrc_buf, sizeof(ssrc_buf), SSRC_FMT, rst.last_ssrc);
             ssrc = ssrc_buf;
         } else {
             ssrc = "NONE";
         }
         RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO, "RTP stream from %s: "
           "SSRC=%s, ssrc_changes=%u, psent=%u, precvd=%u, plost=%d, pdups=%u",
           actor, ssrc, rst.ssrc_changes, rst.psent, rst.precvd,
           rst.plost, rst.pdups);
         if (rst.psent > 0) {
             CALL_METHOD(pvt->rtpp_stats, updatebyname, "rtpa_nsent", rst.psent);
         }
         if (rst.precvd > 0) {
             CALL_METHOD(pvt->rtpp_stats, updatebyname, "rtpa_nrcvd", rst.precvd);
         }
         if (rst.pdups > 0) {
             CALL_METHOD(pvt->rtpp_stats, updatebyname, "rtpa_ndups", rst.pdups);
         }
         if (rst.pecount > 0) {
             CALL_METHOD(pvt->rtpp_stats, updatebyname, "rtpa_perrs", rst.pecount);
         }
         CALL_METHOD(pvt->pub.analyzer->rcnt, decref);
    }
    if (pub->fd != NULL)
        CALL_METHOD(pub->fd->rcnt, decref);
    if (pub->addr != NULL)
        free(pub->addr);
    if (pvt->prev_addr != NULL)
        free(pvt->prev_addr);
    if (pub->codecs != NULL)
        free(pub->codecs);
    if (pvt->rtps != RTPP_UID_NONE)
        CALL_METHOD(pvt->servers_wrt, unreg, pvt->rtps);
    if (pub->resizer != NULL)
        rtp_resizer_free(pvt->rtpp_stats, pub->resizer);
    if (pub->rrc != NULL)
        CALL_METHOD(pub->rrc->rcnt, decref);
    if (pub->pcount != NULL)
        CALL_METHOD(pub->pcount->rcnt, decref);

    CALL_METHOD(pub->ttl->rcnt, decref);
    CALL_METHOD(pub->pcnt_strm->rcnt, decref);
    CALL_METHOD(pvt->pub.log->rcnt, decref);

    pthread_mutex_destroy(&pvt->lock);
    free(pvt);
}
예제 #19
0
int
rtpp_command_ul_handle(struct cfg *cf, struct rtpp_command *cmd,
  struct ul_opts *ulop, int sidx)
{
    int pidx, lport, sessions_active;
    struct rtpp_socket *fds[2];
    const char *actor;
    struct rtpp_session *spa, *spb;

    pidx = 1;
    lport = 0;
    spa = spb = NULL;
    fds[0] = fds[1] = NULL;
    if (sidx != -1) {
        RTPP_DBG_ASSERT(cmd->cca.op == UPDATE || cmd->cca.op == LOOKUP);
        spa = cmd->sp;
        if (spa->rtp->stream[sidx]->fd == NULL || ulop->new_port != 0) {
            if (ulop->local_addr != NULL) {
                spa->rtp->stream[sidx]->laddr = ulop->local_addr;
            }
            if (rtpp_create_listener(cf, spa->rtp->stream[sidx]->laddr, &lport, fds) == -1) {
                RTPP_LOG(spa->log, RTPP_LOG_ERR, "can't create listener");
                reply_error(cmd, ECODE_LSTFAIL_1);
                goto err_undo_0;
            }
            if (spa->rtp->stream[sidx]->fd != NULL && ulop->new_port != 0) {
                RTPP_LOG(spa->log, RTPP_LOG_INFO,
                  "new port requested, releasing %d/%d, replacing with %d/%d",
                  spa->rtp->stream[sidx]->port, spa->rtcp->stream[sidx]->port, lport, lport + 1);
                CALL_METHOD(cf->stable->sessinfo, update, spa, sidx, fds);
            } else {
                RTPP_DBG_ASSERT(spa->rtp->stream[sidx]->fd == NULL);
                spa->rtp->stream[sidx]->fd = fds[0];
                RTPP_DBG_ASSERT(spa->rtcp->stream[sidx]->fd == NULL);
                spa->rtcp->stream[sidx]->fd = fds[1];
                CALL_METHOD(cf->stable->sessinfo, append, spa, sidx);
            }
            spa->rtp->stream[sidx]->port = lport;
            spa->rtcp->stream[sidx]->port = lport + 1;
            if (spa->complete == 0) {
                cmd->csp->nsess_complete.cnt++;
            }
            spa->complete = 1;
        }
        if (ulop->weak)
            spa->rtp->stream[sidx]->weak = 1;
        else if (cmd->cca.op == UPDATE)
            spa->strong = 1;
        lport = spa->rtp->stream[sidx]->port;
        ulop->lia[0] = spa->rtp->stream[sidx]->laddr;
        pidx = (sidx == 0) ? 1 : 0;
        if (cmd->cca.op == UPDATE) {
            CALL_METHOD(spa->rtp->stream[0]->ttl, reset_with,
              cf->stable->max_setup_ttl);
            CALL_METHOD(spa->rtp->stream[1]->ttl, reset_with,
              cf->stable->max_setup_ttl);
            RTPP_LOG(spa->log, RTPP_LOG_INFO,
              "adding %s flag to existing session, new=%d/%d/%d",
              ulop->weak ? ( sidx ? "weak[1]" : "weak[0]" ) : "strong",
              spa->strong, spa->rtp->stream[0]->weak, spa->rtp->stream[1]->weak);
        } else {
            CALL_METHOD(spa->rtp->stream[0]->ttl, reset_with, cf->stable->max_ttl);
            CALL_METHOD(spa->rtp->stream[1]->ttl, reset_with, cf->stable->max_ttl);
        }
        RTPP_LOG(spa->log, RTPP_LOG_INFO,
          "lookup on ports %d/%d, session timer restarted", spa->rtp->stream[0]->port,
          spa->rtp->stream[1]->port);
    } else {
        struct rtpp_hash_table_entry *hte;

        RTPP_DBG_ASSERT(cmd->cca.op == UPDATE);
        RTPP_LOG(cf->stable->glog, RTPP_LOG_INFO,
          "new session %s, tag %s requested, type %s",
          cmd->cca.call_id, cmd->cca.from_tag, ulop->weak ? "weak" : "strong");
        if (cf->stable->slowshutdown != 0) {
            RTPP_LOG(cf->stable->glog, RTPP_LOG_INFO,
              "proxy is in the deorbiting-burn mode, new session rejected");
            reply_error(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(cf->stable->glog, RTPP_LOG_ERR, "can't create listener");
            reply_error(cmd, ECODE_LSTFAIL_2);
            goto err_undo_0;
        }

        /*
         * Session creation. If creation is requested with weak flag,
         * set weak[0].
         */
        spa = rtpp_session_ctor(cf->stable, &cmd->cca, cmd->dtime, ulop->lia,
          ulop->weak, lport, fds);
        if (spa == NULL) {
            handle_nomem(cf, cmd, ECODE_NOMEM_4, ulop,
              fds, NULL);
            return (-1);
        }

        hte = CALL_METHOD(cf->stable->sessions_ht, append_refcnt, spa->call_id,
          spa->rcnt);
        if (hte == NULL) {
            handle_nomem(cf, cmd, ECODE_NOMEM_5, ulop, NULL, spa);
            return (-1);
        }
        if (CALL_METHOD(cf->stable->sessions_wrt, reg, spa->rcnt, spa->seuid) != 0) {
            CALL_METHOD(cf->stable->sessions_ht, remove, spa->call_id, hte);
            handle_nomem(cf, cmd, ECODE_NOMEM_8, ulop, NULL, spa);
            return (-1);
        }

        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.
         */
        sessions_active = CALL_METHOD(cf->stable->sessions_wrt, get_length);
        if (sessions_active > (rtpp_rlim_max(cf) * 80 / (100 * 5)) &&
          cf->nofile_limit_warned == 0) {
            cf->nofile_limit_warned = 1;
            RTPP_LOG(cf->stable->glog, RTPP_LOG_WARN, "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(spa->log, RTPP_LOG_INFO, "new session on a port %d created, "
          "tag %s", lport, cmd->cca.from_tag);
        if (cf->stable->record_all != 0) {
            handle_copy(cf, spa, 0, NULL, 0);
            handle_copy(cf, spa, 1, NULL, 0);
        }
        /* Save ref, it will be decref'd by the command disposal code */
        RTPP_DBG_ASSERT(cmd->sp == NULL);
        cmd->sp = spa;
    }

    if (cmd->cca.op == UPDATE) {
        if (!CALL_METHOD(cf->stable->rtpp_tnset_cf, isenabled) && ulop->notify_socket != NULL)
            RTPP_LOG(spa->log, RTPP_LOG_ERR, "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 (ulop->notify_socket != NULL) {
            struct rtpp_tnotify_target *rttp;

            rttp = CALL_METHOD(cf->stable->rtpp_tnset_cf, lookup, ulop->notify_socket,
              (cmd->rlen > 0) ? sstosa(&cmd->raddr) : NULL, (cmd->rlen > 0) ? cmd->laddr : NULL);
            if (rttp == NULL) {
                RTPP_LOG(spa->log, RTPP_LOG_ERR, "invalid socket name %s", ulop->notify_socket);
                ulop->notify_socket = NULL;
            } else {
                RTPP_LOG(spa->log, RTPP_LOG_INFO, "setting timeout handler");
                spa->timeout_data.notify_target = rttp;
                spa->timeout_data.notify_tag = strdup(ulop->notify_tag);
            }
        } else if (spa->timeout_data.notify_target != NULL) {
            spa->timeout_data.notify_target = NULL;
            RTPP_LOG(spa->log, RTPP_LOG_INFO, "disabling timeout handler");
        }
    }

    if (ulop->ia[0] != NULL && ulop->ia[1] != NULL) {
        CALL_METHOD(spa->rtp->stream[pidx], prefill_addr, &(ulop->ia[0]),
          cmd->dtime);
        CALL_METHOD(spa->rtcp->stream[pidx], prefill_addr, &(ulop->ia[1]),
          cmd->dtime);
    }
    spa->rtp->stream[pidx]->asymmetric = spa->rtcp->stream[pidx]->asymmetric = ulop->asymmetric;
    spa->rtp->stream[pidx]->latch_info.latched = spa->rtcp->stream[pidx]->latch_info.latched = ulop->asymmetric;
    if (spa->rtp->stream[pidx]->codecs != NULL) {
        free(spa->rtp->stream[pidx]->codecs);
        spa->rtp->stream[pidx]->codecs = NULL;
    }
    if (ulop->codecs != NULL) {
        spa->rtp->stream[pidx]->codecs = ulop->codecs;
        ulop->codecs = NULL;
    }
    spa->rtp->stream[NOT(pidx)]->ptime = ulop->requested_ptime;
    actor = CALL_METHOD(spa->rtp->stream[pidx], get_actor);
    if (ulop->requested_ptime > 0) {
        RTPP_LOG(spa->log, RTPP_LOG_INFO, "RTP packets from %s "
          "will be resized to %d milliseconds", actor, ulop->requested_ptime);
    } else if (spa->rtp->stream[pidx]->resizer != NULL) {
          RTPP_LOG(spa->log, RTPP_LOG_INFO, "Resizing of RTP "
          "packets from %s has been disabled", actor);
    }
    if (ulop->requested_ptime > 0) {
        if (spa->rtp->stream[pidx]->resizer != NULL) {
            rtp_resizer_set_ptime(spa->rtp->stream[pidx]->resizer, ulop->requested_ptime);
        } else {
            spa->rtp->stream[pidx]->resizer = rtp_resizer_new(ulop->requested_ptime);
        }
    } else if (spa->rtp->stream[pidx]->resizer != NULL) {
        rtp_resizer_free(cf->stable->rtpp_stats, spa->rtp->stream[pidx]->resizer);
        spa->rtp->stream[pidx]->resizer = NULL;
    }

    RTPP_DBG_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(cmd, &ulop->reply);
    rtpp_command_ul_opts_free(ulop);
    return (0);

err_undo_0:
    rtpp_command_ul_opts_free(ulop);
    return (-1);
}
예제 #20
0
struct ul_opts *
rtpp_command_ul_opts_parse(struct cfg *cf, struct rtpp_command *cmd)
{
    int len, tpf, n, i;
    char c;
    char *cp, *t;
    const char *errmsg;
    struct sockaddr_storage tia;
    struct ul_opts *ulop;

    ulop = rtpp_zmalloc(sizeof(struct ul_opts));
    if (ulop == NULL) {
        reply_error(cmd, ECODE_NOMEM_1);
        goto err_undo_0;
    }
    ul_opts_init(cf, ulop);
    if (cmd->cca.op == UPDATE && cmd->argc > 6) {
        if (cmd->argc == 8) {
            ulop->notify_socket = cmd->argv[6];
            ulop->notify_tag = cmd->argv[7];
        } else {
            ulop->notify_socket = cmd->argv[5];
            ulop->notify_tag = cmd->argv[6];
            cmd->cca.to_tag = NULL;
        }
        len = url_unquote((uint8_t *)ulop->notify_tag, strlen(ulop->notify_tag));
        if (len == -1) {
            RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR,
              "command syntax error - invalid URL encoding");
            reply_error(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 || cf->stable->bindaddr[1] == NULL) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error");
                reply_error(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 || cf->stable->bindaddr[1] == NULL) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error");
                reply_error(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_ptime = strtol(cp + 1, &cp, 10);
            if (ulop->requested_ptime <= 0) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error");
                reply_error(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(cf->stable->glog, RTPP_LOG_ERR, "command syntax error");
                reply_error(cmd, ECODE_PARSE_14);
                goto err_undo_1;
            }
            ulop->codecs = malloc(cp - t + 1);
            if (ulop->codecs == NULL) {
                reply_error(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(cf->stable->glog, RTPP_LOG_ERR, "command syntax error");
                reply_error(cmd, ECODE_PARSE_15);
                goto err_undo_1;
            }
            c = t[len];
            t[len] = '\0';
            ulop->local_addr = host2bindaddr(cf, t, tpf, &errmsg);
            if (ulop->local_addr == NULL) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR,
                  "invalid local address: %s: %s", t, errmsg);
                reply_error(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(cf->stable->glog, RTPP_LOG_ERR, "command syntax error");
                reply_error(cmd, ECODE_PARSE_16);
                goto err_undo_1;
            }
            c = t[len];
            t[len] = '\0';
            ulop->local_addr = alloca(sizeof(struct sockaddr_storage));
            n = resolve(ulop->local_addr, tpf, t, SERVICE, AI_PASSIVE);
            if (n != 0) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR,
                  "invalid remote address: %s: %s", t, gai_strerror(n));
                reply_error(cmd, ECODE_INVLARG_2);
                goto err_undo_1;
            }
            if (local4remote(ulop->local_addr, satoss(ulop->local_addr)) == -1) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR,
                  "can't find local address for remote address: %s", t);
                reply_error(cmd, ECODE_INVLARG_3);
                goto err_undo_1;
            }
            ulop->local_addr = addr2bindaddr(cf, ulop->local_addr, &errmsg);
            if (ulop->local_addr == NULL) {
                RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR,
                  "invalid local address: %s", errmsg);
                reply_error(cmd, ECODE_INVLARG_4);
                goto err_undo_1;
            }
            t[len] = c;
            cp--;
            break;

        case 'n':
        case 'N':
            ulop->new_port = 1;
            break;

        default:
            RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "unknown command modifier `%c'",
              *cp);
            break;
        }
    }
    if (ulop->addr != NULL && ulop->port != NULL && strlen(ulop->addr) >= 7) {
        n = resolve(sstosa(&tia), ulop->pf, ulop->addr, ulop->port, AI_NUMERICHOST);
        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(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(cf->stable->glog, RTPP_LOG_ERR, "getaddrinfo(pf=%d, addr=%s, port=%s): %s",
              ulop->pf, ulop->addr, ulop->port, gai_strerror(n));
        }
    }
    return (ulop);

err_undo_1:
    rtpp_command_ul_opts_free(ulop);
err_undo_0:
    return (NULL);
}
예제 #21
0
파일: rtpp_cfile.c 프로젝트: sippy/rtpproxy
int
rtpp_cfile_process(struct rtpp_cfg_stable *csp)
{
    struct ucl_parser *parser;
    ucl_object_t *conf_root;
    ucl_object_iter_t it_conf;
    const ucl_object_t *obj_file;
    const char *cf_key;
    int fd, ecode;

    ecode = 0;

    fd = open(csp->cfile, O_RDONLY);
    if (fd < 0) {
        RTPP_ELOG(csp->glog, RTPP_LOG_ERR, "open failed: %s", csp->cfile);
        ecode = -1;
        goto e0;
    }

    parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
    if (parser == NULL) {
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "ucl_parser_new() failed");
        ecode = -1;
        goto e1;
    }

    ucl_parser_add_fd(parser, fd);
    conf_root = ucl_parser_get_object(parser);
    if (conf_root == NULL) {
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "ucl_parser_get_object() failed");
        ecode = -1;
        goto e2;
    }
    if (ucl_parser_get_error(parser)) {
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Parse Error occured: %s", ucl_parser_get_error(parser));
        ecode = -1;
        goto e3;
    }

    it_conf = ucl_object_iterate_new(conf_root);
    if (it_conf == NULL) {
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "ucl_object_iterate_new() failed");
        ecode = -1;
        goto e3;
    }
    while ((obj_file = ucl_object_iterate_safe(it_conf, true)) != NULL) {
        cf_key = ucl_object_key(obj_file);
        RTPP_LOG(csp->glog, RTPP_LOG_DBUG, "Entry: %s", cf_key);
        if (strcasecmp(cf_key, "modules") == 0) {
            if (parse_modules(csp, obj_file) < 0) {
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "parse_modules() failed");
                ecode = -1;
                goto e4;
            }
        }
    }
    if (ucl_object_iter_chk_excpn(it_conf)) {
        ecode = -1;
    }
e4:
    ucl_object_iterate_free(it_conf);
e3:
    ucl_object_unref(conf_root);
e2:
    ucl_parser_free(parser);
e1:
    close(fd);
e0:
    return (ecode);
}
예제 #22
0
파일: rtpp_cfile.c 프로젝트: sippy/rtpproxy
static int
parse_modules(struct rtpp_cfg_stable *csp, const ucl_object_t *wop)
{
    ucl_object_iter_t it_conf;
    const ucl_object_t *obj_file;
    const char *cf_key;
    const ucl_object_t *obj_key;
    int ecode, success;
    void *confp;
    const conf_helper_map *fent, *map;
    struct rtpp_module_conf *mcp;
    char mpath[PATH_MAX + 1];
    const char *cp, *mp;
    struct rtpp_module_if *mif;

    it_conf = ucl_object_iterate_new(wop);
    if (it_conf == NULL)
        return (-1);
    ecode = 0;
    while ((obj_file = ucl_object_iterate_safe(it_conf, true)) != NULL) {
        cf_key = ucl_object_key(obj_file);
        RTPP_LOG(csp->glog, RTPP_LOG_DBUG, "\tmodule: %s", cf_key);
        obj_key = ucl_object_find_key(obj_file, "load");
        if (obj_key == NULL) {
            cp = rtpp_module_dsop_canonic(cf_key, mpath, sizeof(mpath));
            if (cp == NULL) {
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Error: Unable to find load parameter in module: %s", cf_key);
                ecode = -1;
                goto e0;
            }
        } else {
            if (obj_key->type != UCL_STRING) {
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Error: \"load\" parameter in %s has a wrong type, string is expected", cf_key);
                ecode = -1;
                goto e0;
            }
            mp = ucl_object_tostring(obj_key);
            cp = realpath(mp, mpath);
            if (cp == NULL) {
                RTPP_ELOG(csp->glog, RTPP_LOG_ERR, "realpath() failed: %s", mp);
                ecode = -1;
                goto e0;
            }
        }
        mif = rtpp_module_if_ctor(cp);
        if (mif == NULL) {
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "dymanic module constructor has failed: %s", cp);
            ecode = -1;
            goto e0;
        }
        if (CALL_METHOD(mif, load, csp, csp->glog) != 0) {
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "%p->load() method has failed: %s", mif, cp);
            goto e1;
        }
        if (CALL_METHOD(mif, get_mconf, &mcp) < 0) {
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "%p->get_mconf() method has failed: %s", mif, cp);
            goto e1;
        }
        fent = NULL;
        if (mcp != NULL) {
            map = mcp->conf_map;
            confp = mcp->conf_data;
        } else {
            map = default_module_map;
            confp = NULL;
        }
        success = conf_helper_mapper(csp->glog, obj_file, map, confp, &fent);
        if (!success) {
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Config parsing issue in section %s",
              cf_key);
            if (fent != NULL && fent->conf_key != NULL) {
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "\tparameter %s", fent->conf_key);
            }
            goto e1;
        }
        if (CALL_METHOD(mif, config) < 0) {
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "%p->config() method has failed: %s", mif, cp);
            goto e1;
        }
        rtpp_list_append(csp->modules_cf, mif);
        continue;
e1:
        ecode = -1;
        CALL_SMETHOD(mif->rcnt, decref);
        goto e0;
    }
e0:
    if (ucl_object_iter_chk_excpn(it_conf)) {
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "UCL has failed with an internal error");
        ecode = -1;
    }
    ucl_object_iterate_free(it_conf);
    return (ecode);
}
예제 #23
0
struct rtpp_module_if *
rtpp_module_if_ctor(struct rtpp_cfg_stable *cfsp, struct rtpp_log *log,
  const char *mpath)
{
    struct rtpp_refcnt *rcnt;
    struct rtpp_module_if_priv *pvt;
    const char *derr;

    pvt = rtpp_rzmalloc(sizeof(struct rtpp_module_if_priv), &rcnt);
    if (pvt == NULL) {
        goto e0;
    }
    pvt->pub.rcnt = rcnt;
    pvt->dmp = dlopen(mpath, RTLD_NOW);
    if (pvt->dmp == NULL) {
        derr = dlerror();
        if (strstr(derr, mpath) == NULL) {
            RTPP_LOG(log, RTPP_LOG_ERR, "can't dlopen(%s): %s", mpath, derr);
        } else {
            RTPP_LOG(log, RTPP_LOG_ERR, "can't dlopen() module: %s", derr);
        }
        goto e1;
    }
    pvt->mip = dlsym(pvt->dmp, "rtpp_module");
    if (pvt->mip == NULL) {
        derr = dlerror();
        if (strstr(derr, mpath) == NULL) {
            RTPP_LOG(log, RTPP_LOG_ERR, "can't find 'rtpp_module' symbol in the %s"
              ": %s", mpath, derr);
        } else {
            RTPP_LOG(log, RTPP_LOG_ERR, "can't find 'rtpp_module' symbol: %s",
              derr);
        }
        goto e2;
    }
    if (!MI_VER_CHCK(pvt->mip)) {
        RTPP_LOG(log, RTPP_LOG_ERR, "incompatible API version in the %s, "
          "consider recompiling the module", mpath);
        goto e2;
    }

#if RTPP_CHECK_LEAKS
    pvt->mip->_malloc = &rtpp_memdeb_malloc;
    pvt->mip->_zmalloc = &rtpp_zmalloc_memdeb;
    pvt->mip->_free = &rtpp_memdeb_free;
    pvt->mip->_realloc = &rtpp_memdeb_realloc;
    pvt->mip->_strdup = &rtpp_memdeb_strdup;
    pvt->mip->_asprintf = &rtpp_memdeb_asprintf;
    pvt->mip->_vasprintf = &rtpp_memdeb_vasprintf;
    pvt->memdeb_p = rtpp_memdeb_init();
    rtpp_memdeb_setlog(pvt->memdeb_p, log);
#else
    pvt->mip->_malloc = (rtpp_module_malloc_t)&malloc;
    pvt->mip->_zmalloc = (rtpp_module_zmalloc_t)&rtpp_zmalloc;
    pvt->mip->_free = (rtpp_module_free_t)&free;
    pvt->mip->_realloc = (rtpp_module_realloc_t)&realloc;
    pvt->mip->_strdup = (rtpp_module_strdup_t)&strdup;
    pvt->mip->_asprintf = rtpp_module_asprintf;
    pvt->mip->_vasprintf = rtpp_module_vasprintf;
#endif
    if (pvt->memdeb_p == NULL) {
        goto e2;
    }
    /* We make a copy, so that the module cannot screw us up */
    pvt->mip->memdeb_p = pvt->memdeb_p;
    pvt->sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0);
    if (pvt->sigterm == NULL) {
        goto e3;
    }
    pvt->req_q = rtpp_queue_init(1, "rtpp_module_if(%s)", pvt->mip->name);
    if (pvt->req_q == NULL) {
        goto e4;
    }
    if (pvt->mip->ctor != NULL) {
        pvt->mpvt = pvt->mip->ctor(cfsp);
        if (pvt->mpvt == NULL) {
            RTPP_LOG(log, RTPP_LOG_ERR, "module '%s' failed to initialize",
              pvt->mip->name);
            goto e5;
        }
    }
    if (pvt->mip->on_session_end.argsize != rtpp_acct_OSIZE()) {
        RTPP_LOG(log, RTPP_LOG_ERR, "incompatible API version in the %s, "
          "consider recompiling the module", mpath);
        goto e6;
    }

    if (pthread_create(&pvt->thread_id, NULL,
      (void *(*)(void *))&rtpp_mif_run, pvt) != 0) {
        goto e6;
    }
    CALL_METHOD(log->rcnt, incref);
    pvt->log = log;
    pvt->pub.do_acct = &rtpp_mif_do_acct;
    CALL_METHOD(pvt->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_mif_dtor,
      pvt);
    return ((&pvt->pub));
e6:
    if (pvt->mip->dtor != NULL) {
        pvt->mip->dtor(pvt->mpvt);
    }
e5:
    rtpp_queue_destroy(pvt->req_q);
#if RTPP_CHECK_LEAKS
    if (rtpp_memdeb_dumpstats(pvt->memdeb_p, 1) != 0) {
        RTPP_LOG(log, RTPP_LOG_ERR, "module '%s' leaked memory in the failed "
          "constructor", pvt->mip->name);
    }
#endif
e4:
    rtpp_wi_free(pvt->sigterm);
e3:
#if RTPP_CHECK_LEAKS
    rtpp_memdeb_dtor(pvt->memdeb_p);
#endif
e2:
    dlclose(pvt->dmp);
e1:
    CALL_METHOD(rcnt, decref);
    free(pvt);
e0:
    return (NULL);
}
예제 #24
0
static void
rtpp_anetio_sthread(struct sthread_args *args)
{
    int n, nsend, i, send_errno, nretry;
    struct rtpp_wi *wi, *wis[100];
#if RTPP_DEBUG_timers
    double tp[3], runtime, sleeptime;
    long run_n;

    runtime = sleeptime = 0.0;
    run_n = 0;
    tp[0] = getdtime();
#endif
    for (;;) {
        nsend = rtpp_queue_get_items(args->out_q, wis, 100, 0);
#if RTPP_DEBUG_timers
        tp[1] = getdtime();
#endif

        for (i = 0; i < nsend; i++) {
	    wi = wis[i];
            if (wi->wi_type == RTPP_WI_TYPE_SGNL) {
                rtpp_wi_free(wi);
                goto out;
            }
            nretry = 0;
            do {
                n = sendto(wi->sock, wi->msg, wi->msg_len, wi->flags,
                  wi->sendto, wi->tolen);
                send_errno = (n < 0) ? errno : 0;
#if RTPP_DEBUG_netio >= 1
                if (wi->debug != 0) {
                    char daddr[MAX_AP_STRBUF];

                    addrport2char_r(wi->sendto, daddr, sizeof(daddr), ':');
                    if (n < 0) {
                        RTPP_ELOG(wi->log, RTPP_LOG_DBUG,
                          "sendto(%d, %p, %lld, %d, %p (%s), %d) = %d",
                          wi->sock, wi->msg, (long long)wi->msg_len, wi->flags,
                          wi->sendto, daddr, wi->tolen, n);
                    } else if (n < wi->msg_len) {
                        RTPP_LOG(wi->log, RTPP_LOG_DBUG,
                          "sendto(%d, %p, %lld, %d, %p (%s), %d) = %d: short write",
                          wi->sock, wi->msg, (long long)wi->msg_len, wi->flags,
                          wi->sendto, daddr, wi->tolen, n);
#if RTPP_DEBUG_netio >= 2
                    } else {
                        RTPP_LOG(wi->log, RTPP_LOG_DBUG,
                          "sendto(%d, %p, %d, %d, %p (%s), %d) = %d",
                          wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, daddr,
                          wi->tolen, n);
#endif
                    }
                }
#endif
                if (n >= 0) {
                    wi->nsend--;
                } else {
                    /* "EPERM" is Linux thing, yield and retry */
                    if ((send_errno == EPERM || send_errno == ENOBUFS)
                      && nretry < RTPP_ANETIO_MAX_RETRY) {
                        sched_yield();
                        nretry++;
                    } else {
                        break;
                    }
                }
            } while (wi->nsend > 0);
            rtpp_wi_free(wi);
        }
#if RTPP_DEBUG_timers
        sleeptime += tp[1] - tp[0];
        tp[0] = getdtime();
        runtime += tp[0] - tp[1];
        if ((run_n % 10000) == 0) {
            RTPP_LOG(args->glog, RTPP_LOG_DBUG, "rtpp_anetio_sthread(%p): run %ld aload = %f filtered = %f", \
              args, run_n, runtime / (runtime + sleeptime), args->average_load.lastval);
        }
        if (runtime + sleeptime > 1.0) {
            recfilter_apply(&args->average_load, runtime / (runtime + sleeptime));
            runtime = sleeptime = 0.0;
        }
        run_n += 1;
#endif
    }
out:
    return;
}