summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/openpgm-svn-r1085/pgm/test/monitor.c')
-rw-r--r--3rdparty/openpgm-svn-r1085/pgm/test/monitor.c349
1 files changed, 349 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c b/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c
new file mode 100644
index 0000000..6569a55
--- /dev/null
+++ b/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c
@@ -0,0 +1,349 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * PGM link monitor.
+ *
+ * Copyright (c) 2006-2007 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include <pgm/pgm.h>
+#include <pgm/backtrace.h>
+#include <pgm/signal.h>
+#include <pgm/log.h>
+
+#include "dump-json.h"
+
+
+/* globals */
+
+static const char* g_network = "239.192.0.1";
+static struct in_addr g_filter /* = { 0 } */;
+
+static GIOChannel* g_io_channel = NULL;
+static GIOChannel* g_stdin_channel = NULL;
+static GMainLoop* g_loop = NULL;
+
+
+static void on_signal (int, gpointer);
+static gboolean on_startup (gpointer);
+static gboolean on_mark (gpointer);
+
+static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer);
+static gboolean on_io_error (GIOChannel*, GIOCondition, gpointer);
+
+static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer);
+
+int
+main (
+ G_GNUC_UNUSED int argc,
+ G_GNUC_UNUSED char *argv[]
+ )
+{
+/* pre-initialise PGM messages module to add hook for GLib logging */
+ pgm_messages_init();
+ log_init ();
+ puts ("monitor");
+
+/* setup signal handlers */
+ signal (SIGSEGV, on_sigsegv);
+ signal (SIGHUP, SIG_IGN);
+ pgm_signal_install (SIGINT, on_signal, g_loop);
+ pgm_signal_install (SIGTERM, on_signal, g_loop);
+
+ g_filter.s_addr = 0;
+
+/* delayed startup */
+ puts ("scheduling startup.");
+ g_timeout_add(0, (GSourceFunc)on_startup, NULL);
+
+/* dispatch loop */
+ g_loop = g_main_loop_new(NULL, FALSE);
+
+ puts ("entering main event loop ... ");
+ g_main_loop_run(g_loop);
+
+ puts ("event loop terminated, cleaning up.");
+
+/* cleanup */
+ g_main_loop_unref(g_loop);
+ g_loop = NULL;
+
+ if (g_io_channel) {
+ puts ("closing socket.");
+
+ GError *err = NULL;
+ g_io_channel_shutdown (g_io_channel, FALSE, &err);
+ g_io_channel = NULL;
+ }
+
+ if (g_stdin_channel) {
+ puts ("unbinding stdin.");
+ g_io_channel_unref (g_stdin_channel);
+ g_stdin_channel = NULL;
+ }
+
+ puts ("finished.");
+ pgm_messages_shutdown();
+ return 0;
+}
+
+static void
+on_signal (
+ int signum,
+ gpointer user_data
+ )
+{
+ GMainLoop* loop = (GMainLoop*)user_data;
+ g_message ("on_signal (signum:%d user-data:%p)", signum, user_data);
+ g_main_loop_quit (loop);
+}
+
+static gboolean
+on_startup (
+ G_GNUC_UNUSED gpointer data
+ )
+{
+ int e;
+
+ puts ("startup.");
+
+/* find PGM protocol id */
+// TODO: fix valgrind errors
+ int ipproto_pgm = IPPROTO_PGM;
+#if HAVE_GETPROTOBYNAME_R
+ char b[1024];
+ struct protoent protobuf, *proto;
+ e = getprotobyname_r("pgm", &protobuf, b, sizeof(b), &proto);
+ if (e != -1 && proto != NULL) {
+ if (proto->p_proto != ipproto_pgm) {
+ printf("Setting PGM protocol number to %i from /etc/protocols.\n");
+ ipproto_pgm = proto->p_proto;
+ }
+ }
+#else
+ struct protoent *proto = getprotobyname("pgm");
+ if (proto != NULL) {
+ if (proto->p_proto != ipproto_pgm) {
+ printf("Setting PGM protocol number to %i from /etc/protocols.\n", proto
+->p_proto);
+ ipproto_pgm = proto->p_proto;
+ }
+ }
+#endif
+
+/* open socket for snooping */
+ puts ("opening raw socket.");
+ int sock = socket(PF_INET, SOCK_RAW, ipproto_pgm);
+ if (sock < 0) {
+ int _e = errno;
+ perror("on_startup() failed");
+
+ if (_e == EPERM && 0 != getuid()) {
+ puts ("PGM protocol requires this program to run as superuser.");
+ }
+ g_main_loop_quit(g_loop);
+ return FALSE;
+ }
+
+/* drop out of setuid 0 */
+ if (0 == getuid()) {
+ puts ("dropping superuser privileges.");
+ setuid((gid_t)65534);
+ setgid((uid_t)65534);
+ }
+
+ char _t = 1;
+ e = setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t));
+ if (e < 0) {
+ perror("on_startup() failed");
+ close(sock);
+ g_main_loop_quit(g_loop);
+ return FALSE;
+ }
+
+/* buffers */
+ int buffer_size = 0;
+ socklen_t len = 0;
+ e = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buffer_size, &len);
+ if (e == 0) {
+ printf ("receive buffer set at %i bytes.\n", buffer_size);
+ }
+ e = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buffer_size, &len);
+ if (e == 0) {
+ printf ("send buffer set at %i bytes.\n", buffer_size);
+ }
+
+/* bind */
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ e = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
+ if (e < 0) {
+ perror("on_startup() failed");
+ close(sock);
+ g_main_loop_quit(g_loop);
+ return FALSE;
+ }
+
+/* multicast */
+ struct ip_mreq mreq;
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ printf ("listening on interface %s.\n", inet_ntoa(mreq.imr_interface));
+ mreq.imr_multiaddr.s_addr = inet_addr(g_network);
+ printf ("subscription on multicast address %s.\n", inet_ntoa(mreq.imr_multiaddr));
+ e = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+ if (e < 0) {
+ perror("on_startup() failed");
+ close(sock);
+ g_main_loop_quit(g_loop);
+ return FALSE;
+ }
+
+/* multicast loopback */
+/* multicast ttl */
+
+/* add socket to event manager */
+ g_io_channel = g_io_channel_unix_new (sock);
+ printf ("socket opened with encoding %s.\n", g_io_channel_get_encoding(g_io_channel));
+
+ /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL);
+ /* guint event = */ g_io_add_watch (g_io_channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, on_io_error, NULL);
+
+/* add stdin to event manager */
+ g_stdin_channel = g_io_channel_unix_new (fileno(stdin));
+ printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel));
+
+ g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL);
+
+/* period timer to indicate some form of life */
+// TODO: Gnome 2.14: replace with g_timeout_add_seconds()
+ g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL);
+
+ puts ("READY");
+ fflush (stdout);
+ return FALSE;
+}
+
+static gboolean
+on_mark (
+ G_GNUC_UNUSED gpointer data
+ )
+{
+ g_message ("-- MARK --");
+ return TRUE;
+}
+
+static gboolean
+on_io_data (
+ GIOChannel* source,
+ G_GNUC_UNUSED GIOCondition condition,
+ G_GNUC_UNUSED gpointer data
+ )
+{
+ char buffer[4096];
+ int fd = g_io_channel_unix_get_fd(source);
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ int len = recvfrom(fd, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len);
+
+ if (g_filter.s_addr && g_filter.s_addr != addr.sin_addr.s_addr) {
+ return TRUE;
+ }
+
+ printf ("%i bytes received from %s.\n", len, inet_ntoa(addr.sin_addr));
+
+ monitor_packet (buffer, len);
+ fflush (stdout);
+
+ return TRUE;
+}
+
+static gboolean
+on_io_error (
+ GIOChannel* source,
+ G_GNUC_UNUSED GIOCondition condition,
+ G_GNUC_UNUSED gpointer data
+ )
+{
+ puts ("on_error.");
+
+ GError *err;
+ g_io_channel_shutdown (source, FALSE, &err);
+
+/* remove event */
+ return FALSE;
+}
+
+/* process input commands from stdin/fd
+ */
+
+static gboolean
+on_stdin_data (
+ GIOChannel* source,
+ G_GNUC_UNUSED GIOCondition condition,
+ G_GNUC_UNUSED gpointer data
+ )
+{
+ gchar* str = NULL;
+ gsize len = 0;
+ gsize term = 0;
+ GError* err = NULL;
+
+ g_io_channel_read_line (source, &str, &len, &term, &err);
+ if (len > 0) {
+ if (term) str[term] = 0;
+
+ if (strcmp(str, "quit") == 0) {
+ g_main_loop_quit(g_loop);
+ } else if (strncmp(str, "filter ", strlen("filter ")) == 0) {
+ unsigned a, b, c, d;
+ int retval = sscanf(str, "filter %u.%u.%u.%u", &a, &b, &c, &d);
+ if (retval == 4) {
+ g_filter.s_addr = (d << 24) | (c << 16) | (b << 8) | a;
+ puts ("READY");
+ } else {
+ printf ("invalid syntax for filter command.");
+ }
+ } else {
+ printf ("unknown command: %s\n", str);
+ }
+ }
+
+ fflush (stdout);
+ g_free (str);
+ return TRUE;
+}
+
+/* eof */