Example #1
0
void *
ropen(struct rtpp_session *sp, const char *rdir, const char *sdir, int orig)
{
    struct rtpp_record_channel *rrc;

    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 (sdir == NULL) {
        sdir = rdir;
        rrc->needspool = 0;
    } else {
        rrc->needspool = 1;
        sprintf(rrc->rpath, "%s/%s=%s.%c.%s", rdir, sp->call_id, sp->tag,
          (orig != 0) ? 'o' : 'a', (sp->rtcp != NULL) ? "rtp" : "rtcp");
    }
    sprintf(rrc->spath, "%s/%s=%s.%c.%s", sdir, sp->call_id, sp->tag,
      (orig != 0) ? 'o' : 'a', (sp->rtcp != NULL) ? "rtp" : "rtcp");
    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;
    }
    return (void *)(rrc);
}
Example #2
0
void
rclose(struct rtpp_session *sp, void *rrc, int keep)
{

    if (RRC_CAST(rrc)->mode != MODE_REMOTE_RTP && RRC_CAST(rrc)->rbuf_len > 0)
	flush_rbuf(sp, rrc);

    if (RRC_CAST(rrc)->fd != -1)
	close(RRC_CAST(rrc)->fd);

    if (RRC_CAST(rrc)->mode == MODE_REMOTE_RTP)
	return;

    if (keep == 0) {
	if (unlink(RRC_CAST(rrc)->spath) == -1)
	    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't remove "
	      "session record %s", RRC_CAST(rrc)->spath);
    } else if (RRC_CAST(rrc)->needspool == 1) {
	if (rename(RRC_CAST(rrc)->spath, RRC_CAST(rrc)->rpath) == -1)
	    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't move "
	      "session record from spool into permanent storage");
    }

    free(rrc);
}
Example #3
0
static int
create_twinlistener(struct cfg_stable *cf, struct sockaddr *ia, int port, int *fds)
{
    struct sockaddr_storage iac;
    int rval, i, flags;

    fds[0] = fds[1] = -1;

    rval = -1;

    for (i = 0; i < 2; i++) {
        fds[i] = socket(ia->sa_family, SOCK_DGRAM, 0);

        if (fds[i] == -1) {
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "can't create %s socket",
                            (ia->sa_family == AF_INET) ? "IPv4" : "IPv6");
            goto failure;
        }

        memcpy(&iac, ia, SA_LEN(ia));
        satosin(&iac)->sin_port = htons(port);

        if (bind(fds[i], sstosa(&iac), SA_LEN(ia)) != 0) {
            if (errno != EADDRINUSE && errno != EACCES) {
                rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "can't bind to the %s port %d",
                                (ia->sa_family == AF_INET) ? "IPv4" : "IPv6", port);
            } else {
                rval = -2;
            }

            goto failure;
        }

        port++;

        if ((ia->sa_family == AF_INET) && (cf->tos >= 0) &&
                (setsockopt(fds[i], IPPROTO_IP, IP_TOS, &cf->tos, sizeof(cf->tos)) == -1))
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "unable to set TOS to %d", cf->tos);

        flags = fcntl(fds[i], F_GETFL);
        fcntl(fds[i], F_SETFL, flags | O_NONBLOCK);
    }

    return 0;

failure:

    for (i = 0; i < 2; i++)
        if (fds[i] != -1) {
            close(fds[i]);
            fds[i] = -1;
        }

    return rval;
}
Example #4
0
void
rwrite(struct rtpp_session *sp, void *rrc, struct sockaddr *saddr, void *buf, int len)
{
    struct iovec v[2];
    struct pkt_hdr hdr;
    int rval;

    if (RRC_CAST(rrc)->fd == -1)
        return;

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

    hdr.time = getctime();
    if (hdr.time == -1) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time");
	goto fatal_error;
    }

    switch (saddr->sa_family) {
    case AF_INET:
	hdr.addr.in4.sin_family = saddr->sa_family;
	hdr.addr.in4.sin_port = satosin(saddr)->sin_port;
	hdr.addr.in4.sin_addr = satosin(saddr)->sin_addr;
	break;

    case AF_INET6:
	hdr.addr.in6.sin_family = saddr->sa_family;
	hdr.addr.in6.sin_port = satosin6(saddr)->sin6_port;
	hdr.addr.in6.sin_addr = satosin6(saddr)->sin6_addr;
	break;

    default:
	abort();
    }

    hdr.plen = len;

    v[0].iov_base = (void *)&hdr;
    v[0].iov_len = sizeof(hdr);
    v[1].iov_base = buf;
    v[1].iov_len = len;

    rval = writev(RRC_CAST(rrc)->fd, v, 2);
    if (rval != -1)
	return;

    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "error while recording session (%s)",
      (sp->rtcp != NULL) ? "RTP" : "RTCP");
fatal_error:
    /* Prevent futher writing if error happens */
    close(RRC_CAST(rrc)->fd);
    RRC_CAST(rrc)->fd = -1;
}
Example #5
0
static void
do_timeout_notification(struct rtpp_notify_wi *wi, int retries)
{
    int result;

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

        /* If connect fails, no notification will be sent */
        if (wi->rttp->connected == 0) {
            rtpp_log_write(RTPP_LOG_ERR, wi->glog, "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_log_ewrite(RTPP_LOG_ERR, wi->glog, "failed to send timeout notification");
        if (retries > 0)
            do_timeout_notification(wi, retries - 1);
    }
}
Example #6
0
static int
controlfd_init_tcp(struct cfg *cf, struct rtpp_ctrl_sock *csp)
{
    struct sockaddr *ifsin;
    char *cp;
    int controlfd, so_rcvbuf, i;

    cp = strrchr(csp->cmd_sock, ':');
    if (cp != NULL) {
        *cp = '\0';
        cp++;
    }
    if (cp == NULL || *cp == '\0')
        cp = CPORT;
    csp->port_ctl = atoi(cp);
    i = (csp->type == RTPC_TCP6) ? AF_INET6 : AF_INET;
    ifsin = sstosa(&csp->bindaddr);
    if (setbindhost(ifsin, i, csp->cmd_sock, cp) != 0)
        exit(1);
    controlfd = socket(i, SOCK_STREAM, 0);
    if (controlfd == -1)
        err(1, "can't create socket");
    so_rcvbuf = 16 * 1024;
    if (setsockopt(controlfd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)) == -1)
        rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable->glog, "unable to set 16K receive buffer size on controlfd");
    if (bind(controlfd, ifsin, SA_LEN(ifsin)) < 0)
        err(1, "can't bind to a socket");
    if (listen(controlfd, 32) != 0)
        err(1, "can't listen on a socket: %s", csp->cmd_sock);

    return (controlfd);
}
Example #7
0
static int
prepare_pkt_hdr_adhoc(struct rtpp_session *sp, struct rtp_packet *packet,
  struct pkt_hdr_adhoc *hdrp, struct sockaddr *daddr, struct sockaddr *ldaddr,
  int ldport, int face)
{

    memset(hdrp, 0, sizeof(*hdrp));
    hdrp->time = packet->rtime;
    if (hdrp->time == -1) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time");
	return -1;
    }
    switch (sstosa(&packet->raddr)->sa_family) {
    case AF_INET:
	hdrp->addr.in4.sin_family = sstosa(&packet->raddr)->sa_family;
	hdrp->addr.in4.sin_port = satosin(&packet->raddr)->sin_port;
	hdrp->addr.in4.sin_addr = satosin(&packet->raddr)->sin_addr;
	break;

    case AF_INET6:
	hdrp->addr.in6.sin_family = sstosa(&packet->raddr)->sa_family;
	hdrp->addr.in6.sin_port = satosin6(&packet->raddr)->sin6_port;
	hdrp->addr.in6.sin_addr = satosin6(&packet->raddr)->sin6_addr;
	break;

    default:
	abort();
    }

    hdrp->plen = packet->size;
    return 0;
}
Example #8
0
int
drop_privileges(struct cfg *cf)
{

    if (cf->stable.run_gname != NULL) {
	if (setgid(cf->stable.run_gid) != 0) {
	    rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable.glog, "can't set current group ID: %d", cf->stable.run_gid);
	    return -1;
	}
    }
    if (cf->stable.run_uname == NULL)
	return 0;
    if (setuid(cf->stable.run_uid) != 0) {
	rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable.glog, "can't set current user ID: %d", cf->stable.run_uid);
	return -1;
    }
    return 0;
}
Example #9
0
static int
init_controlfd(struct cfg *cf)
{
    struct sockaddr_un ifsun;
    struct sockaddr_storage ifsin;
    char *cp;
    int i, controlfd, flags, so_rcvbuf;

    if (cf->stable->umode == 0) {
	unlink(cmd_sock);
	memset(&ifsun, '\0', sizeof ifsun);
#if defined(HAVE_SOCKADDR_SUN_LEN)
	ifsun.sun_len = strlen(cmd_sock);
#endif
	ifsun.sun_family = AF_LOCAL;
	strcpy(ifsun.sun_path, cmd_sock);
	controlfd = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (controlfd == -1)
	    err(1, "can't create socket");
	setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &controlfd,
	  sizeof controlfd);
	if (bind(controlfd, sstosa(&ifsun), sizeof ifsun) < 0)
	    err(1, "can't bind to a socket");
	if ((cf->stable->run_uname != NULL || cf->stable->run_gname != NULL) &&
	  chown(cmd_sock, cf->stable->run_uid, cf->stable->run_gid) == -1)
	    err(1, "can't set owner of the socket");
	if (listen(controlfd, 32) != 0)
	    err(1, "can't listen on a socket");
    } else {
	cp = strrchr(cmd_sock, ':');
	if (cp != NULL) {
	    *cp = '\0';
	    cp++;
	}
	if (cp == NULL || *cp == '\0')
	    cp = CPORT;
	cf->stable->port_ctl = atoi(cp);
	i = (cf->stable->umode == 6) ? AF_INET6 : AF_INET;
	if (setbindhost(sstosa(&ifsin), i, cmd_sock, cp) != 0)
	    exit(1);
	controlfd = socket(i, SOCK_DGRAM, 0);
	if (controlfd == -1)
	    err(1, "can't create socket");
        so_rcvbuf = 16 * 1024;
        if (setsockopt(controlfd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)) == -1)
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable->glog, "unable to set 16K receive buffer size on controlfd");
	if (bind(controlfd, sstosa(&ifsin), SS_LEN(&ifsin)) < 0)
	    err(1, "can't bind to a socket");
    }
    flags = fcntl(controlfd, F_GETFL);
    fcntl(controlfd, F_SETFL, flags | O_NONBLOCK);

    return controlfd;
}
Example #10
0
void
rclose(struct rtpp_session *sp, void *rrc)
{

    if (RRC_CAST(rrc)->fd != -1)
        close(RRC_CAST(rrc)->fd);
    if (RRC_CAST(rrc)->needspool == 1)
        if (rename(RRC_CAST(rrc)->spath, RRC_CAST(rrc)->rpath) == -1)
            rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't move "
              "session record from spool into permanent storage");
    free(rrc);
}
Example #11
0
static int
prepare_pkt_hdr_pcap(struct rtpp_session *sp, struct rtp_packet *packet, struct pkt_hdr_pcap *hdrp)
{

    if (packet->rtime == -1) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time");
	return -1;
    }

    if (sstosa(&packet->raddr)->sa_family != AF_INET) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "only AF_INET pcap format is supported");
	return -1;
    }

    memset(hdrp, 0, sizeof(*hdrp));
    dtime2ts(packet->rtime, &(hdrp->pcaprec_hdr.ts_sec), &(hdrp->pcaprec_hdr.ts_usec));
    hdrp->pcaprec_hdr.orig_len = hdrp->pcaprec_hdr.incl_len = sizeof(*hdrp) -
      sizeof(hdrp->pcaprec_hdr) + packet->size;

    hdrp->family = sstosa(&packet->raddr)->sa_family;

    /* Prepare fake IP header */
    hdrp->iphdr.ip_v = 4;
    hdrp->iphdr.ip_hl = sizeof(hdrp->iphdr) >> 2;
    hdrp->iphdr.ip_len = htons(sizeof(hdrp->iphdr) + sizeof(hdrp->udphdr) + packet->size);
    hdrp->iphdr.ip_src = satosin(&(packet->raddr))->sin_addr;
    hdrp->iphdr.ip_dst = satosin(packet->laddr)->sin_addr;
    hdrp->iphdr.ip_p = IPPROTO_UDP;
    hdrp->iphdr.ip_id = htons(ip_id++);
    hdrp->iphdr.ip_ttl = 127;
    hdrp->iphdr.ip_sum = rtpp_in_cksum(&(hdrp->iphdr), sizeof(hdrp->iphdr));

    /* Prepare fake UDP header */
    hdrp->udphdr.uh_sport = satosin(&packet->raddr)->sin_port;
    hdrp->udphdr.uh_dport = htons(packet->rport);
    hdrp->udphdr.uh_ulen = htons(sizeof(hdrp->udphdr) + packet->size);

    return 0;
}
Example #12
0
static void
reconnect_timeout_handler(struct rtpp_session *sp, struct rtpp_timeout_handler *th)
{
    struct sockaddr_un remote;

    assert(th->socket_name != NULL && th->connected == 0);

    if (th->fd == -1)
    {
        rtpp_log_write(RTPP_LOG_DBUG, sp->log, "connecting timeout socket");
    }
    else
    {
        rtpp_log_write(RTPP_LOG_DBUG, sp->log, "reconnecting timeout socket");
        close(th->fd);
    }
    th->fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (th->fd == -1)
    {
        rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't create timeout socket");
        return;
    }

    remote.sun_family = AF_LOCAL;
    strncpy(remote.sun_path, th->socket_name, sizeof(remote.sun_path) - 1);
#if defined(HAVE_SOCKADDR_SUN_LEN)
    remote.sun_len = strlen(remote.sun_path);
#endif
    if (connect(th->fd, (struct sockaddr *)&remote, sizeof(remote)) == -1)
    {
        rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't connect to timeout socket");
    }
    else
    {
        th->connected = 1;
    }
}
Example #13
0
static void
reconnect_timeout_handler(rtpp_log_t log, struct rtpp_tnotify_target *rttp)
{

    assert (rttp->connected == 0);

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

e0:
    close(rttp->fd);
    rttp->fd = -1;
    return;
}
Example #14
0
void
do_timeout_notification(struct rtpp_session *sp, int retries)
{
    int result, len;
    struct rtpp_timeout_handler *th = sp->timeout_data.handler;

    if (th == NULL)
        return;

    if (th->connected == 0)
    {
        reconnect_timeout_handler(sp, th);

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

    if (sp->timeout_data.notify_tag == NULL)
    {
        len = snprintf(th->notify_buf, sizeof(th->notify_buf), "%d %d\n",
                       sp->ports[0], sp->ports[1]);
    }
    else
    {
        len = snprintf(th->notify_buf, sizeof(th->notify_buf), "%s\n",
                       sp->timeout_data.notify_tag);
    }
    assert(len < (int)sizeof(th->notify_buf));

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

    if (result < 0)
    {
        th->connected = 0;
        rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "failed to send timeout notification");
        if (retries > 0)
            do_timeout_notification(sp, retries - 1);
    }
}
Example #15
0
static int
flush_rbuf(struct rtpp_session *sp, void *rrc)
{
    int rval;

    rval = write(RRC_CAST(rrc)->fd, RRC_CAST(rrc)->rbuf, RRC_CAST(rrc)->rbuf_len);
    if (rval != -1) {
	RRC_CAST(rrc)->rbuf_len = 0;
	return 0;
    }

    rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "error while recording session (%s)",
      (sp->rtcp != NULL) ? "RTP" : "RTCP");
    /* Prevent futher writing if error happens */
    close(RRC_CAST(rrc)->fd);
    RRC_CAST(rrc)->fd = -1;
    return -1;
}
Example #16
0
static int
accept_connection(struct cfg *cf, int controlfd_in)
{
    int controlfd;
    socklen_t rlen;
    struct sockaddr_un ifsun;

    rlen = sizeof(ifsun);
    controlfd = accept(controlfd_in, sstosa(&ifsun), &rlen);
    if (controlfd == -1) {
        if (errno != EWOULDBLOCK) {
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable->glog,
              "can't accept connection on control socket");
        }
        return (-1);
    }
    return (controlfd);
}
Example #17
0
static int
accept_connection(struct cfg *cf, struct rtpp_ctrl_sock *rcsp, struct sockaddr *rap)
{
    int controlfd;
    socklen_t rlen;

    rlen = rtpp_csock_addrlen(rcsp);
    assert(rlen > 0);
    controlfd = accept(rcsp->controlfd_in, rap, &rlen);
    if (controlfd == -1) {
        if (errno != EWOULDBLOCK) {
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable->glog,
              "can't accept connection on control socket");
        }
        return (-1);
    }
    return (controlfd);
}
Example #18
0
int
rtpp_command_stream_doio(struct cfg *cf, struct rtpp_cmd_connection *rcs)
{
    int len, blen;
    char *cp;

    rtpp_command_stream_compact(rcs);
    cp = &(rcs->inbuf[rcs->inbuf_epos]);
    blen = sizeof(rcs->inbuf) - rcs->inbuf_epos;

    for (;;) {
        len = read(rcs->controlfd_in, cp, blen);
        if (len != -1 || (errno != EAGAIN && errno != EINTR))
            break;
    }
    if (len == -1) {
        if (errno != EAGAIN && errno != EINTR)
            rtpp_log_ewrite(RTPP_LOG_ERR, cf->stable->glog, "can't read from control socket");
        return (-1);
    }
    rcs->inbuf_epos += len;
    return (len);
}
Example #19
0
int
main(int argc, char **argv)
{
    int i, len, controlfd;
    double eval, clk;
    long long ncycles_ref, counter;
    double eptime;
    double add_delay;
    struct cfg cf;
    char buf[256];
    struct recfilter loop_error;
    struct PFD phase_detector;
    useconds_t usleep_time;
    struct sched_param sparam;
#if RTPP_DEBUG
    double sleep_time, filter_lastval;
#endif
    memset(&cf, 0, sizeof(cf));

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

    init_config(&cf, argc, argv);

    seedrandom();

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

    controlfd = init_controlfd(&cf);

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

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

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

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

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

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

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

    cf.stable->controlfd = controlfd;

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

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

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

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

        ncycles_ref = llrint(clk);

        eval = PFD_get_error(&phase_detector, clk);

#if RTPP_DEBUG
        filter_lastval = loop_error.lastval;
#endif

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

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

    exit(0);
}
Example #20
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);
}
Example #21
0
int
handle_command(struct cfg *cf, int controlfd, double dtime)
{
    int len, argc, i, pidx, asymmetric;
    int external, pf, lidx, playcount, weak, tpf;
    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, *errmsg;
    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;
    struct sockaddr *local_addr;
    char c;

    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;
    local_addr = NULL;
    codecs = 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;
	    }
	    /*
	     * Only list 20081224 protocol mod as supported if
	     * user actually enabled notification with -n
	     */
	    if (strcmp(argv[1], "20081224") == 0 &&
	      cf->timeout_handler.socket_name == NULL) {
		reply_number(cf, controlfd, &raddr, rlen, cookie, 0);
		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;

	    case 'l':
	    case 'L':
		len = extractaddr(cp + 1, &t, &cp, &tpf);
		if (len == -1) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		c = t[len];
		t[len] = '\0';
		local_addr = host2bindaddr(cf, t, tpf, &errmsg);
		if (local_addr == NULL) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog,
		      "invalid local address: %s: %s", t, errmsg);
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		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->glog, "command syntax error");
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		c = t[len];
		t[len] = '\0';
		local_addr = alloca(sizeof(struct sockaddr_storage));
		n = resolve(local_addr, tpf, t, SERVICE, AI_PASSIVE);
		if (n != 0) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog,
		      "invalid remote address: %s: %s", t, gai_strerror(n));
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		if (local4remote(cf, local_addr, satoss(local_addr)) == -1) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog,
		      "can't find local address for remote address: %s", t);
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		local_addr = addr2bindaddr(cf, local_addr, &errmsg);
		if (local_addr == NULL) {
		    rtpp_log_write(RTPP_LOG_ERR, cf->glog,
		      "invalid local address: %s", errmsg);
		    reply_error(cf, controlfd, &raddr, rlen, cookie, 1);
		    return 0;
		}
		t[len] = c;
		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) {
	    if (local_addr != NULL) {
		spa->laddr[i] = local_addr;
	    }
	    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");

	if (local_addr != NULL) {
	    lia[0] = lia[1] = local_addr;
	    if (lia[0] == NULL) {
		rtpp_log_write(RTPP_LOG_ERR, spa->log,
		  "can't create listener: %s", t);
		reply_error(cf, controlfd, &raddr, rlen, cookie, 10);
		return 0;
	    }
	}
	if (create_listener(cf, lia[0], &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;
}
Example #22
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);
}
Example #23
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);
}
Example #24
0
void
rwrite(struct rtpp_session *sp, void *rrc, struct rtp_packet *packet,
  struct sockaddr *daddr, struct sockaddr *ldaddr, int ldport, int face)
{
    struct iovec v[2];
    union {
	union pkt_hdr_pcap pcap;
	struct pkt_hdr_adhoc adhoc;
    } hdr;
    int rval, hdr_size;
    int (*prepare_pkt_hdr)(struct rtpp_session *, struct rtp_packet *, void *,
      struct sockaddr *, struct sockaddr *, int, int);

    if (RRC_CAST(rrc)->fd == -1)
	return;

    switch (RRC_CAST(rrc)->mode) {
    case MODE_REMOTE_RTP:
	send(RRC_CAST(rrc)->fd, packet->data.buf, packet->size, 0);
	return;

    case MODE_LOCAL_PKT:
	hdr_size = sizeof(hdr.adhoc);
	prepare_pkt_hdr = (void *)&prepare_pkt_hdr_adhoc;
	break;

    case MODE_LOCAL_PCAP:
#if (PCAP_FORMAT == DLT_NULL)
	hdr_size = sizeof(hdr.pcap.null);
#else
        hdr_size = sizeof(hdr.pcap.en10t);
#endif
	prepare_pkt_hdr = (void *)&prepare_pkt_hdr_pcap;
	break;
    }

    /* Check if the write buffer has necessary space, and flush if not */
    if ((RRC_CAST(rrc)->rbuf_len + hdr_size + packet->size > sizeof(RRC_CAST(rrc)->rbuf)) && RRC_CAST(rrc)->rbuf_len > 0)
	if (flush_rbuf(sp, rrc) != 0)
	    return;

    face = (sp->record_single_file == 0) ? 0 : face;

    /* Check if received packet doesn't fit into the buffer, do synchronous write  if so */
    if (RRC_CAST(rrc)->rbuf_len + hdr_size + packet->size > sizeof(RRC_CAST(rrc)->rbuf)) {
	if (prepare_pkt_hdr(sp, packet, (void *)&hdr, daddr, ldaddr, ldport, face) != 0)
	    return;

	v[0].iov_base = (void *)&hdr;
	v[0].iov_len = hdr_size;
	v[1].iov_base = packet->data.buf;
	v[1].iov_len = packet->size;

	rval = writev(RRC_CAST(rrc)->fd, v, 2);
	if (rval != -1)
	    return;

	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "error while recording session (%s)",
	  (sp->rtcp != NULL) ? "RTP" : "RTCP");
	/* Prevent futher writing if error happens */
	close(RRC_CAST(rrc)->fd);
	RRC_CAST(rrc)->fd = -1;
	return;
    }
    if (prepare_pkt_hdr(sp, packet, (void *)(RRC_CAST(rrc)->rbuf + RRC_CAST(rrc)->rbuf_len),
      daddr, ldaddr, ldport, face) != 0)
	return;
    RRC_CAST(rrc)->rbuf_len += hdr_size;
    memcpy(RRC_CAST(rrc)->rbuf + RRC_CAST(rrc)->rbuf_len, packet->data.buf, packet->size);
    RRC_CAST(rrc)->rbuf_len += packet->size;
}
Example #25
0
static int
prepare_pkt_hdr_pcap(struct rtpp_session *sp, struct rtp_packet *packet,
  union pkt_hdr_pcap *hdrp, struct sockaddr *daddr, struct sockaddr *ldaddr,
  int ldport, int face)
{
    struct sockaddr *src_addr, *dst_addr;
    uint16_t src_port, dst_port;
    pcaprec_hdr_t *pcaprec_hdr;
    struct udpip *udpip;
    int pcap_size;

    if (packet->rtime == -1) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time");
	return -1;
    }

    if (face == 0) {
        src_addr = sstosa(&(packet->raddr));
        src_port = satosin(src_addr)->sin_port;
        dst_addr = packet->laddr;
        dst_port = htons(packet->rport);
    } else {
        src_addr = ldaddr;
        src_port = htons(ldport);
        dst_addr = daddr;
        dst_port = satosin(dst_addr)->sin_port;
    }

    if (sstosa(src_addr)->sa_family != AF_INET) {
	rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "only AF_INET pcap format is supported");
	return -1;
    }

    memset(hdrp, 0, sizeof(*hdrp));

#if (PCAP_FORMAT == DLT_NULL)
    hdrp->null.family = sstosa(src_addr)->sa_family;
    pcaprec_hdr = &(hdrp->null.pcaprec_hdr);
    udpip = &(hdrp->null.udpip);
    pcap_size = sizeof(hdrp->null);
#else
    /* Prepare fake ethernet header */
    hdrp->en10t.ether_type = htons(0x800);
    memcpy(hdrp->en10t.ether_dhost + 2, &(satosin(dst_addr)->sin_addr), 4);
    memcpy(hdrp->en10t.ether_shost + 2, &(satosin(src_addr)->sin_addr), 4);
    pcaprec_hdr = &(hdrp->en10t.pcaprec_hdr);
    udpip = &(hdrp->en10t.udpip);
    pcap_size = sizeof(hdrp->en10t);
#endif

    dtime2ts(packet->rtime, &(pcaprec_hdr->ts_sec), &(pcaprec_hdr->ts_usec));
    pcaprec_hdr->orig_len = pcaprec_hdr->incl_len = pcap_size -
      sizeof(*pcaprec_hdr) + packet->size;

    /* Prepare fake IP header */
    udpip->iphdr.ip_v = 4;
    udpip->iphdr.ip_hl = sizeof(udpip->iphdr) >> 2;
    udpip->iphdr.ip_len = htons(sizeof(udpip->iphdr) + sizeof(udpip->udphdr) + packet->size);
    udpip->iphdr.ip_src = satosin(src_addr)->sin_addr;
    udpip->iphdr.ip_dst = satosin(dst_addr)->sin_addr;
    udpip->iphdr.ip_p = IPPROTO_UDP;
    udpip->iphdr.ip_id = htons(ip_id++);
    udpip->iphdr.ip_ttl = 127;
    udpip->iphdr.ip_sum = rtpp_in_cksum(&(udpip->iphdr), sizeof(udpip->iphdr));

    /* Prepare fake UDP header */
    udpip->udphdr.uh_sport = src_port;
    udpip->udphdr.uh_dport = dst_port;
    udpip->udphdr.uh_ulen = htons(sizeof(udpip->udphdr) + packet->size);

    return 0;
}
Example #26
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);
}