I've been learning how to use getaddrinfo() recently. I referred to Wikipedia for an example:
http://en.wikipedia.org/wiki/Getaddrinfo
I made some small modifications to the example code to compile it with Visual C++ 2005.
The modified version is as follows:
int main(){
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
struct addrinfo *res;
int error;
/* resolve the domain name into a list of addresses */
error = getaddrinfo("www.example.com", NULL, NULL, &result);
if (error != 0)
{
fprintf(stderr, "%d\n", error);
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
exit(EXIT_FAILURE);
}
/* loop over all returned results and do inverse lookup */
for (res = result; res != NULL; res = res->ai_next)
{
char hostname[NI_MAXHOST] = "";
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
if (error != 0)
{
fprintf(stderr, "%d\n", WSAGetLastError());
fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
continue;
}
if (*hostname != '\0')
printf("hostname: %s\n", hostname);
}
freeaddrinfo(result);
getchar();
return 0;
}
The execution result is surprisingly failed with a return error:WSANO_DATA.
Nevertheless, I can connect to www.example.com with Google Chrome.
I've also replaced www.example.com with other domain names in the code and done tests. Some of the results are expected while some others are strange:
test: localhost
hostname: localhost
test: www.yahoo.com.tw
hostname: w2.rc.vip.gq1.yahoo.com
hostname: w2.rc.vip.sp1.yahoo.com
The first result is as expected, but the second(www.yahoo.com.tw) is strange. I can't connect to "w2.rc.vip.gq1.yahoo.com" and "w2.rc.vip.sp1.yahoo.com" via the browser.
Could anyone explain why I got the above results and why the original example from Wikipedia didn't work? Thanks a lot.
The example and your code work just fine.
Connecting directly to the address of Yahoo's load balancer should not work as it's meant to forward your request to a front end delivery server based on the domain, subdomain and route.
You can find more info on wiki about Load balancing and how it works.
As for the error, try flushing your DNS cache before retesting. It can be done with ipconfig /flushdns on Windows.
Related
So, I am on Windows 10, and using latest MINGW64 from MSYS2:
$ uname -a
MINGW64_NT-10.0-19043 DESKTOP-XXXXXXX 3.2.0-340.x86_64 2021-08-02 16:30 UTC x86_64 Msys
I have experiencing something strange with Winsock bind, which I can now reconstruct on a minimal working example, which is a basic server code from Winsock Server And Client Example: "getaddrinfo" was not declared in this scope , that I saved as test.cpp (EDIT: code is now with printout, EDIT2: and with input argument):
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 512
//~ #define DEFAULT_PORT "27015"
#define DEFAULT_PORT "9010"
void print_getaddrinfo_response(struct addrinfo *result);
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
char defaultport[8];
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// here, argc==1 for no arguments
if (argc==2) {
snprintf( defaultport, 8, "%s", argv[1] );
} else {
snprintf( defaultport, 8, "%s", DEFAULT_PORT );
}
printf("Listening on port: %s ...", defaultport);
// Resolve the server address and port
iResult = getaddrinfo(NULL, defaultport, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
//print_getaddrinfo_response(result);
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
if (argc==2) { // exit immediately
printf(" exiting\n");
closesocket(ListenSocket);
WSACleanup();
return 0;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket);
// Receive until the peer shuts down the connection
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
// Echo the buffer back to the sender
iSendResult = send( ClientSocket, recvbuf, iResult, 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
void print_getaddrinfo_response(struct addrinfo *result) {
// from https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoa
INT iRetval;
int i = 1;
struct addrinfo *ptr = NULL;
struct sockaddr_in *sockaddr_ipv4;
LPSOCKADDR sockaddr_ip;
char ipstringbuffer[46];
DWORD ipbufferlength = 46;
// Retrieve each address and print out the hex bytes
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
printf("getaddrinfo response %d\n", i++);
printf("\tFlags: 0x%x\n", ptr->ai_flags);
printf("\tFamily: ");
switch (ptr->ai_family) {
case AF_UNSPEC:
printf("Unspecified\n");
break;
case AF_INET:
printf("AF_INET (IPv4)\n");
sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
printf("\tIPv4 address %s\n",
inet_ntoa(sockaddr_ipv4->sin_addr) );
break;
case AF_INET6:
printf("AF_INET6 (IPv6)\n");
// the InetNtop function is available on Windows Vista and later
// sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
// printf("\tIPv6 address %s\n",
// InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstringbuffer, 46) );
// We use WSAAddressToString since it is supported on Windows XP and later
sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
// The buffer length is changed by each call to WSAAddresstoString
// So we need to set it for each iteration through the loop for safety
ipbufferlength = 46;
iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL,
ipstringbuffer, &ipbufferlength );
if (iRetval)
printf("WSAAddressToString failed with %u\n", WSAGetLastError() );
else
printf("\tIPv6 address %s\n", ipstringbuffer);
break;
case AF_NETBIOS:
printf("AF_NETBIOS (NetBIOS)\n");
break;
default:
printf("Other %ld\n", ptr->ai_family);
break;
}
printf("\tSocket type: ");
switch (ptr->ai_socktype) {
case 0:
printf("Unspecified\n");
break;
case SOCK_STREAM:
printf("SOCK_STREAM (stream)\n");
break;
case SOCK_DGRAM:
printf("SOCK_DGRAM (datagram) \n");
break;
case SOCK_RAW:
printf("SOCK_RAW (raw) \n");
break;
case SOCK_RDM:
printf("SOCK_RDM (reliable message datagram)\n");
break;
case SOCK_SEQPACKET:
printf("SOCK_SEQPACKET (pseudo-stream packet)\n");
break;
default:
printf("Other %ld\n", ptr->ai_socktype);
break;
}
printf("\tProtocol: ");
switch (ptr->ai_protocol) {
case 0:
printf("Unspecified\n");
break;
case IPPROTO_TCP:
printf("IPPROTO_TCP (TCP)\n");
break;
case IPPROTO_UDP:
printf("IPPROTO_UDP (UDP) \n");
break;
default:
printf("Other %ld\n", ptr->ai_protocol);
break;
}
printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
printf("\tCanonical name: %s\n", ptr->ai_canonname);
}
}
This I compile in MINGW64:
$ g++ test.cpp -g -o test.exe -lws2_32
... and as far as building goes, it compiles without a problem. But when running:
When you have the code as in the original linked post, with #define DEFAULT_PORT "27015", then there is no problem, and code works - I'm running it from cmd.exe:
D:\>test.exe
getaddrinfo response 1
Flags: 0x0
Family: AF_INET (IPv4)
IPv4 address 0.0.0.0
Socket type: SOCK_STREAM (stream)
Protocol: IPPROTO_TCP (TCP)
Length of this sockaddr: 16
Canonical name: (null)
Bytes received: 7
Bytes sent: 7
Connection closing...
... and the above happens in response to triggering it with telnet (which I call from the MINGW64 bash shell):
$ telnet 127.0.0.1 27015
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello
hello
↔
telnet> q
Connection closed.
When you have the code as in this post, that is, with #define DEFAULT_PORT "9010", it compiles fine; but then when I try to run it,it exits immediately:
D:\>test.exe
getaddrinfo response 1
Flags: 0x0
Family: AF_INET (IPv4)
IPv4 address 0.0.0.0
Socket type: SOCK_STREAM (stream)
Protocol: IPPROTO_TCP (TCP)
Length of this sockaddr: 16
Canonical name: (null)
bind failed with error: 10013
Now, Socket error 10013 is a message which implies that a port is blocked and/or unreachable - which I guess means, port 9010 is blocked somehow?!
But, so far, I cannot confirm that this port is blocked in any way:
Querying the firewall (in administrative command prompt) on the test.exe program gives me:
D:\>netsh firewall show config | findstr test
Enable Inbound test / D:\test.exe
... which I guess means, it is allowed to have incoming connections?
D:\>netsh firewall show config | findstr 9010
D:\>
The above returns nothing, so port 9010 seems to be not explicitly mentioned in firewall.
And querying for open listening port 9010 (as in, if there is a hanging process in the background, preventing test.exe to start up), also returns nothing:
D:\>netstat -a -n | findstr 9010
D:\>
So, how in the world can I debug, and find out/confirm, why is port 9010 in this application inaccessible - but port 27015 works fine ?!
EDIT: I've added printouts in response to comment:
The getaddrinfo function can return a list of results
... and here, it seems, it returns only one - for address 0.0.0.0
Also, I agree with:
you are using a port that someone doesn't want you using.
... and, in essence, I'd like to find out what is that someone that doesn't want me using port 9010 - especially since when I try the above commands, I do not get any message, that anything is using port 9010.
EDIT2: The code can now accept the port via input argument, and if that is the case, it exits immediately (so, all the notes about recompiling and calling, still work).
That means, now I can call a loop like this:
$ for i in $(seq 8080 11000); do ./test.exe $i; done
Listening on port: 8080 ... exiting
Listening on port: 8081 ... exiting
Listening on port: 8082 ... exiting
...
Listening on port: 8818 ... exiting
Listening on port: 8819 ... exiting
Listening on port: 8820 ...bind failed with error: 10013
Listening on port: 8821 ...bind failed with error: 10013
...
Using this technique, I have so far found, that this program cannot bind to ports 8820:9519 [diff 700], 9676:9875 [diff 200] ... and probably others.
The question is: why exactly these ranges fail and not others, and how can I confirm that using any Windows application (GUI or command line?)
Well, finally I found a way, to have an independent check, that confirms the behavior I observe in the question.
In review, I've concluded the program in the Q, cannot bind and listen to at least port ranges 8820:9519 and 9676:9875 - but it can bind to ports for listening, outside of these ranges.
So first, I found: Troubleshoot port exhaustion issues - Windows Client Management | Microsoft Docs:
You can view the dynamic port range on a computer by using the following netsh commands:
netsh int ipv4 show dynamicport tcp
netsh int ipv4 show dynamicport udp
netsh int ipv6 show dynamicport tcp
netsh int ipv6 show dynamicport udp
Now, this in itself does not help - "dynamic ports" are the "ephemeral ports", that is used for only a short period of time for the duration of a communication session. So, now applicable to this problem.
Then, after a lot of misses, finally I hit the following page: Error 10013 when you bind excluded port again - Windows Server | Microsoft Docs:
Assume that you exclude a port by running the following command on a computer that is running Windows Server 2012 R2, Windows Server 2012, or Windows Server 2008 R2:
netsh int ipv4 add excludedportrange protocol = tcp startport = Integer numberofports = 1
Great - except I do not want to exclude ports, I want to show excluded ports - so taking in the syntax from the previous post, I tried this in administrator command prompt (cmd.exe):
D:\>netsh int ipv4 show excludedportrange protocol=tcp
Protocol tcp Port Exclusion Ranges
Start Port End Port
---------- --------
1074 1173
1174 1273
1348 1447
1448 1547
1548 1647
1648 1747
1748 1847
1848 1947
1948 2047
2048 2147
2148 2247
5357 5357
8820 8919 ## 8820:9519
8920 9019 ## 8820:9519
9020 9119 ## 8820:9519
9120 9219 ## 8820:9519
9220 9319 ## 8820:9519
9320 9419 ## 8820:9519
9420 9519 ## 8820:9519
9676 9775 ## 2) 9676:9875
9776 9875 ## 2) 9676:9875
9984 10083
10084 10183
10184 10283
10284 10383
10384 10483
10584 10683
10684 10783
10784 10883
10884 10983
10984 11083
11084 11183
11184 11283
50000 50059 *
* - Administered port exclusions.
You can see where I've marked the "banned" port ranges that I've obtained by running the program in the OP, matched to the ranges output by excludedportrange, with the ## marking.
Well, finally! Questions now abound:
Why does excludedportrange show what is otherwise a single uninterrupted range, as multiple (7 or 2) contiguous ranges ?!
Why is excludedportrange not visible, or configurable, in Windows Firewall (at least I couldn't find it there so far)?
Well, at least I know now why do I observe the behavior that I do; what a relief...
EDIT: and the solution for this was here Huge amount of ports are being reserved · Issue #5306 · microsoft/WSL; also noted on SO here: Cannot bind to some ports due to permission denied
What worked for me:
D:\src\ola_mingw64_install>net stop winnat
The Windows NAT Driver service was stopped successfully.
D:\>net start winnat
The Windows NAT Driver service was started successfully.
D:\>netsh int ipv4 show excludedportrange protocol=tcp store=active
Protocol tcp Port Exclusion Ranges
Start Port End Port
---------- --------
5357 5357
50000 50059 *
* - Administered port exclusions.
D:\>test.exe
Listening on port: 9010 ...Bytes received: 7
Bytes sent: 7
Connection closing...
Well, that was a shitty experience! Imagine, there was a time, when I thought computers and programming would make things easier, lol :)
We have a streaming server implemented using live555 library. This server is deployed on CentOS instance.
Recently we wanted to modify the server socket options, so that it can accept the requests immediately after re-starting the process (either after crash or manual restart).
I have referred to man pages and few web links and set the socket options (SO_REUSEADDR and SO_REUSEPORT) before bind() call.
int setupStreamSocket(UsageEnvironment& env,
Port port, Boolean makeNonBlocking) {
int newSocket = createSocket(SOCK_STREAM);
if (newSocket < 0) {
socketErr(env, "unable to create stream socket: ");
return newSocket;
}
int reuseFlag = 1;
fprintf(stderr,"reuseFlag : %d\n",reuseFlag);
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
closeSocket(newSocket);
return -1;
}
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
closeSocket(newSocket);
return -1;
}
int flag = 1;
setsockopt( newSocket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag) );
if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
int reuse_addr_val, reuse_port_val;
socklen_t reuse_addr_len = sizeof(reuse_addr_val);
socklen_t reuse_port_len = sizeof(reuse_port_val);
getsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_val, &reuse_addr_len);
getsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, &reuse_port_val, &reuse_port_len);
fprintf(stderr,"reuse_addr_val = %d, reuse_port_val = %d\n", reuse_addr_val, reuse_port_val);
if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
char tmpBuffer[100];
sprintf(tmpBuffer, "bind() error (port number: %d): ",
ntohs(port.num()));
socketErr(env, tmpBuffer);
closeSocket(newSocket);
return -1;
}
}
if (makeNonBlocking) {
if (!makeSocketNonBlocking(newSocket)) {
socketErr(env, "failed to make non-blocking: ");
closeSocket(newSocket);
return -1;
}
}
return newSocket;
}
This code works as expected (binding to the address even when a socket is in TIME_WAIT state) if I restart the server with above options.
If I replace previous build (without socket options) with the build created with above code then I have noticed that occasionally bind() is failing with Address already in use error.
When the bind() failed the port/address is in TIME_WAIT state. So the server should able to bind the socket to the address.
tcp 0 0 10.0.1.24:8554 10.0.1.89:27085 TIME_WAIT -
And the getsockopt() of my code printed the flag value (corresponding to SO_REUSEADDR and SO_REUSEPORT) as 1.
reuse_addr_val = 1, reuse_port_val = 1
bind() error (port number: 8554): Address already in use
So I'm wondering why it's failing only few times. Did I miss something in my code ? or is this an expected behavior ?
I have problem with sendto function. I want to get time from UDP server. My code like this:
unsigned char msg[48]={010,0,0,0,0,0,0,0,0};
char* hostname=(char *)"tick.usno.navy.mil";
sockaddr_in server_addr;
WSAData data;
int result=WSAStartup( MAKEWORD( 2, 2 ), &data );
if (result != NO_ERROR) {
printf("WSAStartup failed with error: %d\n", result);
return 1;
}
int client_s = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
if (client_s == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
unsigned short Port = 123;
server_addr.sin_family = AF_INET; // Address family to use
server_addr.sin_port = htons(Port); // Port num to use
server_addr.sin_addr.s_addr = inet_addr(hostname); // IP address to use
char out_buf[BUFFER_SIZE];
int retcode = sendto(client_s, reinterpret_cast<const char*>(msg), sizeof(msg), 0,(struct sockaddr *)&server_addr, sizeof(server_addr));
perror("sendto:");
if (retcode == SOCKET_ERROR) {
printf("sendto failed with error: %d\n", WSAGetLastError());
closesocket(client_s);
WSACleanup();
return 1;
}
My output is like:
sendto:: No error
sendto failed with error: 10013
When I try recive data with recv, I got something wrong. I want get time from UDP server on windows with c++. Where is problem here? Why one error say no error and one error 10013 and how can I fix that?
The old answer (kept below) is informational but not correct for this case.
The problem is most likely these two lines
char* hostname=(char *)"tick.usno.navy.mil";
...
server_addr.sin_addr.s_addr = inet_addr(hostname); // IP address to use
The inet_addr function expects a dotted-decimal IPv4 address. Not an unresolved host-name. If not a valid IPv4 dotted-decimal address is provided, the function will return INADDR_NONE which is not a valid address and will lead to problems when using the address in e.g. sendto. Will it cause the error reported in the question? I honestly don't know, but it will definitely not work as expected.
To resolve a host-name into an IP address you should use getaddrinfo. The linked reference also contains an example on how to use it.
The error 10013 is, if you look at e.g. this Windows socket error reference WSAEACCESS, that there is some permission problems. If you then search a little you will see that ports under 1024 are reserved for the system, and you need elevated privileges to use them.
If you want to create an NTP server or client you need to run your program using elevated access rights, like e.g. using "Run as administrator".
As for the message
sendto:: No error
it comes from the perror call you unconditionally call after sendto. First of all on Windows the socket functions doesn't set errno which perror uses. Secondly, the state of errno is undefined if the previous call to didn't actually fail.
So don't use it unconditionally, and don't use it for the Windows socket functions.
I am create socket class but I want to make my Connect function dynamic and can connect to address(ipv4 or ipv6) use switch to make IPv test and connect to supported IPv just wan to ask if I am right or is there an easy way to make it to make IPv4 or IPv6?
bool Connect(short port,std::string addr,bool vlisten,HWND WindowHandle,WSADATA& wsaData,bool async)
{
if(!hSocket);
{
this->port = port;
this->addr =addr;
this->vlisten = vlisten;
this->WindowHandle = WindowHandle;
this->wsaData =wsaData;
this->init = true;
// Provide big enough buffer, ipv6 should be the biggest
char ipstr[INET6_ADDRSTRLEN];
char ipstr2[INET6_ADDRSTRLEN];
struct sockaddr_in* sockaddr_ipv4;
struct sockaddr_in6* sockaddr_ipv6;
//struct sockaddr_in6* sockaddr_ipv6;
if(WSAStartup(MAKEWORD(2,2),&wsaData) !=0)
{
throw runtime_error("Error WSAStartup:" + WSAGetLastError());
}
if((this->hSocket = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))== INVALID_SOCKET)
{
Close();
throw runtime_error("Error init sockect:" + WSAGetLastError());
}
if(addr != "INADDR_ANY")
{
struct addrinfo *result = nullptr;
getaddrinfo(addr.c_str(), nullptr, nullptr, &result);
struct addrinfo *it;
for (it = result; it != nullptr; it = it->ai_next)
{
//sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(it->ai_addr);
//addr = inet_ntoa(sockaddr_ipv4->sin_addr);
//if (addr != "0.0.0.0") break;
switch (it->ai_family)
{
case AF_UNSPEC:
cout<<"Unspecified\n"<<endl;
break;
case AF_INET:
cout<<"AF_INET (IPv4)\n"<<endl;
sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(it->ai_addr);
//printf("\tIPv4 address %s\n",
addr = inet_ntoa(sockaddr_ipv4->sin_addr);
/*if (addr != "0.0.0.0") break;*/
break;
case AF_INET6:
cout<<"AF_INET (IPv6)\n"<<endl;
sockaddr_ipv6 = reinterpret_cast<sockaddr_in6*>(it->ai_addr);
addr = inet_ntop(it->ai_family,sockaddr_ipv6,(PSTR)ipstr,sizeof(ipstr));
break;
case AF_NETBIOS:
cout<<"AF_NETBIOS (NetBIOS)\n"<<endl;
break;
default:
printf("Other %ld\n", it->ai_family);
break;
}
}
freeaddrinfo(result);
}
}
SOCKADDR_IN sockAddrIn;
memset(&sockAddrIn,0,sizeof(sockAddrIn));
sockAddrIn.sin_port = htons(port);
sockAddrIn.sin_family = AF_INET;
sockAddrIn.sin_addr.s_addr = (addr == "INADDR_ANY" ? htonl(INADDR_ANY) : inet_addr(addr.c_str()));
if(vlisten && (bind(hSocket,reinterpret_cast<SOCKADDR*>(&sockAddrIn),sizeof(sockAddrIn))== SOCKET_ERROR))
{
Close();
throw runtime_error("Error vlisten & bind: " + WSAGetLastError());
}
if(async && WindowHandle)
{
if(WSAAsyncSelect(hSocket,WindowHandle,WM_SOCKET,FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE|FD_ACCEPT) !=0)
{
Close();
throw runtime_error("Error async & WindowHandle: " + WSAGetLastError());
}
}
if(vlisten && (listen(hSocket,SOMAXCONN)== SOCKET_ERROR))
{
Close();
throw runtime_error("Error async & WindowHandle: " + WSAGetLastError());
}
if(!vlisten && (connect(hSocket, reinterpret_cast<SOCKADDR*>(&sockAddrIn), sizeof(sockAddrIn)) == SOCKET_ERROR))
{
if(async && WindowHandle && (WSAGetLastError() != WSAEWOULDBLOCK))
{
Close();
throw runtime_error("Error async & WindowHandle: " + WSAGetLastError());
}
}
}
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 your sockaddr_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).
I would like to ask for help since I don't know what to do anymore. I have a simulator created in c++, where it accepts an id input from a user and checks if it is in the database (created in mysql workbench) which is only in the localhost.
sqlQuery = "SELECT staffaccess.card_number FROM proxycardsim.staffaccess WHERE staffaccess.card_number = "
+ inputID;
if(mysql_ping(theInstance.connects))
{
}
int queryState = mysql_query(theInstance.connects, sqlQuery);
resultSet = mysql_store_result(theInstance.connects);
rowNum = mysql_num_rows(theInstance.resultSet);
if (rowNum == NULL)
{
mysql_free_result(theInstance.resultSet);
return false;
}
else
{
mysql_free_result(theInstance.resultSet);
return true;
}
The thing is that the simulator is connected to another computer that serves as a server (connected through winsock). If the server is up, it works ok or if all the inputs are wrong, but if the server is down(my code will try to connect again to the server pc so I have to call WSACleanup) after inputting one correct value and I input another mysql_query returns an error that mysql server has gone away. Then the program will break when it goes to mysql_num_rows.
I have this code in another function and when I commented them out one by one, I found out that the error is because of WSACleanup(). If the WSACleanup line is not there my query runs ok.
if ( false == theInstance.compareID(m_IDEntry))
{
addData(ConsoleLog,rec,0,0);
}
else
{
// Send an initial buffer
iResult = send( connectSocket, sendBuf, (int)strlen(sendBuf), 0 );
if(false == theInstance.addToLog(m_IDEntry))
{
addData(ConsoleLog,rec,0,3);
}
if (iResult == SOCKET_ERROR) {
closesocket(connectSocket);
WSACleanup();
serverConnect();
iResult = send( connectSocket, sendBuf, (int)strlen(sendBuf), 0 );
}
if (iResult != SOCKET_ERROR) {
addData(ConsoleLog,rec,0,1);
}
iResultRcv = recv(connectSocket, recvbuf, recvbuflen, 0);
if ( iResultRcv <= 0 )
{
addData(ConsoleLog,rec,0,7);
}
}
I hope someone can help me out.
Don't call WSACleanup. WSACleanup is intended to be used when you no longer want to do any socket communication. That's not the case for you.