struct rtpp_weakref_obj * rtpp_weakref_ctor(void) { struct rtpp_weakref_priv *pvt; pvt = rtpp_zmalloc(sizeof(struct rtpp_weakref_priv)); if (pvt == NULL) { return (NULL); } pvt->ht = rtpp_hash_table_ctor(rtpp_ht_key_u64_t, RTPP_HT_NODUPS | RTPP_HT_DUP_ABRT); if (pvt->ht == NULL) { goto e0; } pvt->pub.dtor = &rtpp_weakref_dtor; pvt->pub.reg = &rtpp_weakref_reg; pvt->pub.get_by_idx = &rtpp_wref_get_by_idx; pvt->pub.unreg = &rtpp_weakref_unreg; pvt->pub.foreach = &rtpp_wref_foreach; pvt->pub.get_length = &rtpp_wref_get_length; pvt->pub.purge = &rtpp_wref_purge; return (&pvt->pub); e0: free(pvt); return (NULL); }
struct rtpp_refcnt * rtpp_refcnt_ctor(void *data, rtpp_refcnt_dtor_t dtor_f) { struct rtpp_refcnt_priv *pvt; pvt = rtpp_zmalloc(sizeof(struct rtpp_refcnt_priv)); if (pvt == NULL) { return (NULL); } if (pthread_mutex_init(&pvt->cnt_lock, NULL) != 0) { free(pvt); return (NULL); } pvt->data = data; if (dtor_f != NULL) { pvt->dtor_f = dtor_f; } else { pvt->dtor_f = free; } pvt->pub.attach = &rtpp_refcnt_attach; pvt->pub.incref = &rtpp_refcnt_incref; pvt->pub.decref = &rtpp_refcnt_decref; pvt->pub.getdata = &rtpp_refcnt_getdata; pvt->pub.reg_pd = &rtpp_refcnt_reg_pd; #if RTPP_DEBUG_refcnt pvt->pub.traceen = &rtpp_refcnt_traceen; #endif pvt->cnt = 1; return (&pvt->pub); }
struct rtpp_cmd_rcache_obj * rtpp_cmd_rcache_ctor(struct rtpp_timed_obj *rtpp_timed_cf, double min_ttl) { struct rtpp_cmd_rcache_pvt *pvt; pvt = rtpp_zmalloc(sizeof(struct rtpp_cmd_rcache_pvt)); if (pvt == NULL) { return (NULL); } pvt->ht = rtpp_hash_table_ctor(); if (pvt->ht == NULL) { goto e0; } pvt->timeout = CALL_METHOD(rtpp_timed_cf, schedule, RTPP_RCACHE_CPERD, rtpp_cmd_rcache_cleanup, NULL, pvt); if (pvt->timeout == NULL) { goto e0; } pvt->min_ttl = min_ttl; pvt->rtpp_timed_cf_save = rtpp_timed_cf; pvt->pub.insert = rtpp_cmd_rcache_insert; pvt->pub.lookup = rtpp_cmd_rcache_lookup; pvt->pub.dtor = rtpp_cmd_rcache_dtor; return (&pvt->pub); e0: free(pvt); return (NULL); }
struct rtpp_pcache_obj * rtpp_pcache_ctor(void) { struct rtpp_pcache_obj_full *fp; struct rtpp_pcache_obj *pub; struct rtpp_pcache_obj_priv *pvt; fp = rtpp_zmalloc(sizeof(struct rtpp_pcache_obj_full)); if (fp == NULL) { return (NULL); } pub = &(fp->pub); pvt = &(fp->pvt); pvt->hash_table = rtpp_hash_table_ctor(); if (pvt->hash_table == NULL) { free(fp); return (NULL); } pub->pvt = pvt; pub->open = &rtpp_pcache_obj_open; pub->read = &rtpp_pcache_obj_read; pub->close = &rtpp_pcache_obj_close; pub->dtor = &rtpp_pcache_obj_dtor; #if defined(RTPP_DEBUG) assert((void *)fp == (void *)pub); #endif return (pub); }
static void rtpp_cmd_rcache_insert(struct rtpp_cmd_rcache_obj *pub, const char *cookie, const char *reply, double ctime) { struct rtpp_cmd_rcache_pvt *pvt; struct rtpp_cmd_rcache_entry *rep; struct rtpp_refcnt_obj *rco; pvt = (struct rtpp_cmd_rcache_pvt *)pub; rep = rtpp_zmalloc(sizeof(struct rtpp_cmd_rcache_entry)); if (rep == NULL) { return; } rep->reply = strdup(reply); if (rep->reply == NULL) { goto e1; } rep->etime = ctime + pvt->min_ttl; rco = rtpp_refcnt_ctor(rep, rtpp_cmd_rcache_entry_free); if (rco == NULL) { goto e3; } CALL_METHOD(pvt->ht, append_refcnt, cookie, rco); /* * append_refcnt() either takes ownership in which case it incs refcount * or it drops the ball in which it does not, so we release rco and set * it free. */ CALL_METHOD(rco, decref); return; e3: free(rep->reply); e1: free(rep); }
struct rtp_packet * rtp_packet_alloc() { struct rtp_packet_full *pkt; pkt = rtpp_zmalloc(sizeof(*pkt)); return &(pkt->pub); }
struct rtp_resizer * rtp_resizer_new(int output_ptime) { struct rtp_resizer *this; this = rtpp_zmalloc(sizeof(struct rtp_resizer)); if (this == NULL) return (NULL); rtp_resizer_set_ptime(this, output_ptime); return (this); }
struct rtpp_pcache_fd * rtpp_pcache_obj_open(struct rtpp_pcache_obj *self, const char *fname) { struct rtpp_pcache_fd *p_fd; struct rtpp_pcache_obj_priv *pvt; p_fd = rtpp_zmalloc(sizeof(struct rtpp_pcache_fd)); if (p_fd == NULL) { return (NULL); } pvt = self->pvt; p_fd->hte = CALL_METHOD(pvt->hash_table, append, fname, p_fd); return (p_fd); }
struct rtpp_log_inst * _rtpp_log_open(struct rtpp_cfg_stable *cf, const char *app, const char *call_id) { const char *stritime; const char *tform; char *se; struct rtpp_log_inst *rli; #ifdef RTPP_LOG_ADVANCED int facility; facility = cf->log_facility; if (facility == -1) facility = LOG_DAEMON; if (cf->nodaemon == 0 && syslog_async_opened == 0) { if (syslog_async_init(app, facility) == 0) syslog_async_opened = 1; } #endif rli = rtpp_zmalloc(sizeof(struct rtpp_log_inst)); if (rli == NULL) { return (NULL); } tform = getenv("RTPP_LOG_TFORM"); if (tform != NULL && strcmp(tform, "rel") == 0) { stritime = getenv("RTPP_LOG_TSTART"); if (stritime != NULL) { rli->itime = strtod(stritime, &se); } else { if (iitime == 0.0) { iitime = getdtime(); } rli->itime = iitime; } } if (call_id != NULL) { rli->call_id = strdup(call_id); } if (cf->log_level == -1) { rli->level = (cf->nodaemon != 0) ? RTPP_LOG_DBUG : RTPP_LOG_WARN; } else { rli->level = cf->log_level; } rli->format_se = "%s%s:%s:%s: %s\n"; rli->eformat_se = "%s%s:%s:%s: %s: %s (%d)\n"; rli->format_sl = "%s:%s:%s: %s"; rli->eformat_sl = "%s:%s:%s: %s: %s (%d)"; return (rli); }
struct rtpp_ctrl_sock * rtpp_ctrl_sock_parse(const char *optarg) { struct rtpp_ctrl_sock *rcsp; rcsp = rtpp_zmalloc(sizeof(struct rtpp_ctrl_sock)); if (rcsp == NULL) { return (NULL); } rcsp->type= RTPC_IFSUN; if (strncmp("udp:", optarg, 4) == 0) { rcsp->type= RTPC_UDP4; optarg += 4; } else if (strncmp("udp6:", optarg, 5) == 0) { rcsp->type= RTPC_UDP6; optarg += 5; } else if (strncmp("unix:", optarg, 5) == 0) { rcsp->type= RTPC_IFSUN; optarg += 5; } else if (strncmp("cunix:", optarg, 6) == 0) { rcsp->type= RTPC_IFSUN_C; optarg += 6; } else if (strncmp("systemd:", optarg, 8) == 0) { rcsp->type= RTPC_SYSD; optarg += 8; } else if (strncmp("stdio:", optarg, 6) == 0) { rcsp->type= RTPC_STDIO; optarg += 6; } else if (strncmp("stdioc:", optarg, 7) == 0) { rcsp->type= RTPC_STDIO; rcsp->exit_on_close = 1; optarg += 7; } else if (strncmp("tcp:", optarg, 4) == 0) { rcsp->type= RTPC_TCP4; optarg += 4; } else if (strncmp("tcp6:", optarg, 5) == 0) { rcsp->type= RTPC_TCP6; optarg += 5; } rcsp->cmd_sock = optarg; return (rcsp); }
static struct rtp_analyze_jdata * rtp_analyze_jdata_ctor() { struct rtp_analyze_jdata *jdp; jdp = rtpp_zmalloc(sizeof(*jdp)); if (jdp == NULL) { goto e0; } jdp->ts_dedup = rtpp_ringbuf_ctor(sizeof(jdp->jss.prev_ts), 10); if (jdp->ts_dedup == NULL) { goto e1; } return (jdp); e1: free(jdp); e0: return (NULL); }
static struct rtp_analyze_jitter * rtp_analyze_jt_ctor() { struct rtp_analyze_jitter *jp; jp = rtpp_zmalloc(sizeof(*jp)); if (jp == NULL) { goto e0; } jp->first = rtp_analyze_jdata_ctor(); if (jp->first == NULL) { goto e1; } jp->jdlen = 1; return (jp); e1: free(jp); e0: return (NULL); }
struct rtpp_notify * rtpp_notify_ctor(struct rtpp_log *glog) { struct rtpp_notify_priv *pvt; pvt = rtpp_zmalloc(sizeof(struct rtpp_notify_priv)); if (pvt == NULL) { goto e0; } pvt->nqueue = rtpp_queue_init(1, "rtpp_notify"); if (pvt->nqueue == NULL) { goto e1; } /* Pre-allocate sigterm, so that we don't have any malloc() in dtor() */ pvt->sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0); if (pvt->sigterm == NULL) { goto e2; } if (pthread_create(&pvt->thread_id, NULL, (void *(*)(void *))&rtpp_notify_queue_run, pvt) != 0) { goto e3; } CALL_METHOD(glog->rcnt, incref); pvt->glog = glog; pvt->pub.schedule = &rtpp_notify_schedule; pvt->pub.dtor = &rtpp_notify_dtor; return (&pvt->pub); e3: rtpp_wi_free(pvt->sigterm); e2: rtpp_queue_destroy(pvt->nqueue); e1: free(pvt); e0: return (NULL); }
struct rtp_server * rtp_server_new(const char *name, rtp_type_t codec, int loop, double dtime, int ptime) { struct rtp_server *rp; int fd; char path[PATH_MAX + 1]; sprintf(path, "%s.%d", name, codec); fd = open(path, O_RDONLY); if (fd == -1) return NULL; rp = rtpp_zmalloc(sizeof(*rp)); if (rp == NULL) { close(fd); return NULL; } rp->btime = dtime; rp->dts = 0; rp->fd = fd; rp->loop = (loop > 0) ? loop - 1 : loop; rp->ptime = (ptime > 0) ? ptime : RTPS_TICKS_MIN; rp->rtp = (rtp_hdr_t *)rp->buf; rp->rtp->version = 2; rp->rtp->p = 0; rp->rtp->x = 0; rp->rtp->cc = 0; rp->rtp->mbt = 1; rp->rtp->pt = codec; rp->rtp->ts = 0; rp->rtp->seq = random() & 0xffff; rp->rtp->ssrc = random(); rp->pload = rp->buf + RTP_HDR_LEN(rp->rtp); return rp; }
struct rtpp_anetio_cf * rtpp_netio_async_init(struct cfg *cf, int qlen) { struct rtpp_anetio_cf *netio_cf; int i, ri; netio_cf = rtpp_zmalloc(sizeof(*netio_cf)); if (netio_cf == NULL) return (NULL); for (i = 0; i < SEND_THREADS; i++) { netio_cf->args[i].out_q = rtpp_queue_init(qlen, "RTPP->NET%.2d", i); if (netio_cf->args[i].out_q == NULL) { for (ri = i - 1; ri >= 0; ri--) { rtpp_queue_destroy(netio_cf->args[ri].out_q); } goto e0; } netio_cf->args[i].glog = cf->stable->glog; netio_cf->args[i].dmode = cf->stable->dmode; #ifdef RTPP_DEBUG recfilter_init(&netio_cf->args[i].average_load, 0.9, 0.0, 0); #endif } for (i = 0; i < SEND_THREADS; i++) { netio_cf->args[i].sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0); if (netio_cf->args[i].sigterm == NULL) { for (ri = i - 1; ri >= 0; ri--) { rtpp_wi_free(netio_cf->args[ri].sigterm); } goto e1; } } cf->stable->rtpp_netio_cf = netio_cf; for (i = 0; i < SEND_THREADS; i++) { if (pthread_create(&(netio_cf->thread_id[i]), NULL, (void *(*)(void *))&rtpp_anetio_sthread, &netio_cf->args[i]) != 0) { for (ri = i - 1; ri >= 0; ri--) { rtpp_queue_put_item(netio_cf->args[ri].sigterm, netio_cf->args[ri].out_q); pthread_join(netio_cf->thread_id[ri], NULL); } for (ri = i; ri < SEND_THREADS; ri++) { rtpp_wi_free(netio_cf->args[ri].sigterm); } goto e1; } } return (netio_cf); #if 0 e2: for (i = 0; i < SEND_THREADS; i++) { rtpp_wi_free(netio_cf->args[i].sigterm); } #endif e1: for (i = 0; i < SEND_THREADS; i++) { rtpp_queue_destroy(netio_cf->args[i].out_q); } e0: free(netio_cf); return (NULL); }
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); }
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); }