Winsock Tutorial 5

Error handling with Winsock

Previously we purposely omitted too much detail in error handling so as not to overwhelm newcomers. Now we examine error handling in greater detail. When we are finished, we should be able to troubleshoot our applications so we can pinpoint where a problem may exist with greater efficiency.


For this tutorial we will be working with the final code used back in tutorial 2 (the blocking server).

Prerequisites

Project type: Console
Include files: winsock2.h
Library files: ws2_32.lib



Error Handling

You would remember in our previous tutorials that first we must initialize Winsock. What if this fails for some reason? How would you know what went wrong?

Fortunately, if WSAStartup fails, it will return a Winsock error code. A list of winsock error codes can be found here and also at the bottom of this tutorial for your convenience.

If we modify our Winsock initialization code slightly...
WSADATA WsaDat;
int nResult=WSAStartup(MAKEWORD(2,2),&WsaDat);
if(nResult!=0)
{
	std::cout<<"WSA Initialization failed: "<<nResult<"\r\n";
	WSACleanup();
	system("PAUSE");
	return 0;
}
...we will be able to catch the reason (if any) for our initialization failure.

We can test this by inducing an error into our code. Try changing the following line containing the WSAStartup() to this;

int nResult=WSAStartup(MAKEWORD(0,0),&WsaDat);
We have accidentaly instructed winsock to operate using version 0.0 within the wsock32.dll at runtime. This version doesn't exist. So, if we run the application it will report the following error in our console.

WSA Initialization failed: 10092
Press any key to continue . . .


The error code 10092 translates to WSAVERNOTSUPPORTED. This means, the version we are trying to use doesn't exist. Which is the error we intended to get, with our little test.


Once we are happy that Winsock has initialized correctly, we can now use a handy function to address any further failures.

WSAGetLastError()
The next step was to set up a socket. Again we can modify our code (slightly) to display why socket creation has failed.
SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Socket==INVALID_SOCKET)
{
	int nError=WSAGetLastError();
	std::cout<<"Socket creation failed: "<<nError<<"\r\n";
	WSACleanup();
	system("PAUSE");
	return 0;
}


When we attempt to create our socket the socket will be checked to see if it is valid. If it is not valid we can use WSAGetLastError() to find what has gone amiss.

We can, once again, test this to see that it actually works. Change the following line to;

SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_UDP);

What we have done here is mix and match TCP/IP elements (SOCK_STREAM) and UDP elements (IPPROTO_UDP), which is a big no no. It just wont work like that. We will explore UDP in later tutorials.

Running the application with this change will give you error 10043 (WSAEPROTONOSUPPORT) which means 'protocol not supported'. As we expected.

Now we can catch any errors during socket creation. Great!

We chose to go with the server code in this tutorial as there are more things to go wrong, as you would appreciate. After filling out our SOCKADDR_IN struct (refer to tutorial 2) we bind the socket, remember?

If we add the same error checking code we get this;
if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
{
	int nError=WSAGetLastError();
	std::cout<<"Unable to bind socket: "<<nError<<"\r\n";
	WSACleanup();
	system("PAUSE");
	return 0;
}

We might get 'bind' problems if there is another service using the same port, for example. Don't believe me? Run two instances of the server (with our updated code) and see what happens.

Error 10048 (WSAEADDRINUSE) right? You cant have two servers using the same port number, as we have just found out!

As you see WSAGetLastError() is an essential function to use, if you want to know why your application might be failing.

You should now begining to see a pattern forming with our error checking. Try to modify the rest of the code from tutorial 2 to check for potential problems with the 'listen' and 'shutdown' commands.

Otherwise you can skip to the full source code below.

The Full Code

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
	WSADATA WsaDat;
	int nResult=WSAStartup(MAKEWORD(2,2),&WsaDat);
	if(nResult!=0)
	{
		std::cout<<"WSA Initialization failed: "<<nResult<<"\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(Socket==INVALID_SOCKET)
	{
		int nError=WSAGetLastError();
		std::cout<<"Socket creation failed: "<<nError<<"\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	SOCKADDR_IN serverInf;
	serverInf.sin_family=AF_INET;
	serverInf.sin_addr.s_addr=INADDR_ANY;
	serverInf.sin_port=htons(8888);

	if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
	{
		int nError=WSAGetLastError();
		std::cout<<"Unable to bind socket: "<<nError<<"\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	if(listen(Socket,1)==SOCKET_ERROR)
	{
		int nError=WSAGetLastError();
		std::cout<<"Unable to listen: "<<nError<<"\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	SOCKET TempSock=SOCKET_ERROR;
	while(TempSock==SOCKET_ERROR)
	{
		std::cout<<"Waiting for incoming connections...\r\n";
		TempSock=accept(Socket,NULL,NULL);
	}
	Socket=TempSock;
	std::cout<<"Client connected!\r\n\r\n";

	char *szMessage="Welcome to the server!\r\n";
	send(Socket,szMessage,strlen(szMessage),0);

	// Shutdown our socket
	if(shutdown(Socket,SD_SEND)==SOCKET_ERROR)
	{
		int nError=WSAGetLastError();
		std::cout<<"Unable to shutdown socket: "<<nError<<"\r\n";
		closesocket(Socket);
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	// Close our socket
	closesocket(Socket);

	// Cleanup Winsock
	WSACleanup();
	system("PAUSE");
	return 0;
}


Things to try

Try thinking of other ways to find errors and handle them. Some errors do not always mean death for the program. So, quitting (the application) at the first sign of trouble may not be the answer.

Winsock error codes

10004WSAEINTRInterrupted function call
10009WSAEBADFWSAEBADF
10013WSAEACCESWSAEACCES
10014WSAEFAULTBad address
10022WSAEINVALInvalid argument
10024WSAEMFILEToo many open files
10035WSAEWOULDBLOCKOperation would block
10036WSAEINPROGRESSOperation now in progress
10037WSAEALREADYOperation already in progress
10038WSAENOTSOCKSocket operation on non-socket
10039WSAEDESTADDRREQDestination address required
10040WSAEMSGSIZEMessage too long
10041WSAEPROTOTYPEProtocol wrong type for socket
10042WSAENOPROTOOPTBad protocol option
10043WSAEPROTONOSUPPORTProtocol not supported
10044WSAESOCKTNOSUPPORTSocket type not supported
10045WSAEOPNOTSUPPOperation not supported
10046WSAEPFNOSUPPORTProtocol family not supported
10047WSAEAFNOSUPPORTAddress family not supported by protocol family
10048WSAEADDRINUSEAddress already in use
10049WSAEADDRNOTAVAILCannot assign requested address
10050WSAENETDOWNNetwork is down
10051WSAENETUNREACHNetwork is unreachable
10052WSAENETRESETNetwork dropped connection on reset
10053WSAECONNABORTEDSoftware caused connection abort
10054WSAECONNRESETConnection reset by peer
10055WSAENOBUFSNo buffer space available
10056WSAEISCONNSocket is already connected
10057WSAENOTCONNSocket is not connected
10058WSAESHUTDOWNCannot send after socket shutdown
10059WSAETOOMANYREFSWSAETOOMANYREFS
10060WSAETIMEDOUTConnection timed out
10061WSAECONNREFUSEDConnection refused
10062WSAELOOPWSAELOOP
10063WSAENAMETOOLONGWSAENAMETOOLONG
10064WSAEHOSTDOWNHost is down
10065WSAEHOSTUNREACHNo route to host
10066WSAENOTEMPTYWSAENOTEMPTY
10067WSAEPROCLIMToo many processes
10068WSAEUSERSWSAEUSERS
10069WSAEDQUOTWSAEDQUOT
10070WSAESTALEWSAESTALE
10071WSAEREMOTEWSAEREMOTE
10091WSASYSNOTREADYNetwork subsystem is unavailable
10092WSAVERNOTSUPPORTEDWINSOCK.DLL version out of range
10093WSANOTINITIALISEDSuccessful WSAStartup() not yet performed
10101WSAEDISCONWSAEDISCON
10102WSAENOMOREWSAENOMORE
10103WSAECANCELLEDWSAECANCELLED
10104WSAEINVALIDPROCTABLEWSAEINVALIDPROCTABLE
10105WSAEINVALIDPROVIDERWSAEINVALIDPROVIDER
10106WSAEPROVIDERFAILEDINITWSAEPROVIDERFAILEDINIT
10107WSASYSCALLFAILUREWSASYSCALLFAILURE
10108WSASERVICE_NOT_FOUNDWSASERVICE_NOT_FOUND
10109WSATYPE_NOT_FOUNDWSATYPE_NOT_FOUND
10110WSA_E_NO_MOREWSA_E_NO_MORE
10111WSA_E_CANCELLEDWSA_E_CANCELLED
10112WSAEREFUSEDWSAEREFUSED
11001WSAHOST_NOT_FOUNDHost not found
11002WSATRY_AGAINNon-authoritative host not found
11003WSANO_RECOVERYThis is a non-recoverable error
11004WSANO_DATAValid name, no data record of requested type

Next tutorial

Tutorial 6 - Async sockets in TCP/IP (The Client)