Gcha83
Gcha83

Reputation: 3

Why the value is changing unexpectedly ? inet_ntoa

I'm trying to create a function which gathers all IPs present on the machine and will be able to detect when the IP in parameter is present. 

The Issue is that the value of the variable containing my IP is changing after an inet_ntoa done on another IN_ADDR.

I tried to use std::string without success. I know inet_ntoa is deprecated but I tried something else without success. Also I would like to understand what I'm doing wrong.

void CIPUtilities::AwaitIPAddress(struct sockaddr_in WFIAddr) {
// also tried with AwaitIPAddress(char * IPName)
char* IPName = inet_ntoa(WFIAddr.sin_addr);
printf("\n Waiting for the IP:  %s to be ready.\n", IPName);
int i;
bool ctn = TRUE;

/* Variables used by GetIpAddrTable */
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
IN_ADDR IPAddr;
ULONG outBufLen = 0;
ULONG Iterations = 0;

/* Variables used to return error message */
LPVOID lpMsgBuf;

// Allocate a 15 KB buffer to start with.
outBufLen = WORKING_BUFFER_SIZE;
do {

    do {
        //printf("inside do\n");
        Sleep(300); //to be removed ? Only there to avaoid to loop too much.
        pIPAddrTable = (MIB_IPADDRTABLE*)MALLOC(outBufLen);

        if (pIPAddrTable == NULL) {
            printf("Memory allocation failed for GetIpAddrTable\n");
            //exit(1); // no need to exit we need debug
        }

        dwRetVal = GetIpAddrTable(pIPAddrTable, &outBufLen, 0);

        if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
            FREE(pIPAddrTable);
            pIPAddrTable = NULL;
        }
        else {
            break;
        }
    } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));

    if (dwRetVal == NO_ERROR) {
        // If successful, search the IP from the data we retrived
        for (i = 0; i < (int)pIPAddrTable->dwNumEntries; i++) {
            IPAddr.S_un.S_addr = (u_long)pIPAddrTable->table[i].dwAddr;
            printf("1- The value of IPName is %s\n", IPName);
            printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr));
            printf("2- The value of IPName is %s\n", IPName);
            //if (strcmp(IPName, inet_ntoa(IPAddr)) == 0) {
            //    printf("IP adress[%s] is found in AddrTable\n", inet_ntoa(IPAddr));
            //    ctn = FALSE; // We exit the loop because the adress is created.
            //    break; // no need to parse more addresses.
            //}
        }
    }
    else
    {
        printf("GetIpAddrTable failed with error %d\n", dwRetVal);
        printf("Required size should be %d\n", dwSize);
        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       // Default language
            (LPTSTR)&lpMsgBuf, 0, NULL)) {
            printf("\tError: %s", (char*)lpMsgBuf);
            LocalFree(lpMsgBuf);
        }
        //exit(1);  // no need to exit we need debug
    }

    if (pIPAddrTable) {
        FREE(pIPAddrTable);
        pIPAddrTable = NULL;
    }

} while (ctn);}

Basically the output will be :

Waiting for the IP:  10.0.4.3 to be ready.
1- The value of IPName is 10.0.4.3
        IP Address[0]:          160.223.17.135
2- The value of IPName is 160.223.17.135
1- The value of IPName is 160.223.17.135
        IP Address[1]:          169.254.165.50
2- The value of IPName is 169.254.165.50
1- The value of IPName is 169.254.165.50
        IP Address[2]:          10.0.4.3
2- The value of IPName is 10.0.4.3
1- The value of IPName is 10.0.4.3
        IP Address[3]:          10.0.12.44
2- The value of IPName is 10.0.12.44
1- The value of IPName is 10.0.12.44
        IP Address[4]:          192.168.0.17
2- The value of IPName is 192.168.0.17
1- The value of IPName is 192.168.0.17
        IP Address[5]:          127.0.0.1
2- The value of IPName is 127.0.0.1
1- The value of IPName is 127.0.0.1

I removed some parts of the function to make it more readable.

Upvotes: 0

Views: 331

Answers (1)

Roxxorfreak
Roxxorfreak

Reputation: 380

In short: this happens because you use the returned pointer directly instead of making a copy of the string.

char* IPName = inet_ntoa(WFIAddr.sin_addr);

As stated in the documentation of inet_ntoa (see here for Windows or here for Linux) the result is a pointer to a static buffer:

The string returned is guaranteed to be valid only until the next Windows Sockets function call is made within the same thread. Therefore, the data should be copied before another Windows Sockets call is made.

All you need to do, is copy the contents of the buffer into a string variable.

char IPName[18];
char* temp = inet_ntoa(WFIAddr.sin_addr); 
if (temp != NULL)
{
  strcpy(IPName, temp);
}

(For details about the size of your buffer see here)

And you should, of course, treat the error case (if temp is NULL)

Upvotes: 2

Related Questions