/* -- netcom.cpp --
Game communications across the net for xRTSe
*/
#include "xrtse.h"
BOOL EstablishConnection(void)
{
HWND hwndProc;
// Must be done at the beginning of every WinSock program
WSADATA w; // used to store information about WinSock version
int keyp;
int error = WSAStartup(0x0202, &w); // Fill in w
if (error)
{ // there was an error
xrtse_error("Could not init Winsock2");
return FALSE;
}
if (w.wVersion != 0x0202)
{ // wrong WinSock version!
xrtse_error("Wrong winsock version!");
WSACleanup(); // unload ws2_32.dll
return FALSE;
}
hwndProc = CreateWindow(
"WsockProcWnd", //name of window class
"Winsock Proc", //title
0, //normal window style
0, //X COORD
0, //Y COORD
0, //WIDTH
0, //HEIGHT
HWND_DESKTOP, //no parent window
NULL, //no menu override
g_instance, //handle of this instance
NULL);
if (!hwndProc)
{
xrtse_error("Could not create proc window.");
return FALSE;
}
clear_bitmap(screen);
textout(screen, font, "Choose Connection Type:", 5, 5, makecol(255, 255, 255));
textout(screen, font, " 1. Host -- You must provide your IP address to the other player.", 5, text_height(font) + 5, makecol(255, 255, 255));
textout(screen, font, " 2. Client -- You must input the IP address provided by the other player.", 5, text_height(font) * 2 + 5, makecol(255, 255, 255));
textout(screen, font, "(Press [Esc] to stop the connection process.)", 5, text_height(font) * 4 + 5, makecol(255, 255, 255));
keyp = readkey();
while ((keyp >> 8 != KEY_ESC) && (keyp >> 8 != KEY_1) && (keyp >> 8 != KEY_2))
keyp = readkey();
if (keyp >> 8 == KEY_ESC)
{
DestroyWindow(hwndProc);
return FALSE;
}
if (keyp >> 8 == KEY_1)
{
if (!CreateHostConnection(hwndProc))
{
DestroyWindow(hwndProc);
return FALSE;
}
return TRUE;
}
else //(keyp & 0xFF == '2')
{
if (!CreateClientConnection(hwndProc))
{
DestroyWindow(hwndProc);
return FALSE;
}
return TRUE;
}
if (hwndProc)
DestroyWindow(hwndProc);
return TRUE;
}
BOOL CreateHostConnection(HWND hwndProc)
{
MSG msg;
sockaddr_in addr; // the address structure for a TCP socket
connection1.type = CTYPE_HOST;
connection1.status = CSTAT_NOTCONNECTED;
connection1.can_send = FALSE;
for (int i = 0; i < 99; i++)
connection1.ip[i] = '\0';
connection1.loc_speed = 0;
connection1.rem_speed = 0;
connection1.loc_socket = socket(AF_INET, SOCK_STREAM, 0); // Create socket
if (connection1.loc_socket == INVALID_SOCKET)
{
xrtse_error("Could not create connection socket.");
return FALSE;
}
WSAAsyncSelect(connection1.loc_socket, hwndProc, WM_WSAASYNC, FD_READ | FD_WRITE | FD_ACCEPT | FD_CLOSE);
addr.sin_family = AF_INET; // Address family Internet
addr.sin_port = htons(5001); // Assign port 5001 to this socket
addr.sin_addr.s_addr = htonl(INADDR_ANY); // No destination
if (bind(connection1.loc_socket, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
{ // error
xrtse_error("Could not bind socket.");
WSACleanup(); // unload WinSock
return FALSE; // quit
}
if (listen(connection1.loc_socket, 2) == SOCKET_ERROR)
{
xrtse_error("Could not listen at socket.");
WSACleanup();
return FALSE;
}
connection1.status = CSTAT_WAITING;
clear_bitmap(screen);
textout(screen, font, "Waiting for connection on port 5001 . .", 5, 5, makecol(255, 255, 255));
while (TRUE)
{
if (connection1.status > CSTAT_WAITING)
break;
if (key[KEY_ESC])
{
closesocket(connection1.loc_socket);
WSACleanup();
return FALSE;
}
if (PeekMessage(NULL, hwndProc, 0, 0, PM_NOREMOVE))
{
while (PeekMessage(&msg, hwndProc, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
shutdown(connection1.loc_socket, SD_BOTH);
closesocket(connection1.loc_socket);
DestroyWindow(hwndProc);
WSACleanup();
return TRUE;
}
LRESULT CALLBACK WSHostProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_WSAASYNC:
{
MessageBox(NULL, "Connect request received.", "xRTSE Info", MB_OK | MB_ICONINFORMATION);
// what word?
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
// check for an error
if (!WSAGETSELECTERROR(lParam))
return FALSE;
sockaddr client_sock;
int sock_size = (int)sizeof(client_sock);
// process message
connection1.rem_socket = accept(wParam, &client_sock, &sock_size);
if (connection1.rem_socket == INVALID_SOCKET)
{
xrtse_error("Could not connect to remote client.");
return FALSE;
}
connection1.status = CSTAT_CONNECTED;
return 0;
} //FD_ACCEPT
/*
case FD_WRITE: // we can send data
{
// enter an infinite loop
connection1.can_send = TRUE;
while(TRUE)
{
// read in more data from the file and store it in packet.data.
in.read((char*)&packet.data, MAX_PACKET_SIZE);
// increment the amount of data sent
data_sent += strlen(packet.data);
// send the packet off to the Server if it is filled
if (send(wparam, (char*)(&packet), sizeof(PACKET), 0) == SOCKET_ERROR)
{
// check if the network buffer is full and can send no more
// data. If so then break from the loop
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
// break from the loop if buffer is full
connection1.can_send = FALSE;
break;
}
else // another error
{
// display an error message and clean up
CleanUp();
return 0;
}
}
}
}
break; //FD_WRITE
*/
}
}
case WM_PAINT:
break;
case WM_DESTROY: //terminate the program
PostQuitMessage(0);
break;
default:
//let windows process the rest
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
BOOL CreateClientConnection(HWND hwndProc)
{
MSG msg;
sockaddr_in addr; // the address structure for a TCP socket
sockaddr_in target;
char rem_ip[100];
int keyp;
connection1.type = CTYPE_CLIENT;
connection1.status = CSTAT_NOTCONNECTED;
connection1.can_send = FALSE;
for (int i = 0; i < 99; i++)
connection1.ip[i] = '\0';
connection1.loc_speed = 0;
connection1.rem_speed = 0;
for (int i = 0; i < 99; i++)
rem_ip[i] = '\0';
clear_bitmap(screen);
textout(screen, font, "Enter host IP: _", 5, 5, makecol(255, 255, 255));
while (TRUE)
{
keyp = readkey();
if (keyp >> 8 == KEY_ESC)
return FALSE;
if (keyp >> 8 == KEY_BACKSPACE)
{
if (strlen(rem_ip) > 0)
rem_ip[strlen(rem_ip) - 1] = '\0';
}
else if (keyp >> 8 == KEY_ENTER)
{
if (strlen(rem_ip) <= 0)
return FALSE;
else
break;
}
else
rem_ip[strlen(rem_ip)] = (char)(keyp & 0xFF);
clear_bitmap(screen);
textprintf(screen, font, 5, 5, makecol(255, 255, 255), "Enter host IP: %s_", rem_ip);
}
connection1.loc_socket = socket(AF_INET, SOCK_STREAM, 0); // Create socket
if (connection1.loc_socket == INVALID_SOCKET)
{
xrtse_error("Could not create connection socket.");
return FALSE;
}
//addr.sin_family = AF_INET; // Address family Internet
//addr.sin_port = htons(5001); // Assign port 5001 to this socket
//addr.sin_addr.s_addr = htonl(INADDR_ANY); // No destination
//if (bind(connection1.loc_socket, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
// { // error
// xrtse_error("Could not bind socket.");
// WSACleanup(); // unload WinSock
// return FALSE; // quit
// }
WSAAsyncSelect(connection1.loc_socket, hwndProc, WM_WSAASYNC, FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
connection1.status = CSTAT_WAITING;
clear_bitmap(screen);
textprintf(screen, font, 5, 5, makecol(255, 255, 255), "Connecting to %s on port 5001", rem_ip);
target.sin_family = AF_INET; // address family Internet
target.sin_port = htons(5001); // set server's port number
target.sin_addr.s_addr = inet_addr((const char *)rem_ip); // set server's IP
if (connect(connection1.loc_socket, (LPSOCKADDR)⌖, sizeof(target)) == SOCKET_ERROR)
{ // an error connecting has occurred!
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
while (WSAGetLastError() == WSAEWOULDBLOCK)
{
textout(screen, font, "Blocked...trying again", 50, 50, makecol(255, 255, 255));
rest(750);
if (connect(connection1.loc_socket, (LPSOCKADDR)⌖, sizeof(target)) != SOCKET_ERROR)
break;
if (key[KEY_ESC])
return FALSE;
}
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
xrtse_error("Could not connect to host socket after block reroute.");
WSACleanup();
return FALSE;
}
}
else
{
xrtse_error("Could not connect to host socket.");
WSACleanup();
return FALSE;
}
}
while (TRUE)
{
if (connection1.status > CSTAT_WAITING)
break;
if (key[KEY_ESC])
{
closesocket(connection1.loc_socket);
WSACleanup();
return FALSE;
}
if (PeekMessage(NULL, hwndProc, 0, 0, PM_NOREMOVE))
{
while (PeekMessage(&msg, hwndProc, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
shutdown(connection1.loc_socket, SD_BOTH);
closesocket(connection1.loc_socket);
DestroyWindow(hwndProc);
WSACleanup();
return TRUE;
}
LRESULT CALLBACK WSClientProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_WSAASYNC:
{
// what word?
switch(WSAGETSELECTEVENT(lParam))
{
case FD_CONNECT:
{
// check for an error
if (!WSAGETSELECTERROR(lParam))
return FALSE;
connection1.status = CSTAT_CONNECTED;
return 0;
} //FD_CONNECT
break;
// case FD_READ:
// {
}
}
case WM_PAINT:
break;
case WM_DESTROY: //terminate the program
PostQuitMessage(0);
break;
default:
//let windows process the rest
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//end of netcom.cpp
EDIT: Forgot to mention...this is C++, Win32 API, and Allegro...so the keyboard input and screen output are Allegro stuff, and the message handling is obviously W32API. I'm pretty sure that code has no bugs (but hey, I may be wrong).
Also, the "host" end is crashing on "FD_ACCEPT" (not FD_CONNECT).
[edited by - TDragon on August 27, 2003 3:47:18 PM]
Winsock Async connection problem
I'm programming a multiplayer RTS in C++. The engine is not server based, but establishes a two-way connection between the computers (just two for now). The sockets obviously need to be asynchronous at both ends, rather than the standard client-server setup, but I haven't yet found any actual code for a dual asynchronous connection. So I've cobbled something together myself, in hopes that it would work.
And of course it doesn't. As near as I can tell, the "host" end is crashing as soon as it receives the "FD_ACCEPT" message, and the client end is receiving at least one "WSAEWOULDBLOCK" error, trying to reconnect, then failing.
Here is the code. I am only a beginner at sockets programming, so there is probably some bad code in there. HOWEVER, please do not reply unless you are fairly certain you know what my problem is, or have identified some code that would cause other problems.
This is a cut-and-paste from the source file "netcom.cpp". The struct named "connection1" is defined in "xrtse.h" and merely contains sockets for the local and remote computers, the connection status, and other unimportant info.
Note that some lines are commented out. Some are because I don't want to mess with that area yet and haven't got that far anyway; others are in trying to figure out what's going wrong. Assume that anything having to do with the connecting process has been tried both uncommented and commented.
{[JohnE, Chief Architect and Senior Programmer, Twilight Dragon Media{[+++{GCC/MinGW}+++{Code::Blocks IDE}+++{wxWidgets Cross-Platform Native UI Framework}+++
Okay, I can understand that most people probably don''t want to dig through all that code.
But could someone at least point me at some code that will show me what I need to see?
I''ve already looked at all of gamedev.net''s resources, and the MSDN Library, but I couldn''t find anything in-depth enough.
I''m really stuck here...help me please!
But could someone at least point me at some code that will show me what I need to see?
I''ve already looked at all of gamedev.net''s resources, and the MSDN Library, but I couldn''t find anything in-depth enough.
I''m really stuck here...help me please!
{[JohnE, Chief Architect and Senior Programmer, Twilight Dragon Media{[+++{GCC/MinGW}+++{Code::Blocks IDE}+++{wxWidgets Cross-Platform Native UI Framework}+++
August 29, 2003 11:29 PM
Peer-to-peer is no different than client-server at the socket layer, except both sides need to set the asynchronous mode on the socket.
Take any client/server sample code and just modify it to make the receiving socket non-blocking.
Take any client/server sample code and just modify it to make the receiving socket non-blocking.
How simple you make it sound -- and yet that''s what I''ve unsuccessfully tried to do...
{[JohnE, Chief Architect and Senior Programmer, Twilight Dragon Media{[+++{GCC/MinGW}+++{Code::Blocks IDE}+++{wxWidgets Cross-Platform Native UI Framework}+++
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement