Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug: incorrect network interface returned by net_io_counters(True… #670

Merged
merged 2 commits into from
Aug 26, 2015

Conversation

sk6249
Copy link
Contributor

@sk6249 sk6249 commented Aug 12, 2015

…) and net_if_addrs()

[Bug description]
When network interface contains non-ansii characters, such as Chinese
characters, the network interface name returned by net_io_counters(True)
and net_if_addrs() were truncated or blank string.
[Solution]
This fix ensures these two functions will return correct network
interface names.

…) and net_if_addrs()

[Bug description]
When network interface contains non-ansii characters, such as Chinese
characters, the network interface name returned by net_io_counters(True)
and net_if_addrs() were  truncated or blank string.
[Solution]
This fix ensures these two functions will return correct network
interface names.
@mrjefftang
Copy link
Collaborator

Since pCurrAddresses->FriendlyName is defined as PWCHAR [1], couldn't the same be accomplished by calling PyUnicode_FromWideChar(pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)) or am I missing something?

typedef struct _IP_ADAPTER_ADDRESSES {
...
  PWCHAR                             FriendlyName;
...
} IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES;

PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) [2]

[1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
[2] https://docs.python.org/3/c-api/unicode.html

@sk6249
Copy link
Contributor Author

sk6249 commented Aug 13, 2015

Hi mrjefftang,

Yes, PyUnicode_FromWideChar is better, and can solve this issue.
Here is the new function define which uses PyUnicode_FromWideChar:

/*
 * Return a Python list of named tuples with overall network I/O information
 */
static PyObject *
psutil_net_io_counters(PyObject *self, PyObject *args) {
    DWORD dwRetVal = 0;
    MIB_IFROW *pIfRow = NULL;
    PIP_ADAPTER_ADDRESSES pAddresses = NULL;
    PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;

    PyObject *py_retdict = PyDict_New();
    PyObject *py_nic_info = NULL;
    PyObject *py_nic_name = NULL;

    if (py_retdict == NULL)
        return NULL;
    pAddresses = psutil_get_nic_addresses();
    if (pAddresses == NULL)
        goto error;
    pCurrAddresses = pAddresses;

    while (pCurrAddresses) {
        py_nic_name = NULL;
        py_nic_info = NULL;
        pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW));

        if (pIfRow == NULL) {
            PyErr_NoMemory();
            goto error;
        }

        pIfRow->dwIndex = pCurrAddresses->IfIndex;
        dwRetVal = GetIfEntry(pIfRow);
        if (dwRetVal != NO_ERROR) {
            PyErr_SetString(PyExc_RuntimeError, "GetIfEntry() failed.");
            goto error;
        }

        py_nic_info = Py_BuildValue("(kkkkkkkk)",
                                    pIfRow->dwOutOctets,
                                    pIfRow->dwInOctets,
                                    pIfRow->dwOutUcastPkts,
                                    pIfRow->dwInUcastPkts,
                                    pIfRow->dwInErrors,
                                    pIfRow->dwOutErrors,
                                    pIfRow->dwInDiscards,
                                    pIfRow->dwOutDiscards);
        if (!py_nic_info)
            goto error;

        py_nic_name = PyUnicode_FromWideChar(pCurrAddresses->FriendlyName, 
                                             wcslen(pCurrAddresses->FriendlyName));

        if (py_nic_name == NULL)
            goto error;
        if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info))
            goto error;
        Py_XDECREF(py_nic_name);
        Py_XDECREF(py_nic_info);

        free(pIfRow);
        pCurrAddresses = pCurrAddresses->Next;
    }

    free(pAddresses);
    return py_retdict;

error:
    Py_XDECREF(py_nic_name);
    Py_XDECREF(py_nic_info);
    Py_DECREF(py_retdict);
    if (pAddresses != NULL)
        free(pAddresses);
    if (pIfRow != NULL)
        free(pIfRow);
    return NULL;
}

/*
 * Return NICs addresses.
 */

static PyObject *
psutil_net_if_addrs(PyObject *self, PyObject *args) {
    unsigned int i = 0;
    ULONG family;
    PCTSTR intRet;
    char *ptr;
    char buff[100];
    DWORD bufflen = 100;
    PIP_ADAPTER_ADDRESSES pAddresses = NULL;
    PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;

    PyObject *py_retlist = PyList_New(0);
    PyObject *py_tuple = NULL;
    PyObject *py_address = NULL;
    PyObject *py_mac_address = NULL;
    PyObject *py_nic_name = NULL;

    if (py_retlist == NULL)
        return NULL;

    pAddresses = psutil_get_nic_addresses();
    if (pAddresses == NULL)
        goto error;
    pCurrAddresses = pAddresses;

    while (pCurrAddresses) {
        pUnicast = pCurrAddresses->FirstUnicastAddress;

        py_nic_name = NULL;
        py_nic_name = PyUnicode_FromWideChar(pCurrAddresses->FriendlyName, 
                                             wcslen(pCurrAddresses->FriendlyName));
        if (py_nic_name == NULL)
            goto error;

        // MAC address
        if (pCurrAddresses->PhysicalAddressLength != 0) {
            ptr = buff;
            *ptr = '\0';
            for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) {
                if (i == (pCurrAddresses->PhysicalAddressLength - 1)) {
                    sprintf_s(ptr, _countof(buff), "%.2X\n",
                            (int)pCurrAddresses->PhysicalAddress[i]);
                }
                else {
                    sprintf_s(ptr, _countof(buff), "%.2X-",
                            (int)pCurrAddresses->PhysicalAddress[i]);
                }
                ptr += 3;
            }
            *--ptr = '\0';

#if PY_MAJOR_VERSION >= 3
            py_mac_address = PyUnicode_FromString(buff);
#else
            py_mac_address = PyString_FromString(buff);
#endif
            if (py_mac_address == NULL)
                goto error;

            Py_INCREF(Py_None);
            Py_INCREF(Py_None);
            Py_INCREF(Py_None);
            py_tuple = Py_BuildValue(
                "(OiOOOO)",
                py_nic_name,
                -1,  // this will be converted later to AF_LINK
                py_mac_address,
                Py_None,  // netmask (not supported)
                Py_None,  // broadcast (not supported)
                Py_None  // ptp (not supported on Windows)
            );
            if (! py_tuple)
                goto error;
            if (PyList_Append(py_retlist, py_tuple))
                goto error;
            Py_DECREF(py_tuple);
            Py_DECREF(py_mac_address);
        }

        // find out the IP address associated with the NIC
        if (pUnicast != NULL) {
            for (i = 0; pUnicast != NULL; i++) {
                family = pUnicast->Address.lpSockaddr->sa_family;
                if (family == AF_INET) {
                    struct sockaddr_in *sa_in = (struct sockaddr_in *)
                        pUnicast->Address.lpSockaddr;
                    intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff,
                                       bufflen);
                }
                else if (family == AF_INET6) {
                    struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)
                        pUnicast->Address.lpSockaddr;
                    intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr),
                                       buff, bufflen);
                }
                else {
                    // we should never get here
                    pUnicast = pUnicast->Next;
                    continue;
                }

                if (intRet == NULL) {
                    PyErr_SetFromWindowsErr(GetLastError());
                    goto error;
                }
#if PY_MAJOR_VERSION >= 3
                py_address = PyUnicode_FromString(buff);
#else
                py_address = PyString_FromString(buff);
#endif
                if (py_address == NULL)
                    goto error;

                Py_INCREF(Py_None);
                Py_INCREF(Py_None);
                Py_INCREF(Py_None);
                py_tuple = Py_BuildValue(
                    "(OiOOOO)",
                    py_nic_name,
                    family,
                    py_address,
                    Py_None,  // netmask (not supported)
                    Py_None,  // broadcast (not supported)
                    Py_None  // ptp (not supported on Windows)
                );

                if (! py_tuple)
                    goto error;
                if (PyList_Append(py_retlist, py_tuple))
                    goto error;
                Py_DECREF(py_tuple);
                Py_DECREF(py_address);

                pUnicast = pUnicast->Next;
            }
        }
        Py_DECREF(py_nic_name);
        pCurrAddresses = pCurrAddresses->Next;
    }

    free(pAddresses);
    return py_retlist;

error:
    if (pAddresses)
        free(pAddresses);
    Py_DECREF(py_retlist);
    Py_XDECREF(py_tuple);
    Py_XDECREF(py_address);
    Py_XDECREF(py_nic_name);
    return NULL;
}

Do you have any new comments?

…net_if_addrs

[Bug description]
When network interface contains non-ansii characters, such as Chinese
characters, the network interface name returned by net_io_counters(True)
and net_if_addrs() were truncated or blank.
[Solution]
This fix ensures these two functions will return correct network
interface names. Use PyUnicode_FromWideChar to fix this issue.
@mrjefftang
Copy link
Collaborator

This looks good to me.

giampaolo added a commit that referenced this pull request Aug 26, 2015
Fix bug: incorrect network interface returned by net_io_counters(True…
@giampaolo giampaolo merged commit d8416fb into giampaolo:master Aug 26, 2015
@giampaolo
Copy link
Owner

For the record. This solves the following issues:

Python 2 was not returning unicode:

C:\>C:\python27\python -c "import psutil;  print(psutil.net_if_addrs().keys())"
[..., 'Local Area Connection\xe8']

Python 3 was segfaulting:

C:\>C:\python34\python -c "import psutil;  print(psutil.net_if_addrs().keys())"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
segfault

giampaolo added a commit that referenced this pull request Aug 26, 2015
@giampaolo giampaolo added the bug label Nov 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants