Esempio n. 1
0
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);
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
struct rtp_packet *
rtp_packet_alloc()
{
    struct rtp_packet_full *pkt;

    pkt = rtpp_zmalloc(sizeof(*pkt));

    return &(pkt->pub);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
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);
}
Esempio n. 13
0
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);
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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);
}
Esempio n. 16
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);
}
Esempio n. 17
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);
}