mirror of https://github.com/sipwise/rtpengine.git
Ein Commandline interface, wo man von der console and der rtpengine bestimme Dinge abfragen kann. Author: Frederic-Philippe Metz <Frederic.Metz@1und1.de>pull/60/head
parent
ee655bdcc6
commit
131c9e8110
@ -0,0 +1,308 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "poller.h"
|
||||||
|
#include "aux.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "call.h"
|
||||||
|
#include "cli.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const char* TRUNCATED = " ... Output truncated. Increase Output Buffer ...\n";
|
||||||
|
|
||||||
|
#define truncate_output(x) do { x -= strlen(TRUNCATED)+1; x += sprintf(x,"%s",TRUNCATED); } while (0);
|
||||||
|
|
||||||
|
#define ADJUSTLEN(printlen,outbuflen,replybuffer) do { if (printlen>=(outbufend-replybuffer)) \
|
||||||
|
truncate_output(replybuffer); \
|
||||||
|
replybuffer += (printlen>=outbufend-replybuffer)?outbufend-replybuffer:printlen; } while (0);
|
||||||
|
|
||||||
|
static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) {
|
||||||
|
str callid;
|
||||||
|
struct call* c=0;
|
||||||
|
struct call_monologue *ml;
|
||||||
|
struct call_media *md;
|
||||||
|
struct packet_stream *ps;
|
||||||
|
GSList *l;
|
||||||
|
GList *k, *o;
|
||||||
|
char buf[64];
|
||||||
|
int printlen=0;
|
||||||
|
|
||||||
|
if (len<=1) {
|
||||||
|
printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required.");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++buffer; --len; // one space
|
||||||
|
str_init_len(&callid,buffer,len);
|
||||||
|
|
||||||
|
c = call_get(&callid, m);
|
||||||
|
|
||||||
|
if (!c) {
|
||||||
|
printlen = snprintf(replybuffer,(outbufend-replybuffer), "\nCall Id not found (%s).\n\n",callid.s);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printlen = snprintf (replybuffer,(outbufend-replybuffer), "\ncallid: %30s | deletionmark:%4s | created:%12i\n\n", c->callid.s , c->ml_deleted?"yes":"no", (int)c->created);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
|
||||||
|
for (l = c->monologues; l; l = l->next) {
|
||||||
|
ml = l->data;
|
||||||
|
|
||||||
|
printlen = snprintf(replybuffer,(outbufend-replybuffer), "--- Tag '"STR_FORMAT"', callduration "
|
||||||
|
"%u:%02u , in dialogue with '"STR_FORMAT"'\n",
|
||||||
|
STR_FMT(&ml->tag),
|
||||||
|
(unsigned int) (poller_now - ml->created) / 60,
|
||||||
|
(unsigned int) (poller_now - ml->created) % 60,
|
||||||
|
ml->active_dialogue ? ml->active_dialogue->tag.len : 6,
|
||||||
|
ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
|
||||||
|
for (k = ml->medias.head; k; k = k->next) {
|
||||||
|
md = k->data;
|
||||||
|
|
||||||
|
for (o = md->streams.head; o; o = o->next) {
|
||||||
|
ps = o->data;
|
||||||
|
|
||||||
|
if (PS_ISSET(ps, FALLBACK_RTCP))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
smart_ntop_p(buf, &ps->endpoint.ip46, sizeof(buf));
|
||||||
|
|
||||||
|
printlen = snprintf(replybuffer,(outbufend-replybuffer), "------ Media #%u, port %5u <> %15s:%-5hu%s, "
|
||||||
|
"%llu p, %llu b, %llu e\n",
|
||||||
|
md->index,
|
||||||
|
(unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0),
|
||||||
|
buf, ps->endpoint.port,
|
||||||
|
(!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "",
|
||||||
|
(unsigned long long) ps->stats.packets,
|
||||||
|
(unsigned long long) ps->stats.bytes,
|
||||||
|
(unsigned long long) ps->stats.errors);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printlen = snprintf(replybuffer,(outbufend-replybuffer), "\n");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
|
||||||
|
rwlock_unlock_w(&c->master_lock); // because of call_get(..)
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) {
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
str *ptrkey;
|
||||||
|
struct call *call;
|
||||||
|
int printlen=0;
|
||||||
|
|
||||||
|
static const char* LIST_NUMSESSIONS = "numsessions";
|
||||||
|
static const char* LIST_SESSIONS = "sessions";
|
||||||
|
static const char* LIST_SESSION = "session";
|
||||||
|
|
||||||
|
if (len<=1) {
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required.");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++buffer; --len; // one space
|
||||||
|
|
||||||
|
if (len>=strlen(LIST_NUMSESSIONS) && strncmp(buffer,LIST_NUMSESSIONS,strlen(LIST_NUMSESSIONS)) == 0) {
|
||||||
|
rwlock_lock_r(&m->hashlock);
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "Current Sessions on rtpengine:%i\n", g_hash_table_size(m->callhash));
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
rwlock_unlock_r(&m->hashlock);
|
||||||
|
} else if (len>=strlen(LIST_SESSIONS) && strncmp(buffer,LIST_SESSIONS,strlen(LIST_SESSIONS)) == 0) {
|
||||||
|
rwlock_lock_r(&m->hashlock);
|
||||||
|
if (g_hash_table_size(m->callhash)==0) {
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "No sessions on this media relay.\n");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
rwlock_unlock_r(&m->hashlock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_hash_table_iter_init (&iter, m->callhash);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||||
|
ptrkey = (str*)key;
|
||||||
|
call = (struct call*)value;
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "callid: %30s | deletionmark:%4s | created:%12i\n", ptrkey->s, call->ml_deleted?"yes":"no", (int)call->created);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
}
|
||||||
|
rwlock_unlock_r(&m->hashlock);
|
||||||
|
} else if (len>=strlen(LIST_SESSION) && strncmp(buffer,LIST_SESSION,strlen(LIST_SESSION)) == 0) {
|
||||||
|
cli_incoming_list_callid(buffer+strlen(LIST_SESSION), len-strlen(LIST_SESSION), m, replybuffer, outbufend);
|
||||||
|
} else {
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "%s:%s\n", "Unknown 'list' command", buffer);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) {
|
||||||
|
str termparam;
|
||||||
|
struct call* c=0;
|
||||||
|
int printlen=0;
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
|
||||||
|
if (len<=1) {
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required.");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++buffer; --len; // one space
|
||||||
|
str_init_len(&termparam,buffer,len);
|
||||||
|
|
||||||
|
// --- terminate all calls
|
||||||
|
if (!str_memcmp(&termparam,"all")) {
|
||||||
|
while (g_hash_table_size(m->callhash)) {
|
||||||
|
g_hash_table_iter_init (&iter, m->callhash);
|
||||||
|
g_hash_table_iter_next (&iter, &key, &value);
|
||||||
|
c = (struct call*)value;
|
||||||
|
if (!c) continue;
|
||||||
|
call_destroy(c);
|
||||||
|
}
|
||||||
|
ilog(LOG_INFO,"All calls terminated by operator.");
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "All calls terminated by operator.");
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- terminate a dedicated call id
|
||||||
|
c = call_get(&termparam, m);
|
||||||
|
|
||||||
|
if (!c) {
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "\nCall Id not found (%s).\n\n",termparam.s);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
call_destroy(c);
|
||||||
|
|
||||||
|
printlen = snprintf(replybuffer, outbufend-replybuffer, "\nCall Id (%s) successfully terminated by operator.\n\n",termparam.s);
|
||||||
|
ADJUSTLEN(printlen,outbufend,replybuffer);
|
||||||
|
ilog(LOG_WARN, "Call Id (%s) successfully terminated by operator.",termparam.s);
|
||||||
|
|
||||||
|
rwlock_unlock_w(&c->master_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cli_incoming(int fd, void *p, uintptr_t u) {
|
||||||
|
int nfd;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct cli *cli = (void *) p;
|
||||||
|
socklen_t sinl;
|
||||||
|
static const int BUFLENGTH = 4096*1024;
|
||||||
|
char replybuffer[BUFLENGTH]; memset(&replybuffer,0,BUFLENGTH);
|
||||||
|
char* outbuf = replybuffer;
|
||||||
|
const char* outbufend = replybuffer+BUFLENGTH;
|
||||||
|
static const int MAXINPUT = 1024;
|
||||||
|
char inbuf[MAXINPUT]; memset(&inbuf,0,MAXINPUT);
|
||||||
|
int inlen = 0, readbytes = 0;
|
||||||
|
int rc=0;
|
||||||
|
|
||||||
|
mutex_lock(&cli->lock);
|
||||||
|
next:
|
||||||
|
sinl = sizeof(sin);
|
||||||
|
nfd = accept(fd, (struct sockaddr *) &sin, &sinl);
|
||||||
|
if (nfd == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
sprintf(replybuffer, "Could currently not accept CLI commands. Reason:%s\n", strerror(errno));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ilog(LOG_INFO, "Accept error:%s\n", strerror(errno));
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ilog(LOG_INFO, "New cli connection from " DF, DP(sin));
|
||||||
|
|
||||||
|
do {
|
||||||
|
readbytes = read(nfd, inbuf+inlen, MAXINPUT);
|
||||||
|
if (readbytes == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
ilog(LOG_INFO, "Could currently not read CLI commands. Reason:%s\n", strerror(errno));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ilog(LOG_INFO, "Could currently not read CLI commands. Reason:%s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
inlen += readbytes;
|
||||||
|
} while (readbytes > 0);
|
||||||
|
|
||||||
|
ilog(LOG_INFO, "Got CLI command:%s\n",inbuf);
|
||||||
|
|
||||||
|
static const char* LIST = "list";
|
||||||
|
static const char* TERMINATE = "terminate";
|
||||||
|
|
||||||
|
if (inlen>=strlen(LIST) && strncmp(inbuf,LIST,strlen(LIST)) == 0) {
|
||||||
|
cli_incoming_list(inbuf+strlen(LIST), inlen-strlen(LIST), cli->callmaster, outbuf, outbufend);
|
||||||
|
|
||||||
|
} else if (inlen>=strlen(TERMINATE) && strncmp(inbuf,TERMINATE,strlen(TERMINATE)) == 0) {
|
||||||
|
cli_incoming_terminate(inbuf+strlen(TERMINATE), inlen-strlen(TERMINATE), cli->callmaster, outbuf, outbufend);
|
||||||
|
} else {
|
||||||
|
sprintf(replybuffer, "%s:%s\n", "Unknown or incomplete command:", inbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc += write( nfd, (char *)&replybuffer, strlen(replybuffer) );
|
||||||
|
} while (rc < strlen(replybuffer));
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
close(nfd);
|
||||||
|
mutex_unlock(&cli->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void control_closed(int fd, void *p, uintptr_t u) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m) {
|
||||||
|
struct cli *c;
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct poller_item i;
|
||||||
|
|
||||||
|
if (!p || !m)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nonblock(fd);
|
||||||
|
reuseaddr(fd);
|
||||||
|
|
||||||
|
ZERO(sin);
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = ip;
|
||||||
|
sin.sin_port = htons(port);
|
||||||
|
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (listen(fd, 5))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
c = obj_alloc0("cli_udp", sizeof(*c), NULL);
|
||||||
|
c->fd = fd;
|
||||||
|
c->poller = p;
|
||||||
|
c->callmaster = m;
|
||||||
|
mutex_init(&c->lock);
|
||||||
|
|
||||||
|
ZERO(i);
|
||||||
|
i.fd = fd;
|
||||||
|
i.closed = control_closed;
|
||||||
|
i.readable = cli_incoming;
|
||||||
|
i.obj = &c->obj;
|
||||||
|
if (poller_add_item(p, &i))
|
||||||
|
goto fail2;
|
||||||
|
|
||||||
|
obj_put(c);
|
||||||
|
return c;
|
||||||
|
|
||||||
|
fail2:
|
||||||
|
obj_put(c);
|
||||||
|
fail:
|
||||||
|
close(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CLI_UDP_H_
|
||||||
|
#define CLI_UDP_H_
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
struct cli {
|
||||||
|
struct obj obj;
|
||||||
|
|
||||||
|
struct callmaster *callmaster;
|
||||||
|
int fd;
|
||||||
|
struct poller *poller;
|
||||||
|
mutex_t lock;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m);
|
||||||
|
|
||||||
|
#endif /* CLI_UDP_H_ */
|
@ -1 +1,2 @@
|
|||||||
daemon/rtpengine /usr/sbin/
|
daemon/rtpengine /usr/sbin/
|
||||||
|
utils/rtpengine-ctl /usr/sbin/
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
host=127.0.0.1
|
||||||
|
port=9900
|
||||||
|
error_rc=255
|
||||||
|
|
||||||
|
prgname=${0##*/}
|
||||||
|
prgdir=${0%$prgname}
|
||||||
|
|
||||||
|
showusage() {
|
||||||
|
echo ""
|
||||||
|
echo " rectl [ -ip <ipaddress> -port <port> ] <command>"
|
||||||
|
echo ""
|
||||||
|
echo " Supported commands are:"
|
||||||
|
echo ""
|
||||||
|
echo " list [ numsessions | sessions | session <callid> ]"
|
||||||
|
echo " numsessions : prints the number of sessions"
|
||||||
|
echo " sessions : print one-liner session information"
|
||||||
|
echo " session <callid> : print detail about one session"
|
||||||
|
echo ""
|
||||||
|
echo " terminate [ all | <callid> ]"
|
||||||
|
echo " all : terminates all current sessions"
|
||||||
|
echo " <callid> : session is immediately terminated"
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo " Return Value:"
|
||||||
|
echo " 0 on success with ouput from server side, other values for failure."
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then showusage; fi
|
||||||
|
|
||||||
|
|
||||||
|
command -v nc 2>&1 >/dev/null
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: rectl requires netcat to be installed."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case $1 in
|
||||||
|
"-?"|"-help"|"-h")
|
||||||
|
showusage
|
||||||
|
;;
|
||||||
|
"-ip")
|
||||||
|
shift
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
host=$1
|
||||||
|
else
|
||||||
|
echo "Missing parameter for option '-ip'" >&2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"-port")
|
||||||
|
shift
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
port=$1
|
||||||
|
else
|
||||||
|
echo "Missing parameter for option '-port'" >&2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
varargs="$varargs $1"
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -n ${varargs} | nc ${host} ${port}
|
Loading…
Reference in new issue