/* C source for Winsock Chess Revision 1994-03-15 Modified by Donald Munro for use as a 2 player chess game over a WINSOCK layer on a TCP (or other WinSock supporting) network. Source code and make files for MS Visual C/C++ V1.00/1.50. February/March 1994 All GNU copyright and distribution conditions as described below and in the file COPYING also apply to WinSock Chess. This module is Winsock Chess specific. C source for GNU CHESS Revision: 1990-09-30 Modified by Daryl Baker for use in MS WINDOWS environment Revision 1994-03-15 Modified by Donald Munro for use as a 2 player chess game over a communications link viz WINSOCK or other. Source code and make files for MS Visual C++ V1.00/1.50 Conversion to usage of message crackers for easy conversion to win32 February/March 1994 Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc. Copyright (c) 1988, 1989, 1990 John Stanback This file is part of CHESS. CHESS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the CHESS General Public License for full details. Everyone is granted permission to copy, modify and redistribute CHESS, but only under the conditions described in the CHESS General Public License. A copy of this license is supposed to have been given to you along with CHESS so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ #define NOATOM #define NOCREATESTRUCT #define NOFONT #define NOREGION #define NOSOUND #define NOWH #define NOKANJI #define STRICT #include #include #include #include #include #include #include "resource.h" #include "winsock.h" #include "gnuchess.h" #include "defs.h" #include "chess.h" #define DESIRED_WINSOCK_VERSION 0x0101 #define MINIMUM_WINSOCK_VERSION 0x0001 #define WSCHESS_PORT 1985 extern HWND hwndHostDlg,hwndMain; extern BOOL bHost,bWaiting,bMoveReady,bConnected; extern HINSTANCE hInst; extern MoveInfo moveinfo; extern char szSockDesc[45]; extern HWND hwndHostDlg,hwndMain; extern WORD wPacketSize; extern void (*SendMove)(WORD); extern int User_Move; void WaitForSocket(void); struct sockaddr_in client_addr; SOCKET socketListen,socketServer,socketClient; WORD cbSent,cbReceived;; short oldTCmoves,oldTCminutes; int MsgBox( HWND hwndParent, UINT fuType, LPSTR pszFormat, ... ) //---------------------------- { char szOutput[512]; va_list ArgList; va_start( ArgList, pszFormat ); wvsprintf( szOutput, pszFormat, ArgList ); va_end( ArgList ); return MessageBox( hwndParent, szOutput,"WsChess", fuType ); } LPSTR SocketErrorMsg(int nSockerr) //----------------------------------- { switch( nSockerr ) { case WSAENAMETOOLONG : return "Name too long"; case WSANOTINITIALISED : return "Not initialized"; case WSAENETDOWN : return "Network subsystem down"; case WSASYSNOTREADY : return "System not ready"; case WSAVERNOTSUPPORTED : return "Version is not supported"; case WSAESHUTDOWN : return "Can't send after socket shutdown"; case WSAEINTR : return "Interrupted system call"; case WSAHOST_NOT_FOUND : return "Host not found"; case WSATRY_AGAIN : return "Try again"; case WSANO_RECOVERY : return "Non-recoverable error"; case WSANO_DATA : return "No data record available"; case WSAEBADF : return "Bad file number"; case WSAEWOULDBLOCK : return "Operation would block"; case WSAEINPROGRESS : return "Operation now in progress"; case WSAEALREADY : return "Operation already in progress"; case WSAEFAULT : return "Bad address"; case WSAEDESTADDRREQ : return "Destination address required"; case WSAEMSGSIZE : return "Message too long"; case WSAEPFNOSUPPORT : return "Protocol family not supported"; case WSAENOTEMPTY : return "Directory not empty"; case WSAEPROCLIM : return "EPROCLIM returned"; case WSAEUSERS : return "EUSERS returned"; case WSAEDQUOT : return "Disk quota exceeded"; case WSAESTALE : return "ESTALE returned"; case WSAEINVAL : return "Invalid argument"; case WSAEMFILE : return "Too many open files"; case WSAEACCES : return "Access denied"; case WSAELOOP : return "Too many levels of symbolic links"; case WSAEREMOTE : return "The object is remote"; case WSAENOTSOCK : return "Socket operation on non-socket"; case WSAEADDRNOTAVAIL : return "Can't assign requested address"; case WSAEADDRINUSE : return "Address already in use"; case WSAEAFNOSUPPORT : return "Address family not supported by protocol family"; case WSAESOCKTNOSUPPORT : return "Socket type not supported"; case WSAEPROTONOSUPPORT : return "Protocol not supported"; case WSAENOBUFS : return "No buffer space is supported"; case WSAETIMEDOUT : return "Connection timed out"; case WSAEISCONN : return "Socket is already connected"; case WSAENOTCONN : return "Socket is not connected"; case WSAENOPROTOOPT : return "Bad protocol option"; case WSAECONNRESET : return "Connection reset by peer"; case WSAECONNABORTED : return "Software caused connection abort"; case WSAENETRESET : return "Network was reset"; case WSAECONNREFUSED : return "Connection refused"; case WSAEHOSTDOWN : return "Host is down"; case WSAEHOSTUNREACH : return "Host is unreachable"; case WSAEPROTOTYPE : return "Protocol is wrong type for socket"; case WSAEOPNOTSUPP : return "Operation not supported on socket"; case WSAENETUNREACH : return "ICMP network unreachable"; case WSAETOOMANYREFS : return "Too many references"; default : return "Unknown"; } } void DestroySocket(SOCKET socket) //------------------------------- { LINGER linger; if (socket == INVALID_SOCKET) return; // Hard close linger.l_onoff = TRUE; linger.l_linger = 0; setsockopt(socket,SOL_SOCKET,SO_LINGER,(char FAR *)&linger,sizeof(linger)); closesocket(socket); } //Blocking recv int BlockReceive(SOCKET socket,LPSTR lpszBuf,WORD wLen) //------------------------------------------------ { WORD cbReceived; do { cbReceived = recv(socket,lpszBuf,wLen,0); if (cbReceived == SOCKET_ERROR) return WSAGetLastError(); lpszBuf += cbReceived; wLen -= cbReceived; } while (wLen > 0); *lpszBuf = 0; return 0; } //Blocking send int BlockSend(SOCKET socket,LPSTR lpsBuf,WORD wLen) //------------------------------------------------ { WORD cbSent; do { cbSent = send(socket,lpsBuf,wLen,0); if (cbSent == SOCKET_ERROR) return WSAGetLastError(); lpsBuf += cbSent; wLen -= cbSent; } while (wLen > 0); return 0; } BOOL InitialiseWS(void) //--------------------- { WSADATA wsadata; int nSockerr; nSockerr = WSAStartup( DESIRED_WINSOCK_VERSION, &wsadata ); if( nSockerr != 0 ) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Cannot initialize WinSock, error %d: %s", nSockerr, SocketErrorMsg(nSockerr)); return FALSE; } if( wsadata.wVersion < MINIMUM_WINSOCK_VERSION ) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Windows Sockets version %02X.%02X, Version %02X.%02X Required", LOBYTE(wsadata.wVersion), HIBYTE(wsadata.wVersion), LOBYTE(MINIMUM_WINSOCK_VERSION), HIBYTE(MINIMUM_WINSOCK_VERSION) ); WSACleanup(); return FALSE; } strncpy(szSockDesc,wsadata.szDescription,40); szSockDesc[40] = 0; return TRUE; } BOOL ServerStartWS(void) //---------------------- { struct sockaddr_in srv_addr; socketListen = socket(AF_INET,SOCK_STREAM,0); if (socketListen == INVALID_SOCKET) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not create server socket", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); srv_addr.sin_port = htons(WSCHESS_PORT); if (bind(socketListen,(LPSOCKADDR)&srv_addr,sizeof(srv_addr)) == SOCKET_ERROR) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not bind server socket", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } if (listen(socketListen,1) == SOCKET_ERROR) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not bind server socket", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } if(WSAAsyncSelect(socketListen,hwndMain,WM_SOCKET,FD_ACCEPT) != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not start async listener", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } return TRUE; } BOOL ClientStartWS(LPCSTR lpszServerIPAddr) //---------------------------------------- { struct sockaddr_in srv_addr; char szIpAddr[60]; LPHOSTENT lphostent; unsigned long ulIpAddr; // WIN32 change to int/WORD if same as UNIX! unsigned long FAR *lpulIpAddr; socketClient = socket(PF_INET,SOCK_STREAM,0); if (socketClient == INVALID_SOCKET) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not create client socket", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } memset(&srv_addr,0,sizeof(struct sockaddr_in)); lstrcpy(szIpAddr,lpszServerIPAddr); if ( (lphostent = gethostbyname(lpszServerIPAddr)) == (LPHOSTENT)0L) { ulIpAddr = inet_addr(lpszServerIPAddr); if ( (lphostent = gethostbyaddr(&ulIpAddr,4,PF_INET)) == (LPHOSTENT)0L) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Invalid IP Address", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } } else // valid host name { lpulIpAddr = (unsigned long FAR *) lphostent->h_addr; ulIpAddr = *lpulIpAddr; } if (ulIpAddr == INADDR_NONE) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Invalid IP Address", SocketErrorMsg(WSAGetLastError())); WSACleanup(); return FALSE; } srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = ulIpAddr; srv_addr.sin_port = htons(WSCHESS_PORT); if (connect(socketClient,(LPSOCKADDR)&srv_addr,sizeof(srv_addr)) == SOCKET_ERROR) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %d : Could not connect with host\n%s", WSAGetLastError(), SocketErrorMsg(WSAGetLastError())); DestroySocket(socketClient); WSACleanup(); return FALSE; } if(WSAAsyncSelect(socketClient,hwndMain,WM_SOCKET, FD_READ | FD_CLOSE) != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not start client async processing", SocketErrorMsg(WSAGetLastError())); DestroySocket(socketClient); WSACleanup(); return FALSE; } return TRUE; } void DisconnectWS(void) //--------------------- { if (bHost) { DestroySocket(socketServer); DestroySocket(socketListen); bHost = bConnected = FALSE; } else { DestroySocket(socketClient); bHost = bConnected = FALSE; } SetWindowText(hwndMain,"Winsock Chess (Not Connected)"); WSACleanup(); } void SendMoveWS(WORD cbBytes) //--------------------------- { SOCKET socket; int nErr; if (bHost) socket = socketServer; else socket = socketClient; wPacketSize = cbBytes; cbSent = send(socket,moveinfo.szMove,cbBytes,0); if (cbSent == SOCKET_ERROR) { nErr = WSAGetLastError(); cbSent = 0; if (nErr != WSAEWOULDBLOCK) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Send Error", SocketErrorMsg(WSAGetLastError())); DestroySocket(socket); WSACleanup(); } } if (cbSent >= wPacketSize) { cbSent = 0; wPacketSize = 0; } } void GetOpponentsMoveWS(WORD cbBytes) //---------------------------------- { wPacketSize = cbBytes; bWaiting = TRUE; } void WaitForSocket(void) //---------------------- { MSG msg; while (WSAIsBlocking()) while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) DispatchMessage(&msg); } BOOL CALLBACK ConfirmDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) //----------------------------------------------------------- { SOCKET socket; char *szFileName,szConfirmation[10]; LPSTR lpszGetBuf; unsigned long ulArgp; int cbReceived; switch (message) { case WM_INITDIALOG: PostMessage(hDlg,MSG_CHESS_GET,NULL,lParam); return TRUE; case MSG_CHESS_GET : if (bHost) socket = socketServer; else socket = socketClient; WaitForSocket(); WSAAsyncSelect(socket,hwndMain,0,0L); ulArgp = 0; ioctlsocket(socket,FIONBIO,&ulArgp); BlockSend(socket,"COMG\r\n",7); cbReceived = BlockReceive(socket,szConfirmation,3); if (cbReceived != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Receive Error", SocketErrorMsg(cbReceived)); DestroySocket(socket); if (bHost) DestroySocket(socketListen); WSACleanup(); bHost = bConnected = FALSE; return FALSE; } if (lstrcmp(szConfirmation,"OK") != 0) { SetDlgItemText(hDlg,IDS_WAITING, "Load game request rejected by opponent"); ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE),SW_SHOW); ulArgp = 1; ioctlsocket(socket,FIONBIO,&ulArgp); WSAAsyncSelect(socket,hwndMain,WM_SOCKET, FD_READ | FD_CLOSE); return TRUE; } SetDlgItemText(hDlg,IDS_WAITING,"Loading and Transmitting"); szFileName = (char *) LOWORD((DWORD)lParam); NewGame(hwndMain); GetGame(hwndMain,szFileName); lpszGetBuf = EncodeGame(); BlockSend(socket,lpszGetBuf,4095); GlobalFreePtr(lpszGetBuf); SetDlgItemText(hDlg,IDS_WAITING,"Complete"); ulArgp = 1; ioctlsocket(socket,FIONBIO,&ulArgp); WSAAsyncSelect(socket,hwndMain,WM_SOCKET, FD_READ | FD_CLOSE); ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE),SW_SHOW); return TRUE; case WM_COMMAND: switch (wParam) { case IDB_CONTINUE : EndDialog(hDlg, NULL); return TRUE; } } return (FALSE); } void GetGameWS(void) //------------------- { char szFileName[256]; if (GetFileName(szFileName,OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, MSG_CHESS_GET)) DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_CONFIRM),hwndMain,ConfirmDlg, MAKELPARAM(szFileName,0)); } BOOL CALLBACK ConfirmNewDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) //----------------------------------------------------------- { SOCKET socket; char szConfirmation[10]; unsigned long ulArgp; int cbReceived; short opp; switch (message) { case WM_INITDIALOG: PostMessage(hDlg,MSG_CHESS_NEW,NULL,lParam); return TRUE; case MSG_CHESS_NEW : if (bHost) socket = socketServer; else socket = socketClient; WSAAsyncSelect(socket,hwndMain,0,0L); ulArgp = 0; ioctlsocket(socket,FIONBIO,&ulArgp); lstrcpy(moveinfo.szMove,"COMN\r\n"); BlockSend(socket,"COMN\r\n",7); cbReceived = BlockReceive(socket,szConfirmation,3); if (cbReceived != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Receive Error", SocketErrorMsg(cbReceived)); DestroySocket(socket); if (bHost) DestroySocket(socketListen); WSACleanup(); bHost = bConnected = FALSE; return TRUE; } if (lstrcmp(szConfirmation,"OK") != 0) { SetDlgItemText(hDlg,IDS_WAITING, "New game request rejected by opponent"); ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE),SW_SHOW); } else { opp = opponent; NewGame(hwndMain); if (opp == black) { computer = white; opponent = black; User_Move = FALSE; flag.reverse = !flag.reverse; PostMessage ( hwndMain, MSG_COMPUTER_MOVE, NULL, (LPARAM)NULL); } else { computer = black; opponent = white; User_Move = TRUE; } SetDlgItemText(hDlg,IDS_WAITING,"Complete"); ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE),SW_SHOW); UpdateDisplay(hwndMain,0,0,1,0); flag.force = false; Sdepth = 0; } WaitForSocket(); ulArgp = 1; ioctlsocket(socket,FIONBIO,&ulArgp); WSAAsyncSelect(socket,hwndMain,WM_SOCKET, FD_READ | FD_CLOSE); return TRUE; case WM_COMMAND: switch (wParam) { case IDB_CONTINUE : EndDialog(hDlg, NULL); return TRUE; } } return (FALSE); } void NewGameWS(void) //------------------- { DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIRM),hwndMain,ConfirmNewDlg); } BOOL CALLBACK ConfirmTimeDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) //----------------------------------------------------------- { SOCKET socket; char szConfirmation[10]; unsigned long ulArgp; int cbReceived; switch (message) { case WM_INITDIALOG: PostMessage(hDlg,IDM_TIMECONTROL,NULL,lParam); return TRUE; case IDM_TIMECONTROL : if (bHost) socket = socketServer; else socket = socketClient; WSAAsyncSelect(socket,hwndMain,0,0L); ulArgp = 0; ioctlsocket(socket,FIONBIO,&ulArgp); BlockSend(socket,"COMT\r\n",7); cbReceived = BlockReceive(socket,szConfirmation,3); if (cbReceived != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Receive Error", SocketErrorMsg(cbReceived)); DestroySocket(socket); if (bHost) DestroySocket(socketListen); WSACleanup(); bHost = bConnected = FALSE; return TRUE; } if (lstrcmp(szConfirmation,"OK") != 0) { SetDlgItemText(hDlg,IDS_WAITING, "Set time request rejected by opponent"); TCmoves = oldTCmoves; TCminutes = oldTCminutes; if (TCflag) SetTimeControl (); ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE),SW_SHOW); } else { wsprintf(szConfirmation,"%3d%3d",TCmoves,TCminutes); BlockSend(socket,szConfirmation,7); SetTimeControl (); SetDlgItemText(hDlg,IDS_WAITING,"Complete"); ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE),SW_SHOW); UpdateDisplay(hwndMain,0,0,1,0); } WaitForSocket(); ulArgp = 1; ioctlsocket(socket,FIONBIO,&ulArgp); WSAAsyncSelect(socket,hwndMain,WM_SOCKET, FD_READ | FD_CLOSE); return TRUE; case WM_COMMAND: switch (wParam) { case IDB_CONTINUE : EndDialog(hDlg, NULL); return TRUE; } } return (FALSE); } void SetTimeWS(int id) //-------------------- { oldTCmoves = TCmoves; oldTCminutes = TCminutes; if ( TimeControlDialog (hwndMain, hInst, id) ) { TCflag = (TCmoves>1); DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIRM),hwndMain,ConfirmTimeDlg); } } void OnSocketMessage(HWND hwnd, SOCKET socket, WORD wEvent, WORD wError) //---------------------------------------------------------------------- { WORD cbSnt,wSize; int cliaddr_size, nErr; char szCaption[50]; switch (wEvent) { case FD_ACCEPT : if (! bHost) return; if (socket != socketListen) return; // ??!! if (wError != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not accept connection (FD_ACCEPT)", SocketErrorMsg(wError)); if (bHost) { DestroySocket(socketServer); DestroySocket(socketListen); } else DestroySocket(socketListen); WSACleanup(); SendMessage(hwndHostDlg,WM_CONNECTED,1,0L); return; } // socket should == socketListen cliaddr_size = sizeof(struct sockaddr_in); socketServer = accept(socket,(LPSOCKADDR)&client_addr, &cliaddr_size); if (socketServer == INVALID_SOCKET) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not accept connection (accept)", SocketErrorMsg(WSAGetLastError())); WSACleanup(); SendMessage(hwndHostDlg,WM_CONNECTED,1,0L); return; } //WSAAsyncSelect(socket,hwndMain,0,0); // Only one connect if(WSAAsyncSelect(socketServer,hwndMain,WM_SOCKET, FD_READ | FD_CLOSE) != 0) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Could not start async processing", SocketErrorMsg(WSAGetLastError())); DestroySocket(socketServer); DestroySocket(socket); WSACleanup(); SendMessage(hwndHostDlg,WM_CONNECTED,1,0L); return; } wsprintf((LPSTR)szCaption ,"Winsock Chess (Connected to %s)", (LPSTR)inet_ntoa(client_addr.sin_addr)); SetWindowText(hwndMain,szCaption); SendMessage(hwndHostDlg,WM_CONNECTED,0,0L); break; case FD_WRITE : if ( (wPacketSize-cbSent) <= 0) { cbSent = 0; wPacketSize = 0; break; } cbSnt = send(socket,(moveinfo.szMove+cbSent),(wPacketSize-cbSent),0); if (cbSnt == SOCKET_ERROR) { nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Send Error", SocketErrorMsg(WSAGetLastError())); DestroySocket(socket); WSACleanup(); } else cbSnt = 0; } cbSent += cbSnt; if (cbSent >= wPacketSize) { cbSent = 0; wPacketSize = 0; } break; case FD_READ : wSize = wPacketSize-cbReceived; if (wSize <= 0) { cbReceived = 0; wPacketSize = 0; break; } cbSnt = recv(socket,(moveinfo.szMove+cbReceived),wSize,0); if (cbSnt == SOCKET_ERROR) { nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK) { MsgBox( NULL, MB_ICONSTOP | MB_OK, "Winsock Error %s : Receive Error", SocketErrorMsg(WSAGetLastError())); DestroySocket(socket); WSACleanup(); } else cbSnt = 0; } cbReceived += cbSnt; if (cbReceived >= wPacketSize) { cbReceived = 0; wPacketSize = 0; SendMessage(hwndMain,MSG_COMPUTER_MOVE,NULL,NULL); } break; case FD_CLOSE : DestroySocket(socket); bConnected = FALSE; SetWindowText(hwndMain,"Winsock Chess (Not Connected)"); if (bHost) { DestroySocket(socketListen); bHost = FALSE; } NewGame(hwndMain); WSACleanup(); break; } return; }