Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2021
- 78 participants
- 929 discussions
A minor optimization.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/display.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index b647455a01f..b3ff213ae89 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -586,6 +586,7 @@ static BOOL X11DRV_InitMonitor(HDEVINFO devinfo, const struct x11drv_monitor *mo
{
SP_DEVINFO_DATA device_data = {sizeof(SP_DEVINFO_DATA)};
WCHAR bufferW[MAX_PATH];
+ DWORD length;
HKEY hkey;
BOOL ret = FALSE;
@@ -629,9 +630,9 @@ static BOOL X11DRV_InitMonitor(HDEVINFO devinfo, const struct x11drv_monitor *mo
(const BYTE *)&monitor->rc_work, sizeof(monitor->rc_work), 0))
goto done;
/* Adapter name */
- sprintfW(bufferW, adapter_name_fmtW, video_index + 1);
+ length = sprintfW(bufferW, adapter_name_fmtW, video_index + 1);
if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, DEVPROP_TYPE_STRING,
- (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR), 0))
+ (const BYTE *)bufferW, (length + 1) * sizeof(WCHAR), 0))
goto done;
ret = TRUE;
--
2.30.2
1
0
[PATCH] wordpad: Use large icons for toolbar when DPI is greater than 120.
by Zhiyi Zhang 17 Aug '21
by Zhiyi Zhang 17 Aug '21
17 Aug '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
This is the behavior of wordpad on XP. Newer versions of wordpad use ribbon instead of toolbar so they don't have this problem.
programs/wordpad/wordpad.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/programs/wordpad/wordpad.c b/programs/wordpad/wordpad.c
index d48346e3c4a..e87475ad06b 100644
--- a/programs/wordpad/wordpad.c
+++ b/programs/wordpad/wordpad.c
@@ -1881,7 +1881,7 @@ static LRESULT OnCreate( HWND hWnd )
HFONT font;
HDC hdc;
SIZE name_sz, size_sz;
- int height;
+ int height, dpi;
static const WCHAR wszRichEditDll[] = {'R','I','C','H','E','D','2','0','.','D','L','L','\0'};
static const WCHAR wszRichEditText[] = {'R','i','c','h','E','d','i','t',' ','t','e','x','t','\0'};
static const WCHAR font_text[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0}; /* a long font name */
@@ -1905,8 +1905,12 @@ static LRESULT OnCreate( HWND hWnd )
NULL, 0,
24, 24, 16, 16, sizeof(TBBUTTON));
+ hdc = GetDC(hWnd);
+ dpi = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(hWnd, hdc);
+
ab.hInst = HINST_COMMCTRL;
- ab.nID = IDB_STD_SMALL_COLOR;
+ ab.nID = dpi >= 120 ? IDB_STD_LARGE_COLOR : IDB_STD_SMALL_COLOR;
nStdBitmaps = SendMessageW(hToolBarWnd, TB_ADDBITMAP, 0, (LPARAM)&ab);
AddButton(hToolBarWnd, nStdBitmaps+STD_FILENEW, ID_FILE_NEW);
--
2.30.2
1
0
[PATCH] user32: Report a fake monitor when running on an invisible window station.
by Zhiyi Zhang 17 Aug '21
by Zhiyi Zhang 17 Aug '21
17 Aug '21
The visible window station check was accidentally deleted in 95be042.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51590
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/sysparams.c | 10 +++++++++-
dlls/user32/tests/monitor.c | 7 +++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c
index 1c943767927..24e39206746 100644
--- a/dlls/user32/sysparams.c
+++ b/dlls/user32/sysparams.c
@@ -4111,12 +4111,20 @@ static BOOL CALLBACK enum_mon_callback( HMONITOR monitor, HDC hdc, LPRECT rect,
BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
{
+ BOOL is_winstation_visible = FALSE;
+ USEROBJECTFLAGS flags;
+ HWINSTA winstation;
RECT monitor_rect;
DWORD i = 0;
TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
- if (update_monitor_cache())
+ /* Report physical monitor information only if window station has visible display surfaces */
+ winstation = GetProcessWindowStation();
+ if (GetUserObjectInformationW( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL ))
+ is_winstation_visible = flags.dwFlags & WSF_VISIBLE;
+
+ if (is_winstation_visible && update_monitor_cache())
{
while (TRUE)
{
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 654f77ed617..dfb57d3e2c2 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -1563,6 +1563,7 @@ static void test_EnumDisplayMonitors(void)
static const DWORD DESKTOP_ALL_ACCESS = 0x01ff;
HWINSTA winstation, old_winstation;
HDESK desktop, old_desktop;
+ USEROBJECTFLAGS flags;
INT count, old_count;
DWORD error;
BOOL ret;
@@ -1602,6 +1603,12 @@ static void test_EnumDisplayMonitors(void)
ok(ret, "SetProcessWindowStation failed, error %#x.\n", GetLastError());
ok(winstation == GetProcessWindowStation(), "Expected %p, got %p.\n", GetProcessWindowStation(), winstation);
+ flags.fInherit = FALSE;
+ flags.fReserved = FALSE;
+ flags.dwFlags = WSF_VISIBLE;
+ ret = SetUserObjectInformationW(winstation, UOI_FLAGS, &flags, sizeof(flags));
+ ok(ret, "SetUserObjectInformationW failed, error %#x.\n", GetLastError());
+
desktop = CreateDesktopW(L"test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
ok(!!desktop && desktop != old_desktop, "CreateDesktopW failed, error %#x.\n", GetLastError());
ret = SetThreadDesktop(desktop);
--
2.30.2
1
0
[PATCH 7/7] iphlpapi: Implement AllocateAndGetTcp(Ex)TableFromStack() on top of nsi.
by Huw Davies 17 Aug '21
by Huw Davies 17 Aug '21
17 Aug '21
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/iphlpapi_main.c | 43 +++
dlls/iphlpapi/ipstats.c | 644 ----------------------------------
dlls/iphlpapi/ipstats.h | 2 -
3 files changed, 43 insertions(+), 646 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 65a72379e60..e78689d8f11 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -3240,6 +3240,49 @@ ULONG WINAPI GetTcp6Table2( MIB_TCP6TABLE2 *table, ULONG *size, BOOL sort )
return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE2 );
}
+static DWORD allocate_tcp_table( void **table, BOOL sort, HANDLE heap, DWORD flags,
+ ULONG family, ULONG table_class )
+{
+ DWORD err, size = 0x100, attempt;
+
+ for (attempt = 0; attempt < 5; attempt++)
+ {
+ *table = HeapAlloc( heap, flags, size );
+ if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
+ err = get_extended_tcp_table( *table, &size, sort, family, table_class );
+ if (!err) break;
+ HeapFree( heap, flags, *table );
+ *table = NULL;
+ if (err != ERROR_INSUFFICIENT_BUFFER) break;
+ }
+ return err;
+}
+
+/******************************************************************
+ * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
+ */
+DWORD WINAPI AllocateAndGetTcpTableFromStack( MIB_TCPTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
+{
+ TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
+
+ if (!table) return ERROR_INVALID_PARAMETER;
+
+ return allocate_tcp_table( (void **)table, sort, heap, flags, WS_AF_INET, TCP_TABLE_BASIC_ALL );
+}
+
+/******************************************************************
+ * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
+ */
+DWORD WINAPI AllocateAndGetTcpExTableFromStack( void **table, BOOL sort, HANDLE heap, DWORD flags, DWORD family )
+{
+ TRACE( "table %p, sort %d, heap %p, flags 0x%08x, family %u\n", table, sort, heap, flags, family );
+
+ if (!table || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
+ if (family == WS_AF_INET6) return ERROR_NOT_SUPPORTED;
+
+ return allocate_tcp_table( table, sort, heap, flags, family, TCP_TABLE_OWNER_PID_ALL );
+}
+
/******************************************************************
* GetUdpTable (IPHLPAPI.@)
*
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
index af14cddb0ca..326db56f5bc 100644
--- a/dlls/iphlpapi/ipstats.c
+++ b/dlls/iphlpapi/ipstats.c
@@ -466,77 +466,6 @@ static void *append_table_row( HANDLE heap, DWORD flags, void *table, DWORD *tab
return table;
}
-static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
-{
- DWORD table_size;
-
- switch (class)
- {
- case TCP_TABLE_BASIC_LISTENER:
- case TCP_TABLE_BASIC_CONNECTIONS:
- case TCP_TABLE_BASIC_ALL:
- {
- table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
- if (row_size) *row_size = sizeof(MIB_TCPROW);
- break;
- }
- case TCP_TABLE_OWNER_PID_LISTENER:
- case TCP_TABLE_OWNER_PID_CONNECTIONS:
- case TCP_TABLE_OWNER_PID_ALL:
- {
- table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
- if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
- break;
- }
- case TCP_TABLE_OWNER_MODULE_LISTENER:
- case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
- case TCP_TABLE_OWNER_MODULE_ALL:
- {
- table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]);
- if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_MODULE);
- break;
- }
- default:
- ERR("unhandled class %u\n", class);
- return 0;
- }
- return table_size;
-}
-
-/* Why not a lookup table? Because the TCPS_* constants are different
- on different platforms */
-static inline MIB_TCP_STATE TCPStateToMIBState (int state)
-{
- switch (state)
- {
- case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
- case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
- case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
- case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
- case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
- case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
- case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
- case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
- case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
- case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
- default:
- case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
- }
-}
-
-static int compare_tcp_rows(const void *a, const void *b)
-{
- const MIB_TCPROW *rowA = a;
- const MIB_TCPROW *rowB = b;
- int ret;
-
- if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
- if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
- ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
- if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
- return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
-}
-
struct pid_map
{
unsigned int pid;
@@ -715,289 +644,6 @@ static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entri
#endif
}
-static BOOL match_class( TCP_TABLE_CLASS class, MIB_TCP_STATE state )
-{
- switch (class)
- {
- case TCP_TABLE_BASIC_ALL:
- case TCP_TABLE_OWNER_PID_ALL:
- case TCP_TABLE_OWNER_MODULE_ALL:
- return TRUE;
-
- case TCP_TABLE_BASIC_LISTENER:
- case TCP_TABLE_OWNER_PID_LISTENER:
- case TCP_TABLE_OWNER_MODULE_LISTENER:
- if (state == MIB_TCP_STATE_LISTEN) return TRUE;
- return FALSE;
-
- case TCP_TABLE_BASIC_CONNECTIONS:
- case TCP_TABLE_OWNER_PID_CONNECTIONS:
- case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
- if (state == MIB_TCP_STATE_ESTAB) return TRUE;
- return FALSE;
-
- default:
- ERR( "unhandled class %u\n", class );
- return FALSE;
- }
-}
-
-DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
- DWORD *size )
-{
- MIB_TCPTABLE *table;
- MIB_TCPROW_OWNER_MODULE row;
- DWORD ret = NO_ERROR, count = 16, table_size, row_size;
-
- if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
- return ERROR_INVALID_PARAMETER;
-
- if (!(table = HeapAlloc( heap, flags, table_size )))
- return ERROR_OUTOFMEMORY;
-
- table->dwNumEntries = 0;
-
-#ifdef __linux__
- {
- FILE *fp;
-
- if ((fp = fopen("/proc/net/tcp", "r")))
- {
- char buf[512], *ptr;
- struct pid_map *map = NULL;
- unsigned int num_entries = 0;
- int inode;
-
- if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
-
- /* 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 %*s %*s %*s %*s %*s %d",
- &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
- &row.dwRemotePort, &row.dwState, &inode ) != 6)
- continue;
- row.dwLocalPort = htons( row.dwLocalPort );
- row.dwRemotePort = htons( row.dwRemotePort );
- row.dwState = TCPStateToMIBState( row.dwState );
- if (!match_class( class, row.dwState )) continue;
-
- if (class >= TCP_TABLE_OWNER_PID_LISTENER)
- row.dwOwningPid = find_owning_pid( map, num_entries, inode );
- if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
- {
- row.liCreateTimestamp.QuadPart = 0; /* FIXME */
- memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
- }
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
- break;
- }
- HeapFree( GetProcessHeap(), 0, map );
- fclose( fp );
- }
- else ret = ERROR_NOT_SUPPORTED;
- }
-#elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
- {
- void *data;
- int fd, len;
- mib2_tcpConnEntry_t *entry;
-
- if ((fd = open_streams_mib( "tcp" )) != -1)
- {
- if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
- {
- for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
- {
- row.dwLocalAddr = entry->tcpConnLocalAddress;
- row.dwLocalPort = htons( entry->tcpConnLocalPort );
- row.dwRemoteAddr = entry->tcpConnRemAddress;
- row.dwRemotePort = htons( entry->tcpConnRemPort );
- row.dwState = entry->tcpConnState;
- if (!match_class( class, row.dwState )) continue;
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
- break;
- }
- HeapFree( GetProcessHeap(), 0, data );
- }
- close( fd );
- }
- 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;
- struct pid_map *pMap = NULL;
- unsigned NumEntries;
-
- 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;
- }
-
- if (class >= TCP_TABLE_OWNER_PID_LISTENER) pMap = get_pid_map( &NumEntries );
-
- /* 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))
- {
-#if __FreeBSD_version >= 1200026
- struct xtcpcb *pTCPData = (struct xtcpcb *)pXIG;
- struct xinpcb *pINData = &pTCPData->xt_inp;
- struct xsocket *pSockData = &pINData->xi_socket;
-#else
- struct tcpcb *pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
- struct inpcb *pINData = &((struct xtcpcb *)pXIG)->xt_inp;
- struct xsocket *pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
-#endif
-
- /* 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 (!match_class( class, row.dwState )) continue;
- if (class >= TCP_TABLE_OWNER_PID_LISTENER)
- row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
- if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
- {
- row.liCreateTimestamp.QuadPart = 0; /* FIXME */
- memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
- }
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
- break;
- }
-
- done:
- HeapFree( GetProcessHeap(), 0, pMap );
- HeapFree (GetProcessHeap (), 0, Buf);
- }
-#else
- FIXME( "not implemented\n" );
- ret = ERROR_NOT_SUPPORTED;
-#endif
-
- if (!table) return ERROR_OUTOFMEMORY;
- if (!ret)
- {
- if (order && table->dwNumEntries)
- qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
- *tablep = table;
- }
- else HeapFree( heap, flags, table );
- if (size) *size = get_tcp_table_sizes( class, count, NULL );
- TRACE( "returning ret %u table %p\n", ret, table );
- return ret;
-}
-
-/******************************************************************
- * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
- *
- * Get the TCP connection table.
- * Like GetTcpTable(), but allocate the returned table from heap.
- *
- * PARAMS
- * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
- * allocated and returned.
- * bOrder [In] whether to sort the table
- * heap [In] heap from which the table is allocated
- * flags [In] flags to HeapAlloc
- *
- * RETURNS
- * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
- * returns otherwise.
- */
-DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
- HANDLE heap, DWORD flags )
-{
- TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
-
- if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
- return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
-}
-
-/******************************************************************
- * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
- *
- * Get the TCP connection table.
- * Like GetTcpTable(), but allocate the returned table from heap.
- *
- * PARAMS
- * ppTcpTable [Out] pointer into which the MIB_TCPTABLE_EX is
- * allocated and returned.
- * bOrder [In] whether to sort the table
- * heap [In] heap from which the table is allocated
- * flags [In] flags to HeapAlloc
- * family [In] address family [AF_INET|AF_INET6]
- *
- * RETURNS
- * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
- * returns otherwise.
- */
-DWORD WINAPI AllocateAndGetTcpExTableFromStack( VOID **ppTcpTable, BOOL bOrder,
- HANDLE heap, DWORD flags, DWORD family )
-{
- TRACE("table %p, bOrder %d, heap %p, flags 0x%08x, family %u\n",
- ppTcpTable, bOrder, heap, flags, family);
-
- if (!ppTcpTable || !family)
- return ERROR_INVALID_PARAMETER;
-
- if (family != WS_AF_INET)
- {
- FIXME( "family = %u not supported\n", family );
- return ERROR_NOT_SUPPORTED;
- }
-
- return build_tcp_table( TCP_TABLE_OWNER_PID_ALL, ppTcpTable, bOrder, heap, flags, NULL );
-}
-
static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
{
DWORD table_size;
@@ -1222,71 +868,6 @@ DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE
return ret;
}
-static DWORD get_tcp6_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
-{
- DWORD table_size;
-
- switch (class)
- {
- case TCP_TABLE_BASIC_LISTENER:
- case TCP_TABLE_BASIC_CONNECTIONS:
- case TCP_TABLE_BASIC_ALL:
- {
- table_size = FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
- if (row_size) *row_size = sizeof(MIB_TCP6ROW);
- break;
- }
- case TCP_TABLE_OWNER_PID_LISTENER:
- case TCP_TABLE_OWNER_PID_CONNECTIONS:
- case TCP_TABLE_OWNER_PID_ALL:
- {
- table_size = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
- if (row_size) *row_size = sizeof(MIB_TCP6ROW_OWNER_PID);
- break;
- }
- case TCP_TABLE_OWNER_MODULE_LISTENER:
- case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
- case TCP_TABLE_OWNER_MODULE_ALL:
- {
- table_size = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
- if (row_size) *row_size = sizeof(MIB_TCP6ROW_OWNER_MODULE);
- break;
- }
- default:
- ERR("unhandled class %u\n", class);
- return 0;
- }
- return table_size;
-}
-
-static int compare_tcp6_basic_rows(const void *a, const void *b)
-{
- const MIB_TCP6ROW *rowA = a;
- const MIB_TCP6ROW *rowB = b;
- int ret;
-
- if ((ret = memcmp(&rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr))) != 0) return ret;
- if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
- if ((ret = rowA->dwLocalPort - rowB->dwLocalPort) != 0) return ret;
- if ((ret = memcmp(&rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr))) != 0) return ret;
- if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
- return rowA->dwRemotePort - rowB->dwRemotePort;
-}
-
-static int compare_tcp6_owner_rows(const void *a, const void *b)
-{
- const MIB_TCP6ROW_OWNER_PID *rowA = a;
- const MIB_TCP6ROW_OWNER_PID *rowB = b;
- int ret;
-
- if ((ret = memcmp(&rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr))) != 0) return ret;
- if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
- if ((ret = rowA->dwLocalPort - rowB->dwLocalPort) != 0) return ret;
- if ((ret = memcmp(&rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr))) != 0) return ret;
- if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
- return rowA->dwRemotePort - rowB->dwRemotePort;
-}
-
static DWORD get_udp6_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
{
DWORD table_size;
@@ -1456,231 +1037,6 @@ static DWORD find_ipv6_addr_scope(const IN6_ADDR *addr, const struct ipv6_addr_s
}
#endif
-DWORD build_tcp6_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
- DWORD *size )
-{
- MIB_TCP6TABLE *table;
- DWORD ret = NO_ERROR, count = 16, table_size, row_size;
-
- if (!(table_size = get_tcp6_table_sizes( class, count, &row_size )))
- return ERROR_INVALID_PARAMETER;
-
- if (!(table = HeapAlloc( heap, flags, table_size )))
- return ERROR_OUTOFMEMORY;
-
- table->dwNumEntries = 0;
-
-#ifdef __linux__
- {
- MIB_TCP6ROW_OWNER_MODULE row;
- FILE *fp;
-
- if ((fp = fopen( "/proc/net/tcp6", "r" )))
- {
- char buf[512], *ptr;
- struct pid_map *map = NULL;
- unsigned int num_entries = 0;
- struct ipv6_addr_scope *addr_scopes;
- unsigned int addr_scopes_size = 0;
- int inode;
-
- addr_scopes = get_ipv6_addr_scope_table(&addr_scopes_size);
-
- if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
-
- /* skip header line */
- ptr = fgets( buf, sizeof(buf), fp );
- while ((ptr = fgets( buf, sizeof(buf), fp )))
- {
- DWORD *local_addr = (DWORD *)&row.ucLocalAddr;
- DWORD *remote_addr = (DWORD *)&row.ucRemoteAddr;
-
- if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %*s %*s %*s %*s %*s %*s %*s %d",
- &local_addr[0], &local_addr[1], &local_addr[2], &local_addr[3], &row.dwLocalPort,
- &remote_addr[0], &remote_addr[1], &remote_addr[2], &remote_addr[3], &row.dwRemotePort,
- &row.dwState, &inode ) != 12)
- continue;
- row.dwState = TCPStateToMIBState( row.dwState );
- if (!match_class( class, row.dwState )) continue;
- row.dwLocalScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size);
- row.dwLocalPort = htons( row.dwLocalPort );
- row.dwRemoteScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucRemoteAddr, addr_scopes, addr_scopes_size);
- row.dwRemotePort = htons( row.dwRemotePort );
-
- if (class <= TCP_TABLE_BASIC_ALL)
- {
- /* MIB_TCP6ROW has a different field order */
- MIB_TCP6ROW basic_row;
- basic_row.State = row.dwState;
- memcpy( &basic_row.LocalAddr, &row.ucLocalAddr, sizeof(row.ucLocalAddr) );
- basic_row.dwLocalScopeId = row.dwLocalScopeId;
- basic_row.dwLocalPort = row.dwLocalPort;
- memcpy( &basic_row.RemoteAddr, &row.ucRemoteAddr, sizeof(row.ucRemoteAddr) );
- basic_row.dwRemoteScopeId = row.dwRemoteScopeId;
- basic_row.dwRemotePort = row.dwRemotePort;
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &basic_row, row_size )))
- break;
- continue;
- }
-
- row.dwOwningPid = find_owning_pid( map, num_entries, inode );
- if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
- {
- row.liCreateTimestamp.QuadPart = 0; /* FIXME */
- memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
- }
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
- break;
- }
- HeapFree( GetProcessHeap(), 0, map );
- HeapFree( GetProcessHeap(), 0, addr_scopes );
- fclose( fp );
- }
- else ret = ERROR_NOT_SUPPORTED;
- }
-#elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
- {
- static const char zero[sizeof(IN6_ADDR)] = {0};
-
- MIB_TCP6ROW_OWNER_MODULE row;
- size_t len = 0;
- char *buf = NULL;
- struct xinpgen *xig, *orig_xig;
- struct pid_map *map = NULL;
- unsigned num_entries;
- struct ipv6_addr_scope *addr_scopes = NULL;
- unsigned int addr_scopes_size = 0;
-
- 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;
- }
-
- addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
- if (!addr_scopes)
- {
- ret = ERROR_OUTOFMEMORY;
- goto done;
- }
-
- if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
-
- /* Might be nothing here; first entry is just a header it seems */
- if (len <= sizeof (struct xinpgen)) goto done;
-
- orig_xig = (struct xinpgen *)buf;
- xig = orig_xig;
-
- for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
- xig->xig_len > sizeof (struct xinpgen);
- xig = (struct xinpgen *)((char *)xig + xig->xig_len))
- {
-#if __FreeBSD_version >= 1200026
- struct xtcpcb *tcp = (struct xtcpcb *)xig;
- struct xinpcb *in = &tcp->xt_inp;
- struct xsocket *sock = &in->xi_socket;
-#else
- struct tcpcb *tcp = &((struct xtcpcb *)xig)->xt_tp;
- struct inpcb *in = &((struct xtcpcb *)xig)->xt_inp;
- struct xsocket *sock = &((struct xtcpcb *)xig)->xt_socket;
-#endif
-
- /* Ignore sockets for other protocols */
- if (sock->xso_protocol != IPPROTO_TCP)
- continue;
-
- /* Ignore PCBs that were freed while generating the data */
- if (in->inp_gencnt > orig_xig->xig_gen)
- continue;
-
- /* we're only interested in IPv6 addresses */
- if (!(in->inp_vflag & INP_IPV6) ||
- (in->inp_vflag & INP_IPV4))
- continue;
-
- /* If all 0's, skip it */
- if (!memcmp( &in->in6p_laddr, zero, sizeof(zero) ) && !in->inp_lport &&
- !memcmp( &in->in6p_faddr, zero, sizeof(zero) ) && !in->inp_fport)
- continue;
-
- /* Fill in structure details */
- memcpy( &row.ucLocalAddr, &in->in6p_laddr.s6_addr, sizeof(row.ucLocalAddr) );
- row.dwLocalPort = in->inp_lport;
- row.dwLocalScopeId = find_ipv6_addr_scope( (const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size );
- memcpy( &row.ucRemoteAddr, &in->in6p_faddr.s6_addr, sizeof(row.ucRemoteAddr) );
- row.dwRemotePort = in->inp_fport;
- row.dwRemoteScopeId = find_ipv6_addr_scope( (const IN6_ADDR *)&row.ucRemoteAddr, addr_scopes, addr_scopes_size );
- row.dwState = TCPStateToMIBState( tcp->t_state );
- if (!match_class( class, row.dwState )) continue;
-
- if (class <= TCP_TABLE_BASIC_ALL)
- {
- /* MIB_TCP6ROW has a different field order */
- MIB_TCP6ROW basic_row;
- basic_row.State = row.dwState;
- memcpy( &basic_row.LocalAddr, &row.ucLocalAddr, sizeof(row.ucLocalAddr) );
- basic_row.dwLocalScopeId = row.dwLocalScopeId;
- basic_row.dwLocalPort = row.dwLocalPort;
- memcpy( &basic_row.RemoteAddr, &row.ucRemoteAddr, sizeof(row.ucRemoteAddr) );
- basic_row.dwRemoteScopeId = row.dwRemoteScopeId;
- basic_row.dwRemotePort = row.dwRemotePort;
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &basic_row, row_size )))
- break;
- continue;
- }
-
- row.dwOwningPid = find_owning_pid( map, num_entries, (UINT_PTR)sock->so_pcb );
- if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
- {
- row.liCreateTimestamp.QuadPart = 0; /* FIXME */
- memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
- }
- if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
- break;
- }
-
- done:
- HeapFree( GetProcessHeap(), 0, map );
- HeapFree( GetProcessHeap(), 0, buf );
- HeapFree( GetProcessHeap(), 0, addr_scopes );
- }
-#else
- FIXME( "not implemented\n" );
- ret = ERROR_NOT_SUPPORTED;
-#endif
-
- if (!table) return ERROR_OUTOFMEMORY;
- if (!ret)
- {
- if (order && table->dwNumEntries)
- {
- qsort( table->table, table->dwNumEntries, row_size,
- class <= TCP_TABLE_BASIC_ALL ? compare_tcp6_basic_rows : compare_tcp6_owner_rows );
- }
- *tablep = table;
- }
- else HeapFree( heap, flags, table );
- if (size) *size = get_tcp6_table_sizes( class, count, NULL );
- TRACE( "returning ret %u table %p\n", ret, table );
- return ret;
-}
-
DWORD build_udp6_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
DWORD *size )
{
diff --git a/dlls/iphlpapi/ipstats.h b/dlls/iphlpapi/ipstats.h
index bb0c77758f7..60398609207 100644
--- a/dlls/iphlpapi/ipstats.h
+++ b/dlls/iphlpapi/ipstats.h
@@ -27,8 +27,6 @@
#include "winbase.h"
#include "iprtrmib.h"
-DWORD build_tcp_table(TCP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
-DWORD build_tcp6_table(TCP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
DWORD build_udp_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
DWORD build_udp6_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
--
2.23.0
1
0
17 Aug '21
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/iphlpapi_main.c | 76 ++++++++++++++++++++++++++---------
1 file changed, 58 insertions(+), 18 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 5595088e093..65a72379e60 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -2870,6 +2870,8 @@ DWORD WINAPI GetTcpStatisticsEx( MIB_TCPSTATS *stats, DWORD family )
return err;
}
+#define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
+
static DWORD tcp_table_id( ULONG table_class )
{
switch (table_class)
@@ -2887,6 +2889,7 @@ static DWORD tcp_table_id( ULONG table_class )
case TCP_TABLE_BASIC_ALL:
case TCP_TABLE_OWNER_PID_ALL:
case TCP_TABLE_OWNER_MODULE_ALL:
+ case TCP_TABLE2:
return NSI_TCP_ALL_TABLE;
default:
@@ -2920,6 +2923,11 @@ static DWORD tcp_table_size( ULONG family, ULONG table_class, DWORD row_count, D
return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]) :
FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
+ case TCP_TABLE2:
+ *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW2) : sizeof(MIB_TCP6ROW2);
+ return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE2, table[row_count]) :
+ FIELD_OFFSET(MIB_TCP6TABLE2, table[row_count]);
+
default:
ERR( "unhandled class %u\n", table_class );
return 0;
@@ -2975,6 +2983,18 @@ static void tcp_row_fill( void *table, DWORD num, ULONG family, ULONG table_clas
memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
return;
}
+ case TCP_TABLE2:
+ {
+ MIB_TCPROW2 *row = ((MIB_TCPTABLE2 *)table)->table + num;
+ row->dwState = dyn->state;
+ row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
+ row->dwLocalPort = key->local.Ipv4.sin_port;
+ row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
+ row->dwRemotePort = key->remote.Ipv4.sin_port;
+ row->dwOwningPid = stat->pid;
+ row->dwOffloadState = 0; /* FIXME */
+ return;
+ }
default:
ERR( "Unknown class %d\n", table_class );
return;
@@ -3031,6 +3051,20 @@ static void tcp_row_fill( void *table, DWORD num, ULONG family, ULONG table_clas
memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
return;
}
+ case TCP_TABLE2:
+ {
+ MIB_TCP6ROW2 *row = ((MIB_TCP6TABLE2 *)table)->table + num;
+ memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
+ row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
+ row->dwLocalPort = key->local.Ipv6.sin6_port;
+ memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
+ row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
+ row->dwRemotePort = key->remote.Ipv6.sin6_port;
+ row->State = dyn->state;
+ row->dwOwningPid = stat->pid;
+ row->dwOffloadState = 0; /* FIXME */
+ return;
+ }
default:
ERR( "Unknown class %d\n", table_class );
return;
@@ -3079,6 +3113,12 @@ static int tcp6_row_owner_cmp( const void *a, const void *b )
return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
}
+/*************************************************************************************
+ * get_extended_tcp_table
+ *
+ * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
+ * corresponding to GetTcp(6)Table2()
+ */
DWORD get_extended_tcp_table( void *table, DWORD *size, BOOL sort, ULONG family, ULONG table_class )
{
DWORD err, count, needed, i, num = 0, row_size = 0;
@@ -3182,6 +3222,24 @@ ULONG WINAPI GetTcp6Table( MIB_TCP6TABLE *table, ULONG *size, BOOL sort )
return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE_BASIC_ALL );
}
+/******************************************************************
+ * GetTcpTable2 (IPHLPAPI.@)
+ */
+ULONG WINAPI GetTcpTable2( MIB_TCPTABLE2 *table, ULONG *size, BOOL sort )
+{
+ TRACE( "table %p, size %p, sort %d\n", table, size, sort );
+ return get_extended_tcp_table( table, size, sort, WS_AF_INET, TCP_TABLE2 );
+}
+
+/******************************************************************
+ * GetTcp6Table2 (IPHLPAPI.@)
+ */
+ULONG WINAPI GetTcp6Table2( MIB_TCP6TABLE2 *table, ULONG *size, BOOL sort )
+{
+ TRACE( "table %p, size %p, sort %d\n", table, size, sort );
+ return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE2 );
+}
+
/******************************************************************
* GetUdpTable (IPHLPAPI.@)
*
@@ -3812,24 +3870,6 @@ DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYP
return ERROR_CALL_NOT_IMPLEMENTED;
}
-/******************************************************************
- * GetTcpTable2 (IPHLPAPI.@)
- */
-ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
-{
- FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table, size, order);
- return ERROR_NOT_SUPPORTED;
-}
-
-/******************************************************************
- * GetTcp6Table2 (IPHLPAPI.@)
- */
-ULONG WINAPI GetTcp6Table2(PMIB_TCP6TABLE2 table, PULONG size, BOOL order)
-{
- FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table, size, order);
- return ERROR_NOT_SUPPORTED;
-}
-
/******************************************************************
* ConvertInterfaceAliasToLuid (IPHLPAPI.@)
*/
--
2.23.0
1
0
17 Aug '21
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/iphlpapi_main.c | 350 ++++++++++++++++++++++++++++------
1 file changed, 288 insertions(+), 62 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index b45bcc41724..5595088e093 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -2870,81 +2870,316 @@ DWORD WINAPI GetTcpStatisticsEx( MIB_TCPSTATS *stats, DWORD family )
return err;
}
+static DWORD tcp_table_id( ULONG table_class )
+{
+ switch (table_class)
+ {
+ case TCP_TABLE_BASIC_LISTENER:
+ case TCP_TABLE_OWNER_PID_LISTENER:
+ case TCP_TABLE_OWNER_MODULE_LISTENER:
+ return NSI_TCP_LISTEN_TABLE;
+
+ case TCP_TABLE_BASIC_CONNECTIONS:
+ case TCP_TABLE_OWNER_PID_CONNECTIONS:
+ case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
+ return NSI_TCP_ESTAB_TABLE;
+
+ case TCP_TABLE_BASIC_ALL:
+ case TCP_TABLE_OWNER_PID_ALL:
+ case TCP_TABLE_OWNER_MODULE_ALL:
+ return NSI_TCP_ALL_TABLE;
+
+ default:
+ ERR( "unhandled class %u\n", table_class );
+ return ~0u;
+ }
+}
+
+static DWORD tcp_table_size( ULONG family, ULONG table_class, DWORD row_count, DWORD *row_size )
+{
+ switch (table_class)
+ {
+ case TCP_TABLE_BASIC_LISTENER:
+ case TCP_TABLE_BASIC_CONNECTIONS:
+ case TCP_TABLE_BASIC_ALL:
+ *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW) : sizeof(MIB_TCP6ROW);
+ return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE, table[row_count]) :
+ FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
+
+ case TCP_TABLE_OWNER_PID_LISTENER:
+ case TCP_TABLE_OWNER_PID_CONNECTIONS:
+ case TCP_TABLE_OWNER_PID_ALL:
+ *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW_OWNER_PID) : sizeof(MIB_TCP6ROW_OWNER_PID);
+ return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]) :
+ FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
+
+ case TCP_TABLE_OWNER_MODULE_LISTENER:
+ case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
+ case TCP_TABLE_OWNER_MODULE_ALL:
+ *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW_OWNER_MODULE) : sizeof(MIB_TCP6ROW_OWNER_MODULE);
+ return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]) :
+ FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
+
+ default:
+ ERR( "unhandled class %u\n", table_class );
+ return 0;
+ }
+}
+
+static void tcp_row_fill( void *table, DWORD num, ULONG family, ULONG table_class,
+ struct nsi_tcp_conn_key *key, struct nsi_tcp_conn_dynamic *dyn,
+ struct nsi_tcp_conn_static *stat )
+{
+ if (family == WS_AF_INET)
+ {
+ switch (table_class)
+ {
+ case TCP_TABLE_BASIC_LISTENER:
+ case TCP_TABLE_BASIC_CONNECTIONS:
+ case TCP_TABLE_BASIC_ALL:
+ {
+ MIB_TCPROW *row = ((MIB_TCPTABLE *)table)->table + num;
+ row->u.dwState = dyn->state;
+ row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
+ row->dwLocalPort = key->local.Ipv4.sin_port;
+ row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
+ row->dwRemotePort = key->remote.Ipv4.sin_port;
+ return;
+ }
+ case TCP_TABLE_OWNER_PID_LISTENER:
+ case TCP_TABLE_OWNER_PID_CONNECTIONS:
+ case TCP_TABLE_OWNER_PID_ALL:
+ {
+ MIB_TCPROW_OWNER_PID *row = ((MIB_TCPTABLE_OWNER_PID *)table)->table + num;
+ row->dwState = dyn->state;
+ row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
+ row->dwLocalPort = key->local.Ipv4.sin_port;
+ row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
+ row->dwRemotePort = key->remote.Ipv4.sin_port;
+ row->dwOwningPid = stat->pid;
+ return;
+ }
+ case TCP_TABLE_OWNER_MODULE_LISTENER:
+ case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
+ case TCP_TABLE_OWNER_MODULE_ALL:
+ {
+ MIB_TCPROW_OWNER_MODULE *row = ((MIB_TCPTABLE_OWNER_MODULE *)table)->table + num;
+ row->dwState = dyn->state;
+ row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
+ row->dwLocalPort = key->local.Ipv4.sin_port;
+ row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
+ row->dwRemotePort = key->remote.Ipv4.sin_port;
+ row->dwOwningPid = stat->pid;
+ row->liCreateTimestamp.QuadPart = stat->create_time;
+ row->OwningModuleInfo[0] = stat->mod_info;
+ memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
+ return;
+ }
+ default:
+ ERR( "Unknown class %d\n", table_class );
+ return;
+ }
+ }
+ else
+ {
+ switch (table_class)
+ {
+ case TCP_TABLE_BASIC_LISTENER:
+ case TCP_TABLE_BASIC_CONNECTIONS:
+ case TCP_TABLE_BASIC_ALL:
+ {
+ MIB_TCP6ROW *row = ((MIB_TCP6TABLE *)table)->table + num;
+ row->State = dyn->state;
+ memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
+ row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
+ row->dwLocalPort = key->local.Ipv6.sin6_port;
+ memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
+ row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
+ row->dwRemotePort = key->remote.Ipv6.sin6_port;
+ return;
+ }
+ case TCP_TABLE_OWNER_PID_LISTENER:
+ case TCP_TABLE_OWNER_PID_CONNECTIONS:
+ case TCP_TABLE_OWNER_PID_ALL:
+ {
+ MIB_TCP6ROW_OWNER_PID *row = ((MIB_TCP6TABLE_OWNER_PID *)table)->table + num;
+ memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
+ row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
+ row->dwLocalPort = key->local.Ipv6.sin6_port;
+ memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
+ row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
+ row->dwRemotePort = key->remote.Ipv6.sin6_port;
+ row->dwState = dyn->state;
+ row->dwOwningPid = stat->pid;
+ return;
+ }
+ case TCP_TABLE_OWNER_MODULE_LISTENER:
+ case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
+ case TCP_TABLE_OWNER_MODULE_ALL:
+ {
+ MIB_TCP6ROW_OWNER_MODULE *row = ((MIB_TCP6TABLE_OWNER_MODULE *)table)->table + num;
+ memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
+ row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
+ row->dwLocalPort = key->local.Ipv6.sin6_port;
+ memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
+ row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
+ row->dwRemotePort = key->remote.Ipv6.sin6_port;
+ row->dwState = dyn->state;
+ row->dwOwningPid = stat->pid;
+ row->liCreateTimestamp.QuadPart = stat->create_time;
+ row->OwningModuleInfo[0] = stat->mod_info;
+ memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
+ return;
+ }
+ default:
+ ERR( "Unknown class %d\n", table_class );
+ return;
+ }
+ }
+ ERR( "Unknown family %d\n", family );
+}
+
+static int tcp_row_cmp( const void *a, const void *b )
+{
+ const MIB_TCPROW *rowA = a;
+ const MIB_TCPROW *rowB = b;
+ int ret;
+
+ if ((ret = RtlUlongByteSwap( rowA->dwLocalAddr ) - RtlUlongByteSwap( rowB->dwLocalAddr )) != 0) return ret;
+ if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
+ if ((ret = RtlUlongByteSwap( rowA->dwRemoteAddr ) - RtlUlongByteSwap( rowB->dwRemoteAddr )) != 0) return ret;
+ return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
+}
+
+static int tcp6_row_basic_cmp( const void *a, const void *b )
+{
+ const MIB_TCP6ROW *rowA = a;
+ const MIB_TCP6ROW *rowB = b;
+ int ret;
+
+ if ((ret = memcmp( &rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr) )) != 0) return ret;
+ if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
+ if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
+ if ((ret = memcmp( &rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr) )) != 0) return ret;
+ if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
+ return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
+}
+
+static int tcp6_row_owner_cmp( const void *a, const void *b )
+{
+ const MIB_TCP6ROW_OWNER_PID *rowA = a;
+ const MIB_TCP6ROW_OWNER_PID *rowB = b;
+ int ret;
+
+ if ((ret = memcmp( &rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr) )) != 0) return ret;
+ if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
+ if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
+ if ((ret = memcmp( &rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr) )) != 0) return ret;
+ if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
+ return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
+}
+
+DWORD get_extended_tcp_table( void *table, DWORD *size, BOOL sort, ULONG family, ULONG table_class )
+{
+ DWORD err, count, needed, i, num = 0, row_size = 0;
+ struct nsi_tcp_conn_key *key;
+ struct nsi_tcp_conn_dynamic *dyn;
+ struct nsi_tcp_conn_static *stat;
+
+ if (!size) return ERROR_INVALID_PARAMETER;
+
+ err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, tcp_table_id( table_class ), (void **)&key, sizeof(*key),
+ NULL, 0, (void **)&dyn, sizeof(*dyn),
+ (void **)&stat, sizeof(*stat), &count, 0 );
+ if (err) return err;
+
+ for (i = 0; i < count; i++)
+ if (key[i].local.si_family == family)
+ num++;
+
+ needed = tcp_table_size( family, table_class, num, &row_size );
+ if (!table || *size < needed)
+ {
+ *size = needed;
+ err = ERROR_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ *size = needed;
+ *(DWORD *)table = num;
+ num = 0;
+ for (i = 0; i < count; i++)
+ {
+ if (key[i].local.si_family != family) continue;
+ tcp_row_fill( table, num++, family, table_class, key + i, dyn + i, stat + i );
+ }
+ }
+
+ if (!err && sort)
+ {
+ int (*fn)(const void *, const void *);
+ DWORD offset;
+
+ if (family == WS_AF_INET) fn = tcp_row_cmp;
+ else if (row_size == sizeof(MIB_TCP6ROW)) fn = tcp6_row_basic_cmp;
+ else fn = tcp6_row_owner_cmp;
+
+ offset = tcp_table_size( family, table_class, 0, &row_size );
+ qsort( (BYTE *)table + offset, num, row_size, fn );
+ }
+
+ NsiFreeTable( key, NULL, dyn, stat );
+ return err;
+}
+
+/******************************************************************
+ * GetExtendedTcpTable (IPHLPAPI.@)
+ */
+DWORD WINAPI GetExtendedTcpTable( void *table, DWORD *size, BOOL sort, ULONG family,
+ TCP_TABLE_CLASS table_class, ULONG reserved )
+{
+ TRACE( "table %p, size %p, sort %d, family %u, class %u, reserved %u\n",
+ table, size, sort, family, table_class, reserved );
+
+ if (!ip_module_id( family )) return ERROR_INVALID_PARAMETER;
+ return get_extended_tcp_table( table, size, sort, family, table_class );
+}
+
/******************************************************************
* GetTcpTable (IPHLPAPI.@)
*
* Get the table of active TCP connections.
*
* PARAMS
- * pTcpTable [Out] buffer for TCP connections table
- * pdwSize [In/Out] length of output buffer
- * bOrder [In] whether to order the table
+ * table [Out] buffer for TCP connections table
+ * size [In/Out] length of output buffer
+ * sort [In] whether to order the table
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* NOTES
- * If pdwSize is less than required, the function will return
- * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
+ * If size is less than required, the function will return
+ * ERROR_INSUFFICIENT_BUFFER, and *size will be set to
* the required byte size.
- * If bOrder is true, the returned table will be sorted, first by
+ * If sort is true, the returned table will be sorted, first by
* local address and port number, then by remote address and port
* number.
*/
-DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
+DWORD WINAPI GetTcpTable( MIB_TCPTABLE *table, DWORD *size, BOOL sort )
{
- TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
- return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, WS_AF_INET, TCP_TABLE_BASIC_ALL, 0);
+ TRACE( "table %p, size %p, sort %d\n", table, size, sort );
+ return get_extended_tcp_table( table, size, sort, WS_AF_INET, TCP_TABLE_BASIC_ALL );
}
/******************************************************************
- * GetExtendedTcpTable (IPHLPAPI.@)
+ * GetTcp6Table (IPHLPAPI.@)
*/
-DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
- ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
+ULONG WINAPI GetTcp6Table( MIB_TCP6TABLE *table, ULONG *size, BOOL sort )
{
- DWORD ret, size;
- void *table;
-
- TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
- pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
-
- if (!pdwSize) return ERROR_INVALID_PARAMETER;
-
- if (TableClass >= TCP_TABLE_OWNER_MODULE_LISTENER)
- FIXME("module classes not fully supported\n");
-
- switch (ulAf)
- {
- case WS_AF_INET:
- ret = build_tcp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
- break;
-
- case WS_AF_INET6:
- ret = build_tcp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
- break;
-
- default:
- FIXME("ulAf = %u not supported\n", ulAf);
- ret = ERROR_NOT_SUPPORTED;
- }
-
- if (ret)
- return ret;
-
- if (!pTcpTable || *pdwSize < size)
- {
- *pdwSize = size;
- ret = ERROR_INSUFFICIENT_BUFFER;
- }
- else
- {
- *pdwSize = size;
- memcpy(pTcpTable, table, size);
- }
- HeapFree(GetProcessHeap(), 0, table);
- return ret;
+ TRACE( "table %p, size %p, sort %d\n", table, size, sort );
+ return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE_BASIC_ALL );
}
/******************************************************************
@@ -3586,15 +3821,6 @@ ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
return ERROR_NOT_SUPPORTED;
}
-/******************************************************************
- * GetTcp6Table (IPHLPAPI.@)
- */
-ULONG WINAPI GetTcp6Table(PMIB_TCP6TABLE table, PULONG size, BOOL order)
-{
- TRACE("(table %p, size %p, order %d)\n", table, size, order);
- return GetExtendedTcpTable(table, size, order, WS_AF_INET6, TCP_TABLE_BASIC_ALL, 0);
-}
-
/******************************************************************
* GetTcp6Table2 (IPHLPAPI.@)
*/
--
2.23.0
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/nsi/tests/nsi.c | 2 -
dlls/nsiproxy.sys/tcp.c | 207 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 203 insertions(+), 6 deletions(-)
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index f8ba9aff5da..b5352e2b121 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -906,7 +906,6 @@ static void test_tcp_tables( int family, int table_type )
ok( unstable( row->dwRemotePort == keys[i].remote.Ipv4.sin_port ), "%d vs %d\n",
row->dwRemotePort, keys[i].remote.Ipv4.sin_port );
ok( unstable( row->dwState == dyn->state ), "%x vs %x\n", row->dwState, dyn->state );
-todo_wine_if( !unstable(0) && row->dwOwningPid )
ok( unstable( row->dwOwningPid == stat[i].pid ), "%x vs %x\n", row->dwOwningPid, stat[i].pid );
ok( unstable( row->liCreateTimestamp.QuadPart == stat[i].create_time ), "mismatch\n" );
ok( unstable( row->OwningModuleInfo[0] == stat[i].mod_info ), "mismatch\n");
@@ -927,7 +926,6 @@ todo_wine_if( !unstable(0) && row->dwOwningPid )
ok( unstable( row6->dwRemotePort == keys[i].remote.Ipv6.sin6_port ), "%d vs %d\n",
row6->dwRemotePort, keys[i].remote.Ipv6.sin6_port );
ok( unstable( row6->dwState == dyn->state ), "%x vs %x\n", row6->dwState, dyn->state );
-todo_wine_if( !unstable(0) && row6->dwOwningPid )
ok( unstable( row6->dwOwningPid == stat[i].pid ), "%x vs %x\n", row6->dwOwningPid, stat[i].pid );
ok( unstable( row6->liCreateTimestamp.QuadPart == stat[i].create_time ), "mismatch\n" );
ok( unstable( row6->OwningModuleInfo[0] == stat[i].mod_info ), "mismatch\n");
diff --git a/dlls/nsiproxy.sys/tcp.c b/dlls/nsiproxy.sys/tcp.c
index 5b4a4b68765..27f85ee3104 100644
--- a/dlls/nsiproxy.sys/tcp.c
+++ b/dlls/nsiproxy.sys/tcp.c
@@ -26,6 +26,14 @@
#include <sys/types.h>
#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
@@ -58,6 +66,14 @@
#include <ifaddrs.h>
#endif
+#ifdef HAVE_LIBPROCSTAT_H
+#include <libprocstat.h>
+#endif
+
+#ifdef HAVE_LIBPROC_H
+#include <libproc.h>
+#endif
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
@@ -72,6 +88,7 @@
#include "wine/heap.h"
#include "wine/nsi.h"
#include "wine/debug.h"
+#include "wine/server.h"
#include "nsiproxy_private.h"
@@ -326,6 +343,184 @@ static DWORD find_ipv6_addr_scope( const IN6_ADDR *addr, const struct ipv6_addr_
return -1;
}
+struct pid_map
+{
+ unsigned int pid;
+ unsigned int unix_pid;
+};
+
+static struct pid_map *get_pid_map( unsigned int *num_entries )
+{
+ struct pid_map *map;
+ unsigned int i = 0, buffer_len = 4096, process_count, pos = 0;
+ NTSTATUS ret;
+ char *buffer = NULL, *new_buffer;
+
+ if (!(buffer = heap_alloc( buffer_len ))) return NULL;
+
+ for (;;)
+ {
+ SERVER_START_REQ( list_processes )
+ {
+ wine_server_set_reply( req, buffer, buffer_len );
+ ret = wine_server_call( req );
+ buffer_len = reply->info_size;
+ process_count = reply->process_count;
+ }
+ SERVER_END_REQ;
+
+ if (ret != STATUS_INFO_LENGTH_MISMATCH) break;
+
+ if (!(new_buffer = heap_realloc( buffer, buffer_len )))
+ {
+ heap_free( buffer );
+ return NULL;
+ }
+ buffer = new_buffer;
+ }
+
+ if (!(map = heap_alloc( process_count * sizeof(*map) )))
+ {
+ heap_free( buffer );
+ return NULL;
+ }
+
+ for (i = 0; i < process_count; ++i)
+ {
+ const struct process_info *process;
+
+ pos = (pos + 7) & ~7;
+ process = (const struct process_info *)(buffer + pos);
+
+ map[i].pid = process->pid;
+ map[i].unix_pid = process->unix_pid;
+
+ pos += sizeof(struct process_info) + process->name_len;
+ pos = (pos + 7) & ~7;
+ pos += process->thread_count * sizeof(struct thread_info);
+ }
+
+ heap_free( buffer );
+ *num_entries = process_count;
+ return map;
+}
+
+static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, UINT_PTR inode )
+{
+#ifdef __linux__
+ unsigned int i, len_socket;
+ char socket[32];
+
+ sprintf( socket, "socket:[%lu]", inode );
+ len_socket = strlen( socket );
+ for (i = 0; i < num_entries; i++)
+ {
+ char dir[32];
+ struct dirent *dirent;
+ DIR *dirfd;
+
+ sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
+ if ((dirfd = opendir( dir )))
+ {
+ while ((dirent = readdir( dirfd )))
+ {
+ char link[sizeof(dirent->d_name) + 32], name[32];
+ int len;
+
+ sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
+ if ((len = readlink( link, name, sizeof(name) - 1 )) > 0) name[len] = 0;
+ if (len == len_socket && !strcmp( socket, name ))
+ {
+ closedir( dirfd );
+ return map[i].pid;
+ }
+ }
+ closedir( dirfd );
+ }
+ }
+ return 0;
+#elif defined(HAVE_LIBPROCSTAT)
+ struct procstat *pstat;
+ struct kinfo_proc *proc;
+ struct filestat_list *fds;
+ struct filestat *fd;
+ struct sockstat sock;
+ unsigned int i, proc_count;
+
+ pstat = procstat_open_sysctl();
+ if (!pstat) return 0;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ proc = procstat_getprocs( pstat, KERN_PROC_PID, map[i].unix_pid, &proc_count );
+ if (!proc || proc_count < 1) continue;
+
+ fds = procstat_getfiles( pstat, proc, 0 );
+ if (!fds)
+ {
+ procstat_freeprocs( pstat, proc );
+ continue;
+ }
+
+ STAILQ_FOREACH( fd, fds, next )
+ {
+ char errbuf[_POSIX2_LINE_MAX];
+
+ if (fd->fs_type != PS_FST_TYPE_SOCKET) continue;
+
+ procstat_get_socket_info( pstat, fd, &sock, errbuf );
+
+ if (sock.so_pcb == inode)
+ {
+ procstat_freefiles( pstat, fds );
+ procstat_freeprocs( pstat, proc );
+ procstat_close( pstat );
+ return map[i].pid;
+ }
+ }
+
+ procstat_freefiles( pstat, fds );
+ procstat_freeprocs( pstat, proc );
+ }
+
+ procstat_close( pstat );
+ return 0;
+#elif defined(HAVE_PROC_PIDINFO)
+ struct proc_fdinfo *fds;
+ struct socket_fdinfo sock;
+ unsigned int i, j, n;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ int fd_len = proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, NULL, 0 );
+ if (fd_len <= 0) continue;
+
+ fds = heap_alloc( fd_len );
+ if (!fds) continue;
+
+ proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, fds, fd_len );
+ n = fd_len / sizeof(struct proc_fdinfo);
+ for (j = 0; j < n; j++)
+ {
+ if (fds[j].proc_fdtype != PROX_FDTYPE_SOCKET) continue;
+
+ proc_pidfdinfo( map[i].unix_pid, fds[j].proc_fd, PROC_PIDFDSOCKETINFO, &sock, sizeof(sock) );
+ if (sock.psi.soi_pcb == inode)
+ {
+ heap_free( fds );
+ return map[i].pid;
+ }
+ }
+
+ heap_free( fds );
+ }
+ return 0;
+#else
+ FIXME( "not implemented\n" );
+ return 0;
+#endif
+}
+
static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *key_data, DWORD key_size,
void *rw, DWORD rw_size,
struct nsi_tcp_conn_dynamic *dynamic_data, DWORD dynamic_size,
@@ -338,7 +533,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
struct nsi_tcp_conn_dynamic dyn;
struct nsi_tcp_conn_static stat;
struct ipv6_addr_scope *addr_scopes = NULL;
- unsigned int addr_scopes_size = 0;
+ unsigned int addr_scopes_size = 0, pid_map_size = 0;
+ struct pid_map *pid_map = NULL;
#ifdef __linux__
{
@@ -351,6 +547,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
memset( &key, 0, sizeof(key) );
memset( &dyn, 0, sizeof(dyn) );
memset( &stat, 0, sizeof(stat) );
+ pid_map = get_pid_map( &pid_map_size );
/* skip header line */
ptr = fgets( buf, sizeof(buf), fp );
@@ -368,7 +565,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.local.Ipv4.sin_port = htons( key.local.Ipv4.sin_port );
key.remote.Ipv4.sin_port = htons( key.remote.Ipv4.sin_port );
- stat.pid = 0; /* FIXME */
+ stat.pid = find_owning_pid( pid_map, pid_map_size, inode );
stat.create_time = 0; /* FIXME */
stat.mod_info = 0; /* FIXME */
@@ -412,7 +609,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.remote.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.remote.Ipv6.sin6_addr, addr_scopes,
addr_scopes_size );
- stat.pid = 0; /* FIXME */
+ stat.pid = find_owning_pid( pid_map, pid_map_size, inode );
stat.create_time = 0; /* FIXME */
stat.mod_info = 0; /* FIXME */
@@ -459,6 +656,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
if (len <= sizeof(struct xinpgen)) goto err;
addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
+ pid_map = get_pid_map( &pid_map_size );
orig_xig = (struct xinpgen *)buf;
xig = orig_xig;
@@ -517,7 +715,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
addr_scopes_size );
}
- stat.pid = 0; /* FIXME */
+ stat.pid = find_owning_pid( pid_map, pid_map_size, (UINT_PTR)sock->so_pcb );
stat.create_time = 0; /* FIXME */
stat.mod_info = 0; /* FIXME */
@@ -540,6 +738,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
if (!want_data || num <= *count) *count = num;
else status = STATUS_MORE_ENTRIES;
+ heap_free( pid_map );
heap_free( addr_scopes );
return status;
}
--
2.23.0
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/nsi/tests/nsi.c | 2 -
dlls/nsiproxy.sys/tcp.c | 136 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 132 insertions(+), 6 deletions(-)
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index 8e19df83684..f8ba9aff5da 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -916,14 +916,12 @@ todo_wine_if( !unstable(0) && row->dwOwningPid )
{
ok( unstable( !memcmp( row6->ucLocalAddr, keys[i].local.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ) ),
"mismatch\n" );
-todo_wine_if( !unstable(0) && row6->dwLocalScopeId )
ok( unstable( row6->dwLocalScopeId == keys[i].local.Ipv6.sin6_scope_id ), "%x vs %x\n",
row6->dwLocalScopeId, keys[i].local.Ipv6.sin6_scope_id );
ok( unstable( row6->dwLocalPort == keys[i].local.Ipv6.sin6_port ), "%d vs %d\n",
row6->dwLocalPort, keys[i].local.Ipv6.sin6_port );
ok( unstable( !memcmp( row6->ucRemoteAddr, keys[i].remote.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ) ),
"mismatch\n" );
-todo_wine_if( !unstable(0) && row6->dwRemoteScopeId )
ok( unstable( row6->dwRemoteScopeId == keys[i].remote.Ipv6.sin6_scope_id ), "%x vs %x\n",
row6->dwRemoteScopeId, keys[i].remote.Ipv6.sin6_scope_id );
ok( unstable( row6->dwRemotePort == keys[i].remote.Ipv6.sin6_port ), "%d vs %d\n",
diff --git a/dlls/nsiproxy.sys/tcp.c b/dlls/nsiproxy.sys/tcp.c
index 710aed5d6c3..5b4a4b68765 100644
--- a/dlls/nsiproxy.sys/tcp.c
+++ b/dlls/nsiproxy.sys/tcp.c
@@ -54,6 +54,10 @@
#include <sys/sysctl.h>
#endif
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
@@ -209,6 +213,119 @@ static inline MIB_TCP_STATE tcp_state_to_mib_state( int state )
}
}
+struct ipv6_addr_scope
+{
+ IN6_ADDR addr;
+ DWORD scope;
+};
+
+static struct ipv6_addr_scope *get_ipv6_addr_scope_table( unsigned int *size )
+{
+ struct ipv6_addr_scope *table = NULL;
+ unsigned int table_size = 0, num = 0;
+
+#ifdef __linux__
+ {
+ char buf[512], *ptr;
+ FILE *fp;
+
+ if (!(fp = fopen( "/proc/net/if_inet6", "r" ))) goto failed;
+
+ while ((ptr = fgets( buf, sizeof(buf), fp )))
+ {
+ WORD a[8];
+ DWORD scope;
+ struct ipv6_addr_scope *entry;
+ unsigned int i;
+
+ if (sscanf( ptr, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*s %*s %x",
+ a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, &scope ) != 9)
+ continue;
+
+ if (++num > table_size)
+ {
+ if (!table_size) table_size = 4;
+ else table_size *= 2;
+ if (!(table = heap_realloc( table, table_size * sizeof(table[0]) )))
+ {
+ fclose( fp );
+ goto failed;
+ }
+ }
+
+ entry = table + num - 1;
+ for (i = 0; i < 8; i++)
+ entry->addr.u.Word[i] = htons( a[i] );
+ entry->scope = htons( scope );
+ }
+
+ fclose( fp );
+ }
+#elif defined(HAVE_GETIFADDRS)
+ {
+ struct ifaddrs *addrs, *cur;
+
+ if (getifaddrs( &addrs ) == -1) goto failed;
+
+ for (cur = addrs; cur; cur = cur->ifa_next)
+ {
+ struct sockaddr_in6 *sin6;
+ struct ipv6_addr_scope *entry;
+
+ if (cur->ifa_addr->sa_family != AF_INET6) continue;
+
+ if (++num > table_size)
+ {
+ if (!table_size) table_size = 4;
+ else table_size *= 2;
+ if (!(table = heap_realloc( table, table_size * sizeof(table[0]) )))
+ {
+ freeifaddrs( addrs );
+ goto failed;
+ }
+ }
+
+ sin6 = (struct sockaddr_in6 *)cur->ifa_addr;
+ entry = table + num - 1;
+ memcpy( &entry->addr, &sin6->sin6_addr, sizeof(entry->addr) );
+ entry->scope = sin6->sin6_scope_id;
+ }
+
+ freeifaddrs( addrs );
+ }
+#else
+ FIXME( "not implemented\n" );
+ goto failed;
+#endif
+
+ *size = num;
+ return table;
+
+failed:
+ heap_free( table );
+ return NULL;
+}
+
+static DWORD find_ipv6_addr_scope( const IN6_ADDR *addr, const struct ipv6_addr_scope *table, unsigned int size )
+{
+ const BYTE multicast_scope_mask = 0x0F;
+ const BYTE multicast_scope_shift = 0;
+ unsigned int i;
+
+ if (WS_IN6_IS_ADDR_UNSPECIFIED( addr )) return 0;
+
+ if (WS_IN6_IS_ADDR_MULTICAST( addr ))
+ return htons( (addr->u.Byte[1] & multicast_scope_mask) >> multicast_scope_shift );
+
+ if (!table) return -1;
+
+ for (i = 0; i < size; i++)
+ if (!memcmp( &table[i].addr, addr, sizeof(table[i].addr) ))
+ return table[i].scope;
+
+ return -1;
+}
+
static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *key_data, DWORD key_size,
void *rw, DWORD rw_size,
struct nsi_tcp_conn_dynamic *dynamic_data, DWORD dynamic_size,
@@ -220,6 +337,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
struct nsi_tcp_conn_key key;
struct nsi_tcp_conn_dynamic dyn;
struct nsi_tcp_conn_static stat;
+ struct ipv6_addr_scope *addr_scopes = NULL;
+ unsigned int addr_scopes_size = 0;
#ifdef __linux__
{
@@ -269,6 +388,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
memset( &dyn, 0, sizeof(dyn) );
memset( &stat, 0, sizeof(stat) );
+ addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
+
/* skip header line */
ptr = fgets( buf, sizeof(buf), fp );
while ((ptr = fgets( buf, sizeof(buf), fp )))
@@ -286,8 +407,10 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.local.Ipv6.sin6_family = key.remote.Ipv6.sin6_family = WS_AF_INET6;
key.local.Ipv6.sin6_port = htons( key.local.Ipv6.sin6_port );
key.remote.Ipv6.sin6_port = htons( key.remote.Ipv6.sin6_port );
- key.local.Ipv6.sin6_scope_id = 0; /* FIXME */
- key.remote.Ipv6.sin6_scope_id = 0; /* FIXME */
+ key.local.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.local.Ipv6.sin6_addr, addr_scopes,
+ addr_scopes_size );
+ key.remote.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.remote.Ipv6.sin6_addr, addr_scopes,
+ addr_scopes_size );
stat.pid = 0; /* FIXME */
stat.create_time = 0; /* FIXME */
@@ -335,6 +458,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
/* Might be nothing here; first entry is just a header it seems */
if (len <= sizeof(struct xinpgen)) goto err;
+ addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
+
orig_xig = (struct xinpgen *)buf;
xig = orig_xig;
@@ -384,10 +509,12 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.local.Ipv6.sin6_family = key.remote.Ipv6.sin6_family = WS_AF_INET6;
memcpy( &key.local.Ipv6.sin6_addr, &in->in6p_laddr, sizeof(in->in6p_laddr) );
key.local.Ipv6.sin6_port = in->inp_lport;
+ key.local.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.local.Ipv6.sin6_addr, addr_scopes,
+ addr_scopes_size );
memcpy( &key.remote.Ipv6.sin6_addr, &in->in6p_faddr, sizeof(in->in6p_faddr) );
key.remote.Ipv6.sin6_port = in->inp_fport;
- key.local.Ipv6.sin6_scope_id = 0; /* FIXME */
- key.remote.Ipv6.sin6_scope_id = 0; /* FIXME */
+ key.remote.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.remote.Ipv6.sin6_addr, addr_scopes,
+ addr_scopes_size );
}
stat.pid = 0; /* FIXME */
@@ -413,6 +540,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
if (!want_data || num <= *count) *count = num;
else status = STATUS_MORE_ENTRIES;
+ heap_free( addr_scopes );
return status;
}
--
2.23.0
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/nsi/tests/nsi.c | 101 ++++++++++++++
dlls/nsiproxy.sys/tcp.c | 302 ++++++++++++++++++++++++++++++++++++++++
include/wine/nsi.h | 25 ++++
3 files changed, 428 insertions(+)
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index 33b4e9e6d97..8e19df83684 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -848,6 +848,101 @@ static void test_tcp_stats( int family )
winetest_pop_context();
}
+static void test_tcp_tables( int family, int table_type )
+{
+ DWORD dyn_sizes[] = { FIELD_OFFSET(struct nsi_tcp_conn_dynamic, unk[2]), sizeof(struct nsi_tcp_conn_dynamic) };
+ DWORD i, err, count, table_num, dyn_size, size;
+ struct nsi_tcp_conn_key *keys;
+ struct nsi_tcp_conn_dynamic *dyn_tbl, *dyn;
+ struct nsi_tcp_conn_static *stat;
+ MIB_TCPTABLE_OWNER_MODULE *table;
+ MIB_TCP6TABLE_OWNER_MODULE *table6;
+ MIB_TCPROW_OWNER_MODULE *row;
+ MIB_TCP6ROW_OWNER_MODULE *row6;
+
+ winetest_push_context( "%s: %d", family == AF_INET ? "AF_INET" : "AF_INET6", table_type );
+
+ switch (table_type)
+ {
+ case TCP_TABLE_OWNER_MODULE_ALL: table_num = 3; break;
+ case TCP_TABLE_OWNER_MODULE_CONNECTIONS: table_num = 4; break;
+ case TCP_TABLE_OWNER_MODULE_LISTENER: table_num = 5; break;
+ default: return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dyn_sizes); i++)
+ {
+ err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, table_num, (void **)&keys, sizeof(*keys), NULL, 0,
+ (void **)&dyn_tbl, dyn_sizes[i], (void **)&stat, sizeof(*stat), &count, 0 );
+ if (!err) break;
+ }
+ ok( !err, "got %d\n", err );
+ dyn_size = dyn_sizes[i];
+
+ size = 0;
+ err = GetExtendedTcpTable( NULL, &size, 0, family, table_type, 0 );
+ size *= 2;
+ table = malloc( size );
+ table6 = (MIB_TCP6TABLE_OWNER_MODULE *)table;
+ err = GetExtendedTcpTable( table, &size, 0, family, table_type, 0 );
+ ok( !err, "got %d\n", err );
+
+ row = table->table;
+ row6 = table6->table;
+
+ for (i = 0; i < count; i++)
+ {
+ dyn = (struct nsi_tcp_conn_dynamic *)((BYTE *)dyn_tbl + i * dyn_size);
+ if (keys[i].local.si_family != family) continue;
+
+ if (family == AF_INET)
+ {
+ ok( unstable( row->dwLocalAddr == keys[i].local.Ipv4.sin_addr.s_addr ), "%08x vs %08x\n",
+ row->dwLocalAddr, keys[i].local.Ipv4.sin_addr.s_addr );
+ ok( unstable( row->dwLocalPort == keys[i].local.Ipv4.sin_port ), "%d vs %d\n",
+ row->dwLocalPort, keys[i].local.Ipv4.sin_port );
+ ok( unstable( row->dwRemoteAddr == keys[i].remote.Ipv4.sin_addr.s_addr ), "%08x vs %08x\n",
+ row->dwRemoteAddr, keys[i].remote.Ipv4.sin_addr.s_addr );
+ ok( unstable( row->dwRemotePort == keys[i].remote.Ipv4.sin_port ), "%d vs %d\n",
+ row->dwRemotePort, keys[i].remote.Ipv4.sin_port );
+ ok( unstable( row->dwState == dyn->state ), "%x vs %x\n", row->dwState, dyn->state );
+todo_wine_if( !unstable(0) && row->dwOwningPid )
+ ok( unstable( row->dwOwningPid == stat[i].pid ), "%x vs %x\n", row->dwOwningPid, stat[i].pid );
+ ok( unstable( row->liCreateTimestamp.QuadPart == stat[i].create_time ), "mismatch\n" );
+ ok( unstable( row->OwningModuleInfo[0] == stat[i].mod_info ), "mismatch\n");
+ row++;
+ }
+ else if (family == AF_INET6)
+ {
+ ok( unstable( !memcmp( row6->ucLocalAddr, keys[i].local.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ) ),
+ "mismatch\n" );
+todo_wine_if( !unstable(0) && row6->dwLocalScopeId )
+ ok( unstable( row6->dwLocalScopeId == keys[i].local.Ipv6.sin6_scope_id ), "%x vs %x\n",
+ row6->dwLocalScopeId, keys[i].local.Ipv6.sin6_scope_id );
+ ok( unstable( row6->dwLocalPort == keys[i].local.Ipv6.sin6_port ), "%d vs %d\n",
+ row6->dwLocalPort, keys[i].local.Ipv6.sin6_port );
+ ok( unstable( !memcmp( row6->ucRemoteAddr, keys[i].remote.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ) ),
+ "mismatch\n" );
+todo_wine_if( !unstable(0) && row6->dwRemoteScopeId )
+ ok( unstable( row6->dwRemoteScopeId == keys[i].remote.Ipv6.sin6_scope_id ), "%x vs %x\n",
+ row6->dwRemoteScopeId, keys[i].remote.Ipv6.sin6_scope_id );
+ ok( unstable( row6->dwRemotePort == keys[i].remote.Ipv6.sin6_port ), "%d vs %d\n",
+ row6->dwRemotePort, keys[i].remote.Ipv6.sin6_port );
+ ok( unstable( row6->dwState == dyn->state ), "%x vs %x\n", row6->dwState, dyn->state );
+todo_wine_if( !unstable(0) && row6->dwOwningPid )
+ ok( unstable( row6->dwOwningPid == stat[i].pid ), "%x vs %x\n", row6->dwOwningPid, stat[i].pid );
+ ok( unstable( row6->liCreateTimestamp.QuadPart == stat[i].create_time ), "mismatch\n" );
+ ok( unstable( row6->OwningModuleInfo[0] == stat[i].mod_info ), "mismatch\n");
+ row6++;
+ }
+
+ }
+ free( table );
+ NsiFreeTable( keys, NULL, dyn_tbl, stat );
+ winetest_pop_context();
+}
+
+
START_TEST( nsi )
{
test_nsi_api();
@@ -870,4 +965,10 @@ START_TEST( nsi )
test_tcp_stats( AF_INET );
test_tcp_stats( AF_INET6 );
+ test_tcp_tables( AF_INET, TCP_TABLE_OWNER_MODULE_ALL );
+ test_tcp_tables( AF_INET, TCP_TABLE_OWNER_MODULE_CONNECTIONS );
+ test_tcp_tables( AF_INET, TCP_TABLE_OWNER_MODULE_LISTENER );
+ test_tcp_tables( AF_INET6, TCP_TABLE_OWNER_MODULE_ALL );
+ test_tcp_tables( AF_INET6, TCP_TABLE_OWNER_MODULE_CONNECTIONS );
+ test_tcp_tables( AF_INET6, TCP_TABLE_OWNER_MODULE_LISTENER );
}
diff --git a/dlls/nsiproxy.sys/tcp.c b/dlls/nsiproxy.sys/tcp.c
index 5fe7fcbd72e..710aed5d6c3 100644
--- a/dlls/nsiproxy.sys/tcp.c
+++ b/dlls/nsiproxy.sys/tcp.c
@@ -46,6 +46,10 @@
#include <netinet/tcp_var.h>
#endif
+#ifdef HAVE_NETINET_TCP_FSM_H
+#include <netinet/tcp_fsm.h>
+#endif
+
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
@@ -61,11 +65,26 @@
#include "netiodef.h"
#include "ws2ipdef.h"
#include "tcpmib.h"
+#include "wine/heap.h"
#include "wine/nsi.h"
#include "wine/debug.h"
#include "nsiproxy_private.h"
+#ifndef HAVE_NETINET_TCP_FSM_H
+#define TCPS_ESTABLISHED 1
+#define TCPS_SYN_SENT 2
+#define TCPS_SYN_RECEIVED 3
+#define TCPS_FIN_WAIT_1 4
+#define TCPS_FIN_WAIT_2 5
+#define TCPS_TIME_WAIT 6
+#define TCPS_CLOSED 7
+#define TCPS_CLOSE_WAIT 8
+#define TCPS_LAST_ACK 9
+#define TCPS_LISTEN 10
+#define TCPS_CLOSING 11
+#endif
+
WINE_DEFAULT_DEBUG_CHANNEL(nsi);
static NTSTATUS tcp_stats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
@@ -171,6 +190,265 @@ static NTSTATUS tcp_stats_get_all_parameters( const void *key, DWORD key_size, v
#endif
}
+static inline MIB_TCP_STATE tcp_state_to_mib_state( int state )
+{
+ switch (state)
+ {
+ case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
+ case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
+ case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
+ case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
+ case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
+ case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
+ case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
+ case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
+ case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
+ case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
+ default:
+ case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
+ }
+}
+
+static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *key_data, DWORD key_size,
+ void *rw, DWORD rw_size,
+ struct nsi_tcp_conn_dynamic *dynamic_data, DWORD dynamic_size,
+ struct nsi_tcp_conn_static *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ DWORD num = 0;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOL want_data = key_size || rw_size || dynamic_size || static_size;
+ struct nsi_tcp_conn_key key;
+ struct nsi_tcp_conn_dynamic dyn;
+ struct nsi_tcp_conn_static stat;
+
+#ifdef __linux__
+ {
+ FILE *fp;
+ char buf[512], *ptr;
+ int inode;
+
+ if (!(fp = fopen( "/proc/net/tcp", "r" ))) return ERROR_NOT_SUPPORTED;
+
+ memset( &key, 0, sizeof(key) );
+ memset( &dyn, 0, sizeof(dyn) );
+ memset( &stat, 0, sizeof(stat) );
+
+ /* skip header line */
+ ptr = fgets( buf, sizeof(buf), fp );
+ while ((ptr = fgets( buf, sizeof(buf), fp )))
+ {
+ if (sscanf( ptr, "%*x: %x:%hx %x:%hx %x %*s %*s %*s %*s %*s %d",
+ &key.local.Ipv4.sin_addr.WS_s_addr, &key.local.Ipv4.sin_port,
+ &key.remote.Ipv4.sin_addr.WS_s_addr, &key.remote.Ipv4.sin_port,
+ &dyn.state, &inode ) != 6)
+ continue;
+ dyn.state = tcp_state_to_mib_state( dyn.state );
+ if (filter && filter != dyn.state ) continue;
+
+ key.local.Ipv4.sin_family = key.remote.Ipv4.sin_family = WS_AF_INET;
+ key.local.Ipv4.sin_port = htons( key.local.Ipv4.sin_port );
+ key.remote.Ipv4.sin_port = htons( key.remote.Ipv4.sin_port );
+
+ stat.pid = 0; /* FIXME */
+ stat.create_time = 0; /* FIXME */
+ stat.mod_info = 0; /* FIXME */
+
+ if (num < *count)
+ {
+ if (key_data) *key_data++ = key;
+ if (dynamic_data) *dynamic_data++ = dyn;
+ if (static_data) *static_data++ = stat;
+ }
+ num++;
+ }
+ fclose( fp );
+
+ if ((fp = fopen( "/proc/net/tcp6", "r" )))
+ {
+ memset( &key, 0, sizeof(key) );
+ memset( &dyn, 0, sizeof(dyn) );
+ memset( &stat, 0, sizeof(stat) );
+
+ /* skip header line */
+ ptr = fgets( buf, sizeof(buf), fp );
+ while ((ptr = fgets( buf, sizeof(buf), fp )))
+ {
+ DWORD *local_addr = (DWORD *)&key.local.Ipv6.sin6_addr;
+ DWORD *remote_addr = (DWORD *)&key.remote.Ipv6.sin6_addr;
+
+ if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%hx %8x%8x%8x%8x:%hx %x %*s %*s %*s %*s %*s %*s %*s %d",
+ local_addr, local_addr + 1, local_addr + 2, local_addr + 3, &key.local.Ipv6.sin6_port,
+ remote_addr, remote_addr + 1, remote_addr + 2, remote_addr + 3, &key.remote.Ipv6.sin6_port,
+ &dyn.state, &inode ) != 12)
+ continue;
+ dyn.state = tcp_state_to_mib_state( dyn.state );
+ if (filter && filter != dyn.state ) continue;
+ key.local.Ipv6.sin6_family = key.remote.Ipv6.sin6_family = WS_AF_INET6;
+ key.local.Ipv6.sin6_port = htons( key.local.Ipv6.sin6_port );
+ key.remote.Ipv6.sin6_port = htons( key.remote.Ipv6.sin6_port );
+ key.local.Ipv6.sin6_scope_id = 0; /* FIXME */
+ key.remote.Ipv6.sin6_scope_id = 0; /* FIXME */
+
+ stat.pid = 0; /* FIXME */
+ stat.create_time = 0; /* FIXME */
+ stat.mod_info = 0; /* FIXME */
+
+ if (num < *count)
+ {
+ if (key_data) *key_data++ = key;
+ if (dynamic_data) *dynamic_data++ = dyn;
+ if (static_data) *static_data++ = stat;
+ }
+ num++;
+ }
+ fclose( fp );
+ }
+ }
+#elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_PCBLIST) && defined(HAVE_STRUCT_XINPGEN)
+ {
+ int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_PCBLIST };
+ size_t len = 0;
+ char *buf = NULL;
+ struct xinpgen *xig, *orig_xig;
+
+ if (sysctl( mib, ARRAY_SIZE(mib), NULL, &len, NULL, 0 ) < 0)
+ {
+ ERR( "Failure to read net.inet.tcp.pcblist via sysctl\n" );
+ status = STATUS_NOT_SUPPORTED;
+ goto err;
+ }
+
+ buf = heap_alloc( len );
+ if (!buf)
+ {
+ status = STATUS_NO_MEMORY;
+ goto err;
+ }
+
+ if (sysctl( mib, ARRAY_SIZE(mib), buf, &len, NULL, 0 ) < 0)
+ {
+ ERR( "Failure to read net.inet.tcp.pcblist via sysctl\n" );
+ status = STATUS_NOT_SUPPORTED;
+ goto err;
+ }
+
+ /* Might be nothing here; first entry is just a header it seems */
+ if (len <= sizeof(struct xinpgen)) goto err;
+
+ orig_xig = (struct xinpgen *)buf;
+ xig = orig_xig;
+
+ for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
+ xig->xig_len > sizeof(struct xinpgen);
+ xig = (struct xinpgen *)((char *)xig + xig->xig_len))
+ {
+#if __FreeBSD_version >= 1200026
+ struct xtcpcb *tcp = (struct xtcpcb *)xig;
+ struct xinpcb *in = &tcp->xt_inp;
+ struct xsocket *sock = &in->xi_socket;
+#else
+ struct tcpcb *tcp = &((struct xtcpcb *)xig)->xt_tp;
+ struct inpcb *in = &((struct xtcpcb *)xig)->xt_inp;
+ struct xsocket *sock = &((struct xtcpcb *)xig)->xt_socket;
+#endif
+ static const struct in6_addr zero;
+
+ /* Ignore sockets for other protocols */
+ if (sock->xso_protocol != IPPROTO_TCP) continue;
+
+ /* Ignore PCBs that were freed while generating the data */
+ if (in->inp_gencnt > orig_xig->xig_gen) continue;
+
+ /* we're only interested in IPv4 and IPV6 addresses */
+ if (!(in->inp_vflag & (INP_IPV4 | INP_IPV6))) continue;
+
+ /* If all 0's, skip it */
+ if (in->inp_vflag & INP_IPV4 && !in->inp_laddr.s_addr && !in->inp_lport &&
+ !in->inp_faddr.s_addr && !in->inp_fport) continue;
+ if (in->inp_vflag & INP_IPV6 && !memcmp( &in->in6p_laddr, &zero, sizeof(zero) ) && !in->inp_lport &&
+ !memcmp( &in->in6p_faddr, &zero, sizeof(zero) ) && !in->inp_fport) continue;
+
+ dyn.state = tcp_state_to_mib_state( tcp->t_state );
+ if (filter && filter != dyn.state ) continue;
+
+ if (in->inp_vflag & INP_IPV4)
+ {
+ key.local.Ipv4.sin_family = key.remote.Ipv4.sin_family = WS_AF_INET;
+ key.local.Ipv4.sin_addr.WS_s_addr = in->inp_laddr.s_addr;
+ key.local.Ipv4.sin_port = in->inp_lport;
+ key.remote.Ipv4.sin_addr.WS_s_addr = in->inp_faddr.s_addr;
+ key.remote.Ipv4.sin_port = in->inp_fport;
+ }
+ else
+ {
+ key.local.Ipv6.sin6_family = key.remote.Ipv6.sin6_family = WS_AF_INET6;
+ memcpy( &key.local.Ipv6.sin6_addr, &in->in6p_laddr, sizeof(in->in6p_laddr) );
+ key.local.Ipv6.sin6_port = in->inp_lport;
+ memcpy( &key.remote.Ipv6.sin6_addr, &in->in6p_faddr, sizeof(in->in6p_faddr) );
+ key.remote.Ipv6.sin6_port = in->inp_fport;
+ key.local.Ipv6.sin6_scope_id = 0; /* FIXME */
+ key.remote.Ipv6.sin6_scope_id = 0; /* FIXME */
+ }
+
+ stat.pid = 0; /* FIXME */
+ stat.create_time = 0; /* FIXME */
+ stat.mod_info = 0; /* FIXME */
+
+ if (num < *count)
+ {
+ if (key_data) *key_data++ = key;
+ if (dynamic_data) *dynamic_data++ = dyn;
+ if (static_data) *static_data++ = stat;
+ }
+ num++;
+ }
+ err:
+ heap_free( buf );
+ }
+#else
+ FIXME( "not implemented\n" );
+ status = STATUS_NOT_IMPLEMENTED;
+#endif
+
+ if (!want_data || num <= *count) *count = num;
+ else status = STATUS_MORE_ENTRIES;
+
+ return status;
+}
+
+static NTSTATUS tcp_all_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+
+ return tcp_conns_enumerate_all( 0, key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+}
+
+static NTSTATUS tcp_estab_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+
+ return tcp_conns_enumerate_all( MIB_TCP_STATE_ESTAB, key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+}
+
+static NTSTATUS tcp_listen_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+
+ return tcp_conns_enumerate_all( MIB_TCP_STATE_LISTEN, key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+}
+
static struct module_table tcp_tables[] =
{
{
@@ -182,6 +460,30 @@ static struct module_table tcp_tables[] =
NULL,
tcp_stats_get_all_parameters,
},
+ {
+ NSI_TCP_ALL_TABLE,
+ {
+ sizeof(struct nsi_tcp_conn_key), 0,
+ sizeof(struct nsi_tcp_conn_dynamic), sizeof(struct nsi_tcp_conn_static)
+ },
+ tcp_all_enumerate_all,
+ },
+ {
+ NSI_TCP_ESTAB_TABLE,
+ {
+ sizeof(struct nsi_tcp_conn_key), 0,
+ sizeof(struct nsi_tcp_conn_dynamic), sizeof(struct nsi_tcp_conn_static)
+ },
+ tcp_estab_enumerate_all,
+ },
+ {
+ NSI_TCP_LISTEN_TABLE,
+ {
+ sizeof(struct nsi_tcp_conn_key), 0,
+ sizeof(struct nsi_tcp_conn_dynamic), sizeof(struct nsi_tcp_conn_static)
+ },
+ tcp_listen_enumerate_all,
+ },
{
~0u
}
diff --git a/include/wine/nsi.h b/include/wine/nsi.h
index 3c92fb81aae..39a1ecebda1 100644
--- a/include/wine/nsi.h
+++ b/include/wine/nsi.h
@@ -21,6 +21,8 @@
#include "inaddr.h"
#include "in6addr.h"
+#include "ws2def.h"
+#include "ws2ipdef.h"
#include "winioctl.h"
/* Undocumented NSI NDIS tables */
@@ -294,6 +296,9 @@ struct nsi_ip_forward_static
/* Undocumented NSI TCP tables */
#define NSI_TCP_STATS_TABLE 0
+#define NSI_TCP_ALL_TABLE 3
+#define NSI_TCP_ESTAB_TABLE 4
+#define NSI_TCP_LISTEN_TABLE 5
struct nsi_tcp_stats_dynamic
{
@@ -321,6 +326,26 @@ struct nsi_tcp_stats_static
DWORD unk;
};
+struct nsi_tcp_conn_key
+{
+ SOCKADDR_INET local;
+ SOCKADDR_INET remote;
+};
+
+struct nsi_tcp_conn_dynamic
+{
+ DWORD state;
+ DWORD unk[3];
+};
+
+struct nsi_tcp_conn_static
+{
+ DWORD unk[3];
+ DWORD pid;
+ ULONGLONG create_time;
+ ULONGLONG mod_info;
+};
+
/* Wine specific ioctl interface */
#define IOCTL_NSIPROXY_WINE_ENUMERATE_ALL CTL_CODE(FILE_DEVICE_NETWORK, 0x400, METHOD_BUFFERED, 0)
--
2.23.0
1
0
17 Aug '21
The size is known at the start, so there's no need to grow it.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/ipstats.c | 17 ++---------------
1 file changed, 2 insertions(+), 15 deletions(-)
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
index ececfcdcecd..af14cddb0ca 100644
--- a/dlls/iphlpapi/ipstats.c
+++ b/dlls/iphlpapi/ipstats.c
@@ -546,7 +546,7 @@ struct pid_map
static struct pid_map *get_pid_map( unsigned int *num_entries )
{
struct pid_map *map;
- unsigned int i = 0, map_count = 16, buffer_len = 4096, process_count, pos = 0;
+ unsigned int i = 0, buffer_len = 4096, process_count, pos = 0;
NTSTATUS ret;
char *buffer = NULL, *new_buffer;
@@ -573,7 +573,7 @@ static struct pid_map *get_pid_map( unsigned int *num_entries )
buffer = new_buffer;
}
- if (!(map = HeapAlloc( GetProcessHeap(), 0, map_count * sizeof(*map) )))
+ if (!(map = HeapAlloc( GetProcessHeap(), 0, process_count * sizeof(*map) )))
{
HeapFree( GetProcessHeap(), 0, buffer );
return NULL;
@@ -586,19 +586,6 @@ static struct pid_map *get_pid_map( unsigned int *num_entries )
pos = (pos + 7) & ~7;
process = (const struct process_info *)(buffer + pos);
- if (i >= map_count)
- {
- struct pid_map *new_map;
- map_count *= 2;
- if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, map_count * sizeof(*map))))
- {
- HeapFree( GetProcessHeap(), 0, map );
- HeapFree( GetProcessHeap(), 0, buffer );
- return NULL;
- }
- map = new_map;
- }
-
map[i].pid = process->pid;
map[i].unix_pid = process->unix_pid;
--
2.23.0
1
0