---
# System prepended metadata

title: signal watcher

---

# signal watcher

## Proof of concept

[Here's the snippet](http://gitlab.corp.kbact.org/-/snippets/29)

## Makefile

```shell=
#name of this module
ACT_EXE = ws-ports-status-alerter

# act libs needed by this module
DEP_ACT_LIBS = network

# dbus interfaces needed by this module
DEP_ACT_DBUS = network

ACT_SRCS := $(wildcard src/*.c)
ACT_HEADS := $(wildcard src/*.h)
ACT_OBJ = $(ACT_SRCS:.c=.o)

ACT_TOPDIR = ..
ACT_INCDIR = $(ACT_TOPDIR)/include
ACT_BINDIR = $(ACT_TOPDIR)/.bin

CFLAGS =
LDLIBS = -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed

all: $(ACT_EXE)

$(ACT_OBJ): $(ACT_HEADS)

$(ACT_EXE): $(ACT_OBJ)
	$(CC) $(ACT_OBJ) -g $(LDFLAGS) -o $@

install: $(ACT_EXE)
	mkdir -p $(ACT_BINDIR)
	install -m 0755 $(ACT_EXE) $(ACT_BINDIR)

.PHONY: all clean install

clean:
	rm -f $(ACT_OBJ) $(ACT_EXE)
	$(MAKE) -C test clean

```

## ws-ports-status-alerter.c

```c=
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <glib-2.0/glib.h>
#include <dbus_network.h>


OrgActNetwork *proxyNetwork;
GIOChannel *server_channel
int watchID;
GSList* client_sockets = NULL;

int writeall(int fd, char const* buf, size_t len) {
    while (len > 0) {
        int r = write(fd, buf, len);
        if (r < 0) {
            switch (errno) {
            case EINTR:
                continue;
            default:
                fprintf(stderr, "Failed writing data: %s\n", strerror(errno));
                return -1;
            }
        }
        len -= r;
        buf += r;
    }
    return 0;
}


void cb_signal_iface_change(gpointer dummy, char* content)
{
  char **args = g_strsplit(content, ";", -1);

  if (g_strv_length(args) >= 2)
    {
      gboolean state = strcmp(args[1], "up") == 0;
      char *portName = args[0];
      
      char *stringa_da_mandare = g_strdup_print("%s;%s", portName, state?"UP":"DOWN");

      for (GSList* iter = client_sockets; iter; iter = iter->next)
      {
          int sock = GPOINTER_TO_INT(iter->data);
          writeall(sock, stringa_da_mandare, strlen(stringa_da_mandare));
      }
      
      g_free(stringa_da_mandare);
    }

  g_strfreev(args);
}



static void initClientCB(GObject *source_object, GAsyncResult *result, gpointer user_data)
{
  GError *error = NULL;

  proxyNetwork = org_act_network_proxy_new_finish(result, &error);

  if (error != NULL)
    {
      act_messFatal("ERROR opening network proxy: %s", error->message);
      g_error_free(error);
      
      // quit application
      exit(-1);
    }
  else
  g_signal_connect(proxyNetwork, ACT_NETWORK_SIGNAL_INTERFACE_STATE_CHANGE, G_CALLBACK(cb_signal_iface_change), NULL);
}

static gboolean acceptFromSocket(GIOChannel *source, GIOCondition condition, gpointer data)
{
  int server_sock = g_io_channel_unix_get_fd(source);

  int client_sock = accept(server_sock, NULL, NULL);

  char buf[256] = {0};
  strcpy(buf, "éç°§§§§§ùùùùAAAAAFINE");
  if (writeall(sock, buf, strlen(buf)) < 0)
    {
      g_print("OMMIODIO ERRORE...\n");
    }

  client_sockets = g_slist_prepend(client_sockets, GINT_TO_POINTER(client_sock));

  // close(client_sock);

  return TRUE;
}


static GIOChannel * initialize_channel(int sock)
{
  GIOChannel *iochan = g_io_channel_unix_new(sock);

  GError *error = NULL;
  g_io_channel_set_encoding(iochan, NULL, &error);

  if (error != NULL)
    {
      act_messTraceLog("Error setting encoding for %s: %s", _U(if_name), error->message);
      g_error_free(error);
    }
    
  watchID = g_io_add_watch(info->channel, G_IO_IN, (GIOFunc) acceptFromSocket, NULL);

  return iochan;
}

int main()
{
  // init
  GMainLoop *mainloop = g_main_loop_new(NULL, FALSE);
//#define DBUS_MODE G_BUS_TYPE_SYSTEM
//#define ACT_INTROSPECT_PATH_NETWORK "/org/act/network"
//#define ACT_INTROSPECT_NAME_NETWORK "org.act.network"
  org_act_network_proxy_new_for_bus(DBUS_MODE, G_DBUS_PROXY_FLAGS_NONE,
                                    ACT_INTROSPECT_NAME_NETWORK,
                                    ACT_INTROSPECT_PATH_NETWORK, NULL,
                                    (GAsyncReadyCallback) initClientCB, NULL);
  
  server_channel = initialize_channel(0);

  // enter main loop
  g_main_loop_run(mainloop);
  
  // clean up and exit
  g_main_loop_unref(mainloop);
  return 0;
}

```

## lighttpd.ws-ports-status-alerter.conf

See [here](https://redmine.lighttpd.net/boards/2/topics/8801)

```javascript=
server.port = 9191

server.document-root        = "/www/pages/"

server.modules              = ( "mod_wstunnel" )

wstunnel.ping-interval = 30
wstunnel.server = (
  "" => (
    "websocket" => (
      "socket" => "/tmp/ws-ports-status-alerter.socket",
      "bin-path" => "/var/usr/bin/ws-ports-status-alerter", # lighttpd itself daemonizes the c program
      "max-procs" => 1,
    )
  )
)

```