⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtpp_command.c

📁 RTP Proxy,用于Voip网络数据的代理传递
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> * Copyright (c) 2006-2007 Sippy Software, Inc., http://www.sippysoft.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: rtpp_command.c,v 1.6 2008/04/03 23:05:41 sobomax Exp $ * */#include <sys/types.h>#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#include <assert.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <netdb.h>#include <sched.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "rtpp_command.h"#include "rtpp_log.h"#include "rtpp_record.h"#include "rtpp_session.h"#include "rtpp_util.h"struct proto_cap proto_caps[] = {    /*     * The first entry must be basic protocol version and isn't shown     * as extension on -v.     */    { "20040107", "Basic RTP proxy functionality" },    { "20050322", "Support for multiple RTP streams and MOH" },    { "20060704", "Support for extra parameter in the V command" },    { "20071116", "Support for RTP re-packetization" },    { "20071218", "Support for forking (copying) RTP stream" },    { "20080403", "Support for RTP statistics querying" },    { NULL, NULL }};static int create_twinlistener(struct cfg *, struct sockaddr *, int, int *);static int create_listener(struct cfg *, struct sockaddr *, int, int *, int *);static int handle_delete(struct cfg *, char *, char *, char *, int);static void handle_noplay(struct cfg *, struct rtpp_session *, int);static int handle_play(struct cfg *, struct rtpp_session *, int, char *, char *, int);static void handle_record(struct cfg *, struct rtpp_session *, int, char *);static void handle_query(struct cfg *, int, struct sockaddr_storage *,  socklen_t, char *, struct rtpp_session *, int);static intcreate_twinlistener(struct cfg *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) &&	  (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;}static intcreate_listener(struct cfg *cf, struct sockaddr *ia,  int startport,  int *port, int *fds){    int i, init, rval;    for (i = 0; i < 2; i++)	fds[i] = -1;    init = 0;    if (startport < cf->port_min || startport > cf->port_max)	startport = cf->port_min;    for (*port = startport; *port != startport || init == 0; (*port) += 2) {	init = 1;	rval = create_twinlistener(cf, ia, *port, fds);	if (rval != 0) {	    if (rval == -1)		break;	    if (*port >= cf->port_max)		*port = cf->port_min - 2;	    continue;	}	return 0;    }    return -1;}static voiddoreply(struct cfg *cf, int fd, char *buf, int len,  struct sockaddr_storage *raddr, socklen_t rlen){    buf[len] = '\0';    rtpp_log_write(RTPP_LOG_DBUG, cf->glog, "sending reply \"%s\"", buf);    if (cf->umode == 0) {	write(fd, buf, len);    } else {	while (sendto(fd, buf, len, 0, sstosa(raddr),	  rlen) == -1 && errno == ENOBUFS);    }}static voidreply_number(struct cfg *cf, int fd, struct sockaddr_storage *raddr,  socklen_t rlen, char *cookie, int number){    int len;    char buf[1024 * 8];    if (cookie != NULL)	len = sprintf(buf, "%s %d\n", cookie, number);    else {	len = sprintf(buf, "%d\n", number);    }    doreply(cf, fd, buf, len, raddr, rlen);}static voidreply_ok(struct cfg *cf, int fd, struct sockaddr_storage *raddr,  socklen_t rlen, char *cookie){    reply_number(cf, fd, raddr, rlen, cookie, 0);}static voidreply_port(struct cfg *cf, int fd, struct sockaddr_storage *raddr,  socklen_t rlen, char *cookie, int lport, struct sockaddr **lia){    int len;    char buf[1024 * 8], *cp;    cp = buf;    len = 0;    if (cookie != NULL) {	len = sprintf(cp, "%s ", cookie);	cp += len;    }    if (lia[0] == NULL || ishostnull(lia[0]))	len += sprintf(cp, "%d\n", lport);    else	len += sprintf(cp, "%d %s%s\n", lport, addr2char(lia[0]),	  (lia[0]->sa_family == AF_INET) ? "" : " 6");    doreply(cf, fd, buf, len, raddr, rlen);}static voidreply_error(struct cfg *cf, int fd, struct sockaddr_storage *raddr,  socklen_t rlen, char *cookie, int ecode){    int len;    char buf[1024 * 8];    if (cookie != NULL)	len = sprintf(buf, "%s E%d\n", cookie, ecode);    else	len = sprintf(buf, "E%d\n", ecode);    doreply(cf, fd, buf, len, raddr, rlen);}static voidhandle_nomem(struct cfg *cf, int fd, struct sockaddr_storage *raddr,  socklen_t rlen, char *cookie, int ecode, struct sockaddr **ia, int *fds,  struct rtpp_session *spa, struct rtpp_session *spb){    int i;    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "can't allocate memory");    for (i = 0; i < 2; i++)	if (ia[i] != NULL)	    free(ia[i]);    if (spa != NULL) {	if (spa->call_id != NULL)	    free(spa->call_id);	free(spa);    }    if (spb != NULL)	free(spb);    for (i = 0; i < 2; i++)	if (fds[i] != -1)	    close(fds[i]);    reply_error(cf, fd, raddr, rlen, cookie, ecode);}inthandle_command(struct cfg *cf, int controlfd){    int len, argc, i, j, pidx, asymmetric;    int external, pf, lidx, playcount, weak;    int fds[2], lport, n;    socklen_t rlen;    char buf[1024 * 8];    char *cp, *call_id, *from_tag, *to_tag, *addr, *port, *cookie;    char *pname, *codecs, *recording_name;    struct rtpp_session *spa, *spb;    char **ap, *argv[10];    const char *rname;    struct sockaddr *ia[2], *lia[2];    struct sockaddr_storage raddr;    int requested_nsamples;    enum {DELETE, RECORD, PLAY, NOPLAY, COPY, UPDATE, LOOKUP, QUERY} op;    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;    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 = 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':	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 */	op = PLAY;	rname = "play";	playcount = 1;	pname = argv[2];	codecs = argv[3];	break;    case 'r':    case 'R':	op = RECORD;	rname = "record";	break;    case 'c':    case 'C':	op = COPY;	rname = "copy";	break;    case 's':    case 'S':	op = NOPLAY;	rname = "noplay";	break;    case 'v':    case 'V':	if (argv[0][1] == 'F' || argv[0][1] == 'f') {	    int i, known;	    /*	     * Wait for protocol version datestamp and check whether we	     * know it.	     */	    if (argc != 2 && argc != 3) {		rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");		reply_error(cf, controlfd, &raddr, rlen, cookie, 2);		return 0;	    }	    for (known = i = 0; proto_caps[i].pc_id != NULL; ++i) {		if (!strcmp(argv[1], proto_caps[i].pc_id)) {		    known = 1;		    break;		}	    }	    reply_number(cf, controlfd, &raddr, rlen, cookie, known);	    return 0;	}	if (argc != 1 && argc != 2) {	    rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error");	    reply_error(cf, controlfd, &raddr, rlen, cookie, 2);	    return 0;	}	/* This returns base version. */	reply_number(cf, controlfd, &raddr, rlen, cookie, CPROTOVER);	return 0;    case 'i':    case 'I':	if (cookie == NULL)	    len = sprintf(buf, "sessions created: %llu\nactive sessions: %d\n"	      "active streams: %d\n", cf->sessions_created,	      cf->sessions_active, cf->nsessions / 2);	else	    len = sprintf(buf, "%s sessions created: %llu\nactive sessions: %d\n"	      "active streams: %d\n", cookie, cf->sessions_created,	      cf->sessions_active, cf->nsessions / 2);	for (i = 1; i < cf->nsessions; i++) {	    char addrs[4][256];	    spa = cf->sessions[i];	    if (spa == NULL || spa->sidx[0] != i)		continue;	    /* RTCP twin session */	    if (spa->rtcp == NULL) {		spb = spa->rtp;		buf[len++] = '\t';	    } else {		spb = spa->rtcp;		buf[len++] = '\t';		buf[len++] = 'C';		buf[len++] = ' ';	    }	    addr2char_r(spb->laddr[1], addrs[0], sizeof(addrs[0]));	    if (spb->addr[1] == NULL) {		strcpy(addrs[1], "NONE");	    } else {		sprintf(addrs[1], "%s:%d", addr2char(spb->addr[1]),		  addr2port(spb->addr[1]));	    }	    addr2char_r(spb->laddr[0], addrs[2], sizeof(addrs[2]));	    if (spb->addr[0] == NULL) {		strcpy(addrs[3], "NONE");	    } else {		sprintf(addrs[3], "%s:%d", addr2char(spb->addr[0]),		  addr2port(spb->addr[0]));	    }	    len += sprintf(buf + len,	      "%s/%s: caller = %s:%d/%s, callee = %s:%d/%s, "	      "stats = %lu/%lu/%lu/%lu, ttl = %d\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);	    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;    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) {	if (argc < 5 || argc > 6) {	    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 == 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -