From 3ce9eb0f85618ba22700927b4196a06a152a009c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 2 Mar 2009 12:49:09 +0100 Subject: [PATCH] iphlpapi: Reimplement GetIpForwardTable to avoid parsing the same information three times. --- dlls/iphlpapi/iphlpapi_main.c | 43 ++---- dlls/iphlpapi/ipstats.c | 245 +++++++++++++++------------------- 2 files changed, 117 insertions(+), 171 deletions(-) diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index ffc064a5ade..0c5f2096260 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -1251,48 +1251,31 @@ DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL */ DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder) { - DWORD ret; + DWORD ret; + PMIB_IPFORWARDTABLE table; - TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, - pdwSize, (DWORD)bOrder); - if (!pdwSize) - ret = ERROR_INVALID_PARAMETER; - else { - DWORD numRoutes = getNumRoutes(); - ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE); + TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder); - if (numRoutes > 1) - sizeNeeded += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW); - if (!pIpForwardTable || *pdwSize < sizeNeeded) { - *pdwSize = sizeNeeded; - ret = ERROR_INSUFFICIENT_BUFFER; - } - else { - PMIB_IPFORWARDTABLE table; + if (!pdwSize) return ERROR_INVALID_PARAMETER; - ret = getRouteTable(&table, GetProcessHeap(), 0); - if (!ret) { - sizeNeeded = sizeof(MIB_IPFORWARDTABLE); - if (table->dwNumEntries > 1) - sizeNeeded += (table->dwNumEntries - 1) * sizeof(MIB_IPFORWARDROW); - if (*pdwSize < sizeNeeded) { - *pdwSize = sizeNeeded; + ret = getRouteTable(&table, GetProcessHeap(), 0); + if (!ret) { + DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] ); + if (!pIpForwardTable || *pdwSize < size) { + *pdwSize = size; ret = ERROR_INSUFFICIENT_BUFFER; } else { - *pdwSize = sizeNeeded; - memcpy(pIpForwardTable, table, sizeNeeded); + *pdwSize = size; + memcpy(pIpForwardTable, table, size); if (bOrder) qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries, sizeof(MIB_IPFORWARDROW), IpForwardTableSorter); - ret = NO_ERROR; } HeapFree(GetProcessHeap(), 0, table); - } } - } - TRACE("returning %d\n", ret); - return ret; + TRACE("returning %d\n", ret); + return ret; } diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c index 852b3037580..9cfaa2190b7 100644 --- a/dlls/iphlpapi/ipstats.c +++ b/dlls/iphlpapi/ipstats.c @@ -1044,53 +1044,110 @@ DWORD getNumRoutes(void) #endif } -DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, - DWORD flags) +static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table, + DWORD *count, const MIB_IPFORWARDROW *row ) { - DWORD ret; + if (table->dwNumEntries >= *count) + { + MIB_IPFORWARDTABLE *new_table; + DWORD new_count = table->dwNumEntries * 2; - if (!ppIpForwardTable) - ret = ERROR_INVALID_PARAMETER; - else { - DWORD numRoutes = getNumRoutes(); - DWORD size = sizeof(MIB_IPFORWARDTABLE); - PMIB_IPFORWARDTABLE table; + if (!(new_table = HeapReAlloc( heap, flags, table, + FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] )))) + { + HeapFree( heap, 0, table ); + return NULL; + } + *count = new_count; + table = new_table; + } + memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) ); + return table; +} - if (numRoutes > 1) - size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW); - table = HeapAlloc(heap, flags, size); - if (table) { -#if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) +DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, DWORD flags) +{ + MIB_IPFORWARDTABLE *table; + MIB_IPFORWARDROW row; + DWORD ret = NO_ERROR, count = 16; + + if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER; + + if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] )))) + return ERROR_OUTOFMEMORY; + + table->dwNumEntries = 0; + +#ifdef __linux__ + { + FILE *fp; + + if ((fp = fopen("/proc/net/route", "r"))) + { + char buf[512], *ptr; + DWORD flags; + + /* skip header line */ + ptr = fgets(buf, sizeof(buf), fp); + while ((ptr = fgets(buf, sizeof(buf), fp))) + { + memset( &row, 0, sizeof(row) ); + + while (!isspace(*ptr)) ptr++; + *ptr++ = 0; + if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR) + continue; + + row.dwForwardDest = strtoul(ptr, &ptr, 16); + row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16); + flags = strtoul(ptr + 1, &ptr, 16); + + if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID; + else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; + else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT; + + strtoul(ptr + 1, &ptr, 16); /* refcount, skip */ + strtoul(ptr + 1, &ptr, 16); /* use, skip */ + row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16); + row.dwForwardMask = strtoul(ptr + 1, &ptr, 16); + /* FIXME: other protos might be appropriate, e.g. the default + * route is typically set with MIB_IPPROTO_NETMGMT instead */ + row.dwForwardProto = MIB_IPPROTO_LOCAL; + + if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) + break; + } + fclose(fp); + } + else ret = ERROR_NOT_SUPPORTED; + } +#elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) + { int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0}; size_t needed; - char *buf, *lim, *next, *addrPtr; + char *buf = NULL, *lim, *next, *addrPtr; struct rt_msghdr *rtm; if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) { ERR ("sysctl 1 failed!\n"); - HeapFree (GetProcessHeap (), 0, table); - return NO_ERROR; + ret = ERROR_NOT_SUPPORTED; + goto done; } buf = HeapAlloc (GetProcessHeap (), 0, needed); if (!buf) { - HeapFree (GetProcessHeap (), 0, table); - return ERROR_OUTOFMEMORY; + ret = ERROR_OUTOFMEMORY; + goto done; } if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { - ERR ("sysctl 2 failed!\n"); - HeapFree (GetProcessHeap (), 0, table); - HeapFree (GetProcessHeap (), 0, buf); - return NO_ERROR; + ret = ERROR_NOT_SUPPORTED; + goto done; } - *ppIpForwardTable = table; - table->dwNumEntries = 0; - lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { @@ -1111,15 +1168,11 @@ DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, (rtm->rtm_flags & RTF_MULTICAST)) continue; - memset (&table->table[table->dwNumEntries], 0, - sizeof (MIB_IPFORWARDROW)); - table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index; - table->table[table->dwNumEntries].dwForwardType = - MIB_IPROUTE_TYPE_INDIRECT; - table->table[table->dwNumEntries].dwForwardMetric1 = - rtm->rtm_rmx.rmx_hopcount; - table->table[table->dwNumEntries].dwForwardProto = - MIB_IPPROTO_LOCAL; + memset( &row, 0, sizeof(row) ); + row.dwForwardIfIndex = rtm->rtm_index; + row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; + row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount; + row.dwForwardProto = MIB_IPPROTO_LOCAL; addrPtr = (char *)(rtm + 1); @@ -1152,119 +1205,29 @@ DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, switch (i) { - case RTA_DST: - table->table[table->dwNumEntries].dwForwardDest = addr; - break; - - case RTA_GATEWAY: - table->table[table->dwNumEntries].dwForwardNextHop = addr; - break; - - case RTA_NETMASK: - table->table[table->dwNumEntries].dwForwardMask = addr; - break; - + case RTA_DST: row.dwForwardDest = addr; break; + case RTA_GATEWAY: row.dwForwardNextHop = addr; break; + case RTA_NETMASK: row.dwForwardMask = addr; break; default: WARN ("Unexpected address type 0x%x\n", i); } } - table->dwNumEntries++; + if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) + break; } - - HeapFree (GetProcessHeap (), 0, buf); - ret = NO_ERROR; -#else - FILE *fp; - - ret = NO_ERROR; - *ppIpForwardTable = table; - table->dwNumEntries = 0; - /* get from /proc/net/route, no error if can't */ - fp = fopen("/proc/net/route", "r"); - if (fp) { - char buf[512] = { 0 }, *ptr; - - /* skip header line */ - ptr = fgets(buf, sizeof(buf), fp); - while (ptr && table->dwNumEntries < numRoutes) { - memset(&table->table[table->dwNumEntries], 0, - sizeof(MIB_IPFORWARDROW)); - ptr = fgets(buf, sizeof(buf), fp); - if (ptr) { - DWORD index; - - while (!isspace(*ptr)) - ptr++; - *ptr = '\0'; - ptr++; - if (getInterfaceIndexByName(buf, &index) == NO_ERROR) { - char *endPtr; - - table->table[table->dwNumEntries].dwForwardIfIndex = index; - if (*ptr) { - table->table[table->dwNumEntries].dwForwardDest = - strtoul(ptr, &endPtr, 16); - ptr = endPtr; - } - if (ptr && *ptr) { - table->table[table->dwNumEntries].dwForwardNextHop = - strtoul(ptr, &endPtr, 16); - ptr = endPtr; - } - if (ptr && *ptr) { - DWORD flags = strtoul(ptr, &endPtr, 16); - - if (!(flags & RTF_UP)) - table->table[table->dwNumEntries].dwForwardType = - MIB_IPROUTE_TYPE_INVALID; - else if (flags & RTF_GATEWAY) - table->table[table->dwNumEntries].dwForwardType = - MIB_IPROUTE_TYPE_INDIRECT; - else - table->table[table->dwNumEntries].dwForwardType = - MIB_IPROUTE_TYPE_DIRECT; - ptr = endPtr; - } - if (ptr && *ptr) { - strtoul(ptr, &endPtr, 16); /* refcount, skip */ - ptr = endPtr; - } - if (ptr && *ptr) { - strtoul(ptr, &endPtr, 16); /* use, skip */ - ptr = endPtr; - } - if (ptr && *ptr) { - table->table[table->dwNumEntries].dwForwardMetric1 = - strtoul(ptr, &endPtr, 16); - ptr = endPtr; - } - if (ptr && *ptr) { - table->table[table->dwNumEntries].dwForwardMask = - strtoul(ptr, &endPtr, 16); - ptr = endPtr; - } - /* FIXME: other protos might be appropriate, e.g. the default - * route is typically set with MIB_IPPROTO_NETMGMT instead */ - table->table[table->dwNumEntries].dwForwardProto = - MIB_IPPROTO_LOCAL; - table->dwNumEntries++; - } - } - } - fclose(fp); - } - else - { - ERR ("unimplemented!\n"); - return ERROR_NOT_SUPPORTED; - } -#endif +done: + HeapFree( GetProcessHeap (), 0, buf ); } - else - ret = ERROR_OUTOFMEMORY; - } - return ret; +#else + FIXME( "not implemented\n" ); + ret = ERROR_NOT_SUPPORTED; +#endif + + if (!table) return ERROR_OUTOFMEMORY; + if (!ret) *ppIpForwardTable = table; + else HeapFree( heap, flags, table ); + return ret; } DWORD getNumArpEntries(void)