aboutsummaryrefslogtreecommitdiffstats
path: root/pingu_iface.c
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2011-07-07 14:31:32 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2011-07-07 14:34:26 +0200
commit69c10bc4bf9b1d98a9a0b5860d10cf5fc3b40aa9 (patch)
tree9d5a1cada739de106cca5ba64b7ad2969934a87d /pingu_iface.c
parent22c01818744c1fd386d5d943afe6fda0a51396ed (diff)
downloadpingu-69c10bc4bf9b1d98a9a0b5860d10cf5fc3b40aa9.tar.bz2
pingu-69c10bc4bf9b1d98a9a0b5860d10cf5fc3b40aa9.tar.xz
iface: add initial implementation
Diffstat (limited to 'pingu_iface.c')
-rw-r--r--pingu_iface.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/pingu_iface.c b/pingu_iface.c
new file mode 100644
index 0000000..6dca73c
--- /dev/null
+++ b/pingu_iface.c
@@ -0,0 +1,104 @@
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include <ev.h>
+
+#include "list.h"
+#include "log.h"
+#include "pingu_burst.h"
+#include "pingu_host.h"
+#include "pingu_iface.h"
+#include "pingu_ping.h"
+
+static struct list_head iface_list = LIST_INITIALIZER(iface_list);
+
+static void pingu_iface_socket_cb(struct ev_loop *loop, struct ev_io *w,
+ int revents)
+{
+ struct pingu_iface *iface = container_of(w, struct pingu_iface, socket_watcher);
+
+ if (revents & EV_READ)
+ pingu_ping_read_reply(loop, iface);
+}
+
+static int pingu_iface_init_socket(struct ev_loop *loop,
+ struct pingu_iface *iface)
+{
+ int r;
+ iface->fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (iface->fd < 0) {
+ log_perror("socket");
+ return -1;
+ }
+
+ ev_io_init(&iface->socket_watcher, pingu_iface_socket_cb, iface->fd, EV_READ);
+ ev_io_start(loop, &iface->socket_watcher);
+
+ if (iface->name[0] == '\0')
+ return 0;
+ r = setsockopt(iface->fd, SOL_SOCKET, SO_BINDTODEVICE, iface->name,
+ strlen(iface->name));
+ if (r < 0) {
+ log_perror(iface->name);
+ return -1;
+ }
+ return 0;
+}
+
+struct pingu_iface *pingu_iface_find(const char *name)
+{
+ struct pingu_iface *iface;
+ list_for_each_entry(iface, &iface_list, iface_list_entry) {
+ if (name == NULL) {
+ if (iface->name[0] == '\n')
+ return iface;
+ } else if (strncmp(name, iface->name, sizeof(iface->name)) == 0)
+ return iface;
+ }
+ return NULL;
+}
+
+struct pingu_iface *pingu_iface_find_or_create(struct ev_loop *loop, const char *name)
+{
+ struct pingu_iface *iface = pingu_iface_find(name);
+ if (iface != NULL)
+ return iface;
+
+ iface = calloc(1, sizeof(struct pingu_iface));
+ if (iface == NULL) {
+ log_perror("calloc(iface)");
+ return NULL;
+ }
+
+ if (name != NULL)
+ strlcpy(iface->name, name, sizeof(*iface->name));
+
+ if (pingu_iface_init_socket(loop, iface) == -1) {
+ free(iface);
+ return NULL;
+ }
+ list_init(&iface->ping_list);
+ list_add(&iface->iface_list_entry, &iface_list);
+ return iface;
+}
+
+int pingu_iface_init(struct ev_loop *loop, struct list_head *host_list)
+{
+ struct pingu_host *host;
+ struct pingu_iface *iface;
+ list_for_each_entry(host, host_list, host_list_entry) {
+ iface = pingu_iface_find_or_create(loop, host->interface);
+ if (iface == NULL)
+ return -1;
+ host->iface = iface;
+ }
+ return 0;
+}
+