2012-05-02 16:58:39 +00:00
|
|
|
/*
|
2013-12-04 06:26:55 +00:00
|
|
|
Copyright (C) 2010-2012 Paul Gardner-Stephen
|
|
|
|
Copyright (C) 2010-2013 Serval Project Inc.
|
2012-05-02 16:58:39 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2013-12-07 17:38:14 +00:00
|
|
|
/*
|
|
|
|
Portions Copyright (C) 2013 Petter Reinholdtsen
|
|
|
|
Some 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 COPYRIGHT HOLDERS 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
|
|
|
|
COPYRIGHT HOLDER 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.
|
|
|
|
*/
|
|
|
|
|
2012-05-02 16:58:39 +00:00
|
|
|
/*
|
|
|
|
Android does unix domain sockets, but only stream sockets, not datagram sockets.
|
|
|
|
So we need a separate monitor interface for Android. A bit of a pain, but in
|
|
|
|
fact it lets us make a very Android/Java-friendly interface, without any binary
|
|
|
|
data structures (except for a binary extent for an audio sample block).
|
|
|
|
*/
|
|
|
|
|
2016-10-19 05:57:20 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2012-09-25 04:01:34 +00:00
|
|
|
#include <sys/stat.h>
|
2012-05-02 16:58:39 +00:00
|
|
|
#include "serval.h"
|
2012-12-04 03:42:28 +00:00
|
|
|
#include "conf.h"
|
2012-05-11 21:54:52 +00:00
|
|
|
#include "rhizome.h"
|
2012-09-25 04:01:34 +00:00
|
|
|
#include "cli.h"
|
|
|
|
#include "str.h"
|
2013-09-18 07:06:28 +00:00
|
|
|
#include "strbuf_helpers.h"
|
2012-09-25 04:01:34 +00:00
|
|
|
#include "overlay_address.h"
|
2014-06-13 04:04:10 +00:00
|
|
|
#include "overlay_interface.h"
|
2012-09-25 04:01:34 +00:00
|
|
|
#include "monitor-client.h"
|
2013-11-25 01:45:20 +00:00
|
|
|
#include "socket.h"
|
2013-11-25 02:39:54 +00:00
|
|
|
#include "dataformats.h"
|
2014-06-11 04:13:56 +00:00
|
|
|
#include "server.h"
|
2015-08-31 05:48:08 +00:00
|
|
|
#include "route_link.h"
|
2017-11-24 00:03:39 +00:00
|
|
|
#include "debug.h"
|
2018-04-03 05:02:06 +00:00
|
|
|
#include "mdp_services.h"
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2012-09-05 09:23:22 +00:00
|
|
|
#ifdef HAVE_UCRED_H
|
|
|
|
#include <ucred.h>
|
|
|
|
#endif
|
|
|
|
|
2012-09-06 05:01:25 +00:00
|
|
|
#ifdef linux
|
2012-05-21 02:52:50 +00:00
|
|
|
#if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED)
|
|
|
|
#define SO_PEERCRED LOCAL_PEERCRED
|
|
|
|
#endif
|
2012-09-06 05:01:25 +00:00
|
|
|
#endif
|
2012-05-03 02:41:13 +00:00
|
|
|
|
2012-05-03 17:46:06 +00:00
|
|
|
#define MONITOR_LINE_LENGTH 160
|
2012-05-02 16:58:39 +00:00
|
|
|
#define MONITOR_DATA_SIZE MAX_AUDIO_BYTES
|
|
|
|
struct monitor_context {
|
2012-07-02 03:49:54 +00:00
|
|
|
struct sched_ent alarm;
|
2012-09-27 06:57:37 +00:00
|
|
|
// monitor interest bitmask
|
2012-05-02 16:58:39 +00:00
|
|
|
int flags;
|
2012-09-27 06:57:37 +00:00
|
|
|
// what types of audio can we write to this client?
|
|
|
|
// (packed bits)
|
|
|
|
unsigned char supported_codecs[CODEC_FLAGS_LENGTH];
|
|
|
|
|
2012-05-02 16:58:39 +00:00
|
|
|
char line[MONITOR_LINE_LENGTH];
|
|
|
|
int line_length;
|
2016-09-06 02:54:00 +00:00
|
|
|
enum {
|
|
|
|
MONITOR_STATE_UNUSED,
|
|
|
|
MONITOR_STATE_COMMAND,
|
|
|
|
MONITOR_STATE_DATA
|
|
|
|
} state;
|
2012-05-02 16:58:39 +00:00
|
|
|
unsigned char buffer[MONITOR_DATA_SIZE];
|
|
|
|
int data_expected;
|
|
|
|
int data_offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_MONITOR_SOCKETS 8
|
2014-02-25 03:25:49 +00:00
|
|
|
unsigned monitor_socket_count=0;
|
2012-05-02 16:58:39 +00:00
|
|
|
struct monitor_context monitor_sockets[MAX_MONITOR_SOCKETS];
|
|
|
|
|
2012-07-02 03:49:54 +00:00
|
|
|
int monitor_process_command(struct monitor_context *c);
|
|
|
|
int monitor_process_data(struct monitor_context *c);
|
2012-06-25 07:20:23 +00:00
|
|
|
static void monitor_new_client(int s);
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2012-07-02 03:49:54 +00:00
|
|
|
struct sched_ent named_socket;
|
2012-07-02 06:34:00 +00:00
|
|
|
struct profile_total named_stats;
|
|
|
|
struct profile_total client_stats;
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2018-04-03 05:02:06 +00:00
|
|
|
static void monitor_setup_sockets()
|
2012-05-02 16:58:39 +00:00
|
|
|
{
|
2018-06-01 08:10:09 +00:00
|
|
|
if (serverMode == SERVER_NOT_RUNNING)
|
2018-04-03 05:02:06 +00:00
|
|
|
return;
|
|
|
|
|
2013-09-18 07:06:28 +00:00
|
|
|
int sock = -1;
|
2013-09-18 18:43:06 +00:00
|
|
|
if ((sock = esocket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
2012-05-28 05:24:33 +00:00
|
|
|
goto error;
|
2013-11-25 01:45:20 +00:00
|
|
|
struct socket_address addr;
|
|
|
|
if (make_local_sockaddr(&addr, "monitor.socket") == -1)
|
2012-05-28 05:24:33 +00:00
|
|
|
goto error;
|
2014-02-20 04:14:38 +00:00
|
|
|
if (socket_bind(sock, &addr) == -1)
|
2012-05-28 05:24:33 +00:00
|
|
|
goto error;
|
2013-09-18 07:06:28 +00:00
|
|
|
if (socket_listen(sock, MAX_MONITOR_SOCKETS) == -1)
|
|
|
|
goto error;
|
|
|
|
if (socket_set_reuseaddr(sock, 1) == -1)
|
2012-05-28 05:24:33 +00:00
|
|
|
WHY("Could not indicate reuse addresses. Not necessarily a problem (yet)");
|
2013-09-18 07:06:28 +00:00
|
|
|
socket_set_rcvbufsize(sock, 64 * 1024);
|
2012-07-02 03:49:54 +00:00
|
|
|
named_socket.function=monitor_poll;
|
2012-07-02 05:50:30 +00:00
|
|
|
named_stats.name="monitor_poll";
|
|
|
|
named_socket.stats=&named_stats;
|
2012-07-02 03:49:54 +00:00
|
|
|
named_socket.poll.fd=sock;
|
|
|
|
named_socket.poll.events=POLLIN;
|
|
|
|
watch(&named_socket);
|
2013-11-25 01:45:20 +00:00
|
|
|
INFOF("Monitor socket: fd=%d %s", sock, alloca_socket_address(&addr));
|
2018-04-03 05:02:06 +00:00
|
|
|
return;
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2013-09-18 07:06:28 +00:00
|
|
|
error:
|
|
|
|
if (sock != -1)
|
2013-06-18 06:58:26 +00:00
|
|
|
close(sock);
|
2018-06-01 08:10:09 +00:00
|
|
|
serverMode = SERVER_NOT_RUNNING;
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2018-04-03 05:02:06 +00:00
|
|
|
DEFINE_TRIGGER(startup, monitor_setup_sockets);
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2014-10-03 01:46:41 +00:00
|
|
|
#define monitor_write_error(C,E) _monitor_write_error(__WHENCE__, C, E)
|
|
|
|
static int _monitor_write_error(struct __sourceloc __whence, struct monitor_context *c, const char *error){
|
2012-09-25 04:01:34 +00:00
|
|
|
char msg[256];
|
2014-10-03 01:46:41 +00:00
|
|
|
WHY(error);
|
2012-09-25 04:01:34 +00:00
|
|
|
snprintf(msg, sizeof(msg), "\nERROR:%s\n", error);
|
|
|
|
write_str(c->alarm.poll.fd, msg);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-02 03:49:54 +00:00
|
|
|
void monitor_poll(struct sched_ent *alarm)
|
2012-05-02 16:58:39 +00:00
|
|
|
{
|
2012-07-03 05:43:39 +00:00
|
|
|
int s;
|
2012-05-08 22:05:05 +00:00
|
|
|
unsigned char buffer[1024];
|
|
|
|
struct sockaddr *ignored_address=(struct sockaddr *)&buffer[0];
|
2012-05-02 16:58:39 +00:00
|
|
|
socklen_t ignored_length=sizeof(ignored_address);
|
|
|
|
|
|
|
|
/* Check for new connections */
|
2012-06-22 11:06:59 +00:00
|
|
|
/* We don't care about the peer's address */
|
2012-06-25 07:20:23 +00:00
|
|
|
ignored_length = 0;
|
2014-04-07 05:54:23 +00:00
|
|
|
while ((s = accept(alarm->poll.fd,NULL, &ignored_length))!= -1) {
|
2012-06-25 07:20:23 +00:00
|
|
|
monitor_new_client(s);
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2012-06-28 06:07:36 +00:00
|
|
|
if (errno != EAGAIN) {
|
2012-06-22 11:06:59 +00:00
|
|
|
WHY_perror("accept");
|
2012-06-28 06:07:36 +00:00
|
|
|
}
|
2012-06-22 03:55:41 +00:00
|
|
|
}
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2012-09-25 04:01:34 +00:00
|
|
|
static void monitor_close(struct monitor_context *c){
|
2014-02-25 03:25:49 +00:00
|
|
|
INFOF("Tearing down monitor client fd=%d", c->alarm.poll.fd);
|
2012-08-22 05:20:14 +00:00
|
|
|
|
2018-06-01 08:10:09 +00:00
|
|
|
if (serverMode != SERVER_NOT_RUNNING && (c->flags & MONITOR_QUIT_ON_DISCONNECT)){
|
2016-09-06 02:54:00 +00:00
|
|
|
INFOF("Stopping server due to client disconnecting");
|
2017-09-12 05:54:10 +00:00
|
|
|
server_close();
|
2014-06-11 04:13:56 +00:00
|
|
|
}
|
2012-07-02 03:49:54 +00:00
|
|
|
unwatch(&c->alarm);
|
|
|
|
close(c->alarm.poll.fd);
|
|
|
|
c->alarm.poll.fd=-1;
|
2014-02-25 03:25:49 +00:00
|
|
|
c->state=MONITOR_STATE_UNUSED;
|
|
|
|
c->flags=0;
|
2012-07-02 03:49:54 +00:00
|
|
|
}
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2017-09-12 05:54:10 +00:00
|
|
|
static void monitor_shutdown()
|
|
|
|
{
|
|
|
|
if (named_socket.poll.fd == -1)
|
|
|
|
return;
|
|
|
|
unwatch(&named_socket);
|
|
|
|
close(named_socket.poll.fd);
|
|
|
|
named_socket.poll.fd=-1;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for(i=monitor_socket_count -1;i>=0;i--)
|
|
|
|
monitor_close(&monitor_sockets[i]);
|
|
|
|
}
|
|
|
|
DEFINE_TRIGGER(shutdown, monitor_shutdown);
|
|
|
|
|
2012-07-02 03:49:54 +00:00
|
|
|
void monitor_client_poll(struct sched_ent *alarm)
|
2012-06-22 03:55:41 +00:00
|
|
|
{
|
2012-08-08 01:26:05 +00:00
|
|
|
/* Read available data from a monitor socket */
|
2012-07-02 03:49:54 +00:00
|
|
|
struct monitor_context *c=(struct monitor_context *)alarm;
|
|
|
|
errno=0;
|
|
|
|
int bytes;
|
2016-09-06 02:54:00 +00:00
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
if (alarm->poll.revents & POLLIN) {
|
|
|
|
switch(c->state) {
|
2016-09-06 02:54:00 +00:00
|
|
|
case MONITOR_STATE_UNUSED:
|
|
|
|
FATAL("should not poll unused client");
|
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
case MONITOR_STATE_COMMAND:
|
|
|
|
bytes = 1;
|
|
|
|
while(bytes == 1) {
|
|
|
|
if (c->line_length >= MONITOR_LINE_LENGTH) {
|
2012-09-25 04:01:34 +00:00
|
|
|
c->line_length=0;
|
|
|
|
monitor_write_error(c,"Command too long");
|
2016-09-06 02:54:00 +00:00
|
|
|
DEBUG(monitor, "close monitor because command too long");
|
2012-09-25 04:01:34 +00:00
|
|
|
monitor_close(c);
|
|
|
|
return;
|
2012-08-22 05:20:14 +00:00
|
|
|
}
|
2016-09-06 02:54:00 +00:00
|
|
|
bytes = read_nonblock(c->alarm.poll.fd, &c->line[c->line_length], 1);
|
|
|
|
if (bytes == -1) {
|
|
|
|
DEBUG(monitor, "close monitor due to read error");
|
|
|
|
monitor_close(c);
|
2014-06-12 06:33:52 +00:00
|
|
|
return;
|
2012-08-22 05:20:14 +00:00
|
|
|
}
|
2016-09-06 02:54:00 +00:00
|
|
|
if (bytes == -2 || bytes == 0)
|
|
|
|
continue; // no bytes available to read
|
2014-06-12 06:33:52 +00:00
|
|
|
|
2012-09-25 04:01:34 +00:00
|
|
|
// silently skip all \r characters
|
|
|
|
if (c->line[c->line_length] == '\r')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// parse data length as soon as we see the : delimiter,
|
|
|
|
// so we can read the rest of the line into the start of the buffer
|
|
|
|
if (c->data_expected==0 && c->line[0]=='*' && c->line[c->line_length]==':'){
|
|
|
|
c->line[c->line_length]=0;
|
|
|
|
c->data_expected=atoi(c->line +1);
|
|
|
|
c->line_length=0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->line[c->line_length] == '\n') {
|
2016-09-06 02:54:00 +00:00
|
|
|
// got whole command line, start reading data if required
|
2012-09-25 04:01:34 +00:00
|
|
|
c->line[c->line_length]=0;
|
|
|
|
c->state=MONITOR_STATE_DATA;
|
|
|
|
c->data_offset=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
c->line_length += bytes;
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2012-09-25 04:01:34 +00:00
|
|
|
|
2016-09-06 02:54:00 +00:00
|
|
|
// if run out of characters to read before reaching the end of a command, then check for HUP
|
|
|
|
// now in case the client terminated abnormally
|
|
|
|
if (c->state != MONITOR_STATE_DATA)
|
2012-09-25 04:01:34 +00:00
|
|
|
break;
|
2016-09-06 02:54:00 +00:00
|
|
|
// else fall through...
|
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
case MONITOR_STATE_DATA:
|
2012-09-25 04:01:34 +00:00
|
|
|
if (c->data_expected - c->data_offset >0){
|
2016-09-06 02:54:00 +00:00
|
|
|
bytes = read_nonblock(c->alarm.poll.fd, &c->buffer[c->data_offset], c->data_expected - c->data_offset);
|
|
|
|
if (bytes == -2 || bytes == 0)
|
|
|
|
break; // no bytes available to read
|
|
|
|
if (bytes == -1) {
|
|
|
|
DEBUG(monitor, "close monitor due to read error");
|
|
|
|
monitor_close(c);
|
|
|
|
return;
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2016-09-06 02:54:00 +00:00
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
c->data_offset += bytes;
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2012-09-25 04:01:34 +00:00
|
|
|
|
2016-09-06 02:54:00 +00:00
|
|
|
// if run out of characters to read before reaching the expected number, then check for HUP
|
|
|
|
// now in case the client terminated abnormally
|
2012-09-25 04:01:34 +00:00
|
|
|
if (c->data_offset < c->data_expected)
|
|
|
|
break;
|
|
|
|
|
2016-09-06 02:54:00 +00:00
|
|
|
// we have received all of the binary data we were expecting
|
2012-09-25 04:01:34 +00:00
|
|
|
monitor_process_command(c);
|
|
|
|
|
|
|
|
// reset parsing state
|
2012-08-22 05:20:14 +00:00
|
|
|
c->state = MONITOR_STATE_COMMAND;
|
2012-09-25 04:01:34 +00:00
|
|
|
c->data_expected = 0;
|
|
|
|
c->data_offset = 0;
|
|
|
|
c->line_length = 0;
|
2016-09-06 02:54:00 +00:00
|
|
|
|
|
|
|
// poll again to finish processing all queued commands before checking for HUP, so that any
|
|
|
|
// queued "quit" command (quit on HUP) is processed before the HUP is handled
|
|
|
|
return;
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2012-08-22 05:20:14 +00:00
|
|
|
}
|
|
|
|
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
|
2016-09-06 02:54:00 +00:00
|
|
|
DEBUGF(monitor, "client disconnection (%s)", alloca_poll_events(alarm->poll.revents));
|
2012-09-25 04:01:34 +00:00
|
|
|
monitor_close(c);
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
|
|
|
}
|
2012-06-25 07:20:23 +00:00
|
|
|
|
|
|
|
static void monitor_new_client(int s) {
|
2012-09-05 09:23:22 +00:00
|
|
|
#ifdef SO_PEERCRED
|
2012-06-22 11:06:59 +00:00
|
|
|
struct ucred ucred;
|
|
|
|
socklen_t len;
|
2012-07-03 05:43:39 +00:00
|
|
|
int res;
|
2012-09-05 09:23:22 +00:00
|
|
|
#elif defined(HAVE_GETPEEREID)
|
2012-06-22 11:06:59 +00:00
|
|
|
gid_t othergid;
|
2012-09-05 09:23:22 +00:00
|
|
|
#elif defined(HAVE_UCRED_H)
|
|
|
|
ucred_t *ucred;
|
2012-06-22 11:06:59 +00:00
|
|
|
#endif
|
|
|
|
uid_t otheruid;
|
2014-02-25 03:25:49 +00:00
|
|
|
struct monitor_context *c=NULL;
|
2012-06-22 11:06:59 +00:00
|
|
|
|
2012-07-10 07:03:39 +00:00
|
|
|
if (set_nonblock(s) == -1)
|
|
|
|
goto error;
|
2012-06-22 11:06:59 +00:00
|
|
|
|
2012-09-05 09:23:22 +00:00
|
|
|
#ifdef SO_PEERCRED
|
|
|
|
/* Linux way */
|
2012-06-22 11:06:59 +00:00
|
|
|
len = sizeof(ucred);
|
|
|
|
res = getsockopt(s, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
|
|
|
|
if (res) {
|
|
|
|
WHY_perror("getsockopt(SO_PEERCRED)");
|
|
|
|
goto error;
|
|
|
|
}
|
2016-11-07 00:08:23 +00:00
|
|
|
if ((size_t)len < sizeof(ucred)) {
|
2013-07-15 00:29:24 +00:00
|
|
|
WHYF("getsockopt(SO_PEERCRED) returned the wrong size (Got %d expected %d)", len, (int)sizeof(ucred));
|
2012-06-22 11:06:59 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
otheruid = ucred.uid;
|
2012-09-05 09:23:22 +00:00
|
|
|
#elif defined(HAVE_UCRED_H)
|
|
|
|
/* Solaris way */
|
|
|
|
if (getpeerucred(s, &ucred) != 0) {
|
2012-10-19 05:39:20 +00:00
|
|
|
WHY_perror("getpeerucred");
|
2012-09-05 09:23:22 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
otheruid = ucred_geteuid(ucred);
|
|
|
|
ucred_free(ucred);
|
|
|
|
#elif defined(HAVE_GETPEEREID)
|
|
|
|
/* BSD way */
|
2012-06-22 11:06:59 +00:00
|
|
|
if (getpeereid(s, &otheruid, &othergid) != 0) {
|
2012-10-19 05:39:20 +00:00
|
|
|
WHY_perror("getpeereid");
|
2012-06-22 11:06:59 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-09-05 09:23:22 +00:00
|
|
|
#else
|
|
|
|
#error No way to get socket peer credentials
|
2012-06-22 11:06:59 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (otheruid != getuid()) {
|
2012-12-04 03:42:28 +00:00
|
|
|
if (otheruid != config.monitor.uid){
|
2012-08-08 01:26:05 +00:00
|
|
|
WHYF("monitor.socket client has wrong uid (%d versus %d)", otheruid,getuid());
|
|
|
|
write_str(s, "\nCLOSE:Incorrect UID\n");
|
|
|
|
goto error;
|
|
|
|
}
|
2012-07-02 03:49:54 +00:00
|
|
|
}
|
2014-02-25 03:25:49 +00:00
|
|
|
|
|
|
|
unsigned i;
|
|
|
|
for (i=0;i<monitor_socket_count;i++){
|
|
|
|
if (monitor_sockets[i].state == MONITOR_STATE_UNUSED){
|
|
|
|
c = &monitor_sockets[i];
|
|
|
|
break;
|
|
|
|
}
|
2012-06-22 11:06:59 +00:00
|
|
|
}
|
2012-07-02 03:49:54 +00:00
|
|
|
|
2014-02-25 03:25:49 +00:00
|
|
|
if (!c){
|
|
|
|
if (monitor_socket_count >= MAX_MONITOR_SOCKETS) {
|
|
|
|
write_str(s, "\nCLOSE:All sockets busy\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = &monitor_sockets[monitor_socket_count++];
|
|
|
|
}
|
2012-07-02 03:49:54 +00:00
|
|
|
c->alarm.function = monitor_client_poll;
|
2012-07-02 05:50:30 +00:00
|
|
|
client_stats.name = "monitor_client_poll";
|
|
|
|
c->alarm.stats=&client_stats;
|
2012-07-02 03:49:54 +00:00
|
|
|
c->alarm.poll.fd = s;
|
2016-09-06 02:54:00 +00:00
|
|
|
c->alarm.poll.events = POLLIN | POLLHUP;
|
2012-07-02 03:49:54 +00:00
|
|
|
c->line_length = 0;
|
|
|
|
c->state = MONITOR_STATE_COMMAND;
|
2012-09-27 06:57:37 +00:00
|
|
|
write_str(s,"\nINFO:You are talking to servald\n");
|
2012-07-02 03:49:54 +00:00
|
|
|
INFOF("Got %d clients", monitor_socket_count);
|
|
|
|
watch(&c->alarm);
|
2012-06-26 02:50:49 +00:00
|
|
|
|
2012-06-22 11:06:59 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
close(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-27 06:57:37 +00:00
|
|
|
void monitor_get_all_supported_codecs(unsigned char *codecs){
|
|
|
|
int i, j;
|
|
|
|
bzero(codecs,CODEC_FLAGS_LENGTH);
|
|
|
|
for(i=monitor_socket_count -1;i>=0;i--) {
|
|
|
|
if (monitor_sockets[i].flags & MONITOR_VOMP){
|
|
|
|
for (j=0;j<CODEC_FLAGS_LENGTH;j++)
|
|
|
|
codecs[j]|=monitor_sockets[i].supported_codecs[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 06:51:46 +00:00
|
|
|
static void monitor_announce_peer(struct subscriber *subscriber, int prior_reachable)
|
|
|
|
{
|
|
|
|
monitor_tell_formatted(MONITOR_LINKS, "\nLINK:%d:%s:%s\n",
|
|
|
|
subscriber->hop_count,
|
|
|
|
subscriber->prior_hop ? alloca_tohex_sid_t(subscriber->prior_hop->sid) : "",
|
|
|
|
alloca_tohex_sid_t(subscriber->sid));
|
|
|
|
|
|
|
|
if ((prior_reachable & REACHABLE) && (!(subscriber->reachable & REACHABLE)))
|
|
|
|
monitor_tell_formatted(MONITOR_PEERS, "\nOLDPEER:%s\n", alloca_tohex_sid_t(subscriber->sid));
|
|
|
|
if ((!(prior_reachable & REACHABLE)) && (subscriber->reachable & REACHABLE))
|
|
|
|
monitor_tell_formatted(MONITOR_PEERS, "\nNEWPEER:%s\n", alloca_tohex_sid_t(subscriber->sid));
|
|
|
|
}
|
|
|
|
DEFINE_TRIGGER(link_change, monitor_announce_peer);
|
|
|
|
|
2016-09-13 04:44:21 +00:00
|
|
|
static int monitor_announce_all_peers(void **record, void *UNUSED(context))
|
2013-05-08 04:12:11 +00:00
|
|
|
{
|
2016-09-13 04:44:21 +00:00
|
|
|
struct subscriber *subscriber = *record;
|
2013-05-08 04:12:11 +00:00
|
|
|
if (subscriber->reachable&REACHABLE)
|
2016-05-09 06:51:46 +00:00
|
|
|
monitor_announce_peer(subscriber, REACHABLE_NONE);
|
2013-05-08 04:12:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_set(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c=context->context;
|
2013-02-12 07:30:37 +00:00
|
|
|
if (strcase_startswith(parsed->args[1],"vomp",NULL)){
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags|=MONITOR_VOMP;
|
2012-09-27 06:57:37 +00:00
|
|
|
// store the list of supported codecs against the monitor connection,
|
|
|
|
// since we need to forget about them when the client disappears.
|
2013-12-10 05:51:23 +00:00
|
|
|
unsigned i;
|
2013-02-12 07:30:37 +00:00
|
|
|
for (i = 2; i < parsed->argc; ++i) {
|
|
|
|
int codec = atoi(parsed->args[i]);
|
2012-09-27 06:57:37 +00:00
|
|
|
if (codec>=0 && codec <=255)
|
|
|
|
set_codec_flag(codec, c->supported_codecs);
|
|
|
|
}
|
2014-06-11 04:13:56 +00:00
|
|
|
}else if (strcase_startswith(parsed->args[1],"rhizome", NULL)){
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags|=MONITOR_RHIZOME;
|
2014-06-11 04:13:56 +00:00
|
|
|
}else if (strcase_startswith(parsed->args[1],"peers", NULL)){
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags|=MONITOR_PEERS;
|
2013-05-08 04:12:11 +00:00
|
|
|
enum_subscribers(NULL, monitor_announce_all_peers, NULL);
|
2014-06-11 04:13:56 +00:00
|
|
|
}else if (strcase_startswith(parsed->args[1],"dnahelper", NULL)){
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags|=MONITOR_DNAHELPER;
|
2014-06-11 04:13:56 +00:00
|
|
|
}else if (strcase_startswith(parsed->args[1],"links", NULL)){
|
2013-05-02 04:57:23 +00:00
|
|
|
c->flags|=MONITOR_LINKS;
|
2016-05-09 06:51:46 +00:00
|
|
|
enum_subscribers(NULL, monitor_announce_all_peers, NULL);
|
2014-06-11 04:13:56 +00:00
|
|
|
}else if (strcase_startswith(parsed->args[1],"quit", NULL)){
|
2016-09-06 02:54:00 +00:00
|
|
|
c->flags|=MONITOR_QUIT_ON_DISCONNECT;
|
2014-06-13 04:04:10 +00:00
|
|
|
}else if (strcase_startswith(parsed->args[1],"interface", NULL)){
|
|
|
|
c->flags|=MONITOR_INTERFACE;
|
2018-04-03 05:02:06 +00:00
|
|
|
unsigned i;
|
|
|
|
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
|
|
|
|
if (overlay_interfaces[i].state == INTERFACE_STATE_UP)
|
|
|
|
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%u:%s:UP\n", i, overlay_interfaces[i].name);
|
|
|
|
}
|
2013-05-08 04:12:11 +00:00
|
|
|
}else
|
2012-09-25 04:01:34 +00:00
|
|
|
return monitor_write_error(c,"Unknown monitor type");
|
|
|
|
|
|
|
|
char msg[1024];
|
|
|
|
snprintf(msg,sizeof(msg),"\nMONITORSTATUS:%d\n",c->flags);
|
|
|
|
write_str(c->alarm.poll.fd,msg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_clear(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c=context->context;
|
2013-02-12 07:30:37 +00:00
|
|
|
if (strcase_startswith(parsed->args[1],"vomp",NULL))
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags&=~MONITOR_VOMP;
|
2013-02-12 07:30:37 +00:00
|
|
|
else if (strcase_startswith(parsed->args[1],"rhizome", NULL))
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags&=~MONITOR_RHIZOME;
|
2013-02-12 07:30:37 +00:00
|
|
|
else if (strcase_startswith(parsed->args[1],"peers", NULL))
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags&=~MONITOR_PEERS;
|
2013-02-12 07:30:37 +00:00
|
|
|
else if (strcase_startswith(parsed->args[1],"dnahelper", NULL))
|
2012-09-25 04:01:34 +00:00
|
|
|
c->flags&=~MONITOR_DNAHELPER;
|
2013-05-02 04:57:23 +00:00
|
|
|
else if (strcase_startswith(parsed->args[1],"links", NULL))
|
|
|
|
c->flags&=~MONITOR_LINKS;
|
2014-06-11 04:13:56 +00:00
|
|
|
else if (strcase_startswith(parsed->args[1],"quit", NULL))
|
2016-09-06 02:54:00 +00:00
|
|
|
c->flags&=~MONITOR_QUIT_ON_DISCONNECT;
|
2014-06-13 04:04:10 +00:00
|
|
|
else if (strcase_startswith(parsed->args[1],"interface", NULL))
|
|
|
|
c->flags&=~MONITOR_INTERFACE;
|
2012-09-25 04:01:34 +00:00
|
|
|
else
|
|
|
|
return monitor_write_error(c,"Unknown monitor type");
|
|
|
|
|
|
|
|
char msg[1024];
|
2012-09-28 02:00:03 +00:00
|
|
|
snprintf(msg,sizeof(msg),"\nINFO:%d\n",c->flags);
|
2012-09-25 04:01:34 +00:00
|
|
|
write_str(c->alarm.poll.fd,msg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_lookup_match(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c = context->context;
|
2013-02-12 07:30:37 +00:00
|
|
|
const char *sid = parsed->args[2];
|
|
|
|
const char *ext = parsed->args[4];
|
|
|
|
const char *name = parsed->argc >= 4 ? parsed->args[5] : "";
|
2012-09-25 04:01:34 +00:00
|
|
|
|
2014-01-31 00:08:52 +00:00
|
|
|
mdp_port_t dest_port = atoi(parsed->args[3]);
|
|
|
|
sid_t dest;
|
|
|
|
if (str_to_sid_t(&dest, sid) == -1)
|
2012-09-25 04:01:34 +00:00
|
|
|
return monitor_write_error(c,"Invalid SID");
|
2014-01-31 00:08:52 +00:00
|
|
|
|
|
|
|
struct subscriber *destination = find_subscriber(dest.binary, sizeof(dest), 1);
|
2012-08-10 05:58:56 +00:00
|
|
|
|
2012-09-25 04:01:34 +00:00
|
|
|
char uri[256];
|
2016-10-19 09:26:11 +00:00
|
|
|
snprintf(uri, sizeof(uri), "sid://%s/external/%s", alloca_tohex_sid_t(get_my_subscriber(1)->sid), ext);
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(monitor, "Sending response to %s for %s", sid, uri);
|
2016-10-19 09:26:11 +00:00
|
|
|
overlay_mdp_dnalookup_reply(destination, dest_port, get_my_subscriber(1), uri, ext, name);
|
2012-08-10 05:58:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_call(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c=context->context;
|
2013-10-09 08:24:21 +00:00
|
|
|
sid_t sid;
|
|
|
|
if (str_to_sid_t(&sid, parsed->args[1]) == -1)
|
2012-09-25 04:01:34 +00:00
|
|
|
return monitor_write_error(c,"invalid SID, so cannot place call");
|
2013-10-09 08:24:21 +00:00
|
|
|
struct subscriber *remote = find_subscriber(sid.binary, SID_SIZE, 1);
|
2016-10-19 09:26:11 +00:00
|
|
|
vomp_dial(get_my_subscriber(1), remote, parsed->args[2], parsed->args[3]);
|
2012-09-25 04:01:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-02 16:58:39 +00:00
|
|
|
|
2013-12-09 07:52:18 +00:00
|
|
|
static int monitor_call_ring(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-02-12 07:30:37 +00:00
|
|
|
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
|
2012-09-25 04:01:34 +00:00
|
|
|
if (!call)
|
2013-02-12 07:30:37 +00:00
|
|
|
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
|
2012-10-23 02:56:38 +00:00
|
|
|
else
|
|
|
|
vomp_ringing(call);
|
2012-09-25 04:01:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-02 17:30:34 +00:00
|
|
|
|
2013-12-09 07:52:18 +00:00
|
|
|
static int monitor_call_pickup(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-02-12 07:30:37 +00:00
|
|
|
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
|
2012-09-25 04:01:34 +00:00
|
|
|
if (!call)
|
2013-02-12 07:30:37 +00:00
|
|
|
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
|
2012-10-23 02:56:38 +00:00
|
|
|
else
|
|
|
|
vomp_pickup(call);
|
2012-09-25 04:01:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-03 17:54:53 +00:00
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_call_audio(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c=context->context;
|
2013-02-12 07:30:37 +00:00
|
|
|
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
|
2012-11-14 05:20:22 +00:00
|
|
|
|
|
|
|
if (!call){
|
2013-02-12 07:30:37 +00:00
|
|
|
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
|
2012-11-14 05:20:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-12 07:30:37 +00:00
|
|
|
int codec_type = atoi(parsed->args[2]);
|
|
|
|
int time = parsed->argc >=4 ? atoi(parsed->args[3]) : -1;
|
|
|
|
int sequence = parsed->argc >= 5 ? atoi(parsed->args[4]) : -1;
|
2012-11-14 05:20:22 +00:00
|
|
|
|
|
|
|
vomp_received_audio(call, codec_type, time, sequence, c->buffer, c->data_expected);
|
2012-09-25 04:01:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-09 07:52:18 +00:00
|
|
|
static int monitor_call_hangup(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-02-12 07:30:37 +00:00
|
|
|
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
|
2012-09-25 04:01:34 +00:00
|
|
|
if (!call)
|
2013-02-12 07:30:37 +00:00
|
|
|
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
|
2012-10-23 02:56:38 +00:00
|
|
|
else
|
|
|
|
vomp_hangup(call);
|
2012-09-25 04:01:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_call_dtmf(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-02-12 07:30:37 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c=context->context;
|
2013-02-12 07:30:37 +00:00
|
|
|
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
|
2012-09-25 04:01:34 +00:00
|
|
|
if (!call)
|
|
|
|
return monitor_write_error(c,"Invalid call token");
|
2013-02-12 07:30:37 +00:00
|
|
|
const char *digits = parsed->args[2];
|
2012-09-25 04:01:34 +00:00
|
|
|
|
2013-12-10 05:51:23 +00:00
|
|
|
unsigned i;
|
2012-09-25 04:01:34 +00:00
|
|
|
for(i=0;i<strlen(digits);i++) {
|
|
|
|
int digit=vomp_parse_dtmf_digit(digits[i]);
|
|
|
|
if (digit<0)
|
|
|
|
monitor_write_error(c,"Invalid DTMF digit");
|
|
|
|
else{
|
|
|
|
/* 80ms standard tone duration, so that it is a multiple
|
|
|
|
of the majority of codec time units (70ms is the nominal
|
|
|
|
DTMF tone length for most systems). */
|
|
|
|
unsigned char code = digit <<4;
|
2012-11-14 05:20:22 +00:00
|
|
|
vomp_received_audio(call, VOMP_CODEC_DTMF, -1, -1, &code, 1);
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2012-05-03 18:14:41 +00:00
|
|
|
}
|
2012-09-25 04:01:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-03 07:21:27 +00:00
|
|
|
static int monitor_help(const struct cli_parsed *parsed, struct cli_context *context);
|
2013-03-18 06:09:08 +00:00
|
|
|
|
|
|
|
struct cli_schema monitor_commands[] = {
|
|
|
|
{monitor_help,{"help",NULL},0,""},
|
2012-09-27 06:57:37 +00:00
|
|
|
{monitor_set,{"monitor","vomp","<codec>","...",NULL},0,""},
|
2012-09-25 04:01:34 +00:00
|
|
|
{monitor_set,{"monitor","<type>",NULL},0,""},
|
|
|
|
{monitor_clear,{"ignore","<type>",NULL},0,""},
|
2013-01-16 05:22:06 +00:00
|
|
|
{monitor_lookup_match,{"lookup","match","<sid>","<port>","<ext>","[<name>]",NULL},0,""},
|
2012-09-25 04:01:34 +00:00
|
|
|
{monitor_call, {"call","<sid>","<local_did>","<remote_did>",NULL},0,""},
|
|
|
|
{monitor_call_ring, {"ringing","<token>",NULL},0,""},
|
|
|
|
{monitor_call_pickup, {"pickup","<token>",NULL},0,""},
|
2012-11-14 05:20:22 +00:00
|
|
|
{monitor_call_audio,{"audio","<token>","<type>","[<time>]","[<sequence>]",NULL},0,""},
|
2012-09-25 04:01:34 +00:00
|
|
|
{monitor_call_hangup, {"hangup","<token>",NULL},0,""},
|
|
|
|
{monitor_call_dtmf, {"dtmf","<token>","<digits>",NULL},0,""},
|
2013-10-30 17:19:54 +00:00
|
|
|
{NULL, {NULL, NULL, NULL, NULL},0,NULL},
|
2012-09-25 04:01:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int monitor_process_command(struct monitor_context *c)
|
2012-05-02 16:58:39 +00:00
|
|
|
{
|
2012-09-25 04:01:34 +00:00
|
|
|
char *argv[16]={NULL,};
|
|
|
|
int argc = parse_argv(c->line, ' ', argv, 16);
|
|
|
|
|
2013-02-13 07:13:24 +00:00
|
|
|
struct cli_parsed parsed;
|
2013-07-03 07:21:27 +00:00
|
|
|
struct cli_context context={.context=c};
|
2014-08-18 09:08:05 +00:00
|
|
|
if (cli_parse(argc, (const char *const*)argv, monitor_commands, NULL, &parsed) || cli_invoke(&parsed, &context))
|
2012-09-25 04:01:34 +00:00
|
|
|
return monitor_write_error(c, "Invalid command");
|
|
|
|
return 0;
|
2012-05-02 16:58:39 +00:00
|
|
|
}
|
2012-05-02 17:30:34 +00:00
|
|
|
|
2014-08-18 09:08:05 +00:00
|
|
|
static int monitor_help(const struct cli_parsed *parsed, struct cli_context *context)
|
2013-03-18 06:09:08 +00:00
|
|
|
{
|
2016-09-06 01:49:45 +00:00
|
|
|
DEBUG_cli_parsed(monitor, parsed);
|
2013-07-03 07:21:27 +00:00
|
|
|
struct monitor_context *c=context->context;
|
2013-03-18 06:09:08 +00:00
|
|
|
strbuf b = strbuf_alloca(16384);
|
|
|
|
strbuf_puts(b, "\nINFO:Usage\n");
|
2014-08-18 09:08:05 +00:00
|
|
|
cli_usage_parsed(parsed, XPRINTF_STRBUF(b));
|
2013-03-18 06:09:08 +00:00
|
|
|
(void)write_all(c->alarm.poll.fd, strbuf_str(b), strbuf_len(b));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-08 03:03:23 +00:00
|
|
|
static void monitor_announce_bundle(rhizome_manifest *m)
|
2022-06-02 02:38:27 +00:00
|
|
|
{
|
|
|
|
// This message can contain the entire manifest, which itself can be 1024 bytes long.
|
|
|
|
// Thus we need to allow more space.
|
|
|
|
char msg[2048];
|
2013-12-06 01:40:08 +00:00
|
|
|
int len = snprintf(msg,1024,"\n*%zd:BUNDLE:%s\n",
|
2013-07-02 02:37:04 +00:00
|
|
|
m->manifest_all_bytes,
|
2016-09-27 00:58:46 +00:00
|
|
|
alloca_tohex_rhizome_bid_t(m->keypair.public_key));
|
2022-06-02 02:38:27 +00:00
|
|
|
|
|
|
|
if ((len+m->manifest_all_bytes)<sizeof(msg)) {
|
|
|
|
bcopy(m->manifestdata, &msg[len], m->manifest_all_bytes);
|
|
|
|
len+=m->manifest_all_bytes;
|
|
|
|
msg[len++]='\n';
|
|
|
|
}
|
2013-07-02 02:37:04 +00:00
|
|
|
monitor_tell_clients(msg, len, MONITOR_RHIZOME);
|
2012-05-11 21:54:52 +00:00
|
|
|
}
|
2016-03-08 03:03:23 +00:00
|
|
|
DEFINE_TRIGGER(bundle_add, monitor_announce_bundle);
|
2012-05-11 21:54:52 +00:00
|
|
|
|
2012-08-06 05:16:46 +00:00
|
|
|
// test if any monitor clients are interested in a particular type of event
|
|
|
|
int monitor_client_interested(int mask){
|
|
|
|
int i;
|
|
|
|
for(i=monitor_socket_count -1;i>=0;i--) {
|
|
|
|
if (monitor_sockets[i].flags & mask)
|
|
|
|
return 1;
|
|
|
|
}
|
2012-05-18 10:50:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-25 05:30:07 +00:00
|
|
|
int monitor_tell_clients(char *msg, int msglen, int mask)
|
2012-05-18 10:50:18 +00:00
|
|
|
{
|
2017-09-12 05:54:10 +00:00
|
|
|
int i, count=0;
|
2012-06-27 07:24:42 +00:00
|
|
|
IN();
|
2012-07-10 07:03:39 +00:00
|
|
|
for(i=monitor_socket_count -1;i>=0;i--) {
|
|
|
|
if (monitor_sockets[i].flags & mask) {
|
|
|
|
// DEBUG("Writing AUDIOPACKET to client");
|
2016-03-29 06:05:48 +00:00
|
|
|
if ( write_all_nonblock(monitor_sockets[i].alarm.poll.fd, msg, msglen) == -1) {
|
2016-09-06 02:54:00 +00:00
|
|
|
INFOF("Tear down monitor client #%d due to write error", i);
|
2012-09-25 04:01:34 +00:00
|
|
|
monitor_close(&monitor_sockets[i]);
|
2017-09-12 05:54:10 +00:00
|
|
|
}else{
|
|
|
|
count++;
|
2012-05-02 18:07:03 +00:00
|
|
|
}
|
|
|
|
}
|
2012-07-10 07:03:39 +00:00
|
|
|
}
|
2017-09-12 05:54:10 +00:00
|
|
|
RETURN(count);
|
2012-05-02 17:30:34 +00:00
|
|
|
}
|
2012-08-08 01:26:05 +00:00
|
|
|
|
|
|
|
int monitor_tell_formatted(int mask, char *fmt, ...){
|
|
|
|
char msg[1024];
|
|
|
|
int n;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
n=vsnprintf(msg, sizeof(msg), fmt, ap);
|
|
|
|
va_end(ap);
|
2017-09-12 05:54:10 +00:00
|
|
|
return monitor_tell_clients(msg, n, mask);
|
2012-08-08 01:26:05 +00:00
|
|
|
}
|
2016-03-07 23:46:20 +00:00
|
|
|
|
2018-04-03 05:02:06 +00:00
|
|
|
static void monitor_dna_helper(struct internal_mdp_header *header, const char *did)
|
|
|
|
{
|
|
|
|
monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n",
|
|
|
|
alloca_tohex_sid_t(header->source->sid), header->source_port,
|
|
|
|
did);
|
|
|
|
}
|
|
|
|
DEFINE_TRIGGER(dna_lookup, monitor_dna_helper);
|
|
|
|
|
|
|
|
|
2017-09-12 05:54:10 +00:00
|
|
|
static void monitor_interface_change(struct overlay_interface *interface, unsigned UNUSED(count)){
|
2016-04-27 03:44:09 +00:00
|
|
|
unsigned i = interface - overlay_interfaces;
|
2016-03-07 23:46:20 +00:00
|
|
|
if (interface->state==INTERFACE_STATE_UP)
|
2016-04-27 03:44:09 +00:00
|
|
|
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%u:%s:UP\n", i, interface->name);
|
2016-03-07 23:46:20 +00:00
|
|
|
else if(interface->state==INTERFACE_STATE_DOWN)
|
2016-04-27 03:44:09 +00:00
|
|
|
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%u:%s:DOWN\n", i, interface->name);
|
2016-03-07 23:46:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_TRIGGER(iupdown, monitor_interface_change);
|
|
|
|
|
|
|
|
|