Your code has multiple issues:
- First, you correctly called
getaddrinfo()
, but then you completely threw away the results without using them. - You called
listen()
but you appear to intend to make an outgoing connection;listen()
is meant to listen for incoming connections. - Instead of using the information from
getaddrinfo()
you ignore it and assume IPv4 when filling out yoursockaddr_in
structure. This part of the code should just be scrapped. - There's no need to explicitly check the returned address family. You won't get any address families that the computer can't handle.
- You appear to be writing a single method which does more than one thing, i.e. both make outgoing connections and accept incoming connections. Methods should only do one thing.
Let's go back to the beginning and get a minimal outgoing connection up. I'm omitting anything here not directly related to creating the connection (e.g. the call to WSAAsyncSelect()
and other stuff which belongs in separate methods anyway):
// Connect to a remote host, given its address and port number.
bool Connect(short port, std::string addr)
{
struct addrinfo *result, *rp;
// TODO: You passed us an integer port number. We need a C string.
// Clean up this mess.
char portstr[255];
portstr = sprintf("%d", port);
if (getaddrinfo(addr.c_str(), portstr, nullptr, &result)) {
throw runtime_error("getaddrinfo: " + WSAGetLastError());
}
// A host can have multiple addresses. Try each of them in turn until
// one succeeds. Typically this will try the IPv6 address first, if
// one exists, then the IPv4 address. The OS controls this ordering
// and you should not attempt to alter it. (RFC 6724)
for (rp = result; rp != nullptr; rp = rp->ai_next) {
this->hSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
// Check socket creation failed; maybe harmless (e.g. computer
// doesn't have IPv6 connectivity). Real errors will get thrown below.
if (this->hSocket == -1)
continue;
if (connect(this->hSocket, rp->ai_addr, rp->ai_addrlen) != -1)
break; // Success
close(this->hSocket);
}
if (rp == NULL) { // No address succeeded
throw runtime_error("connect: " + WSAGetLastError());
}
freeaddrinfo(result);
// Now this->hSocket has an open socket connection. Enjoy!
}
The major thing to note is that getaddrinfo()
handles all the heavy lifting for you. The structure it returns has all the information needed to create the connection; you only have to use it.
If you want the connection information, such as address and family, you can copy those out of rp
and store them somewhere before it goes out of scope.
Writing the separate method to handle incoming connections is left as an exercise for the reader. Your example code appears to be partly based on the sample on the MSDN page for getaddrinfo; the Linux getaddrinfo
manual page has much better examples (the sample code actually works with minimal change on Windows).