]> git.meshlink.io Git - catta/blob - src/iface-windows.c
e3ca771b212c02dc8af671b72c48fa14d2774558
[catta] / src / iface-windows.c
1 /***
2   This file is part of catta.
3
4   catta is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2.1 of the
7   License, or (at your option) any later version.
8
9   catta is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12   Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with catta; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA.
18 ***/
19
20 #include "iface-windows.h"
21 #include "iface.h"
22
23 #include <catta/malloc.h>
24 #include <catta/log.h>
25 #include <iphlpapi.h>
26 #include "hashmap.h"
27 #include "util.h"   // catta_format_mac_address
28
29
30 // for the luid-to-idx hashmap
31 static unsigned luid_hash(const void *data)
32 {
33     return ((NET_LUID *)data)->Info.NetLuidIndex;
34 }
35 static int luid_equal(const void *a, const void *b)
36 {
37     return (((NET_LUID *)a)->Value == ((NET_LUID *)b)->Value);
38 }
39
40 static CattaIfIndex find_ifindex(CattaInterfaceMonitor *m, NET_LUID luid)
41 {
42     CattaIfIndex *pi = NULL;
43     NET_LUID *key = NULL;
44
45     if((pi = catta_hashmap_lookup(m->osdep.idxmap, &luid)) == NULL) {
46         // allocate memory for the hashmap key and value
47         key = catta_malloc(sizeof(luid));
48         pi = catta_malloc(sizeof(CattaIfIndex));
49         if(!key || !pi)
50             goto fail;
51
52         *key = luid;
53             
54         // find an index for this luid
55         *pi = m->osdep.nidx;
56         if(*pi < 0)  // overflow
57             goto fail;
58
59         // register the index
60         if(catta_hashmap_replace(m->osdep.idxmap, key, pi) < 0)
61             goto fail;
62         m->osdep.nidx++;
63     }
64
65     return *pi;
66
67 fail:
68     catta_free(key);
69     catta_free(pi);
70     return -1;
71 }
72
73 // integrate the information from an IP_ADAPTER_ADDRESSES structure
74 // as returned by GetAdaptersAddresses into the CattaInterfaceMonitor
75 static void ip_adapter_address(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
76 {
77     CattaIfIndex idx;
78     CattaHwInterface *hw;
79
80     // look up the interface index by LUID
81     if((idx = find_ifindex(m, p->Luid)) < 0) {
82         catta_log_error("could not allocate index ip_adapter_address");
83         return;
84     }
85
86     // find the CattaHwInterface by index or allocate a new one
87     if((hw = catta_interface_monitor_get_hw_interface(m, idx)) == NULL) {
88         if((hw = catta_hw_interface_new(m, idx)) == NULL) {
89             catta_log_error("catta_hw_interface_new failed in ip_adapter_address");
90             return;
91         }
92     }
93
94     // fill the CattaHwInterface struct with data
95     hw->flags_ok =
96         (p->OperStatus & IfOperStatusUp) &&
97         !(p->IfType & IF_TYPE_SOFTWARE_LOOPBACK) &&
98         !(p->Flags & IP_ADAPTER_NO_MULTICAST) &&
99         (m->server->config.allow_point_to_point || !(p->IfType & IF_TYPE_PPP));
100             // XXX what about IF_TYPE_TUNNEL?
101
102     catta_free(hw->name);
103     hw->name = catta_strdup(p->AdapterName);
104
105     hw->mtu = p->Mtu;
106
107     hw->mac_address_size = p->PhysicalAddressLength;
108     if (hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
109       hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
110     memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
111
112     // XXX process addresses
113
114     // XXX debugging, remove
115    { 
116      char mac[256]; 
117      catta_log_debug("======\n name: %s\n index:%d\n mtu:%d\n mac:%s\n flags_ok:%d\n======",  
118                     hw->name, hw->index,  
119                     hw->mtu,  
120                     catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size), 
121                     hw->flags_ok); 
122    } 
123 }
124
125
126 int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m)
127 {
128     m->osdep.nidx = 0;
129     m->osdep.idxmap = catta_hashmap_new(luid_hash, luid_equal, catta_free, catta_free);
130     if(m->osdep.idxmap == NULL) {
131         catta_log_error("out of memory in catta_interface_monitor_init_osdep");
132         return -1;
133     }
134
135     // XXX register callbacks to get notified of interface/address changes
136
137     return 0;
138 }
139
140 void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m)
141 {
142     catta_hashmap_free(m->osdep.idxmap);
143 }
144
145 void catta_interface_monitor_sync(CattaInterfaceMonitor *m)
146 {
147     IP_ADAPTER_ADDRESSES *buf = NULL;
148     IP_ADAPTER_ADDRESSES *p;
149     ULONG bufsize = 15000;
150     ULONG r;
151
152     // allocate a buffer and call GetAdaptersAddresses
153     // retry with the correct size if the buffer was too small
154     do {
155         catta_free(buf);    // no-op on first iteration
156         if((buf = catta_malloc(bufsize)) == NULL) {
157             catta_log_error("malloc failed in catta_interface_monitor_sync");
158             return;
159         }
160
161         r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, buf, &bufsize);
162     } while(r == ERROR_BUFFER_OVERFLOW);
163
164     if(r != NO_ERROR) {
165         catta_log_error("GetAdaptersAddresses failed: %u", (unsigned int)r);
166         return;
167     }
168
169     // XXX remove interfaces for adapters that are no longer in the list
170
171     // create 'CattaInterface's for every adapter
172     for(p=buf; p; p=p->Next)
173         ip_adapter_address(m, p);
174
175     catta_free(buf);
176
177     m->list_complete = 1;
178     catta_interface_monitor_check_relevant(m);
179     catta_interface_monitor_update_rrs(m, 0);
180     catta_log_info("Network interface enumeration completed.");
181 }