]> git.meshlink.io Git - catta/blobdiff - src/iface-windows.c
remove debug output on initial interface enumeration
[catta] / src / iface-windows.c
index 09ab8209453602ad207aab343cabcb3c0edb5653..37dc702559673ba4695a397caf6ce5719a772dce 100644 (file)
@@ -46,6 +46,17 @@ struct ChangeEvent {
 };
 
 
+// helper: determine the global_scope flag for an address
+static void set_global_scope_flag(CattaInterfaceAddress *ifaddr, const CattaAddress *addr)
+{
+    if(addr->proto == CATTA_PROTO_INET6) {
+        const struct in6_addr *ia = (struct in6_addr *)addr->data.ipv6.address;
+        ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL(ia) || IN6_IS_ADDR_MULTICAST(ia));
+    } else {
+        ifaddr->global_scope = 1;
+    }
+}
+
 // integrate the information from an IP_ADAPTER_UNICAST_ADDRESS structure for
 // given CattaHwInterface into the CattaInterfaceMonitor
 static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
@@ -91,27 +102,7 @@ static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
         }
     }
 
-    // set global scope flag
-    // XXX should we use the IP_ADAPTER_ADDRESS_DNS_ELIGIBLE flag for this?
-    //     it looks like it gets set for IPv4 addresses that are not localhost
-    //     and for IPv6 addresses with global scope. not sure about multicast
-    //     addresses.
-    if(addr.proto == CATTA_PROTO_INET6)
-        ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr.data.data)
-                                 || IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr.data.data));
-    else
-        ifaddr->global_scope = 1;
-
-    // XXX debugging, remove
-    {
-        char s[CATTA_ADDRESS_STR_MAX];
-        catta_log_debug(" address: %s\n"
-                        "   global_scope: %d\n"
-                        "   flags: 0x%.4x",
-            catta_address_snprint(s, sizeof(s), &addr),
-            ifaddr->global_scope,
-            (unsigned int)a->Flags);
-    }
+    set_global_scope_flag(ifaddr, &addr);
 }
 
 // integrate the information from an IP_ADAPTER_ADDRESSES structure
@@ -151,6 +142,7 @@ static void ip_adapter(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
     }
 
     // fill the CattaHwInterface struct with data
+    // notice: this code is essentially duplicated in update_hw_interface()
     hw->flags_ok =
         (p->OperStatus == IfOperStatusUp) &&
         !(p->IfType == IF_TYPE_SOFTWARE_LOOPBACK) &&
@@ -170,36 +162,10 @@ static void ip_adapter(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
         hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
     memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
 
-    // XXX debugging, remove
-    {
-        char mac[256];
-        catta_log_debug(" name: %s\n"
-                        " index: %d\n"
-                        "   IfIndex: %u\n"
-                        "   Ipv6IfIndex: %u\n"
-                        " mtu: %d\n"
-                        " mac: %s\n"
-                        " flags_ok: %d\n"
-                        "   type: %u\n"
-                        "   status: %u\n"
-                        "   multicast: %d\n"
-                        "   flags: 0x%.4x",
-            hw->name, hw->index,
-            (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex,
-            hw->mtu,
-            catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
-            hw->flags_ok,
-            (unsigned int)p->IfType,
-            (unsigned int)p->OperStatus,
-            !(p->Flags & IP_ADAPTER_NO_MULTICAST),
-            (unsigned int)p->Flags);
-    }
-
     // process addresses
     // XXX remove addresses that are no longer in the list
     for(a=p->FirstUnicastAddress; a; a=a->Next)
         ip_adapter_unicast_address(m, hw, a);
-    catta_log_debug("=====");
 }
 
 
@@ -214,8 +180,7 @@ static void queue_event(CattaInterfaceMonitor *m, ChangeEvent *ev)
 
     if(!pthread_mutex_lock(&m->osdep.mutex)) {
         // queue the event
-        // XXX event ordering!!
-        CATTA_LLIST_PREPEND(ChangeEvent, event, m->osdep.events, ev);
+        CATTA_LLIST_APPEND(ChangeEvent, event, m->osdep.events, ev);
 
         // wake the handler
         writepipe(m->osdep.pipefd[1], &c, sizeof(c));
@@ -255,20 +220,139 @@ static void WINAPI acn_callback(void *m, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTI
     queue_event(m, new_event(ADDRESS_CHANGE_EVENT, type, row, sizeof(*row)));
 }
 
+static void update_hw_interface(CattaHwInterface *hw)
+{
+    MIB_IF_ROW2 row;
+    DWORD r;
+    size_t n;
+    int multicast;  // synthetic flag
+
+    row.InterfaceLuid.Value = 0;
+    row.InterfaceIndex = hw->index;
+    if((r = GetIfEntry2(&row)) != NO_ERROR) {
+        catta_log_error("GetIfEntry2 failed for iface %d (error %u)", hw->index, (unsigned int)r);
+        return;
+    }
+
+    // fill the CattaHwInterface struct with data
+    // notice: this code is essentially duplicated from ip_adapter()
+    // notice: not sure where to find the IP_ADAPTER_NO_MULTICAST flag from an
+    //         MIB_IF_ROW2 struct, so try to deduce it otherwise
+    //         cf. http://msdn.microsoft.com/en-us/windows/desktop/ff568739(v=vs.100).aspx
+    multicast = row.AccessType == NET_IF_ACCESS_BROADCAST ||
+                row.AccessType == NET_IF_ACCESS_POINT_TO_POINT;
+    hw->flags_ok =
+        (row.OperStatus == IfOperStatusUp) &&
+        !(row.Type == IF_TYPE_SOFTWARE_LOOPBACK) &&
+        multicast &&
+        (hw->monitor->server->config.allow_point_to_point || !(row.Type == IF_TYPE_PPP));
+            // XXX what about IF_TYPE_TUNNEL?
+
+    n = wcstombs(NULL, row.Alias, 0) + 1;
+    catta_free(hw->name);
+    hw->name = catta_new(char, n);
+    wcstombs(hw->name, row.Alias, n);
+
+    hw->mtu = row.Mtu;
+
+    hw->mac_address_size = row.PhysicalAddressLength;
+    if(hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
+        hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
+    memcpy(hw->mac_address, row.PhysicalAddress, hw->mac_address_size);
+
+    // XXX debugging, remove
+    {
+        char mac[256];
+        catta_log_debug(" name: %s\n"
+                        " mtu: %d\n"
+                        " mac: %s\n"
+                        " flags_ok: %d\n"
+                        "   type: %u\n"
+                        "   status: %u\n"
+                        "   multicast: %d\n"
+                        "   access type: %d",
+            hw->name,
+            hw->mtu,
+            catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
+            hw->flags_ok,
+            (unsigned int)row.Type,
+            (unsigned int)row.OperStatus,
+            multicast,
+            (int)row.AccessType);
+    }
+
+    catta_hw_interface_check_relevant(hw);
+    catta_hw_interface_update_rrs(hw, 0);
+}
+
 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);
+    CattaIfIndex idx = row->InterfaceIndex;
+    CattaProtocol proto = catta_af_to_proto(row->Family);
+    const char *protostr = catta_proto_to_string(proto);
+    CattaInterface *iface;
+    CattaHwInterface *hw;
+
+    // XXX debug, remove
+    {
+        const char *typestr = NULL;
+
+        switch(type) {
+            case MibParameterNotification:  typestr = "ParameterNotification"; break;
+            case MibAddInstance:            typestr = "AddInstance"; break;
+            case MibDeleteInstance:         typestr = "DeleteInstance"; break;
+            default:                        typestr = "Unknown";
+        }
+
+        catta_log_debug("interface %s on iface %d for %s", typestr, idx, protostr);
+    }
+
+    // see if we know this interface
+    iface = catta_interface_monitor_get_interface(m, idx, proto);
+    hw = iface ? iface->hardware : catta_interface_monitor_get_hw_interface(m, idx);
+
+    // print debug messages for some unexpected cases
+    if(type==MibParameterNotification && !iface)
+        catta_log_debug("ParameterNotification received for unknown interface %d (%s)", idx, protostr);
+    if(type==MibDeleteInstance && !iface)
+        catta_log_debug("DeleteInstance received for unknown interface %d (%s)", idx, protostr);
+    if(type==MibAddInstance && iface)
+        catta_log_debug("AddInstance received for existing interface %d (%s)", idx, protostr);
+    if(iface && !hw)
+        catta_log_debug("missing CattaHwInterface for interface %d (%s)", idx, protostr);
 
     switch(type) {
     case MibParameterNotification:
-        catta_log_debug(" notification type: ParameterNotification");
-        break;
     case MibAddInstance:
-        catta_log_debug(" notification type: AddInstance");
+        // create the physical interface if it is missing
+        if(!hw) {
+            if((hw = catta_hw_interface_new(m, idx)) == NULL) {
+                catta_log_error("catta_hw_interface_new failed in handle_iface_event");
+                return;
+            }
+        }
+
+        // create the protocol-specific interface if it is missing
+        if(!iface) {
+            if((iface = catta_interface_new(m, hw, proto)) == NULL) {
+                catta_log_error("catta_interface_new failed in handle_iface_event");
+                return;
+            }
+        }
+
+        assert(iface != NULL);
+        assert(hw != NULL);
+        assert(iface->hardware == hw);
+
+        update_hw_interface(hw);
         break;
     case MibDeleteInstance:
-        catta_log_debug(" notification type: DeleteInstance");
+        if(iface)
+            catta_interface_free(iface, 0);
+
+        // free the hardware interface when there are no more protocol-specific interfaces
+        if(hw && !hw->interfaces)
+            catta_hw_interface_free(hw, 0);
         break;
     default:
         catta_log_debug("unexpected type (%d) of interface change notification received", type);
@@ -277,23 +361,114 @@ static void handle_iface_event(CattaInterfaceMonitor *m, MIB_IPINTERFACE_ROW *ro
 
 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);
+    CattaIfIndex idx = row->InterfaceIndex;
+    CattaInterfaceAddress *ifaddr;
+    CattaInterface *iface;
+    CattaAddress addr;
+    const char *protostr;
+
+    // fill addr struct for address lookup
+    switch(row->Address.si_family) {
+    case AF_INET:
+        memcpy(addr.data.data, &row->Address.Ipv4.sin_addr, sizeof(struct in_addr));
+        break;
+    case AF_INET6:
+        memcpy(addr.data.data, &row->Address.Ipv6.sin6_addr, sizeof(struct in6_addr));
+        break;
+    default:
+        catta_log_debug("unexpected address family on interface %d: %u", idx, row->Address.si_family);
+        return;
+    }
+    addr.proto = catta_af_to_proto(row->Address.si_family);
+    protostr = catta_proto_to_string(addr.proto);
+
+    // XXX debug, remove
+    {
+        const char *typestr = NULL;
+        char buf[CATTA_ADDRESS_STR_MAX];
+
+        switch(type) {
+            case MibParameterNotification:  typestr = "ParameterNotification"; break;
+            case MibAddInstance:            typestr = "AddInstance"; break;
+            case MibDeleteInstance:         typestr = "DeleteInstance"; break;
+            default:                        typestr = "Unknown";
+        }
+
+        catta_log_debug("%s for %s address %s on iface %d",
+                        typestr, protostr,
+                        catta_address_snprint(buf, sizeof(buf), &addr),
+                        idx);
+    }
+
+    // see if we know this address/interface
+    iface = catta_interface_monitor_get_interface(m, idx, addr.proto);
+    ifaddr = iface ? catta_interface_monitor_get_address(m, iface, &addr) : NULL;
+
+    // print debug messages for some unexpected cases
+    if(type==MibParameterNotification && !ifaddr)
+        catta_log_debug("ParameterNotification received for unknown address on interface %d (%s)", idx, protostr);
+    if(type==MibDeleteInstance && !ifaddr)
+        catta_log_debug("DeleteInstance received for unknown address on interface %d (%s)", idx, protostr);
+    if(type==MibAddInstance && ifaddr)
+        catta_log_debug("AddInstance received for existing address on interface %d (%s)", idx, protostr);
+    if(ifaddr && !iface)
+        catta_log_debug("missing CattaInterface for address on interface %d (%s)", idx, protostr);
 
     switch(type) {
     case MibParameterNotification:
-        catta_log_debug(" notification type: ParameterNotification");
-        break;
     case MibAddInstance:
-        catta_log_debug(" notification type: AddInstance");
+        // fetch the full event data
+        if(GetUnicastIpAddressEntry(row) != NO_ERROR) {
+            catta_log_error("GetUnicastIpAddressEntry failed in handle_addr_event");
+            return;
+        }
+
+        // skip addresses that are not suitable as source addresses
+        if(row->SkipAsSource)
+            return;
+
+        // create the interface if it is missing
+        if(!iface) {
+            CattaHwInterface *hw;
+
+            if((hw = catta_interface_monitor_get_hw_interface(m, idx)) == NULL) {
+                catta_log_error("interface %d not found in handle_addr_event", idx);
+                return;
+            }
+
+            if((iface = catta_interface_new(m, hw, addr.proto)) == NULL) {
+                catta_log_error("catta_interface_new failed in handle_addr_event");
+                return;
+            }
+        }
+        assert(iface != NULL);
+
+        // create the interface-associated address if it is missing
+        if(!ifaddr) {
+            unsigned prefixlen = row->OnLinkPrefixLength;
+
+            if((ifaddr = catta_interface_address_new(m, iface, &addr, prefixlen)) == NULL) {
+                catta_log_error("catta_interface_address_new failed in handle_addr_event");
+                return;
+            }
+        }
+        assert(ifaddr != NULL);
+
+        set_global_scope_flag(ifaddr, &addr);
+        catta_log_debug("   global_scope: %d", ifaddr->global_scope); // XXX debugging, remove
         break;
     case MibDeleteInstance:
-        catta_log_debug(" notification type: DeleteInstance");
+        if(ifaddr)
+            catta_interface_address_free(ifaddr);
         break;
     default:
         catta_log_debug("unexpected type (%d) of address change notification received", type);
     }
+
+    if(iface) {
+        catta_interface_check_relevant(iface);
+        catta_interface_update_rrs(iface, 0);
+    }
 }
 
 static void handle_events(CattaInterfaceMonitor *m)