Reputation: 11
I wrote this program to communicate internally with a server listening on port 27015. But the return value from the connect()
give me error 10047. There was no problem with socket creating and getaddrinfo()
return wasn't an error. I don't know why the socket won't connect, could it be a problem with the concert of network-byte and host-byte?
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#define DEFAULT_PORT "27015"
using namespace std;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) {
WSADATA wsaData;
// Initialize Winsock version 2.2
int ret;
// holds server info//
if (ret = WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
std::cout << "WSAStartup failed with error %ld\n", WSAGetLastError());
return 0;
}
else{
cout << "The current status is:" << wsaData.szSystemStatus << "\n";
}
// Setup Winsock communication code here
struct addrinfo *result = NULL, *ptr = NULL, hints;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
memset(&hints, 0, sizeof(hints));
int iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET Sending_socket;
Sending_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Sending_socket == INVALID_SOCKET){
cout << "socket error\n";
WSACleanup();
return 0;
}
// now we connect to the server ,RetCode=return of connect()
int RetCode = connect(Sending_socket, result->ai_addr, (int)result->ai_addrlen);
if (RetCode != 0) {
int num_attempt = 0;
while (RetCode != 0 && num_attempt != 100){
printf("Error at socket(): %ld\n", WSAGetLastError());
RetCode = connect(Sending_socket, result->ai_addr, (int)result->ai_addrlen);
num_attempt++;
}
}
else {
cout << "connect okay \n";
}
int them ;
closesocket(Sending_socket);
// When your application is finished call WSACleanup
them = WSACleanup();
// making sure to cleanup
if (them != 0){
cout << "WSACleanup failed with error " << WSAGetLastError();
// and exit
return 1;
}
return 1;
}
Upvotes: 0
Views: 3141
Reputation: 595971
Error 10047 is WSAEAFNOSUPPORT
, which happens when you try to give connect()
an IP address whose family is not supported by the socket that is being connected, ie by passing an AF_INET
address to an AF_INET6
socket, or an AF_INET6
address to an AF_INET
socket. In this case, the latter is happening.
And the reason this is happening is because your call to memset(&hints, 0, sizeof(hints));
is in the wrong place!
You declare the hints
variable and don't zero it out initially, then you start to fill it in for an AF_INET
socket, but then you zero it out with memset()
just before you give it to getaddrinfo()
. So getaddrinfo()
sees the hints.ai_family
value is 0 (AF_UNSPEC
) thus giving permission for getaddrinfo()
to return EITHER/BOTH an IPv4 OR/AND an IPv6 address for "localhost"
. Most likely, getaddrinfo()
is outputting an AF_INET6
address at the front of the output list (remember, getaddrinfo()
outputs a null-terminated linked list of resolved IP addresses).
Then you proceed to create a new socket using a hard-coded AF_INET
as the socket family, instead of using the value from result->ai_family
, and then you give result->ai_addr
to connect()
, which fails with error 10047 if that IP address is an AF_INET6
address and not an AF_INET
address.
With that said, try something more like this:
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#define DEFAULT_PORT "27015"
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
WSADATA wsaData;
int ret;
// Initialize Winsock version 2.2
ret = WSAStartup(MAKEWORD(2,2), &wsaData);
if (ret != 0)
{
std::cout << "WSAStartup failed with error " << ret << "\n";
return 0;
}
std::cout << "The current status is:" << wsaData.szSystemStatus << "\n";
// Setup Winsock communication code here
struct addrinfo *result = NULL, *ptr = NULL, hints;
memset(&hints, 0, sizeof(hints)); // <-- MOVED HERE!!!
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
ret = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
if (ret != 0)
{
std::cout << "getaddrinfo failed: " << ret << "\n";
WSACleanup();
return 0;
}
SOCKET Sending_socket = INVALID_SOCKET;
for (int num_attempt = 0; num_attempt < 100; ++num_attempt)
{
Sending_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (Sending_socket == INVALID_SOCKET)
{
std::cout << "socket failed: " << WSAGetLastError() << "\n";
freeaddrinfo(result);
WSACleanup();
return 0;
}
// now we connect to the server
ret = connect(Sending_socket, result->ai_addr, (int)result->ai_addrlen);
if (ret == 0)
break;
std::cout << "Error at socket(): " << WSAGetLastError() << "\n";
closesocket(Sending_socket);
Sending_socket = INVALID_SOCKET;
}
/* alternatively:
SOCKET Sending_socket = INVALID_SOCKET;
for (int num_attempt = 0; Sending_socket == INVALID_SOCKET && num_attempt < 100; ++num_attempt)
{
for(ptr = result; ptr != NULL; ptr = ptr->ai_next)
{
Sending_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (Sending_socket == INVALID_SOCKET)
{
std::cout << "socket failed: " << WSAGetLastError() << "\n";
freeaddrinfo(result);
WSACleanup();
return 0;
}
// now we connect to the server
ret = connect(Sending_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (ret == 0)
break;
std::cout << "Error at socket(): " << WSAGetLastError() << "\n";
closesocket(Sending_socket);
Sending_socket = INVALID_SOCKET;
}
}
*/
freeaddrinfo(result);
if (Sending_socket != INVALID_SOCKET)
{
std::cout << "connect okay\n";
// use Sending_socket as needed...
closesocket(Sending_socket);
ret = 1;
}
else
{
std::cout << "connect not okay\n";
ret = 0;
}
// When your application is finished call WSACleanup
WSACleanup();
return ret;
}
Upvotes: 2
Reputation: 33931
Quoting Microsoft's documentation for inet_addr function
The
inet_addr
function converts a string containing an IPv4 dotted-decimal address into a proper address for theIN_ADDR
structure.
Emphasis mine. No dotted decimal address, no address.
Also worth noting from the documentation page's section on the return value,
If the string in the
cp
parameter does not contain a legitimate Internet address, for example if a portion of an "a.b.c.d" address exceeds 255, theninet_addr
returns the valueINADDR_NONE
.
Always check the return value to make sure it's not giving an error message.
Upvotes: 1