winsock connect() throws error but works anyways ??

Started by
8 comments, last by CPPNick 13 years, 9 months ago
I made a little program to try out windows sockets, but I have a strange problem. The program can connect and send data just fine, but for some reason, connect() is giving me a SOCKET_ERROR even though it is working. When I call WSAGetLastError, it returns 0 too..

Anyone have any ideas?

here is my code:
I commented where I get the error in "bool Connect(...)"
"

#include "deskconnect.h"int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,  LPSTR lpCmdLine, int nCmdShow){ 	MSG msg;	WNDCLASSEX cmain;	cmain.cbSize        = sizeof(WNDCLASSEX);	cmain.style         = CS_HREDRAW | CS_VREDRAW;	cmain.lpfnWndProc   = MainProc;	cmain.cbClsExtra    = 0;	cmain.cbWndExtra    = 0;	cmain.hIcon         = LoadIcon(NULL, IDI_APPLICATION);	cmain.hCursor       = LoadCursor(NULL, IDC_ARROW);	cmain.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	cmain.lpszMenuName  = NULL;	cmain.lpszClassName = L"deskConnect";	cmain.hInstance     = hInstance;	cmain.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);	RegisterClassEx(&cmain);	mWnd = CreateWindow(L"deskConnect", L"Desk Connect", WS_OVERLAPPEDWINDOW, 300, 300, 512, 384, NULL, NULL, hInstance, NULL);	CreateWindow(L"button", L"Listen", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 5, 5, 80, 25, mWnd, (HMENU)BTN_LISTEN, hInstance, NULL);	CreateWindow(L"button", L"Connect", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 85, 5, 80, 25, mWnd, (HMENU)BTN_CONNECT, hInstance, NULL);	CreateWindow(L"button", L"Send", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 165, 5, 80, 25, mWnd, (HMENU)BTN_SEND, hInstance, NULL);	CreateWindow(L"button", L"Screenshot", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 245, 5, 80, 25, mWnd, (HMENU)BTN_SCREENSHOT, hInstance, NULL);	if(!mWnd) return 0;	ShowWindow(mWnd, SW_SHOWNORMAL);	UpdateWindow(mWnd);		if(!WSAInit())	{		MessageBox(mWnd, L"Couldn't initialize winsock", L"Socket error", MB_OK | MB_ICONERROR);		return 0;	}		while(GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}LRESULT CALLBACK MainProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam){    switch(Msg)    {		case SOCKET_MESSAGE:			switch (WSAGETSELECTEVENT(lParam)) //If so, which one is it?            {				case FD_ACCEPT:					//Connection request was made					memset(&userAddr, 0, sizeof(SOCKADDR));					tmpSocket = accept(mSocket, (LPSOCKADDR)&userAddr, &sizeAddr);					//CloseSocket(mSocket);					mSocket = tmpSocket;					break;				case FD_CONNECT:					//MessageBox(hWnd, L"Connection successful!", L"status", MB_OK);					//Connection was made successfully					break;				case FD_READ:					//Incoming data; get ready to receive					memset(buffer, 0, sizeof(buffer));					recv(mSocket, buffer, sizeof(buffer)-1, 0);					MessageBoxA(hWnd, buffer, "status", MB_OK);					break;				case FD_CLOSE:					CloseSocket(mSocket);					//Lost the connection					MessageBox(hWnd, L"Connection lost!", L"status", MB_OK);					break;            }			break;		case WM_COMMAND:			switch(LOWORD(wParam))			{			case BTN_LISTEN:				CloseSocket(mSocket);				mSocket = CreateTCPSocket(hWnd);				Listen(mSocket, 21234);				break;			case BTN_CONNECT:				CloseSocket(mSocket);				mSocket = CreateTCPSocket(hWnd);				Connect(mSocket, "127.0.0.1", 21234);				break;			case BTN_SEND:				if(mSocket) send(mSocket, "Hello World!", 12, 0);				break;			case BTN_SCREENSHOT:				//BitBlt(GetWindowDC(hWnd),0,0,300,300,GetWindowDC(GetDesktopWindow()),0,0,SRCCOPY);				GetScreenBits();				break;			}			break;		case WM_DESTROY:			CloseSocket(mSocket);			WSACleanup();			PostQuitMessage(WM_QUIT);			break;		default:			return DefWindowProc(hWnd, Msg, wParam, lParam);		}    return true;}bool WSAInit(){	WSADATA wsadata;		if(WSAStartup(SCK_VERSION2, &wsadata) != 0) //0 = success	{		return false;	}		if(wsadata.wVersion != SCK_VERSION2)	{		WSACleanup();		return false;	}	return true;}SOCKET CreateTCPSocket(HWND hWindow){	if(mSocket)	{		EMSG("Socket already opened");		return 0;	}		SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	if(sock == INVALID_SOCKET)	{		EMSG("Couldn't create socket.");		return 0;	}	if(WSAAsyncSelect(sock, hWindow, SOCKET_MESSAGE, FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE) == SOCKET_ERROR)	{		EMSG("Failed to select window");		return 0;	}		return sock;}bool Connect(SOCKET sock, char *IPAddress, unsigned int port){	SOCKADDR_IN addr;		addr.sin_family = AF_INET;	addr.sin_port = htons(port);	addr.sin_addr.S_un.S_addr = inet_addr(IPAddress);	int error = connect(sock, (LPSOCKADDR)&addr, sizeof(addr));	//CONNECT RETURNS ERROR, BUT WORKS ANYWAYS	if(error != 0)	{		EMSG("Connection failed!");		iMSG32(WSAGetLastError());   //ALSO, THIS RETURNS O  =(		return false;	}	return true;}bool Listen(SOCKET sock, unsigned int port){	SOCKADDR_IN addr;	addr.sin_family = AF_INET;	addr.sin_port = htons(port);	addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);	if(bind(sock, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)	{		EMSG("could not bind socket");		return false;	}		if(listen(sock, SOMAXCONN) == SOCKET_ERROR)	{		EMSG("could not listen");		return false;	}	return true;}void CloseSocket(SOCKET sock){	if(sock)  closesocket(sock);}BYTE *GetScreenBits(){	RECT wRect;	HWND hDesktop = GetDesktopWindow();	GetWindowRect(hDesktop, &wRect);		BITMAPINFO bmi;	memset(&bmi, 0, sizeof(BITMAPINFO));	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);	bmi.bmiHeader.biWidth = wRect.right;	bmi.bmiHeader.biHeight = wRect.bottom;	bmi.bmiHeader.biPlanes = 1;	bmi.bmiHeader.biBitCount = 8;	bmi.bmiHeader.biCompression = BI_RGB;		BYTE *pixels;	HDC hdcScreen = GetWindowDC(hDesktop);	HDC hDC = CreateCompatibleDC(hdcScreen);	HBITMAP bmSource = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pixels, NULL, NULL);	SelectObject(hDC, bmSource);	BitBlt(hDC, 0, 0, wRect.right, wRect.bottom, hdcScreen, 0, 0, SRCCOPY);	BitBlt(GetWindowDC(mWnd), 0, 0, 400, 400, hDC, 0, 0, SRCCOPY);	DeleteObject(bmSource);	DeleteDC(hDC);	ReleaseDC(hDesktop, hdcScreen);	return pixels;}
Advertisement
Try zeroing out the address structure (ZeroMemory(&addr, sizeof(addr))), before filling it in, as it contains 8 extra bytes that are supposed to be zero.

What does EMSG look like?
If you for example call MessageBox or a similar function, the last error returned from WSAGetLastError will be reset to 0, and therefore you might miss it. You must call WSAGetLastError immediately after connect returns an error.
awesome. I had no idea that WSAGetLastError would be reset by MessageBox. The error is 10035, which is not a fatal error, so I guess I'll just ignore it.

thanks =D
As soon as you call WSAAsyncSelect() the socket is put into non-blocking mode. From the connect() msdn docs:

Return Values
If no error occurs, this function returns zero. If an error occurs, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.

On a blocking socket, the return value indicates success or failure of the connection attempt.

With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, this function will return SOCKET_ERROR and WSAGetLastError will return WSAEWOULDBLOCK. The following list shows the three scenarios that are possible in this case:

Use the select function to determine the completion of the connection request by checking to see if the socket is writeable.
If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
Until the connection attempt completes on a nonblocking socket, all subsequent calls to connect on the same socket will fail with the error code WSAEALREADY and with WSAEISCONN when the connection completes successfully. Due to ambiguities in the Winsock, error codes returned from connect while a connection is already pending may vary among implementations. As a result, it is not recommended that applications use multiple calls to connect to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error codes the same way that they handle WSAEALREADY to ensure robust execution.

If the error code returned indicates the connection attempt failed (that is, WSAECONNREFUSED, WSAENETUNREACH, or WSAETIMEDOUT), the application can call connect again for the same socket.

--Z
I understand how ignoring that message could cause complications at the user's fingertips, but I don't understand how to handle it. I remember using Winsock in Visual Basic, which had a State variable. Isn't there something like that for C++ Winsock too? or something? It doesn't make any sense at all to me why they would pass the CONNECT message before the application actually connects =/

this is what I stuck in there for now, which I guess wouldn't work if the connection took too long
	int error = connect(sock, (LPSOCKADDR)&addr, sizeof(addr));	if(error != 0)	{		error = WSAGetLastError();		if(error != 0 && error != 10035)		{			EMSG("Connection failed!");			CloseSocket(mSocket);			WSACleanup();			return false;		}	}	return true;


should I change it to a loop and just keep calling error = WSAGetLastError();?
Do not use "async" sockets on Windows. They are just inherently broken. The Forum FAQ talks a little bit about why, and what you can do instead.
enum Bool { True, False, FileNotFound };
hplus0603: I don't see what you are talking about in the FAQ...All it says is that they are not available on Unix, but offer great performance.

I have everything worked out, except that the problem Zimans was trying to address is actually turning out to be more troublesome then I expected...

How can I tell from the client side when a connection has been made for sure?

EDIT:I think I figured this out.
to connected, I go like this:
int error = connect(sock, (LPSOCKADDR)&addr, sizeof(addr));if(error != 0){	error = WSAGetLastError();	if(error != WSAEWOULDBLOCK)	{		EMSG("Connection failed!");		CloseSocket(mSocket);		return FALSE;	}}

this way, if its just not connecting right away, we wont concider it a failure.

and then when FD_CONNECT is finally called, if there is no error, then the connection has been made for sure, and the flag can be set to true.
case FD_CONNECT:if(!WSAGETSELECTERROR(lParam)){	bConnected = TRUE;	IMSG("Connection successful.");}//Connection was made successfullybreak;


can anyone see anything wrong with doing it this way?
thanks again for the help.

EDIT:
Quote:How can I tell from the client side when a connection has been made for sure?

I got around to reading up on the "select" function too, but the way I have done it is also ok right?

EDIT:also, I understand now that all I have to do is wait until after the call to connect to call WSAAsyncSelect(), so that I can use the return value from connect instead of the FD_CONNECT message.

24 hours ago, I had never tried socket programming outside of visual basic 6...I think I'm doing pretty well =D

[Edited by - CPPNick on July 7, 2010 7:34:56 PM]
You should use WSAEWOULDBLOCK instead of 10035. It's good programing practice and aids readability.

Since the connect() operation is non-blocking, it will return immideately with WSAEWOULDBLOCK. Any error other than WSAEWOULDBLOCK is a real error and you should abort.

When the socket finally connects or errors the FD_CONNECT event will trigger.

Foe event based signaling:
At this point you have to query the socket to see if the connect actually succeeded. To do this, call getsockopt ( socket, SOL_SOCKET, SO_ERROR, .., .. ) to get the error code associated with the socket. If it is non-zero, you have an error and that value is what error occured. If it is 0, the connection was a success.

For message based signaling:
You are doing it correctly. When FD_CONNECT occurs, you check the error code provided and if it is 0, you are connected.

You don't need to use select() ( which I don't think you are ).

--Z
To be clear: The Forum FAQ recommends overlapped I/O on sockets with I/O completion ports. That's not the same thing as "async" sockets. WSAAsyncSelect(), or anything that expects to send Windows messages from I/O, really, is what's troublesome.
enum Bool { True, False, FileNotFound };
Thanks a lot guys, it seems to be working without any errors now. I'll take another look at the forum too.

here is the final code:
#pragma comment (lib, "ws2_32.lib")#include <windows.h>#include <winsock.h>#define SCK_VERSION2 0x0202#define SOCKET_MESSAGE WM_USER+1#define DEFAULT_BUFLEN 1024#define DEFAULT_PORT 21234#define BTN_LISTEN 0x8801#define BTN_CONNECT 0x8802#define BTN_SEND 0x8803#define BTN_DISCONNECT 0x8804#define TXT_IP 0x8806#define EMSG(x) MessageBoxA(mWnd, x, "Error", MB_OK | MB_ICONERROR)#define QMSG(x) MessageBoxA(mWnd, x, "Error", MB_OK | MB_OKCANCEL | MB_ICONWARNING)#define IMSG(x) MessageBoxA(mWnd, x, "Error", MB_OK | MB_ICONINFORMATION)BOOL bActiveSocket = FALSE;BOOL bConnected = FALSE;HWND mWnd;HWND hwndEdit = 0;char szText[512];SOCKET tmpSocket = 0;SOCKET mSocket = 0;SOCKADDR_IN userAddr;int sizeAddr = sizeof(userAddr);int flag = 1;LRESULT CALLBACK MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);void CloseSocket(SOCKET sock);BOOL CreateTCPSocket(HWND hWindow);BOOL Connect(SOCKET sock, char *IPAddress, unsigned int port);BOOL Listen(SOCKET sock, unsigned int port);void Process(SOCKET sock);int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,  LPSTR lpCmdLine, int nCmdShow){ 	MSG msg;	WNDCLASSEX cmain;	cmain.cbSize        = sizeof(WNDCLASSEX);	cmain.style         = CS_HREDRAW | CS_VREDRAW;	cmain.lpfnWndProc   = MainProc;	cmain.cbClsExtra    = 0;	cmain.cbWndExtra    = 0;	cmain.hIcon         = LoadIcon(NULL, IDI_APPLICATION);	cmain.hCursor       = LoadCursor(NULL, IDC_ARROW);	cmain.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	cmain.lpszMenuName  = NULL;	cmain.lpszClassName = L"deskConnect";	cmain.hInstance     = hInstance;	cmain.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);	RegisterClassEx(&cmain);	mWnd = CreateWindow(L"deskConnect", L"Desk Connect", WS_OVERLAPPEDWINDOW, 300, 300, 512, 384, NULL, NULL, hInstance, NULL);	CreateWindow(L"button", L"Listen", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 5, 5, 80, 25, mWnd, (HMENU)BTN_LISTEN, hInstance, NULL);	CreateWindow(L"button", L"Connect", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 85, 5, 80, 25, mWnd, (HMENU)BTN_CONNECT, hInstance, NULL);	CreateWindow(L"button", L"Send", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 165, 5, 80, 25, mWnd, (HMENU)BTN_SEND, hInstance, NULL);	CreateWindow(L"button", L"Disconnect", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 245, 5, 80, 25, mWnd, (HMENU)BTN_DISCONNECT, hInstance, NULL);	hwndEdit = CreateWindow(L"edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 5, 40, 125, 20, mWnd, (HMENU)TXT_IP, hInstance, NULL);	if(!mWnd) return 0;	ShowWindow(mWnd, SW_SHOWNORMAL);	UpdateWindow(mWnd);		SetWindowTextA(hwndEdit, "127.0.0.1");	while(GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}LRESULT CALLBACK MainProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam){    switch(Msg)    {		case SOCKET_MESSAGE:			switch (WSAGETSELECTEVENT(lParam))            {				case FD_ACCEPT:					memset(&userAddr, 0, sizeof(SOCKADDR));					tmpSocket = accept(wParam, (LPSOCKADDR)&userAddr, &sizeAddr);					closesocket(mSocket);					mSocket = tmpSocket;					if(mSocket == INVALID_SOCKET)					{						EMSG("Connection failed!");						CloseSocket(mSocket);						break;					}					bConnected = TRUE;					IMSG("Client connected.");					break;				case FD_CONNECT:					if(!WSAGETSELECTERROR(lParam))					{						bConnected = TRUE;						IMSG("Connection successful.");					}					else					{						EMSG("Connection failed!");					}					break;				case FD_READ:					Process(wParam);					break;				case FD_CLOSE:					CloseSocket(mSocket);					EMSG("Connection lost!");					break;            }			break;		case WM_COMMAND:			switch(LOWORD(wParam))			{			case BTN_LISTEN:				if(bActiveSocket)				{					if(QMSG("This will reset the connection.")  == IDOK)					{						CloseSocket(mSocket);					}					else					{						break;					}				}				bActiveSocket = CreateTCPSocket(hWnd);				if(bActiveSocket)					 Listen(mSocket, DEFAULT_PORT);				break;			case BTN_CONNECT:				if(bActiveSocket)				{					if(QMSG("This will reset the connection.")  == IDOK)					{						CloseSocket(mSocket);					}					else					{						break;					}				}				bActiveSocket = CreateTCPSocket(hWnd);				if(bActiveSocket)					Connect(mSocket, szText, DEFAULT_PORT);				break;			case BTN_SEND:				if(bConnected)				{					send(mSocket, "Hello World!", 12, 0);				}				else				{					EMSG("Not connected.");				}				break;			case BTN_DISCONNECT:				CloseSocket(mSocket);				break;			case TXT_IP:				if(HIWORD(wParam) == EN_UPDATE)				{					ZeroMemory(szText, 512);					GetWindowTextA(hwndEdit, szText, 512);					InvalidateRect(hwndEdit, NULL, TRUE);				}			}			break;		case WM_DESTROY:			CloseSocket(mSocket);			PostQuitMessage(WM_QUIT);			break;		default:			return DefWindowProc(hWnd, Msg, wParam, lParam);		}    return TRUE;}BOOL CreateTCPSocket(HWND hWindow){	WSADATA wsadata;		if(WSAStartup(SCK_VERSION2, &wsadata) != 0)		return FALSE;		if(wsadata.wVersion != SCK_VERSION2)	{		WSACleanup();		return FALSE;	}		mSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	if(mSocket == INVALID_SOCKET)	{		EMSG("Couldn't create socket.");		WSACleanup();		return FALSE;	}	setsockopt(mSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));	WSAAsyncSelect(mSocket, hWindow, SOCKET_MESSAGE, FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE);	return TRUE;}BOOL Connect(SOCKET sock, char *IPAddress, unsigned int port){	SOCKADDR_IN addr;	ZeroMemory(&addr, sizeof(addr));	addr.sin_family = AF_INET;	addr.sin_port = htons(port);	addr.sin_addr.S_un.S_addr = inet_addr(IPAddress);	int error = connect(sock, (LPSOCKADDR)&addr, sizeof(addr));	if(error != 0)	{		error = WSAGetLastError();		if(error != WSAEWOULDBLOCK)		{			EMSG("Connection failed!");			CloseSocket(mSocket);			return FALSE;		}	}	return TRUE;}BOOL Listen(SOCKET sock, unsigned int port){	SOCKADDR_IN addr;	addr.sin_family = AF_INET;	addr.sin_port = htons(port);	addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);	if(bind(sock, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)	{		EMSG("Could not bind socket");		CloseSocket(mSocket);		return FALSE;	}	if(listen(sock, SOMAXCONN) == SOCKET_ERROR)	{		EMSG("could not listen");		CloseSocket(mSocket);		return FALSE;	}	return TRUE;}void Process(SOCKET sock){	char buffer[DEFAULT_BUFLEN];	memset(buffer, 0, sizeof(buffer));	int bytesRecv = recv(sock, buffer, sizeof(buffer), 0);	IMSG(buffer);}void CloseSocket(SOCKET sock){	if(sock)  closesocket(sock);	WSACleanup();	bActiveSocket = FALSE;	bConnected = FALSE;}

This topic is closed to new replies.

Advertisement