iphlpapi: Reimplement GetIpForwardTable to avoid parsing the same information three times.

This commit is contained in:
Alexandre Julliard 2009-03-02 12:49:09 +01:00
parent add9e025c2
commit 3ce9eb0f85
2 changed files with 117 additions and 171 deletions

View File

@ -1251,48 +1251,31 @@ DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL
*/ */
DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder) 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, TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
pdwSize, (DWORD)bOrder);
if (!pdwSize)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numRoutes = getNumRoutes();
ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE);
if (numRoutes > 1) if (!pdwSize) return ERROR_INVALID_PARAMETER;
sizeNeeded += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
if (!pIpForwardTable || *pdwSize < sizeNeeded) {
*pdwSize = sizeNeeded;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
PMIB_IPFORWARDTABLE table;
ret = getRouteTable(&table, GetProcessHeap(), 0); ret = getRouteTable(&table, GetProcessHeap(), 0);
if (!ret) { if (!ret) {
sizeNeeded = sizeof(MIB_IPFORWARDTABLE); DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
if (table->dwNumEntries > 1) if (!pIpForwardTable || *pdwSize < size) {
sizeNeeded += (table->dwNumEntries - 1) * sizeof(MIB_IPFORWARDROW); *pdwSize = size;
if (*pdwSize < sizeNeeded) {
*pdwSize = sizeNeeded;
ret = ERROR_INSUFFICIENT_BUFFER; ret = ERROR_INSUFFICIENT_BUFFER;
} }
else { else {
*pdwSize = sizeNeeded; *pdwSize = size;
memcpy(pIpForwardTable, table, sizeNeeded); memcpy(pIpForwardTable, table, size);
if (bOrder) if (bOrder)
qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries, qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
sizeof(MIB_IPFORWARDROW), IpForwardTableSorter); sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
ret = NO_ERROR;
} }
HeapFree(GetProcessHeap(), 0, table); HeapFree(GetProcessHeap(), 0, table);
}
} }
} TRACE("returning %d\n", ret);
TRACE("returning %d\n", ret); return ret;
return ret;
} }

View File

@ -1044,53 +1044,110 @@ DWORD getNumRoutes(void)
#endif #endif
} }
DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
DWORD flags) DWORD *count, const MIB_IPFORWARDROW *row )
{ {
DWORD ret; if (table->dwNumEntries >= *count)
{
MIB_IPFORWARDTABLE *new_table;
DWORD new_count = table->dwNumEntries * 2;
if (!ppIpForwardTable) if (!(new_table = HeapReAlloc( heap, flags, table,
ret = ERROR_INVALID_PARAMETER; FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
else { {
DWORD numRoutes = getNumRoutes(); HeapFree( heap, 0, table );
DWORD size = sizeof(MIB_IPFORWARDTABLE); return NULL;
PMIB_IPFORWARDTABLE table; }
*count = new_count;
table = new_table;
}
memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
return table;
}
if (numRoutes > 1) DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, DWORD flags)
size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW); {
table = HeapAlloc(heap, flags, size); MIB_IPFORWARDTABLE *table;
if (table) { MIB_IPFORWARDROW row;
#if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) 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}; int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
size_t needed; size_t needed;
char *buf, *lim, *next, *addrPtr; char *buf = NULL, *lim, *next, *addrPtr;
struct rt_msghdr *rtm; struct rt_msghdr *rtm;
if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
{ {
ERR ("sysctl 1 failed!\n"); ERR ("sysctl 1 failed!\n");
HeapFree (GetProcessHeap (), 0, table); ret = ERROR_NOT_SUPPORTED;
return NO_ERROR; goto done;
} }
buf = HeapAlloc (GetProcessHeap (), 0, needed); buf = HeapAlloc (GetProcessHeap (), 0, needed);
if (!buf) if (!buf)
{ {
HeapFree (GetProcessHeap (), 0, table); ret = ERROR_OUTOFMEMORY;
return ERROR_OUTOFMEMORY; goto done;
} }
if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
{ {
ERR ("sysctl 2 failed!\n"); ret = ERROR_NOT_SUPPORTED;
HeapFree (GetProcessHeap (), 0, table); goto done;
HeapFree (GetProcessHeap (), 0, buf);
return NO_ERROR;
} }
*ppIpForwardTable = table;
table->dwNumEntries = 0;
lim = buf + needed; lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) 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)) (rtm->rtm_flags & RTF_MULTICAST))
continue; continue;
memset (&table->table[table->dwNumEntries], 0, memset( &row, 0, sizeof(row) );
sizeof (MIB_IPFORWARDROW)); row.dwForwardIfIndex = rtm->rtm_index;
table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index; row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
table->table[table->dwNumEntries].dwForwardType = row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
MIB_IPROUTE_TYPE_INDIRECT; row.dwForwardProto = MIB_IPPROTO_LOCAL;
table->table[table->dwNumEntries].dwForwardMetric1 =
rtm->rtm_rmx.rmx_hopcount;
table->table[table->dwNumEntries].dwForwardProto =
MIB_IPPROTO_LOCAL;
addrPtr = (char *)(rtm + 1); addrPtr = (char *)(rtm + 1);
@ -1152,119 +1205,29 @@ DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
switch (i) switch (i)
{ {
case RTA_DST: case RTA_DST: row.dwForwardDest = addr; break;
table->table[table->dwNumEntries].dwForwardDest = addr; case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
break; case RTA_NETMASK: row.dwForwardMask = addr; break;
case RTA_GATEWAY:
table->table[table->dwNumEntries].dwForwardNextHop = addr;
break;
case RTA_NETMASK:
table->table[table->dwNumEntries].dwForwardMask = addr;
break;
default: default:
WARN ("Unexpected address type 0x%x\n", i); WARN ("Unexpected address type 0x%x\n", i);
} }
} }
table->dwNumEntries++; if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
break;
} }
done:
HeapFree (GetProcessHeap (), 0, buf); 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
} }
else #else
ret = ERROR_OUTOFMEMORY; FIXME( "not implemented\n" );
} ret = ERROR_NOT_SUPPORTED;
return ret; #endif
if (!table) return ERROR_OUTOFMEMORY;
if (!ret) *ppIpForwardTable = table;
else HeapFree( heap, flags, table );
return ret;
} }
DWORD getNumArpEntries(void) DWORD getNumArpEntries(void)