I wrote a program to get local host name. if it is not obvious, I mean to get the host name of the local machine similar to gethostname
method, not to get the string localhost
I'm using getaddrinfo
with NULL
for host name and then call to getnameinfo
with the first address.
It works perfectly on windows machines, and giving me the canonical host name, but in Linux it failed to give me the local host name and gives me ::
for IPv6 or 0.0.0.0
for IPv4.
Note that I'm using AI_PASSIVE
flag in getaddrinfo
, means it gives me no more than two addresses.
In the getnameinfo
if I use the NI_NAMEREQD
it fail.
I'm doing so because I have a server, sometimes I want to listen to all interfaces and sometimes to a specific interface, I'm already have the addrinfo
and I just want to get the hostname from it if possible.
How can I make it work on Linux? did I missed anything?
Thanks for any help.
Here is my code: (cross platform, windows and Linux, just copy & past) You can compile and run on both and see the difference.
#include <iostream>
#ifdef WIN32
#ifdef UNICODE
#undef UNICODE /* don't want Unicode, to keep code compatibility */
#endif
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
class CWSAInitializer{
public:
CWSAInitializer(){
WSADATA data;
WSAStartup(MAKEWORD(2,2),&data);
}
~CWSAInitializer(){
WSACleanup();
}
}autoInit;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
const char* get_hostname(struct addrinfo* info, char buff[], int buff_len)
{
int addrlen = (int)info->ai_addrlen;
int res = getnameinfo(info->ai_addr, addrlen, buff, buff_len, NULL, 0, 0);
if(res){
return NULL;
}
return buff;
}
int main ()
{
char temp[100];
addrinfo *ai,hints;
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_PASSIVE;
int res = getaddrinfo(NULL, "0", &hints, &ai);
if(res){
std::cerr<<gai_strerror(res)<<std::endl;
return -1;
}
std::cout<< get_hostname(ai,temp,100)<<std::endl;
freeaddrinfo(ai);
return 0;
}
EDIT
The server should accept client from other machines as well, so it can't report listening on
::
or0.0.0.0
.I know I can patch it like this:
if(std::string("::") == hostname || std::string("0.0.0.0") == hostname)
gethostname(hostname,100)
- I don't want to get
localhost
as result, unless the address is127.0.0.1
or::1
.