mirror of
https://github.com/reactos/wine.git
synced 2024-11-29 06:30:37 +00:00
iphlpapi: Reimplement GetTcpTable to avoid parsing the same information three times.
This commit is contained in:
parent
d069e498e1
commit
53d522bc54
@ -343,7 +343,7 @@ DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
|
||||
ppTcpTable, bOrder, heap, flags);
|
||||
|
||||
*ppTcpTable = NULL;
|
||||
ret = getTcpTable(ppTcpTable, 0, heap, flags);
|
||||
ret = getTcpTable(ppTcpTable, heap, flags);
|
||||
if (!ret && bOrder)
|
||||
qsort((*ppTcpTable)->table, (*ppTcpTable)->dwNumEntries,
|
||||
sizeof(MIB_TCPROW), TcpTableSorter);
|
||||
@ -1603,39 +1603,31 @@ DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
|
||||
*/
|
||||
DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
|
||||
{
|
||||
DWORD ret;
|
||||
DWORD ret;
|
||||
PMIB_TCPTABLE table;
|
||||
|
||||
TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize,
|
||||
(DWORD)bOrder);
|
||||
if (!pdwSize)
|
||||
ret = ERROR_INVALID_PARAMETER;
|
||||
else {
|
||||
DWORD numEntries = getNumTcpEntries();
|
||||
DWORD size = sizeof(MIB_TCPTABLE);
|
||||
TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
|
||||
|
||||
if (numEntries > 1)
|
||||
size += (numEntries - 1) * sizeof(MIB_TCPROW);
|
||||
if (!pTcpTable || *pdwSize < size) {
|
||||
*pdwSize = size;
|
||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
||||
if (!pdwSize) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
ret = getTcpTable(&table, GetProcessHeap(), 0);
|
||||
if (!ret) {
|
||||
DWORD size = FIELD_OFFSET( MIB_TCPTABLE, table[table->dwNumEntries] );
|
||||
if (!pTcpTable || *pdwSize < size) {
|
||||
*pdwSize = size;
|
||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
else {
|
||||
*pdwSize = size;
|
||||
memcpy(pTcpTable, table, size);
|
||||
if (bOrder)
|
||||
qsort(pTcpTable->table, pTcpTable->dwNumEntries,
|
||||
sizeof(MIB_TCPROW), TcpTableSorter);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, table);
|
||||
}
|
||||
else {
|
||||
ret = getTcpTable(&pTcpTable, numEntries, 0, 0);
|
||||
if (!ret) {
|
||||
size = sizeof(MIB_TCPTABLE);
|
||||
if (pTcpTable->dwNumEntries > 1)
|
||||
size += (pTcpTable->dwNumEntries - 1) * sizeof(MIB_TCPROW);
|
||||
*pdwSize = size;
|
||||
|
||||
if (bOrder)
|
||||
qsort(pTcpTable->table, pTcpTable->dwNumEntries,
|
||||
sizeof(MIB_TCPROW), TcpTableSorter);
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("returning %d\n", ret);
|
||||
return ret;
|
||||
TRACE("returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1556,6 +1556,26 @@ DWORD getNumTcpEntries(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
|
||||
DWORD *count, const MIB_TCPROW *row )
|
||||
{
|
||||
if (table->dwNumEntries >= *count)
|
||||
{
|
||||
MIB_TCPTABLE *new_table;
|
||||
DWORD new_count = table->dwNumEntries * 2;
|
||||
|
||||
if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, 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;
|
||||
}
|
||||
|
||||
|
||||
/* Why not a lookup table? Because the TCPS_* constants are different
|
||||
on different platforms */
|
||||
@ -1579,178 +1599,129 @@ static DWORD TCPStateToMIBState (int state)
|
||||
}
|
||||
|
||||
|
||||
DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
|
||||
DWORD flags)
|
||||
DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags)
|
||||
{
|
||||
DWORD numEntries;
|
||||
PMIB_TCPTABLE table;
|
||||
#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
|
||||
size_t Len = 0;
|
||||
char *Buf;
|
||||
struct xinpgen *pXIG, *pOrigXIG;
|
||||
MIB_TCPTABLE *table;
|
||||
MIB_TCPROW row;
|
||||
DWORD ret = NO_ERROR, count = 16;
|
||||
|
||||
if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
table->dwNumEntries = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen("/proc/net/tcp", "r")))
|
||||
{
|
||||
char buf[512], *ptr;
|
||||
DWORD dummy;
|
||||
|
||||
/* skip header line */
|
||||
ptr = fgets(buf, sizeof(buf), fp);
|
||||
while ((ptr = fgets(buf, sizeof(buf), fp)))
|
||||
{
|
||||
if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
|
||||
&row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
|
||||
continue;
|
||||
row.dwLocalPort = htons( row.dwLocalPort );
|
||||
row.dwRemotePort = htons( row.dwRemotePort );
|
||||
row.dwState = TCPStateToMIBState( row.dwState );
|
||||
if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
|
||||
break;
|
||||
}
|
||||
fclose( fp );
|
||||
}
|
||||
else ret = ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
#elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
|
||||
{
|
||||
size_t Len = 0;
|
||||
char *Buf = NULL;
|
||||
struct xinpgen *pXIG, *pOrigXIG;
|
||||
|
||||
if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
|
||||
{
|
||||
ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
|
||||
ret = ERROR_NOT_SUPPORTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
Buf = HeapAlloc (GetProcessHeap (), 0, Len);
|
||||
if (!Buf)
|
||||
{
|
||||
ret = ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
|
||||
{
|
||||
ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
|
||||
ret = ERROR_NOT_SUPPORTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Might be nothing here; first entry is just a header it seems */
|
||||
if (Len <= sizeof (struct xinpgen)) goto done;
|
||||
|
||||
pOrigXIG = (struct xinpgen *)Buf;
|
||||
pXIG = pOrigXIG;
|
||||
|
||||
for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
|
||||
pXIG->xig_len > sizeof (struct xinpgen);
|
||||
pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
|
||||
{
|
||||
struct tcpcb *pTCPData = NULL;
|
||||
struct inpcb *pINData;
|
||||
struct xsocket *pSockData;
|
||||
|
||||
pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
|
||||
pINData = &((struct xtcpcb *)pXIG)->xt_inp;
|
||||
pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
|
||||
|
||||
/* Ignore sockets for other protocols */
|
||||
if (pSockData->xso_protocol != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
/* Ignore PCBs that were freed while generating the data */
|
||||
if (pINData->inp_gencnt > pOrigXIG->xig_gen)
|
||||
continue;
|
||||
|
||||
/* we're only interested in IPv4 addresses */
|
||||
if (!(pINData->inp_vflag & INP_IPV4) ||
|
||||
(pINData->inp_vflag & INP_IPV6))
|
||||
continue;
|
||||
|
||||
/* If all 0's, skip it */
|
||||
if (!pINData->inp_laddr.s_addr &&
|
||||
!pINData->inp_lport &&
|
||||
!pINData->inp_faddr.s_addr &&
|
||||
!pINData->inp_fport)
|
||||
continue;
|
||||
|
||||
/* Fill in structure details */
|
||||
row.dwLocalAddr = pINData->inp_laddr.s_addr;
|
||||
row.dwLocalPort = pINData->inp_lport;
|
||||
row.dwRemoteAddr = pINData->inp_faddr.s_addr;
|
||||
row.dwRemotePort = pINData->inp_fport;
|
||||
row.dwState = TCPStateToMIBState (pTCPData->t_state);
|
||||
if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
|
||||
}
|
||||
|
||||
done:
|
||||
HeapFree (GetProcessHeap (), 0, Buf);
|
||||
}
|
||||
#else
|
||||
FILE *fp;
|
||||
char buf[512] = { 0 }, *ptr;
|
||||
FIXME( "not implemented\n" );
|
||||
ret = ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
|
||||
if (!ppTcpTable)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
numEntries = getNumTcpEntries ();
|
||||
|
||||
if (!*ppTcpTable)
|
||||
{
|
||||
DWORD size = sizeof(MIB_TCPTABLE);
|
||||
|
||||
if (numEntries > 1)
|
||||
size += (numEntries - 1) * sizeof (MIB_TCPROW);
|
||||
*ppTcpTable = HeapAlloc (heap, flags, size);
|
||||
if (!*ppTcpTable)
|
||||
{
|
||||
ERR ("Out of memory!\n");
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
maxEntries = numEntries;
|
||||
}
|
||||
|
||||
table = *ppTcpTable;
|
||||
table->dwNumEntries = 0;
|
||||
if (!numEntries)
|
||||
return NO_ERROR;
|
||||
|
||||
#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
|
||||
|
||||
if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
|
||||
{
|
||||
ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
Buf = HeapAlloc (GetProcessHeap (), 0, Len);
|
||||
if (!Buf)
|
||||
{
|
||||
ERR ("Out of memory!\n");
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
|
||||
{
|
||||
ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
|
||||
HeapFree (GetProcessHeap (), 0, Buf);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
/* Might be nothing here; first entry is just a header it seems */
|
||||
if (Len <= sizeof (struct xinpgen))
|
||||
{
|
||||
HeapFree (GetProcessHeap (), 0, Buf);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
pOrigXIG = (struct xinpgen *)Buf;
|
||||
pXIG = pOrigXIG;
|
||||
|
||||
for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
|
||||
(pXIG->xig_len > sizeof (struct xinpgen)) &&
|
||||
(table->dwNumEntries < maxEntries);
|
||||
pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
|
||||
{
|
||||
struct tcpcb *pTCPData = NULL;
|
||||
struct inpcb *pINData;
|
||||
struct xsocket *pSockData;
|
||||
|
||||
pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
|
||||
pINData = &((struct xtcpcb *)pXIG)->xt_inp;
|
||||
pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
|
||||
|
||||
/* Ignore sockets for other protocols */
|
||||
if (pSockData->xso_protocol != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
/* Ignore PCBs that were freed while generating the data */
|
||||
if (pINData->inp_gencnt > pOrigXIG->xig_gen)
|
||||
continue;
|
||||
|
||||
/* we're only interested in IPv4 addresses */
|
||||
if (!(pINData->inp_vflag & INP_IPV4) ||
|
||||
(pINData->inp_vflag & INP_IPV6))
|
||||
continue;
|
||||
|
||||
/* If all 0's, skip it */
|
||||
if (!pINData->inp_laddr.s_addr &&
|
||||
!pINData->inp_lport &&
|
||||
!pINData->inp_faddr.s_addr &&
|
||||
!pINData->inp_fport)
|
||||
continue;
|
||||
|
||||
/* Fill in structure details */
|
||||
table->table[table->dwNumEntries].dwLocalAddr =
|
||||
pINData->inp_laddr.s_addr;
|
||||
table->table[table->dwNumEntries].dwLocalPort =
|
||||
pINData->inp_lport;
|
||||
table->table[table->dwNumEntries].dwRemoteAddr =
|
||||
pINData->inp_faddr.s_addr;
|
||||
table->table[table->dwNumEntries].dwRemotePort =
|
||||
pINData->inp_fport;
|
||||
table->table[table->dwNumEntries].dwState =
|
||||
TCPStateToMIBState (pTCPData->t_state);
|
||||
|
||||
table->dwNumEntries++;
|
||||
}
|
||||
|
||||
HeapFree (GetProcessHeap (), 0, Buf);
|
||||
#else
|
||||
/* get from /proc/net/tcp, no error if can't */
|
||||
fp = fopen("/proc/net/tcp", "r");
|
||||
if (!fp)
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
|
||||
/* skip header line */
|
||||
ptr = fgets(buf, sizeof(buf), fp);
|
||||
while (ptr && table->dwNumEntries < maxEntries) {
|
||||
memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
|
||||
ptr = fgets(buf, sizeof(buf), fp);
|
||||
if (ptr) {
|
||||
char *endPtr;
|
||||
|
||||
while (ptr && *ptr && *ptr != ':')
|
||||
ptr++;
|
||||
if (ptr && *ptr)
|
||||
ptr++;
|
||||
if (ptr && *ptr) {
|
||||
table->table[table->dwNumEntries].dwLocalAddr =
|
||||
strtoul(ptr, &endPtr, 16);
|
||||
ptr = endPtr;
|
||||
}
|
||||
if (ptr && *ptr) {
|
||||
ptr++;
|
||||
table->table[table->dwNumEntries].dwLocalPort =
|
||||
htons ((unsigned short)strtoul(ptr, &endPtr, 16));
|
||||
ptr = endPtr;
|
||||
}
|
||||
if (ptr && *ptr) {
|
||||
table->table[table->dwNumEntries].dwRemoteAddr =
|
||||
strtoul(ptr, &endPtr, 16);
|
||||
ptr = endPtr;
|
||||
}
|
||||
if (ptr && *ptr) {
|
||||
ptr++;
|
||||
table->table[table->dwNumEntries].dwRemotePort =
|
||||
htons ((unsigned short)strtoul(ptr, &endPtr, 16));
|
||||
ptr = endPtr;
|
||||
}
|
||||
if (ptr && *ptr) {
|
||||
DWORD state = strtoul(ptr, &endPtr, 16);
|
||||
|
||||
table->table[table->dwNumEntries].dwState =
|
||||
TCPStateToMIBState (state);
|
||||
ptr = endPtr;
|
||||
}
|
||||
table->dwNumEntries++;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
#endif
|
||||
|
||||
return NO_ERROR;
|
||||
if (!table) return ERROR_OUTOFMEMORY;
|
||||
if (!ret) *ppTcpTable = table;
|
||||
else HeapFree( heap, flags, table );
|
||||
return ret;
|
||||
}
|
||||
|
@ -83,7 +83,6 @@ DWORD getNumTcpEntries(void);
|
||||
/* Allocates the TCP state table from heap and returns it to you in *ppTcpTable.
|
||||
* Returns NO_ERROR on success, something else on failure.
|
||||
*/
|
||||
DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
|
||||
DWORD flags);
|
||||
DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags);
|
||||
|
||||
#endif /* ndef WINE_IPSTATS_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user