diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2020-01-02 05:28:29 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2020-01-02 05:28:29 +0100 |
commit | 616f519b1f9f2d59e68eccea2f234b1c0e6ff5ed (patch) | |
tree | c8f7d03fc70fe467918b54c352eaa5d1c0d03e31 | |
parent | 8d184ed7d1c5c10cc38c577b0d7f681e69c2d8d4 (diff) | |
parent | 0cbab098df8f8d6e242917d44c2231e0a35c8c11 (diff) | |
download | psutil-616f519b1f9f2d59e68eccea2f234b1c0e6ff5ed.tar.gz |
Merge branch 'master' of github.com:giampaolo/psutil
-rw-r--r-- | psutil/_psutil_windows.c | 463 | ||||
-rw-r--r-- | psutil/arch/windows/process_handles.c | 3 | ||||
-rw-r--r-- | psutil/arch/windows/process_info.c | 271 | ||||
-rw-r--r-- | psutil/arch/windows/process_info.h | 7 | ||||
-rw-r--r-- | psutil/arch/windows/process_utils.c | 286 | ||||
-rw-r--r-- | psutil/arch/windows/process_utils.h | 11 | ||||
-rw-r--r-- | psutil/arch/windows/socks.c | 484 | ||||
-rw-r--r-- | psutil/arch/windows/socks.h | 9 | ||||
-rwxr-xr-x | scripts/internal/winmake.py | 54 | ||||
-rwxr-xr-x | setup.py | 6 |
10 files changed, 853 insertions, 741 deletions
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index f35d0076..660e08af 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -27,7 +27,7 @@ #include <wtsapi32.h> // users() #include <PowrProf.h> // cpu_freq() #if (_WIN32_WINNT >= 0x0600) // Windows >= Vista -#include <ws2tcpip.h> // net_connections() +#include <ws2tcpip.h> // net_io_counters() #endif // Link with Iphlpapi.lib @@ -36,10 +36,12 @@ #include "arch/windows/ntextapi.h" #include "arch/windows/global.h" #include "arch/windows/security.h" +#include "arch/windows/process_utils.h" #include "arch/windows/process_info.h" #include "arch/windows/process_handles.h" #include "arch/windows/inet_ntop.h" #include "arch/windows/services.h" +#include "arch/windows/socks.h" #include "arch/windows/wmi.h" #include "_psutil_common.h" @@ -54,7 +56,6 @@ #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define LO_T 1e-7 #define HI_T 429.4967296 -#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) #ifndef AF_INET6 #define AF_INET6 23 #endif @@ -1355,464 +1356,6 @@ error: } -// https://msdn.microsoft.com/library/aa365928.aspx -// TODO properly handle return code -static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call, - ULONG address_family, - PVOID * data, DWORD * size) -{ - // Due to other processes being active on the machine, it's possible - // that the size of the table increases between the moment where we - // query the size and the moment where we query the data. Therefore, it's - // important to call this in a loop to retry if that happens. - // See https://github.com/giampaolo/psutil/pull/1335 concerning 0xC0000001 error - // and https://github.com/giampaolo/psutil/issues/1294 - DWORD error = ERROR_INSUFFICIENT_BUFFER; - *size = 0; - *data = NULL; - error = call(NULL, size, FALSE, address_family, - TCP_TABLE_OWNER_PID_ALL, 0); - while (error == ERROR_INSUFFICIENT_BUFFER || error == 0xC0000001) - { - *data = malloc(*size); - if (*data == NULL) { - error = ERROR_NOT_ENOUGH_MEMORY; - continue; - } - error = call(*data, size, FALSE, address_family, - TCP_TABLE_OWNER_PID_ALL, 0); - if (error != NO_ERROR) { - free(*data); - *data = NULL; - } - } - return error; -} - - -// https://msdn.microsoft.com/library/aa365930.aspx -// TODO properly check return value -static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call, - ULONG address_family, - PVOID * data, DWORD * size) -{ - // Due to other processes being active on the machine, it's possible - // that the size of the table increases between the moment where we - // query the size and the moment where we query the data. Therefore, it's - // important to call this in a loop to retry if that happens. - // See https://github.com/giampaolo/psutil/pull/1335 concerning 0xC0000001 error - // and https://github.com/giampaolo/psutil/issues/1294 - DWORD error = ERROR_INSUFFICIENT_BUFFER; - *size = 0; - *data = NULL; - error = call(NULL, size, FALSE, address_family, - UDP_TABLE_OWNER_PID, 0); - while (error == ERROR_INSUFFICIENT_BUFFER || error == 0xC0000001) - { - *data = malloc(*size); - if (*data == NULL) { - error = ERROR_NOT_ENOUGH_MEMORY; - continue; - } - error = call(*data, size, FALSE, address_family, - UDP_TABLE_OWNER_PID, 0); - if (error != NO_ERROR) { - free(*data); - *data = NULL; - } - } - - if (error == ERROR_NOT_ENOUGH_MEMORY) { - PyErr_NoMemory(); - return 1; - } - if (error != NO_ERROR) { - PyErr_SetFromWindowsErr(error); - return 1; - } - return 0; -} - - -#define psutil_conn_decref_objs() \ - Py_DECREF(_AF_INET); \ - Py_DECREF(_AF_INET6);\ - Py_DECREF(_SOCK_STREAM);\ - Py_DECREF(_SOCK_DGRAM); - - -/* - * Return a list of network connections opened by a process - */ -static PyObject * -psutil_net_connections(PyObject *self, PyObject *args) { - static long null_address[4] = { 0, 0, 0, 0 }; - unsigned long pid; - int pid_return; - PVOID table = NULL; - DWORD tableSize; - DWORD error; - PMIB_TCPTABLE_OWNER_PID tcp4Table; - PMIB_UDPTABLE_OWNER_PID udp4Table; - PMIB_TCP6TABLE_OWNER_PID tcp6Table; - PMIB_UDP6TABLE_OWNER_PID udp6Table; - ULONG i; - CHAR addressBufferLocal[65]; - CHAR addressBufferRemote[65]; - - PyObject *py_retlist; - PyObject *py_conn_tuple = NULL; - PyObject *py_af_filter = NULL; - PyObject *py_type_filter = NULL; - PyObject *py_addr_tuple_local = NULL; - PyObject *py_addr_tuple_remote = NULL; - PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); - PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); - PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); - PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); - - // Import some functions. - if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) - goto error; - - if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { - psutil_conn_decref_objs(); - PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); - return NULL; - } - - if (pid != -1) { - pid_return = psutil_pid_is_running(pid); - if (pid_return == 0) { - psutil_conn_decref_objs(); - return NoSuchProcess(""); - } - else if (pid_return == -1) { - psutil_conn_decref_objs(); - return NULL; - } - } - - py_retlist = PyList_New(0); - if (py_retlist == NULL) { - psutil_conn_decref_objs(); - return NULL; - } - - // TCP IPv4 - - if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && - (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) - { - table = NULL; - py_conn_tuple = NULL; - py_addr_tuple_local = NULL; - py_addr_tuple_remote = NULL; - tableSize = 0; - - error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable, - AF_INET, &table, &tableSize); - if (error != 0) - goto error; - tcp4Table = table; - for (i = 0; i < tcp4Table->dwNumEntries; i++) { - if (pid != -1) { - if (tcp4Table->table[i].dwOwningPid != pid) { - continue; - } - } - - if (tcp4Table->table[i].dwLocalAddr != 0 || - tcp4Table->table[i].dwLocalPort != 0) - { - struct in_addr addr; - - addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; - psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal); - py_addr_tuple_local = Py_BuildValue( - "(si)", - addressBufferLocal, - BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); - } - else { - py_addr_tuple_local = PyTuple_New(0); - } - - if (py_addr_tuple_local == NULL) - goto error; - - // On Windows <= XP, remote addr is filled even if socket - // is in LISTEN mode in which case we just ignore it. - if ((tcp4Table->table[i].dwRemoteAddr != 0 || - tcp4Table->table[i].dwRemotePort != 0) && - (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) - { - struct in_addr addr; - - addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; - psutil_rtlIpv4AddressToStringA(&addr, addressBufferRemote); - py_addr_tuple_remote = Py_BuildValue( - "(si)", - addressBufferRemote, - BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); - } - else - { - py_addr_tuple_remote = PyTuple_New(0); - } - - if (py_addr_tuple_remote == NULL) - goto error; - - py_conn_tuple = Py_BuildValue( - "(iiiNNiI)", - -1, - AF_INET, - SOCK_STREAM, - py_addr_tuple_local, - py_addr_tuple_remote, - tcp4Table->table[i].dwState, - tcp4Table->table[i].dwOwningPid); - if (!py_conn_tuple) - goto error; - if (PyList_Append(py_retlist, py_conn_tuple)) - goto error; - Py_CLEAR(py_conn_tuple); - } - - free(table); - table = NULL; - tableSize = 0; - } - - // TCP IPv6 - if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && - (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1) && - (psutil_rtlIpv6AddressToStringA != NULL)) - { - table = NULL; - py_conn_tuple = NULL; - py_addr_tuple_local = NULL; - py_addr_tuple_remote = NULL; - tableSize = 0; - - error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable, - AF_INET6, &table, &tableSize); - if (error != 0) - goto error; - tcp6Table = table; - for (i = 0; i < tcp6Table->dwNumEntries; i++) - { - if (pid != -1) { - if (tcp6Table->table[i].dwOwningPid != pid) { - continue; - } - } - - if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) - != 0 || tcp6Table->table[i].dwLocalPort != 0) - { - struct in6_addr addr; - - memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); - psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal); - py_addr_tuple_local = Py_BuildValue( - "(si)", - addressBufferLocal, - BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); - } - else { - py_addr_tuple_local = PyTuple_New(0); - } - - if (py_addr_tuple_local == NULL) - goto error; - - // On Windows <= XP, remote addr is filled even if socket - // is in LISTEN mode in which case we just ignore it. - if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) - != 0 || - tcp6Table->table[i].dwRemotePort != 0) && - (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) - { - struct in6_addr addr; - - memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); - psutil_rtlIpv6AddressToStringA(&addr, addressBufferRemote); - py_addr_tuple_remote = Py_BuildValue( - "(si)", - addressBufferRemote, - BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); - } - else { - py_addr_tuple_remote = PyTuple_New(0); - } - - if (py_addr_tuple_remote == NULL) - goto error; - - py_conn_tuple = Py_BuildValue( - "(iiiNNiI)", - -1, - AF_INET6, - SOCK_STREAM, - py_addr_tuple_local, - py_addr_tuple_remote, - tcp6Table->table[i].dwState, - tcp6Table->table[i].dwOwningPid); - if (!py_conn_tuple) - goto error; - if (PyList_Append(py_retlist, py_conn_tuple)) - goto error; - Py_CLEAR(py_conn_tuple); - } - - free(table); - table = NULL; - tableSize = 0; - } - - // UDP IPv4 - - if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && - (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) - { - table = NULL; - py_conn_tuple = NULL; - py_addr_tuple_local = NULL; - py_addr_tuple_remote = NULL; - tableSize = 0; - error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable, - AF_INET, &table, &tableSize); - if (error != 0) - goto error; - udp4Table = table; - for (i = 0; i < udp4Table->dwNumEntries; i++) - { - if (pid != -1) { - if (udp4Table->table[i].dwOwningPid != pid) { - continue; - } - } - - if (udp4Table->table[i].dwLocalAddr != 0 || - udp4Table->table[i].dwLocalPort != 0) - { - struct in_addr addr; - - addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; - psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal); - py_addr_tuple_local = Py_BuildValue( - "(si)", - addressBufferLocal, - BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); - } - else { - py_addr_tuple_local = PyTuple_New(0); - } - - if (py_addr_tuple_local == NULL) - goto error; - - py_conn_tuple = Py_BuildValue( - "(iiiNNiI)", - -1, - AF_INET, - SOCK_DGRAM, - py_addr_tuple_local, - PyTuple_New(0), - PSUTIL_CONN_NONE, - udp4Table->table[i].dwOwningPid); - if (!py_conn_tuple) - goto error; - if (PyList_Append(py_retlist, py_conn_tuple)) - goto error; - Py_CLEAR(py_conn_tuple); - } - - free(table); - table = NULL; - tableSize = 0; - } - - // UDP IPv6 - - if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && - (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1) && - (psutil_rtlIpv6AddressToStringA != NULL)) - { - table = NULL; - py_conn_tuple = NULL; - py_addr_tuple_local = NULL; - py_addr_tuple_remote = NULL; - tableSize = 0; - error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable, - AF_INET6, &table, &tableSize); - if (error != 0) - goto error; - udp6Table = table; - for (i = 0; i < udp6Table->dwNumEntries; i++) { - if (pid != -1) { - if (udp6Table->table[i].dwOwningPid != pid) { - continue; - } - } - - if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) - != 0 || udp6Table->table[i].dwLocalPort != 0) - { - struct in6_addr addr; - - memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); - psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal); - py_addr_tuple_local = Py_BuildValue( - "(si)", - addressBufferLocal, - BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); - } - else { - py_addr_tuple_local = PyTuple_New(0); - } - - if (py_addr_tuple_local == NULL) - goto error; - - py_conn_tuple = Py_BuildValue( - "(iiiNNiI)", - -1, - AF_INET6, - SOCK_DGRAM, - py_addr_tuple_local, - PyTuple_New(0), - PSUTIL_CONN_NONE, - udp6Table->table[i].dwOwningPid); - if (!py_conn_tuple) - goto error; - if (PyList_Append(py_retlist, py_conn_tuple)) - goto error; - Py_CLEAR(py_conn_tuple); - } - - free(table); - table = NULL; - tableSize = 0; - } - - psutil_conn_decref_objs(); - return py_retlist; - -error: - psutil_conn_decref_objs(); - Py_XDECREF(py_conn_tuple); - Py_XDECREF(py_addr_tuple_local); - Py_XDECREF(py_addr_tuple_remote); - Py_DECREF(py_retlist); - if (table != NULL) - free(table); - return NULL; -} - - /* * Get process priority as a Python integer. */ diff --git a/psutil/arch/windows/process_handles.c b/psutil/arch/windows/process_handles.c index 5966669e..40b209ee 100644 --- a/psutil/arch/windows/process_handles.c +++ b/psutil/arch/windows/process_handles.c @@ -8,10 +8,11 @@ #include <windows.h> #include <Psapi.h> #include <Python.h> + #include "ntextapi.h" #include "global.h" #include "process_handles.h" -#include "process_info.h" +#include "process_utils.h" #include "../../_psutil_common.h" CRITICAL_SECTION g_cs; diff --git a/psutil/arch/windows/process_info.c b/psutil/arch/windows/process_info.c index 5ea5f765..a9c2c131 100644 --- a/psutil/arch/windows/process_info.c +++ b/psutil/arch/windows/process_info.c @@ -16,6 +16,7 @@ #include "global.h" #include "security.h" #include "process_info.h" +#include "process_utils.h" #include "../../_psutil_common.h" @@ -138,276 +139,6 @@ typedef struct { #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) -/* - * Return 1 if PID exists, 0 if not, -1 on error. - */ -int -psutil_pid_in_pids(DWORD pid) { - DWORD *proclist = NULL; - DWORD numberOfReturnedPIDs; - DWORD i; - - proclist = psutil_get_pids(&numberOfReturnedPIDs); - if (proclist == NULL) - return -1; - for (i = 0; i < numberOfReturnedPIDs; i++) { - if (proclist[i] == pid) { - free(proclist); - return 1; - } - } - free(proclist); - return 0; -} - - -/* - * Given a process HANDLE checks whether it's actually running. - * Returns: - * - 1: running - * - 0: not running - * - -1: WindowsError - * - -2: AssertionError - */ -int -psutil_is_phandle_running(HANDLE hProcess, DWORD pid) { - DWORD processExitCode = 0; - - if (hProcess == NULL) { - if (GetLastError() == ERROR_INVALID_PARAMETER) { - // Yeah, this is the actual error code in case of - // "no such process". - if (! psutil_assert_pid_not_exists( - pid, "iphr: OpenProcess() -> ERROR_INVALID_PARAMETER")) { - return -2; - } - return 0; - } - return -1; - } - - if (GetExitCodeProcess(hProcess, &processExitCode)) { - // XXX - maybe STILL_ACTIVE is not fully reliable as per: - // http://stackoverflow.com/questions/1591342/#comment47830782_1591379 - if (processExitCode == STILL_ACTIVE) { - if (! psutil_assert_pid_exists( - pid, "iphr: GetExitCodeProcess() -> STILL_ACTIVE")) { - return -2; - } - return 1; - } - else { - // We can't be sure so we look into pids. - if (psutil_pid_in_pids(pid) == 1) { - return 1; - } - else { - CloseHandle(hProcess); - return 0; - } - } - } - - CloseHandle(hProcess); - if (! psutil_assert_pid_not_exists( pid, "iphr: exit fun")) { - return -2; - } - return -1; -} - - -/* - * Given a process HANDLE checks whether it's actually running and if - * it does return it, else return NULL with the proper Python exception - * set. - */ -HANDLE -psutil_check_phandle(HANDLE hProcess, DWORD pid) { - int ret = psutil_is_phandle_running(hProcess, pid); - if (ret == 1) { - return hProcess; - } - else if (ret == 0) { - return NoSuchProcess(""); - } - else if (ret == -1) { - if (GetLastError() == ERROR_ACCESS_DENIED) - return PyErr_SetFromWindowsErr(0); - else - return PyErr_SetFromOSErrnoWithSyscall("OpenProcess"); - } - else { - return NULL; - } -} - - -/* - * A wrapper around OpenProcess setting NSP exception if process - * no longer exists. - * "pid" is the process pid, "dwDesiredAccess" is the first argument - * exptected by OpenProcess. - * Return a process handle or NULL. - */ -HANDLE -psutil_handle_from_pid(DWORD pid, DWORD access) { - HANDLE hProcess; - - if (pid == 0) { - // otherwise we'd get NoSuchProcess - return AccessDenied(""); - } - // needed for GetExitCodeProcess - access |= PROCESS_QUERY_LIMITED_INFORMATION; - hProcess = OpenProcess(access, FALSE, pid); - return psutil_check_phandle(hProcess, pid); -} - - -DWORD * -psutil_get_pids(DWORD *numberOfReturnedPIDs) { - // Win32 SDK says the only way to know if our process array - // wasn't large enough is to check the returned size and make - // sure that it doesn't match the size of the array. - // If it does we allocate a larger array and try again - - // Stores the actual array - DWORD *procArray = NULL; - DWORD procArrayByteSz; - int procArraySz = 0; - - // Stores the byte size of the returned array from enumprocesses - DWORD enumReturnSz = 0; - - do { - procArraySz += 1024; - if (procArray != NULL) - free(procArray); - procArrayByteSz = procArraySz * sizeof(DWORD); - procArray = malloc(procArrayByteSz); - if (procArray == NULL) { - PyErr_NoMemory(); - return NULL; - } - if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) { - free(procArray); - PyErr_SetFromWindowsErr(0); - return NULL; - } - } while (enumReturnSz == procArraySz * sizeof(DWORD)); - - // The number of elements is the returned size / size of each element - *numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD); - - return procArray; -} - - -int -psutil_assert_pid_exists(DWORD pid, char *err) { - if (PSUTIL_TESTING) { - if (psutil_pid_in_pids(pid) == 0) { - PyErr_SetString(PyExc_AssertionError, err); - return 0; - } - } - return 1; -} - - -int -psutil_assert_pid_not_exists(DWORD pid, char *err) { - if (PSUTIL_TESTING) { - if (psutil_pid_in_pids(pid) == 1) { - PyErr_SetString(PyExc_AssertionError, err); - return 0; - } - } - return 1; -} - - -/* -/* Check for PID existance by using OpenProcess() + GetExitCodeProcess. -/* Returns: - * 1: pid exists - * 0: it doesn't - * -1: error - */ -int -psutil_pid_is_running(DWORD pid) { - HANDLE hProcess; - DWORD exitCode; - DWORD err; - - // Special case for PID 0 System Idle Process - if (pid == 0) - return 1; - if (pid < 0) - return 0; - hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); - if (NULL == hProcess) { - err = GetLastError(); - // Yeah, this is the actual error code in case of "no such process". - if (err == ERROR_INVALID_PARAMETER) { - if (! psutil_assert_pid_not_exists( - pid, "pir: OpenProcess() -> INVALID_PARAMETER")) { - return -1; - } - return 0; - } - // Access denied obviously means there's a process to deny access to. - else if (err == ERROR_ACCESS_DENIED) { - if (! psutil_assert_pid_exists( - pid, "pir: OpenProcess() ACCESS_DENIED")) { - return -1; - } - return 1; - } - // Be strict and raise an exception; the caller is supposed - // to take -1 into account. - else { - PyErr_SetFromOSErrnoWithSyscall("OpenProcess(PROCESS_VM_READ)"); - return -1; - } - } - - if (GetExitCodeProcess(hProcess, &exitCode)) { - CloseHandle(hProcess); - // XXX - maybe STILL_ACTIVE is not fully reliable as per: - // http://stackoverflow.com/questions/1591342/#comment47830782_1591379 - if (exitCode == STILL_ACTIVE) { - if (! psutil_assert_pid_exists( - pid, "pir: GetExitCodeProcess() -> STILL_ACTIVE")) { - return -1; - } - return 1; - } - // We can't be sure so we look into pids. - else { - return psutil_pid_in_pids(pid); - } - } - else { - err = GetLastError(); - CloseHandle(hProcess); - // Same as for OpenProcess, assume access denied means there's - // a process to deny access to. - if (err == ERROR_ACCESS_DENIED) { - if (! psutil_assert_pid_exists( - pid, "pir: GetExitCodeProcess() -> ERROR_ACCESS_DENIED")) { - return -1; - } - return 1; - } - else { - PyErr_SetFromOSErrnoWithSyscall("GetExitCodeProcess"); - return -1; - } - } -} - - /* Given a pointer into a process's memory, figure out how much data can be * read from it. */ static int diff --git a/psutil/arch/windows/process_info.h b/psutil/arch/windows/process_info.h index 4278c4df..afbbb72d 100644 --- a/psutil/arch/windows/process_info.h +++ b/psutil/arch/windows/process_info.h @@ -15,15 +15,8 @@ #define HANDLE_TO_PYNUM(handle) PyLong_FromUnsignedLong((unsigned long) handle) #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj)) -DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); -HANDLE psutil_handle_from_pid(DWORD pid, DWORD dwDesiredAccess); -int psutil_pid_is_running(DWORD pid); int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer); - -int psutil_assert_pid_exists(DWORD pid, char *err); -int psutil_assert_pid_not_exists(DWORD pid, char *err); - PyObject* psutil_get_cmdline(long pid, int use_peb); PyObject* psutil_get_cwd(long pid); PyObject* psutil_get_environ(long pid); diff --git a/psutil/arch/windows/process_utils.c b/psutil/arch/windows/process_utils.c new file mode 100644 index 00000000..a81a3253 --- /dev/null +++ b/psutil/arch/windows/process_utils.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Helper process functions. + */ + +#include <Python.h> +#include <windows.h> +#include <Psapi.h> +#include <tlhelp32.h> + +#include "ntextapi.h" +#include "global.h" +#include "process_utils.h" +#include "../../_psutil_common.h" + + +DWORD * +psutil_get_pids(DWORD *numberOfReturnedPIDs) { + // Win32 SDK says the only way to know if our process array + // wasn't large enough is to check the returned size and make + // sure that it doesn't match the size of the array. + // If it does we allocate a larger array and try again + + // Stores the actual array + DWORD *procArray = NULL; + DWORD procArrayByteSz; + int procArraySz = 0; + + // Stores the byte size of the returned array from enumprocesses + DWORD enumReturnSz = 0; + + do { + procArraySz += 1024; + if (procArray != NULL) + free(procArray); + procArrayByteSz = procArraySz * sizeof(DWORD); + procArray = malloc(procArrayByteSz); + if (procArray == NULL) { + PyErr_NoMemory(); + return NULL; + } + if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) { + free(procArray); + PyErr_SetFromWindowsErr(0); + return NULL; + } + } while (enumReturnSz == procArraySz * sizeof(DWORD)); + + // The number of elements is the returned size / size of each element + *numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD); + + return procArray; +} + +/* + * Return 1 if PID exists, 0 if not, -1 on error. + */ +int +psutil_pid_in_pids(DWORD pid) { + DWORD *proclist = NULL; + DWORD numberOfReturnedPIDs; + DWORD i; + + proclist = psutil_get_pids(&numberOfReturnedPIDs); + if (proclist == NULL) + return -1; + for (i = 0; i < numberOfReturnedPIDs; i++) { + if (proclist[i] == pid) { + free(proclist); + return 1; + } + } + free(proclist); + return 0; +} + + +/* + * Given a process HANDLE checks whether it's actually running. + * Returns: + * - 1: running + * - 0: not running + * - -1: WindowsError + * - -2: AssertionError + */ +int +psutil_is_phandle_running(HANDLE hProcess, DWORD pid) { + DWORD processExitCode = 0; + + if (hProcess == NULL) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + // Yeah, this is the actual error code in case of + // "no such process". + if (! psutil_assert_pid_not_exists( + pid, "iphr: OpenProcess() -> ERROR_INVALID_PARAMETER")) { + return -2; + } + return 0; + } + return -1; + } + + if (GetExitCodeProcess(hProcess, &processExitCode)) { + // XXX - maybe STILL_ACTIVE is not fully reliable as per: + // http://stackoverflow.com/questions/1591342/#comment47830782_1591379 + if (processExitCode == STILL_ACTIVE) { + if (! psutil_assert_pid_exists( + pid, "iphr: GetExitCodeProcess() -> STILL_ACTIVE")) { + return -2; + } + return 1; + } + else { + // We can't be sure so we look into pids. + if (psutil_pid_in_pids(pid) == 1) { + return 1; + } + else { + CloseHandle(hProcess); + return 0; + } + } + } + + CloseHandle(hProcess); + if (! psutil_assert_pid_not_exists( pid, "iphr: exit fun")) { + return -2; + } + return -1; +} + + +/* + * Given a process HANDLE checks whether it's actually running and if + * it does return it, else return NULL with the proper Python exception + * set. + */ +HANDLE +psutil_check_phandle(HANDLE hProcess, DWORD pid) { + int ret = psutil_is_phandle_running(hProcess, pid); + if (ret == 1) { + return hProcess; + } + else if (ret == 0) { + return NoSuchProcess(""); + } + else if (ret == -1) { + if (GetLastError() == ERROR_ACCESS_DENIED) + return PyErr_SetFromWindowsErr(0); + else + return PyErr_SetFromOSErrnoWithSyscall("OpenProcess"); + } + else { + return NULL; + } +} + + +/* + * A wrapper around OpenProcess setting NSP exception if process + * no longer exists. + * "pid" is the process pid, "dwDesiredAccess" is the first argument + * exptected by OpenProcess. + * Return a process handle or NULL. + */ +HANDLE +psutil_handle_from_pid(DWORD pid, DWORD access) { + HANDLE hProcess; + + if (pid == 0) { + // otherwise we'd get NoSuchProcess + return AccessDenied(""); + } + // needed for GetExitCodeProcess + access |= PROCESS_QUERY_LIMITED_INFORMATION; + hProcess = OpenProcess(access, FALSE, pid); + return psutil_check_phandle(hProcess, pid); +} + + +int +psutil_assert_pid_exists(DWORD pid, char *err) { + if (PSUTIL_TESTING) { + if (psutil_pid_in_pids(pid) == 0) { + PyErr_SetString(PyExc_AssertionError, err); + return 0; + } + } + return 1; +} + + +int +psutil_assert_pid_not_exists(DWORD pid, char *err) { + if (PSUTIL_TESTING) { + if (psutil_pid_in_pids(pid) == 1) { + PyErr_SetString(PyExc_AssertionError, err); + return 0; + } + } + return 1; +} + + +/* +/* Check for PID existance by using OpenProcess() + GetExitCodeProcess. +/* Returns: + * 1: pid exists + * 0: it doesn't + * -1: error + */ +int +psutil_pid_is_running(DWORD pid) { + HANDLE hProcess; + DWORD exitCode; + DWORD err; + + // Special case for PID 0 System Idle Process + if (pid == 0) + return 1; + if (pid < 0) + return 0; + hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (NULL == hProcess) { + err = GetLastError(); + // Yeah, this is the actual error code in case of "no such process". + if (err == ERROR_INVALID_PARAMETER) { + if (! psutil_assert_pid_not_exists( + pid, "pir: OpenProcess() -> INVALID_PARAMETER")) { + return -1; + } + return 0; + } + // Access denied obviously means there's a process to deny access to. + else if (err == ERROR_ACCESS_DENIED) { + if (! psutil_assert_pid_exists( + pid, "pir: OpenProcess() ACCESS_DENIED")) { + return -1; + } + return 1; + } + // Be strict and raise an exception; the caller is supposed + // to take -1 into account. + else { + PyErr_SetFromOSErrnoWithSyscall("OpenProcess(PROCESS_VM_READ)"); + return -1; + } + } + + if (GetExitCodeProcess(hProcess, &exitCode)) { + CloseHandle(hProcess); + // XXX - maybe STILL_ACTIVE is not fully reliable as per: + // http://stackoverflow.com/questions/1591342/#comment47830782_1591379 + if (exitCode == STILL_ACTIVE) { + if (! psutil_assert_pid_exists( + pid, "pir: GetExitCodeProcess() -> STILL_ACTIVE")) { + return -1; + } + return 1; + } + // We can't be sure so we look into pids. + else { + return psutil_pid_in_pids(pid); + } + } + else { + err = GetLastError(); + CloseHandle(hProcess); + // Same as for OpenProcess, assume access denied means there's + // a process to deny access to. + if (err == ERROR_ACCESS_DENIED) { + if (! psutil_assert_pid_exists( + pid, "pir: GetExitCodeProcess() -> ERROR_ACCESS_DENIED")) { + return -1; + } + return 1; + } + else { + PyErr_SetFromOSErrnoWithSyscall("GetExitCodeProcess"); + return -1; + } + } +} diff --git a/psutil/arch/windows/process_utils.h b/psutil/arch/windows/process_utils.h new file mode 100644 index 00000000..a7171c5c --- /dev/null +++ b/psutil/arch/windows/process_utils.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); +HANDLE psutil_handle_from_pid(DWORD pid, DWORD dwDesiredAccess); +int psutil_pid_is_running(DWORD pid); +int psutil_assert_pid_exists(DWORD pid, char *err); +int psutil_assert_pid_not_exists(DWORD pid, char *err); diff --git a/psutil/arch/windows/socks.c b/psutil/arch/windows/socks.c new file mode 100644 index 00000000..b44a247b --- /dev/null +++ b/psutil/arch/windows/socks.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// Fixes clash between winsock2.h and windows.h +#define WIN32_LEAN_AND_MEAN + +#include <Python.h> +#include <windows.h> +#if (_WIN32_WINNT >= 0x0600) // Windows >= Vista +#include <ws2tcpip.h> +#endif + +#include "ntextapi.h" +#include "global.h" +#include "process_utils.h" +#include "../../_psutil_common.h" + + +#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) + +#ifndef AF_INET6 +#define AF_INET6 23 +#endif + + +// https://msdn.microsoft.com/library/aa365928.aspx +// TODO properly handle return code +static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call, + ULONG address_family, + PVOID * data, DWORD * size) +{ + // Due to other processes being active on the machine, it's possible + // that the size of the table increases between the moment where we + // query the size and the moment where we query the data. Therefore, it's + // important to call this in a loop to retry if that happens. + // See https://github.com/giampaolo/psutil/pull/1335 concerning 0xC0000001 error + // and https://github.com/giampaolo/psutil/issues/1294 + DWORD error = ERROR_INSUFFICIENT_BUFFER; + *size = 0; + *data = NULL; + error = call(NULL, size, FALSE, address_family, + TCP_TABLE_OWNER_PID_ALL, 0); + while (error == ERROR_INSUFFICIENT_BUFFER || error == 0xC0000001) + { + *data = malloc(*size); + if (*data == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + continue; + } + error = call(*data, size, FALSE, address_family, + TCP_TABLE_OWNER_PID_ALL, 0); + if (error != NO_ERROR) { + free(*data); + *data = NULL; + } + } + return error; +} + + +// https://msdn.microsoft.com/library/aa365930.aspx +// TODO properly check return value +static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call, + ULONG address_family, + PVOID * data, DWORD * size) +{ + // Due to other processes being active on the machine, it's possible + // that the size of the table increases between the moment where we + // query the size and the moment where we query the data. Therefore, it's + // important to call this in a loop to retry if that happens. + // See https://github.com/giampaolo/psutil/pull/1335 concerning 0xC0000001 error + // and https://github.com/giampaolo/psutil/issues/1294 + DWORD error = ERROR_INSUFFICIENT_BUFFER; + *size = 0; + *data = NULL; + error = call(NULL, size, FALSE, address_family, + UDP_TABLE_OWNER_PID, 0); + while (error == ERROR_INSUFFICIENT_BUFFER || error == 0xC0000001) + { + *data = malloc(*size); + if (*data == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + continue; + } + error = call(*data, size, FALSE, address_family, + UDP_TABLE_OWNER_PID, 0); + if (error != NO_ERROR) { + free(*data); + *data = NULL; + } + } + + if (error == ERROR_NOT_ENOUGH_MEMORY) { + PyErr_NoMemory(); + return 1; + } + if (error != NO_ERROR) { + PyErr_SetFromWindowsErr(error); + return 1; + } + return 0; +} + + +#define psutil_conn_decref_objs() \ + Py_DECREF(_AF_INET); \ + Py_DECREF(_AF_INET6);\ + Py_DECREF(_SOCK_STREAM);\ + Py_DECREF(_SOCK_DGRAM); + + +/* + * Return a list of network connections opened by a process + */ +PyObject * +psutil_net_connections(PyObject *self, PyObject *args) { + static long null_address[4] = { 0, 0, 0, 0 }; + unsigned long pid; + int pid_return; + PVOID table = NULL; + DWORD tableSize; + DWORD error; + PMIB_TCPTABLE_OWNER_PID tcp4Table; + PMIB_UDPTABLE_OWNER_PID udp4Table; + PMIB_TCP6TABLE_OWNER_PID tcp6Table; + PMIB_UDP6TABLE_OWNER_PID udp6Table; + ULONG i; + CHAR addressBufferLocal[65]; + CHAR addressBufferRemote[65]; + + PyObject *py_retlist; + PyObject *py_conn_tuple = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + PyObject *py_addr_tuple_local = NULL; + PyObject *py_addr_tuple_remote = NULL; + PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); + PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); + PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); + PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); + + // Import some functions. + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) + goto error; + + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { + psutil_conn_decref_objs(); + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + return NULL; + } + + if (pid != -1) { + pid_return = psutil_pid_is_running(pid); + if (pid_return == 0) { + psutil_conn_decref_objs(); + return NoSuchProcess(""); + } + else if (pid_return == -1) { + psutil_conn_decref_objs(); + return NULL; + } + } + + py_retlist = PyList_New(0); + if (py_retlist == NULL) { + psutil_conn_decref_objs(); + return NULL; + } + + // TCP IPv4 + + if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + + error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable, + AF_INET, &table, &tableSize); + if (error != 0) + goto error; + tcp4Table = table; + for (i = 0; i < tcp4Table->dwNumEntries; i++) { + if (pid != -1) { + if (tcp4Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (tcp4Table->table[i].dwLocalAddr != 0 || + tcp4Table->table[i].dwLocalPort != 0) + { + struct in_addr addr; + + addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; + psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + // On Windows <= XP, remote addr is filled even if socket + // is in LISTEN mode in which case we just ignore it. + if ((tcp4Table->table[i].dwRemoteAddr != 0 || + tcp4Table->table[i].dwRemotePort != 0) && + (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) + { + struct in_addr addr; + + addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; + psutil_rtlIpv4AddressToStringA(&addr, addressBufferRemote); + py_addr_tuple_remote = Py_BuildValue( + "(si)", + addressBufferRemote, + BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); + } + else + { + py_addr_tuple_remote = PyTuple_New(0); + } + + if (py_addr_tuple_remote == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET, + SOCK_STREAM, + py_addr_tuple_local, + py_addr_tuple_remote, + tcp4Table->table[i].dwState, + tcp4Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_CLEAR(py_conn_tuple); + } + + free(table); + table = NULL; + tableSize = 0; + } + + // TCP IPv6 + if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1) && + (psutil_rtlIpv6AddressToStringA != NULL)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + + error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable, + AF_INET6, &table, &tableSize); + if (error != 0) + goto error; + tcp6Table = table; + for (i = 0; i < tcp6Table->dwNumEntries; i++) + { + if (pid != -1) { + if (tcp6Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) + != 0 || tcp6Table->table[i].dwLocalPort != 0) + { + struct in6_addr addr; + + memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); + psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + // On Windows <= XP, remote addr is filled even if socket + // is in LISTEN mode in which case we just ignore it. + if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) + != 0 || + tcp6Table->table[i].dwRemotePort != 0) && + (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) + { + struct in6_addr addr; + + memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); + psutil_rtlIpv6AddressToStringA(&addr, addressBufferRemote); + py_addr_tuple_remote = Py_BuildValue( + "(si)", + addressBufferRemote, + BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); + } + else { + py_addr_tuple_remote = PyTuple_New(0); + } + + if (py_addr_tuple_remote == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET6, + SOCK_STREAM, + py_addr_tuple_local, + py_addr_tuple_remote, + tcp6Table->table[i].dwState, + tcp6Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_CLEAR(py_conn_tuple); + } + + free(table); + table = NULL; + tableSize = 0; + } + + // UDP IPv4 + + if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable, + AF_INET, &table, &tableSize); + if (error != 0) + goto error; + udp4Table = table; + for (i = 0; i < udp4Table->dwNumEntries; i++) + { + if (pid != -1) { + if (udp4Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (udp4Table->table[i].dwLocalAddr != 0 || + udp4Table->table[i].dwLocalPort != 0) + { + struct in_addr addr; + + addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; + psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET, + SOCK_DGRAM, + py_addr_tuple_local, + PyTuple_New(0), + PSUTIL_CONN_NONE, + udp4Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_CLEAR(py_conn_tuple); + } + + free(table); + table = NULL; + tableSize = 0; + } + + // UDP IPv6 + + if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && + (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1) && + (psutil_rtlIpv6AddressToStringA != NULL)) + { + table = NULL; + py_conn_tuple = NULL; + py_addr_tuple_local = NULL; + py_addr_tuple_remote = NULL; + tableSize = 0; + error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable, + AF_INET6, &table, &tableSize); + if (error != 0) + goto error; + udp6Table = table; + for (i = 0; i < udp6Table->dwNumEntries; i++) { + if (pid != -1) { + if (udp6Table->table[i].dwOwningPid != pid) { + continue; + } + } + + if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) + != 0 || udp6Table->table[i].dwLocalPort != 0) + { + struct in6_addr addr; + + memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); + psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal); + py_addr_tuple_local = Py_BuildValue( + "(si)", + addressBufferLocal, + BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); + } + else { + py_addr_tuple_local = PyTuple_New(0); + } + + if (py_addr_tuple_local == NULL) + goto error; + + py_conn_tuple = Py_BuildValue( + "(iiiNNiI)", + -1, + AF_INET6, + SOCK_DGRAM, + py_addr_tuple_local, + PyTuple_New(0), + PSUTIL_CONN_NONE, + udp6Table->table[i].dwOwningPid); + if (!py_conn_tuple) + goto error; + if (PyList_Append(py_retlist, py_conn_tuple)) + goto error; + Py_CLEAR(py_conn_tuple); + } + + free(table); + table = NULL; + tableSize = 0; + } + + psutil_conn_decref_objs(); + return py_retlist; + +error: + psutil_conn_decref_objs(); + Py_XDECREF(py_conn_tuple); + Py_XDECREF(py_addr_tuple_local); + Py_XDECREF(py_addr_tuple_remote); + Py_DECREF(py_retlist); + if (table != NULL) + free(table); + return NULL; +} diff --git a/psutil/arch/windows/socks.h b/psutil/arch/windows/socks.h new file mode 100644 index 00000000..cd9ba58d --- /dev/null +++ b/psutil/arch/windows/socks.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Jeff Tang. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <Python.h> + +PyObject *psutil_net_connections(PyObject *self, PyObject *args); diff --git a/scripts/internal/winmake.py b/scripts/internal/winmake.py index 116809ca..c471ad0b 100755 --- a/scripts/internal/winmake.py +++ b/scripts/internal/winmake.py @@ -12,6 +12,8 @@ that they should be deemed illegal! """ from __future__ import print_function +import atexit +import ctypes import errno import fnmatch import functools @@ -59,6 +61,12 @@ _cmds = {} if PY3: basestring = str +GREEN = 2 +YELLOW = 6 +RED = 4 +DEFAULT_COLOR = 7 + + # =================================================================== # utils # =================================================================== @@ -84,6 +92,26 @@ def safe_print(text, file=sys.stdout, flush=False): file.write("\n") +def stderr_handle(): + GetStdHandle = ctypes.windll.Kernel32.GetStdHandle + STD_ERROR_HANDLE_ID = ctypes.c_ulong(0xfffffff4) + GetStdHandle.restype = ctypes.c_ulong + handle = GetStdHandle(STD_ERROR_HANDLE_ID) + atexit.register(ctypes.windll.Kernel32.CloseHandle, handle) + return handle + + +def win_colorprint(s, color=3): + color += 8 # bold + handle = stderr_handle() + SetConsoleTextAttribute = ctypes.windll.Kernel32.SetConsoleTextAttribute + SetConsoleTextAttribute(handle, color) + try: + print(s) + finally: + SetConsoleTextAttribute(handle, DEFAULT_COLOR) + + def sh(cmd, nolog=False): if not nolog: safe_print("cmd: " + cmd) @@ -211,13 +239,37 @@ def build(): # Make sure setuptools is installed (needed for 'develop' / # edit mode). sh('%s -c "import setuptools"' % PYTHON) - sh("%s setup.py build" % PYTHON) + + # Print coloured warnings in real time. + cmd = [PYTHON, "setup.py", "build"] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + try: + for line in iter(p.stdout.readline, b''): + if PY3: + line = line.decode() + line = line.strip() + if 'warning' in line: + win_colorprint(line, YELLOW) + elif 'error' in line: + win_colorprint(line, RED) + else: + print(line) + # retcode = p.poll() + p.communicate() + if p.returncode: + win_colorprint("failure", RED) + sys.exit(p.returncode) + finally: + p.terminate() + p.wait() + # Copies compiled *.pyd files in ./psutil directory in order to # allow "import psutil" when using the interactive interpreter # from within this directory. sh("%s setup.py build_ext -i" % PYTHON) # Make sure it actually worked. sh('%s -c "import psutil"' % PYTHON) + win_colorprint("success", GREEN) @cmd @@ -142,12 +142,14 @@ if WINDOWS: 'psutil._psutil_windows', sources=sources + [ 'psutil/_psutil_windows.c', + 'psutil/arch/windows/process_utils.c', 'psutil/arch/windows/process_info.c', 'psutil/arch/windows/process_handles.c', 'psutil/arch/windows/security.c', 'psutil/arch/windows/inet_ntop.c', 'psutil/arch/windows/services.c', 'psutil/arch/windows/global.c', + 'psutil/arch/windows/socks.c', 'psutil/arch/windows/wmi.c', ], define_macros=macros, @@ -406,8 +408,8 @@ def main(): else: ur = "http://www.microsoft.com/en-us/download/" ur += "details.aspx?id=44266" - print(hilite("VisualStudio is not installed; get it from %s" % ur), - ok=False, file=sys.stderr) + s = "VisualStudio is not installed; get it from %s" % ur + print(hilite(s, ok=False), file=sys.stderr) if __name__ == '__main__': |