Trying to get a program to return an IP address along with a port number so I can create an effective TCP Client/Server program. Struggling with the function getaddrinfo() at the moment and understand that the 2nd argument in the function is what designates the port number. I can get it to return an IP but can't get it to return a port number. I'm inputting the host name and port designation (ex. http or telnet) in string form and trying to get back an IP address and port number associated with it.
I've tried inputting AI_NUMERICSERV into ai.flags in order to input the numeric value of the port number besides specifying "http" and "telnet". Just trying to understand network programming for the first time.
int main(int argc, char **argv){
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// hints.ai_flags = AI_NUMERICSERV;//leaving this off for now
if((status = getaddrinfo(argv[1], argv[2], &hints, &res)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
`for(p = res; p != NULL; p = p->ai_next)
{
void *addr;
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf("%s\n", ipstr);
}
printf("IP addresses for %s:\n\n", argv[1]); //displays IP correctly
printf("Port for %s: ", argv[2]); // doesn't display port number
freeaddrinfo(res);
return 0;
}
I keep expecting a port number output next to IP address output but I always get just the IP address and not the port number.
You need to read the port(s) returned by res->ai_addr...
printf("port=%h\n", ntohs(((struct sockaddr_in*)(res->ai_addr)) ->sin_port));
If you are just trying to figure out what port(s) are associated with specific services, and you are on a *nix host, you can also just grep /etc/services.
Related
The IP address is 192.168.23.4. I am able to get the hostname from the ipaddress using the following code snippet:
struct sockaddr_in sa;
char str[INET_ADDRSTRLEN];
inet_pton(AF_INET, "192.168.23.4", &(sa.sin_addr));
struct sockaddr_in saGNI;
char hostname[NI_MAXHOST];
char servInfo[NI_MAXSERV];
u_short port = 27015;
saGNI.sin_family = AF_INET;
saGNI.sin_addr.s_addr = sa.sin_addr.s_addr;
saGNI.sin_port = htons(port);
DWORD dwRetval = getnameinfo((struct sockaddr *) &saGNI,
sizeof(struct sockaddr),
hostname,
NI_MAXHOST, servInfo, NI_MAXSERV, NI_NUMERICSERV);
printf("HostName: %s", hostname);
I am getting an output of the form
ComputerName.domain.com
How do I get the Computername from the hostname?
Eg Input
ComputerName.domain.com
Eg Output
ComputerName
Is there any way to directly get the ComputerName of a system whose IP address is known?
I am looking for the same result as displayed using the Hostname command on the remote system.
Check the manual pages for getnameinfo
http://man7.org/linux/man-pages/man3/getnameinfo.3.html
According to the manual pages, you should set the NI_NOFQDN flags.
NI_NOFQDN
If set, return only the hostname part of the fully qualified
domain name for local hosts.
As suggested by emirc,
the following code is printing Computername:
struct sockaddr_in sa;
char str[INET_ADDRSTRLEN];
inet_pton(AF_INET, "192.168.23.4", &(sa.sin_addr));
struct sockaddr_in saGNI;
char hostname[NI_MAXHOST];
char servInfo[NI_MAXSERV];
u_short port = 27015;
saGNI.sin_family = AF_INET;
saGNI.sin_addr.s_addr = sa.sin_addr.s_addr;
saGNI.sin_port = htons(port);
DWORD dwRetval = getnameinfo((struct sockaddr *) &saGNI,
sizeof(struct sockaddr),
hostname,
NI_MAXHOST, servInfo, NI_MAXSERV, NI_NOFQDN);
printf("HostName: %s", hostname);
Note:
I have changed the flag from
NI_NUMERICSERV
to
NI_NOFQDN
You mean, you want to truncate the string before the first period?
std::string host(hostname);
size_t pos = host.find('.');
if (pos != std::string::npos)
{
host = host.substr(0,pos);
}
strcpy(hostname, host.c_str());
If you are interested in finding the host name of the computer on which the code is running, Boost.Asio could simplify the task:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
int main() {
std::string hostname = boost::asio::ip::host_name();
std::cout << "hostname = " << hostname << std::endl;
}
Note that this needs to be compiled with the -lpthread option.
Context: My C++ application needs to know on which computer it is running in order to do specific behavior. So my application gets the IP address of the computer and then check that address in a configuration file with an IP list in order to determine the computer's role. All computers have a fixed IP address. I am using gethostname, getaddrinfo and inet_ntop in order to do that.
Problem: On some target platform's computers, getaddrinfo returns the old IP address (the address before I set the fixed value). But if I am doing "ipconfig" in the cmd, the expected fixed value is shown. It is also pingable by other computers. All computers have only 1 network card, IPv6 is disabled.
Platform: Windows 7 x64.
IDE: Visual Studio 2015.
I would like to have the actual fixed IP address.
Thank you for your help!
Code sample:
// [Some stuff...]
addrinfo hints;
addrinfo *pResults;
int returnedCode;
char hostName[1024];
if (0 != (returnedCode = gethostname(hostName, sizeof hostName)))
{
// Error handling stuff.
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // Only want IPv4.
hints.ai_socktype = SOCK_DGRAM; // UDP stream sockets.
hints.ai_flags = AI_PASSIVE; // Fill in my IP for me.
if (0 != (returnedCode = getaddrinfo(hostName, NULL, &hints, &pResults)))
{
// Error handling.
}
struct addrinfo* res;
char buffer[INET_ADDRSTRLEN];
std::string localIP;
for (res = pResults; res != NULL; res = res->ai_next)
{
if (res->ai_family == AF_INET)
{
const char* ip = inet_ntop(AF_INET,
&((struct sockaddr_in *)res->ai_addr)->sin_addr, buffer, INET_ADDRSTRLEN);
if ((NULL == ip) || (nullptr == ip))
{
// Error handling.
}
else
{
localIP = std::string(ip);
}
}
}
freeaddrinfo(pResults); // free the linked-list
WSACleanup();
// [More stuff...]
I'm programming a server/client system using winsock2 and it works great when I connect the client to the server name or the server IPv6 address. However, when I use the server IPv4 address I get error "Connection refused" from the call to connect() in the client.
This error occurs with either my client or using telnet. However, I can successfully ping the server using either of the three name, IPv4 or IPv6.
I've tried this running both server and client on the same machine, on separate machines, and firewalls deactivated on all machines.
Here is an excerpt of my server initialization and listening code:
SOCKET sockfd = INVALID_SOCKET, in_socketID;
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
struct addrinfo *ip;
sockaddr_storage incoming_addr;
int addr_size;
int tmp_err;
const char *sPort = "20152";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
tmp_err = getaddrinfo(NULL, sPort, &hints, &servinfo);
if (tmp_err != 0)
throw exception("ERROR: getaddrinfo failed");
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL && sockfd == INVALID_SOCKET; p = p->ai_next)
{
ip = p;
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == INVALID_SOCKET)
{
cerr << "ERROR on socket(): " << WSAGetLastError() << endl;
} // end if
else if (bind(sockfd, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
{
cerr << "ERROR on bind(): " << WSAGetLastError() << endl;
closesocket(sockfd);
sockfd = INVALID_SOCKET;
} // end if
} // end for
if (sockfd == INVALID_SOCKET)
{
// looped off the end of the list with no successful bind
throw exception("ERROR: Failed to bind socket");
}
// clean up
if (servinfo)
freeaddrinfo(servinfo);
if (listen(sockfd, SOMAXCONN ) == SOCKET_ERROR)
throw exception("Listen failed");
while (true)
{
memset(&incoming_addr, 0, sizeof(incoming_addr));
addr_size = sizeof(incoming_addr);
in_socketID = accept(socketID, (sockaddr *)&incoming_addr, &addr_size);
// do stuff with incoming connection
}
This is my client code:
int sockfd = INVALID_SOCKET;
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
struct addrinfo *ip;
int tmp_err;
const char *sHost = "192.168.1.136";
const char *sPort = "20152";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // use TCP
tmp_err = getaddrinfo(sHost, // web address or ip to connect to
sPort, // port or protocol
&hints, // initialized hints structure
&servinfo); // return structure
if (tmp_err != 0)
throw exception("ERROR: getaddrinfo failed");
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL && sockfd == INVALID_SOCKET; p = p->ai_next)
{
ip = p;
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == INVALID_SOCKET)
{
cerr << "ERROR on socket(): " << WSAGetLastError() << endl;
//continue;
} // end if
else if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0)
{
cerr << "ERROR on connect(): " << WSAGetLastError() << endl;
closesocket(sockfd);
sockfd = INVALID_SOCKET;
//continue;
} // end if
} // end for
if (sockfd == INVALID_SOCKET)
throw exception("ERROR: Failed to connect");
// clean up
if (servinfo)
freeaddrinfo(servinfo);
// do stuff with new socket
I already read several similar questions in the site, but none answered this issue.
How can I connect also to the server IPv4 address? I need help, please.
Thanks.
EDIT:
From a suggestion given by user Sorayuki, I made some changes just to test if his theory was correct.
I was able to connect to the IPv4 by changing on the server
hints.ai_family = AF_UNSPEC;
to
hints.ai_family = AF_INET;
I knew it would obviously work, but when I do this, of course IPv6 doesn't work.
It appears user Sorayuki was right and my loop was connecting to IPv6.
It seems that there is no easy way to unify IPv6 and IPv4. Your socket must listen to either one or the other which makes the process really annoying.
According to the documentation, the old style to listen to both IPv4 and IPv6 is to create a socket for each and listen on both. This is for Windows Server 2003 and Windows XP SP1.
The preferred modern style (Windows Vista, 7 and 8) is to turn your socket into a dual socket and it will listen to both IPv4 and IPv6. However, your client must also be able to set up a dual socket, so, if your application is serving an old client, you are stuck with the old method.
Thanks!
This is because binding to an IPv6 address does not magically bind to an IPv4 address as well.
On Linux, by default binding to [::] will cause IPv6 and IPv4 to work (unless /proc/sys/net/ipv6/bindv6only is set to 1).
However, on Mac OS X and Windows, binding to [::] will only work for IPv6. You must also bind to an IPv4 address (or 0.0.0.0) for it to work.
Your logic described in your comment "loop through all the results and bind to the first we can" is precisely the problem here. You should both bind to [::] with the IPV6_V6ONLY flag (see setsockopt()) and 0.0.0.0.
Is it because that you bind your server socket to an IPv6 address?
in the "for" loop, IPv6 address appearing before IPv4 address seems to cause your server's socket listen on an IPv6 address.
So your server is not listening on any IPv4 address, cause all connection towards IPv4 address of server is refused.
Try to see all listening port is on which IP address with tool or some command (eg. netstat)
have you tried to run the server and client on the same machine?
this sounds like a firewall problem.
if you succeed connecting telnet / your application on the same machine you'll know this is the problem.
I've been using getaddrinfo for looking up socket addresses for basic socket commands. Recently, though, the addresses it returns to me are for bogus IP addresses, which I have found using inet_ntop. I've tried my code, as well as that provided in Beej's Guide, and they both produce the same results. Here's the code:
struct addrinfo hints, *info;
int status;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if(status = getaddrinfo(address, port, &hints, &info)) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
}
char ip4[INET_ADDRSTRLEN];
inet_ntop(AF_INET, info->ai_addr, ip4, INET_ADDRSTRLEN);
std::cout<<ip4<<std::endl;
No matter what address I use, it always gives me an IP of the form
16.2.x.y
where 256*x + y is equal to the port number. Has anyone ever seen this happen, or can anyone guess why it's giving me this?
Shouldn't you be passing
((sockaddr_in const *)info->ai_addr)->sin_addr
to inet_ntop?
I am creating a winsock UDP program. code i am using is shown below.
I am always getting port assignment error.
I am not able to understand why port always allocated is zero. If some can help me with this....
void UDPecho(const char *, const char *);
void errexit(const char *, ...);
#define LINELEN 128
#define WSVERS MAKEWORD(2, 0)
void main(int argc, char *argv[])
{
char *host = "localhost";
char *service = "echo";
WSADATA wsadata;
switch (argc) {
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: UDPecho [host [port]]\n");
exit(1);
}
if (WSAStartup(WSVERS, &wsadata))
errexit("WSAStartup failed\n");
UDPecho(host, service);
WSACleanup();
exit(0);
}
void UDPecho(const char *host, const char *service)
{
char buf[LINELEN+1];
SOCKET s;
int nchars;
struct hostent *phe;
struct servent *pse;
struct protoent *ppe;
struct sockaddr_in sin, my_sin;
int type, status, client_port, size;
char *transport = "udp";
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = pse->s_port;
else if ( (sin.sin_port = htons((u_short)atoi(service)))== 0)
errexit("can't get \"%s\" service entry\n", service);
/* Map host name to IP address, allowing for dotted decimal */
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
errexit("can't get \"%s\" host entry\n", host);
printf("Our target server is at address %s\n", inet_ntoa(sin.sin_addr));
printf("The size of an FD set is %d\n", sizeof(FD_SET));
/* Map protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s == INVALID_SOCKET)
errexit("can't create socket: %d\n", GetLastError());
size = sizeof(sin);
memset(&my_sin, 0, sizeof(sin));
getsockname (s, (struct sockaddr *) &my_sin, &size);
client_port = ntohs(my_sin.sin_port);
if (client_port != 0)
printf ("We are using port %2d\n", client_port);
else {
printf("No port assigned yet\n");
}
}
void errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
WSACleanup();
exit(1);
}
UDP doesn't bind to the listening port until you either issue a sendto() or a bind() on the socket. The latter lets you select the port that you want to listen on. Sendto(), on the other hand, will pick an ephemeral port for you. I would expect that the port will remain zero until you do one of these two things.
Clarification
I looked into this a little more after some of the comment. According to the Single UNIX Specification the result of calling socket() is an unbound socket. A socket is bound explicitly by calling bind() or implicitly sendto().
Think of a socket's name as a tuple containing its (Address Family, Protocol, local IP Address, and local Port Number). The first two are specified in the socket() call and the last two by calling bind(). In the case of connectionless protocols, a call to sendto() on a disconnected socket will result in an implicit bind to an OS chosen port number.
The most surprising thing is that the only reference that I can find to this behavior is in the remarks section of the Microsoft documentation for sendto().
If the socket is unbound, unique values are assigned to the local association by the system and the socket is then marked as bound. An application can use getsockname (Windows Sockets) to determine the local socket name in this case.
The Single UNIX Specification for getsockname() states:
If the socket has not been bound to a local name, the value stored in the object pointed to by address is unspecified.
It seems that a successful return with an unspecified result is the "standard" behavior... hmmm... The implementations that I have tried all return successfully with a socket address of 0.0.0.0:0 which corresponds to INADDR_ANY with an unspecified port. After calling either bind() or sendto(), getsockname() returns a populated socket address though the address portion might still be INADDR_ANY.