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: ConsoleInclude 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
| 10004 | WSAEINTR | Interrupted function call |
| 10009 | WSAEBADF | WSAEBADF |
| 10013 | WSAEACCES | WSAEACCES |
| 10014 | WSAEFAULT | Bad address |
| 10022 | WSAEINVAL | Invalid argument |
| 10024 | WSAEMFILE | Too many open files |
| 10035 | WSAEWOULDBLOCK | Operation would block |
| 10036 | WSAEINPROGRESS | Operation now in progress |
| 10037 | WSAEALREADY | Operation already in progress |
| 10038 | WSAENOTSOCK | Socket operation on non-socket |
| 10039 | WSAEDESTADDRREQ | Destination address required |
| 10040 | WSAEMSGSIZE | Message too long |
| 10041 | WSAEPROTOTYPE | Protocol wrong type for socket |
| 10042 | WSAENOPROTOOPT | Bad protocol option |
| 10043 | WSAEPROTONOSUPPORT | Protocol not supported |
| 10044 | WSAESOCKTNOSUPPORT | Socket type not supported |
| 10045 | WSAEOPNOTSUPP | Operation not supported |
| 10046 | WSAEPFNOSUPPORT | Protocol family not supported |
| 10047 | WSAEAFNOSUPPORT | Address family not supported by protocol family |
| 10048 | WSAEADDRINUSE | Address already in use |
| 10049 | WSAEADDRNOTAVAIL | Cannot assign requested address |
| 10050 | WSAENETDOWN | Network is down |
| 10051 | WSAENETUNREACH | Network is unreachable |
| 10052 | WSAENETRESET | Network dropped connection on reset |
| 10053 | WSAECONNABORTED | Software caused connection abort |
| 10054 | WSAECONNRESET | Connection reset by peer |
| 10055 | WSAENOBUFS | No buffer space available |
| 10056 | WSAEISCONN | Socket is already connected |
| 10057 | WSAENOTCONN | Socket is not connected |
| 10058 | WSAESHUTDOWN | Cannot send after socket shutdown |
| 10059 | WSAETOOMANYREFS | WSAETOOMANYREFS |
| 10060 | WSAETIMEDOUT | Connection timed out |
| 10061 | WSAECONNREFUSED | Connection refused |
| 10062 | WSAELOOP | WSAELOOP |
| 10063 | WSAENAMETOOLONG | WSAENAMETOOLONG |
| 10064 | WSAEHOSTDOWN | Host is down |
| 10065 | WSAEHOSTUNREACH | No route to host |
| 10066 | WSAENOTEMPTY | WSAENOTEMPTY |
| 10067 | WSAEPROCLIM | Too many processes |
| 10068 | WSAEUSERS | WSAEUSERS |
| 10069 | WSAEDQUOT | WSAEDQUOT |
| 10070 | WSAESTALE | WSAESTALE |
| 10071 | WSAEREMOTE | WSAEREMOTE |
| 10091 | WSASYSNOTREADY | Network subsystem is unavailable |
| 10092 | WSAVERNOTSUPPORTED | WINSOCK.DLL version out of range |
| 10093 | WSANOTINITIALISED | Successful WSAStartup() not yet performed |
| 10101 | WSAEDISCON | WSAEDISCON |
| 10102 | WSAENOMORE | WSAENOMORE |
| 10103 | WSAECANCELLED | WSAECANCELLED |
| 10104 | WSAEINVALIDPROCTABLE | WSAEINVALIDPROCTABLE |
| 10105 | WSAEINVALIDPROVIDER | WSAEINVALIDPROVIDER |
| 10106 | WSAEPROVIDERFAILEDINIT | WSAEPROVIDERFAILEDINIT |
| 10107 | WSASYSCALLFAILURE | WSASYSCALLFAILURE |
| 10108 | WSASERVICE_NOT_FOUND | WSASERVICE_NOT_FOUND |
| 10109 | WSATYPE_NOT_FOUND | WSATYPE_NOT_FOUND |
| 10110 | WSA_E_NO_MORE | WSA_E_NO_MORE |
| 10111 | WSA_E_CANCELLED | WSA_E_CANCELLED |
| 10112 | WSAEREFUSED | WSAEREFUSED |
| 11001 | WSAHOST_NOT_FOUND | Host not found |
| 11002 | WSATRY_AGAIN | Non-authoritative host not found |
| 11003 | WSANO_RECOVERY | This is a non-recoverable error |
| 11004 | WSANO_DATA | Valid name, no data record of requested type |