+// place the event into the queue to be handled (by the main thread)
+// and wake the event handler if necessary
+static void queue_event(CattaInterfaceMonitor *m, ChangeEvent *ev)
+{
+ char c = 'X';
+
+ if(!ev)
+ return;
+
+ if(!pthread_mutex_lock(&m->osdep.mutex)) {
+ // queue the event
+ // XXX event ordering!!
+ CATTA_LLIST_PREPEND(ChangeEvent, event, m->osdep.events, ev);
+
+ // wake the handler
+ writepipe(m->osdep.pipefd[1], &c, sizeof(c));
+
+ pthread_mutex_unlock(&m->osdep.mutex);
+ } else {
+ catta_log_debug(__FILE__": queue_event: could not lock mutex");
+ catta_free(ev);
+ }
+}
+
+// copy the given data row into an appropriate change event struct
+static ChangeEvent *new_event(ChangeEventType type, MIB_NOTIFICATION_TYPE ntype, void *row, size_t n)
+{
+ ChangeEvent *ev;
+
+ if(!row)
+ return NULL;
+
+ if(!(ev = catta_new(ChangeEvent, 1)))
+ return NULL;
+
+ ev->type = type;
+ ev->notification_type = ntype;
+ memcpy(&ev->data, row, n);
+
+ return ev;
+}
+
+static void WINAPI icn_callback(void *m, MIB_IPINTERFACE_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ queue_event(m, new_event(INTERFACE_CHANGE_EVENT, type, row, sizeof(*row)));
+}
+
+static void WINAPI acn_callback(void *m, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ queue_event(m, new_event(ADDRESS_CHANGE_EVENT, type, row, sizeof(*row)));
+}
+
+static void handle_iface_event(CattaInterfaceMonitor *m, MIB_IPINTERFACE_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ catta_log_debug("interface change event on iface %u for address family %u",
+ (unsigned int)row->InterfaceIndex, (unsigned int)row->Family);
+
+ switch(type) {
+ case MibParameterNotification:
+ catta_log_debug(" notification type: ParameterNotification");
+ break;
+ case MibAddInstance:
+ catta_log_debug(" notification type: AddInstance");
+ break;
+ case MibDeleteInstance:
+ catta_log_debug(" notification type: DeleteInstance");
+ break;
+ default:
+ catta_log_debug("unexpected type (%d) of interface change notification received", type);
+ }
+}
+
+static void handle_addr_event(CattaInterfaceMonitor *m, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE type)
+{
+ catta_log_debug("address change event on iface %u for address family %u",
+ (unsigned int)row->InterfaceIndex,
+ (unsigned int)row->Address.si_family);
+
+ switch(type) {
+ case MibParameterNotification:
+ catta_log_debug(" notification type: ParameterNotification");
+ break;
+ case MibAddInstance:
+ catta_log_debug(" notification type: AddInstance");
+ break;
+ case MibDeleteInstance:
+ catta_log_debug(" notification type: DeleteInstance");
+ break;
+ default:
+ catta_log_debug("unexpected type (%d) of address change notification received", type);
+ }
+}
+
+static void handle_events(CattaInterfaceMonitor *m)
+{
+ char buf[16];
+ ChangeEvent *ev;
+
+ if(!pthread_mutex_lock(&m->osdep.mutex)) {
+ // clear the pipe
+ while(readpipe(m->osdep.pipefd[0], buf, sizeof(buf)) == sizeof(buf)) {}
+
+ while((ev = m->osdep.events) != NULL) {
+ CATTA_LLIST_REMOVE(ChangeEvent, event, m->osdep.events, ev);
+
+ // dispatch to the appropriate handler
+ switch(ev->type) {
+ case INTERFACE_CHANGE_EVENT:
+ handle_iface_event(m, &ev->data.iface, ev->notification_type);
+ break;
+ case ADDRESS_CHANGE_EVENT:
+ handle_addr_event(m, &ev->data.addr, ev->notification_type);
+ break;
+ default:
+ catta_log_debug("unhandled change event type in handle_events");
+ }
+
+ catta_free(ev);
+ }
+
+ pthread_mutex_unlock(&m->osdep.mutex);
+ }
+}
+
+static void pipe_callback(CattaWatch *w, int fd, CattaWatchEvent event, void *m)
+{
+ // silence "unused parameter" warnings
+ (void)w;
+ (void)fd;
+ (void)event;
+
+ handle_events(m);
+}
+
+