mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-24 23:36:46 +00:00
71ed78e058
Change a test case: configuration options are now case sensitive. Fix config file load and parse logic in conf.c, always copy 'debug' flags from config.debug. The config schema 'interfaces' option is no longer MANDATORY. Introduce new CLIFLAG_PERMISSIVE_CONFIG to supress bad-config ERROR messages from the 'config set' and 'config get' commands. Refactor cli_execute() into cli_parse() and cli_invoke(). Use *const* struct command_line_option everywhere.
327 lines
9.3 KiB
C
327 lines
9.3 KiB
C
/*
|
|
Copyright (C) 2012 Serval Project
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <poll.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "serval.h"
|
|
#include "conf.h"
|
|
#include "cli.h"
|
|
#include "monitor-client.h"
|
|
#include "str.h"
|
|
#include "constants.h"
|
|
|
|
int call_token=-1;
|
|
int seen_audio=0;
|
|
int monitor_client_fd=-1;
|
|
struct monitor_state *monitor_state;
|
|
|
|
struct line_state{
|
|
struct sched_ent alarm;
|
|
int fd;
|
|
char line_buff[1024];
|
|
int line_pos;
|
|
void (*process_line)(char *line);
|
|
};
|
|
|
|
static void send_hangup(int session_id){
|
|
monitor_client_writeline(monitor_client_fd, "hangup %06x\n",session_id);
|
|
}
|
|
static void send_ringing(int session_id){
|
|
monitor_client_writeline(monitor_client_fd, "ringing %06x\n",session_id);
|
|
}
|
|
static void send_pickup(int session_id){
|
|
monitor_client_writeline(monitor_client_fd, "pickup %06x\n",session_id);
|
|
}
|
|
static void send_call(const char *sid, const char *caller_id, const char *remote_ext){
|
|
monitor_client_writeline(monitor_client_fd, "call %s %s %s\n", sid, caller_id, remote_ext);
|
|
}
|
|
|
|
#if 0
|
|
This function commented out to avoid "defined but not used" compiler warning. Once you need
|
|
it, just get rid of the #if0..#endif and this comment.
|
|
-- Andrew Bettison <andrew@servalproject.com>
|
|
|
|
static void send_audio(int session_id, unsigned char *buffer, int len, int codec){
|
|
monitor_client_writeline_and_data(monitor_client_fd, buffer, len, "audio %06x %d\n", session_id, codec);
|
|
}
|
|
|
|
#endif
|
|
|
|
static int remote_call(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
|
|
if (call_token != -1){
|
|
send_hangup(token);
|
|
printf("Rejected incoming call, already busy\n");
|
|
fflush(stdout);
|
|
return 1;
|
|
}
|
|
|
|
call_token = token;
|
|
seen_audio = 0;
|
|
printf("Incoming call from %s (%s)\n",argv[3],argv[4]);
|
|
fflush(stdout);
|
|
send_ringing(token);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_ringing(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
if (call_token == token){
|
|
printf("They're ringing\n");
|
|
fflush(stdout);
|
|
}else
|
|
send_hangup(token);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_pickup(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
if (call_token == token){
|
|
printf("They've picked up\n");
|
|
fflush(stdout);
|
|
}else
|
|
send_hangup(token);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_dialing(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
if (call_token == -1){
|
|
call_token=token;
|
|
seen_audio=0;
|
|
printf("Dialling\n");
|
|
fflush(stdout);
|
|
}else
|
|
send_hangup(token);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_hangup(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
if (call_token == token){
|
|
printf("Call ended\n");
|
|
fflush(stdout);
|
|
call_token=-1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int remote_audio(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
if (call_token == token){
|
|
if (!seen_audio){
|
|
printf("Incoming audio\n");
|
|
fflush(stdout);
|
|
seen_audio=1;
|
|
}
|
|
}else
|
|
send_hangup(token);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_codecs(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int token = strtol(argv[0], NULL, 16);
|
|
if (call_token == token){
|
|
int i;
|
|
printf("Codec list");
|
|
for (i=1;i<argc;i++)
|
|
printf(" %s",argv[i]);
|
|
printf("\n");
|
|
fflush(stdout);
|
|
}else
|
|
send_hangup(token);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
int i;
|
|
printf("%s",cmd);
|
|
for (i=0;i<argc;i++){
|
|
printf(" %s",argv[i]);
|
|
}
|
|
printf("\n");
|
|
if (dataLen){
|
|
dump(NULL,data,dataLen);
|
|
}
|
|
fflush(stdout);
|
|
return 1;
|
|
}
|
|
|
|
static int remote_noop(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
|
return 1;
|
|
}
|
|
|
|
struct monitor_command_handler console_handlers[]={
|
|
{.command="CALLFROM", .handler=remote_call},
|
|
{.command="RINGING", .handler=remote_ringing},
|
|
{.command="ANSWERED", .handler=remote_pickup},
|
|
{.command="CALLTO", .handler=remote_dialing},
|
|
{.command="HANGUP", .handler=remote_hangup},
|
|
{.command="AUDIOPACKET", .handler=remote_audio},
|
|
{.command="CODECS", .handler=remote_codecs},
|
|
{.command="INFO", .handler=remote_print},
|
|
{.command="CALLSTATUS", .handler=remote_noop},
|
|
{.command="KEEPALIVE", .handler=remote_noop},
|
|
{.command="MONITORSTATUS", .handler=remote_noop},
|
|
};
|
|
|
|
static int console_dial(int argc, const char *const *argv, const struct command_line_option *o, void *context){
|
|
if (call_token!=-1){
|
|
printf("Already in a call\n");
|
|
return 0;
|
|
}
|
|
const char *sid=argv[1];
|
|
const char *local=argc>=3?argv[2]:"";
|
|
const char *remote=argc>=4?argv[3]:"";
|
|
send_call(sid, local, remote);
|
|
return 0;
|
|
}
|
|
|
|
static int console_answer(int argc, const char *const *argv, const struct command_line_option *o, void *context){
|
|
if (call_token==-1){
|
|
printf("No active call to answer\n");
|
|
fflush(stdout);
|
|
}else
|
|
send_pickup(call_token);
|
|
return 0;
|
|
}
|
|
|
|
static int console_hangup(int argc, const char *const *argv, const struct command_line_option *o, void *context){
|
|
if (call_token==-1){
|
|
printf("No call to hangup\n");
|
|
fflush(stdout);
|
|
}else
|
|
send_hangup(call_token);
|
|
return 0;
|
|
}
|
|
|
|
static int console_usage(int argc, const char *const *argv, const struct command_line_option *o, void *context);
|
|
|
|
struct command_line_option console_commands[]={
|
|
{console_answer,{"answer",NULL},0,"Answer an incoming phone call"},
|
|
{console_dial,{"call","<sid>","[<local_number>]","[<remote_extension>]",NULL},0,"Start dialling a given person"},
|
|
{console_hangup,{"hangup",NULL},0,"Hangup the phone line"},
|
|
{console_usage,{"help",NULL},0,"This usage message"},
|
|
{NULL},
|
|
};
|
|
|
|
static int console_usage(int argc, const char *const *argv, const struct command_line_option *o, void *context){
|
|
cli_usage(console_commands);
|
|
fflush(stdout);
|
|
return 0;
|
|
}
|
|
|
|
static void console_command(char *line){
|
|
char *argv[16];
|
|
int argc = parse_argv(line, ' ', argv, 16);
|
|
|
|
int ret = cli_parse(argc, (const char *const*)argv, console_commands);
|
|
if (ret == -1) {
|
|
printf("Unknown command, try help\n");
|
|
fflush(stdout);
|
|
} else {
|
|
cli_invoke(&console_commands[ret], argc, (const char *const*)argv, NULL);
|
|
}
|
|
}
|
|
|
|
static void read_lines(struct sched_ent *alarm){
|
|
struct line_state *state=(struct line_state *)alarm;
|
|
set_nonblock(STDIN_FILENO);
|
|
int bytes = read(state->alarm.poll.fd, state->line_buff + state->line_pos, sizeof(state->line_buff) - state->line_pos);
|
|
set_block(STDIN_FILENO);
|
|
int i = state->line_pos;
|
|
int processed=0;
|
|
state->line_pos+=bytes;
|
|
char *line_start=state->line_buff;
|
|
|
|
for (;i<state->line_pos;i++){
|
|
if (state->line_buff[i]=='\n'){
|
|
state->line_buff[i]=0;
|
|
if (*line_start)
|
|
state->process_line(line_start);
|
|
processed=i+1;
|
|
line_start = state->line_buff + processed;
|
|
}
|
|
}
|
|
|
|
if (processed){
|
|
// squash unprocessed data back to the start of the buffer
|
|
state->line_pos -= processed;
|
|
bcopy(state->line_buff, line_start, state->line_pos);
|
|
}
|
|
}
|
|
|
|
static void monitor_read(struct sched_ent *alarm){
|
|
if (monitor_client_read(alarm->poll.fd, monitor_state, console_handlers,
|
|
sizeof(console_handlers)/sizeof(struct monitor_command_handler))<0){
|
|
unwatch(alarm);
|
|
monitor_client_close(alarm->poll.fd, monitor_state);
|
|
alarm->poll.fd=-1;
|
|
monitor_client_fd=-1;
|
|
}
|
|
}
|
|
|
|
int app_vomp_console(int argc, const char *const *argv, const struct command_line_option *o, void *context)
|
|
{
|
|
static struct profile_total stdin_profile={
|
|
.name="read_lines",
|
|
};
|
|
struct line_state stdin_state={
|
|
.alarm.poll.fd = STDIN_FILENO,
|
|
.alarm.poll.events = POLLIN,
|
|
.alarm.function = read_lines,
|
|
.alarm.stats=&stdin_profile,
|
|
.process_line=console_command,
|
|
};
|
|
static struct profile_total monitor_profile={
|
|
.name="monitor_read",
|
|
};
|
|
struct sched_ent monitor_alarm={
|
|
.poll.events = POLLIN,
|
|
.function = monitor_read,
|
|
.stats=&monitor_profile,
|
|
};
|
|
|
|
monitor_client_fd = monitor_client_open(&monitor_state);
|
|
|
|
monitor_client_writeline(monitor_client_fd, "monitor vomp %d %d %d\n",
|
|
VOMP_CODEC_8ULAW,VOMP_CODEC_8ALAW,VOMP_CODEC_PCM);
|
|
|
|
set_nonblock(monitor_client_fd);
|
|
|
|
monitor_alarm.poll.fd = monitor_client_fd;
|
|
watch(&monitor_alarm);
|
|
|
|
watch(&stdin_state.alarm);
|
|
|
|
while(monitor_client_fd!=-1){
|
|
fd_poll();
|
|
}
|
|
|
|
unwatch(&stdin_state.alarm);
|
|
|
|
return 0;
|
|
}
|