I have set up a Winsock2 connection but I need to cover the case where internet is down. Here is my code;
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if(WSAStartup(MAKEWORD(2,2),&w)) return 0;
sockaddr_in sad;
sad.sin_family=AF_INET;
sad.sin_addr.s_addr=inet_addr("200.20.186.76");
sad.sin_port=htons(123);
sockaddr saddr;
int saddr_l=sizeof(saddr);
int s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(s==INVALID_SOCKET) return 0;
char msg[48]={8};
if(sendto(s,msg,sizeof(msg),0,(sockaddr*)&sad,sizeof(sad))==SOCKET_ERROR) return 0;
if(recvfrom(s,msg,48,0,&saddr,&saddr_l)==SOCKET_ERROR) return 0;
if(closesocket(s)==SOCKET_ERROR) return 0;
if(WSACleanup()) return 0;
return 0;
}
Here it waits for the call to return as it's documented. I have two questions.
select
When issuing a blocking Winsock call such as sendto, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread.
How to do that?
If you want to issue a recvfrom() and have it return immediately, then decide on your own how long to wait (I'm assuming Windows since you included winsock2.h), you can make an asynchronous OVERLAPPED request, then wait for the completion at any time by waiting for the hEvent member of the OVERLAPPED struct to be signaled.
Here's an updated sample based off your original code.
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if (WSAStartup(MAKEWORD(2, 2), &w)) return 0;
sockaddr_in sad;
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("200.20.186.76");
sad.sin_port = htons(123);
sockaddr saddr;
int saddr_l = sizeof(saddr);
int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) return 0;
char msg[48] = { 8 };
if (sendto(s, msg, sizeof(msg), 0, (sockaddr*)&sad, sizeof(sad)) == SOCKET_ERROR) return 0;
OVERLAPPED ov{};
ov.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (ov.hEvent == nullptr) return 0;
WSABUF wsabuffer{};
wsabuffer.buf = msg;
wsabuffer.len = 48;
DWORD flags = 0;
if (WSARecvFrom(s, &wsabuffer, 1, nullptr, &flags, &saddr, &saddr_l, &ov, nullptr) == SOCKET_ERROR)
{
DWORD gle = WSAGetLastError();
if (gle != WSA_IO_PENDING) return 0;
}
for (DWORD recv_count = 0; recv_count < 6; ++recv_count)
{
DWORD wait = WaitForSingleObject(ov.hEvent, 10000);
if (wait == WAIT_FAILED) return 0;
if (wait == WAIT_OBJECT_0) break; // WSARecvFrom completed
if (wait == WAIT_TIMEOUT) continue; // WSARecvFrom is still pended waiting for data
}
// assuming WSARecvFrom completed - i.e. ov.hEvent was signaled
DWORD transferred;
if (WSAGetOverlappedResult(s, &ov, &transferred, FALSE, &flags))
{
// WSARecvFrom completed successfully - 'transferred' shows the # of bytes that were received
}
else
{
DWORD gle = WSAGetLastError();
gle;
// WSARecvFrom failed with the error code in 'gle'
}
if (closesocket(s) == SOCKET_ERROR) return 0;
// with real code, we must guarantee that hEvent is set after calling closesocket
// e.g. if we get here in an error path
// closesocket() won't guarantee all async IO has completed before returning
WaitForSingleObject(ov.hEvent, INFINITE);
if (WSACleanup()) return 0;
return 0;
}