aboutsummaryrefslogtreecommitdiffstats
path: root/netlink-notify.c
diff options
context:
space:
mode:
authorGravatar Christian Hesse <mail@eworm.de>2013-04-15 22:36:55 +0200
committerGravatar Christian Hesse <mail@eworm.de>2013-04-15 22:36:55 +0200
commitee6296abb65f348e17464145b12d388dd970deee (patch)
tree522719c55ae54921163bf355070c15c892e5c820 /netlink-notify.c
parent1d9e6a40051e63662dc21d4d402e7d09178ea393 (diff)
downloadnetlink-notify-ee6296abb65f348e17464145b12d388dd970deee.tar.gz
netlink-notify-ee6296abb65f348e17464145b12d388dd970deee.tar.zst
initial commit0.3.0
Diffstat (limited to 'netlink-notify.c')
-rw-r--r--netlink-notify.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/netlink-notify.c b/netlink-notify.c
new file mode 100644
index 0000000..9679a45
--- /dev/null
+++ b/netlink-notify.c
@@ -0,0 +1,171 @@
+/*
+ * (C) 2011-2013 by Christian Hesse <mail@eworm.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libnotify/notify.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/if.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
+#define PROGNAME "netlink-notify"
+
+#define NOTIFICATION_TIMEOUT 10000
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#define ICON_NETWORK_ONLINE "network-transmit-receive"
+#define ICON_NETWORK_OFFLINE "network-error"
+
+#define TEXT_TOPIC "Netlink Notification"
+#define TEXT_NOTIFICATION "Interface <b>%s</b> is <b>%s</b>."
+#define TEXT_NOTIFICATION_DEBUG "%s: Interface %s (index %d) is %s.\n"
+
+// we need these to be global...
+unsigned int netlinksize = 1; // never use 0 and avoid overwriting the main pointer...
+size_t * notificationref;
+char * program = NULL;
+
+static int data_attr_cb(const struct nlattr * attr, void * data) {
+ const struct nlattr ** tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case IFLA_MTU:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ fprintf(stderr, "%s: Invalid netlink attribute.\n", program);
+ return MNL_CB_ERROR;
+ }
+ break;
+ case IFLA_IFNAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
+ fprintf(stderr, "%s: Invalid netlink attribute.\n", program);
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int data_cb(const struct nlmsghdr * nlh, void * data) {
+ struct nlattr * tb[IFLA_MAX + 1] = {};
+ struct ifinfomsg * ifm = mnl_nlmsg_get_payload(nlh);
+
+ char * notifystr = NULL;
+ const char * interface = NULL;
+ NotifyNotification * notification = NULL;
+ unsigned int errcount = 0;
+
+ gboolean res = FALSE;
+ GError * error = NULL;
+
+ mnl_attr_parse(nlh, sizeof(* ifm), data_attr_cb, tb);
+
+ interface = mnl_attr_get_str(tb[IFLA_IFNAME]);
+ notifystr = malloc(strlen(interface) + strlen(TEXT_NOTIFICATION) + 1); // 2* %s is enough for "down", but we need an additional byte for \n
+ sprintf(notifystr, TEXT_NOTIFICATION, interface, (ifm->ifi_flags & IFF_RUNNING ? "up" : "down"));
+#if DEBUG
+ printf(TEXT_NOTIFICATION_DEBUG, program, interface, ifm->ifi_index, (ifm->ifi_flags & IFF_RUNNING ? "up" : "down"));
+#endif
+
+ if (netlinksize < ifm->ifi_index) {
+ notificationref = realloc(notificationref, (ifm->ifi_index + 1) * sizeof(size_t));
+ while(netlinksize < ifm->ifi_index)
+ notificationref[++netlinksize] = 0;
+ }
+
+ if (notificationref[ifm->ifi_index] == 0) {
+ notification = notify_notification_new(TEXT_TOPIC, notifystr, (ifm->ifi_flags & IFF_RUNNING ? ICON_NETWORK_ONLINE : ICON_NETWORK_OFFLINE));
+ notificationref[ifm->ifi_index] = (size_t)notification;
+ } else {
+ notification = (NotifyNotification *)notificationref[ifm->ifi_index];
+ notify_notification_update(notification, TEXT_TOPIC, notifystr, (ifm->ifi_flags & IFF_RUNNING ? ICON_NETWORK_ONLINE : ICON_NETWORK_OFFLINE));
+ }
+
+ notify_notification_set_timeout(notification, NOTIFICATION_TIMEOUT);
+ notify_notification_set_category(notification, PROGNAME);
+ notify_notification_set_urgency(notification, NOTIFY_URGENCY_NORMAL);
+
+ while(!notify_notification_show(notification, &error)) {
+ if (errcount > 1) {
+ fprintf(stderr, "%s: Looks like we can not reconnect to notification daemon... Exiting.\n", program);
+ exit(EXIT_FAILURE);
+ } else {
+ g_printerr("%s: Error \"%s\" while trying to show notification. Trying to reconnect.\n", program, error->message);
+ errcount++;
+
+ g_error_free(error);
+ error = NULL;
+
+ notify_uninit();
+
+ usleep(500 * 1000);
+
+ if(!notify_init(PROGNAME)) {
+ fprintf(stderr, "%s: Can't create notify.\n", program);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ errcount = 0;
+
+ free(notifystr);
+
+ return MNL_CB_OK;
+}
+
+int main(int argc, char ** argv) {
+ struct mnl_socket * nl;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret;
+
+ program = argv[0];
+
+ printf("%s: %s v%s (compiled: " __DATE__ ", " __TIME__ ")\n", argv[0], PROGNAME, VERSION);
+
+ if(!notify_init(PROGNAME)) {
+ fprintf(stderr, "%s: Can't create notify.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (!nl) {
+ fprintf(stderr, "%s: Can't create netlink socket.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (mnl_socket_bind(nl, RTMGRP_LINK, MNL_SOCKET_AUTOPID) < 0) {
+ fprintf(stderr, "%s: Can't bind netlink socket.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, 0, 0, data_cb, NULL);
+ if (ret <= 0)
+ break;
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ }
+ if (ret == -1) {
+ fprintf(stderr, "%s: An error occured reading from netlink socket.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ mnl_socket_close(nl);
+
+ return EXIT_SUCCESS;
+}