Whenever I attempt to run my app on macOS Catalina 10.15.2 (19C57) or Linux 5.4.3-arch1-1 x86_64 GNU/Linux, I get:
_rSockd: bind: Address already in use
libc++abi.dylib: terminating with uncaught exception of type std::runtime_error: failed to bind to socket
[1] 31181 abort Saol/saol
Now I have checked for open ports with sudo netstat -tulp udp and sudo lsof -i udp, but none of these report any applications of mine using these ports. Nothing is currently listening on the port(45100).
I have browsed several similar posts that mentioned adding the SO_REUSEADDR, but this did not change anything when I have it or when I don't.
Posts also mentioned checking for something using the port, but I was unable (I believe unless the above commands were the wrong ones to use) to find my ports locked up. I have tried several different ports(currently using 45100); the _port var is set to an int before the _Init function is called. getaddrinfo's second argument is a const char *service, and stated in the man pages:
service sets the port in each returned address structure. If this
argument is a service name (see services(5)), it is translated to the
corresponding port number. This argument can also be specified as a
decimal number, which is simply converted to binary. If service is
NULL, then the port number of the returned socket addresses will be
left uninitialized. If AI_NUMERICSERV is specified in hints.ai_flags
and service is not NULL, then service must point to a string contain‐
ing a numeric port number. This flag is used to inhibit the invoca‐
tion of a name resolution service in cases where it is known not to
be required.
All I am doing to the _port is this: int -> string -> char *
Below is the relevant section of my code:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#define PORT "45100"
auto main(void) -> int {
int rv;
int _rSockd;
const char * port = std::to_string(8080).c_str();
struct addrinfo hints;
struct addrinfo *servinfo;
struct addrinfo *p;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) {
std::cerr << "getaddrinfo: " << std::endl << gai_strerror(rv) << std::endl;
throw std::runtime_error("failed to getaddrinfo");
}
for(p = servinfo; p != NULL; p = p->ai_next) {
if((_rSockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
std::perror("_rSockd: socket");
close(_rSockd);
continue;
}
if(bind(_rSockd, p->ai_addr, p->ai_addrlen) == -1) {
close(_rSockd);
std::perror("_rSockd: bind");
continue;
}
break;
}
if(p == NULL) {
throw std::runtime_error("failed to bind to socket");
}
freeaddrinfo(servinfo);
return 0;
}
Any help would be appreciated; I feel I have been staring at it too long and am missing something basic.
NOTE: When I added the MCVE (the above updated code), I no longer have my issue when running with port 8080 and 45100. So I will now explain the ??build?? process now to see if this is causing the issue.
UPDATE
When I made the MCVE, it worked. It never had the issues from my project base.
My project is a library being called from another executable project. libSaol has the netcode, saol is the executable that links libSaol.
To be honest, this confuses me more...
Related
Note: I looked extensively at a similar (but not duplicate) question here: GetAddrInfo cannot resolve ipv6.google.com (but nslookup can). This question is 9 years old, the OP is not experiencing the exact same behavior as I am, and the already-accepted answer does not solve my problem—in fact, I am specifically following the advice of that answer to no avail in the sample code below, and I'm getting a different error than on that question. Furthermore, the likelihood that I would succeed in getting anyone to engage on a question that old by merely commenting on it is nil. It is not the same problem as the problem I am having today, so I am created a new, more-detailed question.
I have a Windows 10 machine running Visual Studio 2017 and a Windows Server 2016 machine running Visual Studio 2019. Both of the machines have IPv4 and IPv6 addresses configured. On both machines, nslookup.exe returns the expected results for three different domains:
> nslookup www.google.com
...
Addresses: 2607:f8b0:4002:80a::2004
172.217.3.228
...
> nslookup ipv4.google.com
...
Addresses: 74.125.136.102
...
> nslookup ipv6.google.com
...
Addresses: 2607:f8b0:4002:812::200e
...
Now I'm trying to write an example program that uses GetAddrInfo to lookup these same three domains:
#include <iostream>
#include <sstream>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32.Lib")
int main(int argc, char* argv[])
{
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
int err( WSAStartup(wVersionRequested, &wsaData) );
if (err != 0)
{
std::cout << "WSAStartup failed with error " << err << std::endl << std::flush;
return 1;
}
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM; // so that we get each IP address once, instead of once per socket type
hints.ai_protocol = 0; // we don't care about the protocol
hints.ai_canonname = NULL; // should be NULL for hints
hints.ai_addr = NULL; // should be NULL for hints
hints.ai_next = NULL; // should be NULL for hints
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC; // I vary this and the hostname below
struct addrinfo* results;
int error = getaddrinfo("ipv6.google.com", NULL, &hints, &results);
if (error != 0)
{
std::ostringstream msg;
std::cout << "Could not resolve hostname due to ";
std::cout << "the following error in getaddrinfo: " << error << ": ";
if (error == -11)
{
std::cout << "EAI_SYSTEM";
}
else
{
std::cout << gai_strerrorA(error);
}
std::cout << std::endl << std::flush;
return 1;
}
for (struct addrinfo* result = results; result != NULL; result = result->ai_next)
{
if (result->ai_family == AF_INET6)
{
char buffer[INET6_ADDRSTRLEN];
std::string ipv6Str(
inet_ntop(
AF_INET6,
&((struct sockaddr_in6*)result->ai_addr)->sin6_addr,
buffer,
sizeof(buffer)));
std::cout << ipv6Str << std::endl << std::flush;
}
else
{
char buffer[INET_ADDRSTRLEN];
std::string ipv4Str(
inet_ntop(
AF_INET,
&((struct sockaddr_in*)result->ai_addr)->sin_addr,
buffer,
sizeof(buffer)));
std::cout << ipv4Str << std::endl << std::flush;
}
}
freeaddrinfo(results);
return 0;
}
For simplicity, I'm just changing the hints.ai_family and hard-coded hostname, then re-compiling and re-running (with Visual Studio). These are the results I get:
Hostname
hints.ai_family
Result
Expected?
www.google.com
AF_UNSPEC
One IPv4 and one IPv6 address
✅
www.google.com
AF_INET
One IPv4 address only
✅
www.google.com
AF_INET6
Err 11004: Name valid, no data
⛔️
ipv4.google.com
AF_UNSPEC
One IPv4 address only
✅
ipv4.google.com
AF_INET
One IPv4 address only
✅
ipv4.google.com
AF_INET6
Err 11004: Name valid, no data
✅
ipv6.google.com
AF_UNSPEC
Err 11004: Name valid, no data
⛔️
ipv6.google.com
AF_INET
Err 11004: Name valid, no data
✅
ipv6.google.com
AF_INET6
Err 11004: Name valid, no data
⛔️
I've hammered at this for a full day now and I can't get getaddrinfo to return the expected results. Why isn't this working? It appears that nslookup.exe using something other than getaddrinfo (perhaps a more low-level query of root and glue name servers), because it works fine there. Also note that this code (with different includes and without the WSA startup procedure) is working just fine in RedHat, CentOS, Ubuntu, and macOS High Sierra.
Some things I've tried other than varying the ai_family, all of which yield the same results as in the table below:
ai_flags = AI_NUMERICSERV
ai_flags = AI_ALL
ai_flags = AI_ALL | AI_NUMERICSERV
ai_socktype = SOCK_DGRAM
ai_socktype = 0
ai_protocol = IPPROTO_TCP
Also, it turns out that ipv6.google.com is actually a CNAME for ipv6.l.google.com, so I tried using that domain, instead, to no avail.
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 needed to open a socket from a specific local network card using WinSock. I asked about this and got an answer here. In short, the answer advises that you first bind to the local interface, then call connect.
However, when I do this, I get a WSAEADDRNOTAVAIL (10049) "The requested address is not valid in its context.". Why is this?
Assuming the sample code below is part of an application running on the local box 192.168.1.3 and is attempting to connect to remote server 192.168.1.4. I've checked and double-checked that the local and remote addresses are correct. I can ping both ways (from local to remote and remote to local).
I've tried ports other than 0 for the local; no difference. If I remove the bind before the connect, it then works, but I'm then not able to specify a network interface.
So, any idea why I keep getting WSAEADDRNOTAVAIL ?
addrinfo localhints = {0};
localhints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
localhints.ai_family = AF_INET;
localhints.ai_socktype = SOCK_STREAM;
localhints.ai_protocol = IPPROTO_TCP;
addrinfo *localaddr = NULL;
getaddrinfo("192.168.1.3", "0", &localhints, &localaddr);
bind(s, localaddr->ai_addr, localaddr->ai_addrlen);
freeaddrinfo(localaddr);
addrinfo remotehints = {0};
remotehints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
remotehints.ai_family = AF_INET;
remotehints.ai_socktype = SOCK_STREAM;
remotehints.ai_protocol = IPPROTO_TCP;
addrinfo *remoteaddr = NULL;
getaddrinfo("192.168.1.4", "12345", &remotehints, &remoteaddr);
connect(s, remoteaddr->ai_addr, remoteaddr->ai_addrlen);
freeaddrinfo(remoteaddr);
EDIT: This sample code intentionally has no error checking, so that my intent could be communicated in the most efficient way.
EDIT 2: A bind to 192.168.1.3 causes connect to fail. A bind to 127.0.0.1 works. Yes, I'm 100% sure that 192.168.1.3 is the correct local IP.
EDIT 3: Right! On a whim, I tried the test app on my home PC and it works fine. So, at least the code does work, and the trouble must be related to my work PC.
OK, turns out #claptrap was right.
I had disabled my firewall, but unknown to me, our IT department has some other firewally-thingy tightly integrated into the enterprise virus scanner (which I can't uninstall or disable). Once I managed to get IT to temporarily disabled it, everything worked as expected.
Always check error codes when calling API functions, eg:
addrinfo localhints = {0};
localhints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
localhints.ai_family = AF_INET;
localhints.ai_socktype = SOCK_STREAM;
localhints.ai_protocol = IPPROTO_TCP;
addrinfo *localaddr = NULL;
int ret = getaddrinfo("192.168.1.3", "0", &localhints, &localaddr);
if (ret == 0)
{
ret = bind(s, localaddr->ai_addr, localaddr->ai_addrlen);
freeaddrinfo(localaddr);
if (ret == 0)
{
addrinfo remotehints = {0};
remotehints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
remotehints.ai_family = AF_INET;
remotehints.ai_socktype = SOCK_STREAM;
remotehints.ai_protocol = IPPROTO_TCP;
addrinfo *remoteaddr = NULL;
ret = getaddrinfo("192.168.1.4", "12345", &remotehints, &remoteaddr);
if (ret == 0)
{
ret = connect(s, remoteaddr->ai_addr, remoteaddr->ai_addrlen);
freeaddrinfo(remoteaddr);
if (ret == 0)
{
// connect succeeded...
// can use getsockname() here to discover which port was actually bound to, if needed.
// On some OS versions, bind() does not perform the actual binding immediately,
// connect() does the actual binding instead since it can make more informed choices based on the target address being connected to...
}
else
{
// connect failed...
}
}
else
{
// getaddrinfo() failed
}
}
else
{
// bind failed
}
}
else
{
// getaddrinfo() failed...
}
How far does the code actually get?
i wrote a class encapsulating some of the winsock functions to imitate a simple TCP socket for my needs...
When i try to run a simple connect-and-send-data-to-server test the "client" fails on its call to connect with the error code of 10049 (WSAEADDRNOTAVAIL) connect function on MSDN
What I am doing is (code below):
Server:
Create a Server Socket -> Bind it to Port 12345
Put the Socket in listen mode
Call accept
Client
Create a socket -> Bind it to a random port
Call Connect: connect to localhost, port 12345
=> the call to connect fails with Error 10049, as described above
Here is the main function including the "server":
HANDLE hThread = NULL;
Inc::CSocketTCP ServerSock;
Inc::CSocketTCP ClientSock;
try
{
ServerSock.Bind(L"", L"12345");
ServerSock.Listen(10);
//Spawn the senders-thread
hThread = (HANDLE)_beginthreadex(nullptr, 0, Procy, nullptr, 0, nullptr);
//accept
ServerSock.Accept(ClientSock);
//Adjust the maximum packet size
ClientSock.SetPacketSize(100);
//receive data
std::wstring Data;
ClientSock.Receive(Data);
std::wcout << "Received:\t" << Data << std::endl;
}
catch(std::exception& e)
{...
Client thread function
unsigned int WINAPI Procy(void* p)
{
Sleep(1500);
try{
Inc::CSocketTCP SenderSock;
SenderSock.Bind(L"", L"123456");
SenderSock.Connect(L"localhost", L"12345");
//Adjust packet size
SenderSock.SetPacketSize(100);
//Send Data
std::wstring Data = L"Hello Bello!";
SenderSock.Send(Data);
}
catch(std::exception& e)
{
std::wcout << e.what() << std::endl;
}...
The Connect-Function
int Inc::CSocketTCP::Connect(const std::wstring& IP, const std::wstring& Port)
{
//NOTE: assert that the socket is valid
assert(m_Socket != INVALID_SOCKET);
//for debuggin: convert WStringToString here
std::string strIP = WStringToString(IP), strPort = WStringToString(Port);
Incgetaddrinfo AddyResolver;
addrinfo hints = {}, *pFinal = nullptr;
hints.ai_family = AF_INET;
//resolve the ip/port-combination for the connection process
INT Ret = AddyResolver(strIP.c_str(), strPort.c_str(), &hints, &pFinal);
if(Ret)
{
//error handling: throw an error description
std::string ErrorString("Resolving Process failed (Connect): ");
ErrorString.append(Inc::NumberToString<INT>(Ret));
throw(std::runtime_error(ErrorString.c_str()));
}
/*---for debbuging---*/
sockaddr_in *pP = (sockaddr_in*)(pFinal->ai_addr);
u_short Porty = ntohs(pP->sin_port);
char AddBuffer[20] = "";
InetNtopA(AF_INET, (PVOID)&pP->sin_addr, AddBuffer, 20);
/*--------------------------------------------------------*/
if(connect(m_Socket, pFinal->ai_addr, pFinal->ai_addrlen) == SOCKET_ERROR)
{
int ErrorCode = WSAGetLastError();
if((ErrorCode == WSAETIMEDOUT) || (ErrorCode == WSAEHOSTUNREACH) || (ErrorCode == WSAENETUNREACH))
{
//Just Unreachable
return TCP_TARGETUNREACHABLE;
}
//real errors now
std::string ErrorString("Connection Process failed: ");
ErrorString.append(Inc::NumberToString<int>(ErrorCode));
throw(std::runtime_error(ErrorString.c_str()));
}
return TCP_SUCCESS;
}
Additional Information:
-Incgetaddrinfo is a function object encapuslating getaddrinfo...
-Noone of the server functions return any error and work as expected when stepping through them using the debugger or when letting them run solely...
I'd be glad to hear your suggestions what the rpoblem might be...
Edit: It works when I dont connect to ("localhost","12345"), but to ("",12345)...
When look into the address resolution process of getaddrinfo it gives 127.0.0.1 for "localhost" and my real IP for ""
Why doesn't it work with my loopback-IP?
You have the answer in your question:
... it gives 127.0.0.1 for "localhost" and my real IP for ""
This means your server binds to the real IP of the interface instead of INADDR_ANY, i.e. it doesn't listen on the loopback.
Edit 0:
You don't really need name resolution when creating listening socket. Just bind() it to INADDR_ANY to listen on all available interfaces (including the loopback).
In my case, this error was caused by not calling htonl on INADDR_LOOPBACK before assigning it to address.sin_addr.s_addr.
Make sure you convert to network byte order, or you'll get 0x0100007f (1.0.0.127) instead of 0x7f000001 (127.0.0.1) for your loopback address and the bind will fail with code 10049 (WSAEADDRNOTAVAIL).