Linux: Implemented sockets/netplay + fixed uninitialized variable crash
This commit is contained in:
parent
2c8c1be648
commit
a6579fbfdb
4 changed files with 121 additions and 143 deletions
|
@ -13,13 +13,17 @@ unique_ptr<GameClient> GameClient::Instance;
|
|||
|
||||
GameClient::GameClient()
|
||||
{
|
||||
_stop = false;
|
||||
|
||||
MessageManager::RegisterNotificationListener(this);
|
||||
}
|
||||
|
||||
GameClient::~GameClient()
|
||||
{
|
||||
_stop = true;
|
||||
_clientThread->join();
|
||||
if(_clientThread) {
|
||||
_clientThread->join();
|
||||
}
|
||||
MessageManager::UnregisterNotificationListener(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ unique_ptr<GameServer> GameServer::Instance;
|
|||
|
||||
GameServer::GameServer(uint16_t listenPort, string hostPlayerName)
|
||||
{
|
||||
_stop = false;
|
||||
_port = listenPort;
|
||||
_hostPlayerName = hostPlayerName;
|
||||
_hostControllerPort = 0;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
class SaveStateMessage : public NetMessage
|
||||
{
|
||||
private:
|
||||
uint8_t* _stateData;
|
||||
uint32_t _dataSize;
|
||||
uint8_t* _stateData = nullptr;
|
||||
uint32_t _dataSize = 0;
|
||||
|
||||
CodeInfo* _cheats;
|
||||
uint32_t _cheatArraySize;
|
||||
uint32_t _cheatArraySize = 0;
|
||||
|
||||
protected:
|
||||
virtual void ProtectedStreamState()
|
||||
|
|
|
@ -1,34 +1,64 @@
|
|||
#include "stdafx.h"
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
#include "UPnPPortMapper.h"
|
||||
#include "Socket.h"
|
||||
using namespace std;
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma comment(lib,"ws2_32.lib") //Winsock Library
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <Windows.h>
|
||||
#pragma comment(lib,"ws2_32.lib") //Winsock Library
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define INVALID_SOCKET (uintptr_t)-1
|
||||
#define SOCKET_ERROR -1
|
||||
#define WSAGetLastError() errno
|
||||
#define SOCKADDR_IN sockaddr_in
|
||||
#define SOCKADDR sockaddr
|
||||
#define TIMEVAL timeval
|
||||
#define SD_SEND SHUT_WR
|
||||
#define closesocket close
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define ioctlsocket ioctl
|
||||
#endif
|
||||
|
||||
#define BUFFER_SIZE 200000
|
||||
|
||||
Socket::Socket()
|
||||
{
|
||||
WSADATA wsaDat;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0) {
|
||||
std::cout << "WSAStartup failed." << std::endl;
|
||||
_sendBuffer = new char[BUFFER_SIZE];
|
||||
_bufferPosition = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaDat;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0) {
|
||||
std::cout << "WSAStartup failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
return;
|
||||
}
|
||||
_cleanupWSA = true;
|
||||
#endif
|
||||
|
||||
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(_socket == INVALID_SOCKET) {
|
||||
std::cout << "Socket creation failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
_cleanupWSA = true;
|
||||
|
||||
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(_socket == INVALID_SOCKET) {
|
||||
std::cout << "Socket creation failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
SetSocketOptions();
|
||||
}
|
||||
SetSocketOptions();
|
||||
}
|
||||
|
||||
_sendBuffer = new char[200000];
|
||||
_bufferPosition = 0;
|
||||
}
|
||||
|
||||
Socket::Socket(uintptr_t socket)
|
||||
|
@ -41,7 +71,7 @@ Socket::Socket(uintptr_t socket)
|
|||
SetSocketOptions();
|
||||
}
|
||||
|
||||
_sendBuffer = new char[200000];
|
||||
_sendBuffer = new char[BUFFER_SIZE];
|
||||
_bufferPosition = 0;
|
||||
}
|
||||
|
||||
|
@ -54,9 +84,12 @@ Socket::~Socket()
|
|||
if(_socket != INVALID_SOCKET) {
|
||||
Close();
|
||||
}
|
||||
if(_cleanupWSA) {
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if(_cleanupWSA) {
|
||||
WSACleanup();
|
||||
}
|
||||
#endif
|
||||
|
||||
delete[] _sendBuffer;
|
||||
}
|
||||
|
@ -74,7 +107,7 @@ void Socket::SetSocketOptions()
|
|||
|
||||
//Disable nagle's algorithm to improve latency
|
||||
u_long value = 1;
|
||||
setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(value));
|
||||
setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(value));
|
||||
}
|
||||
|
||||
void Socket::SetConnectionErrorFlag()
|
||||
|
@ -135,8 +168,13 @@ bool Socket::Connect(const char* hostname, uint16_t port)
|
|||
connect(_socket, addrInfo->ai_addr, (int)addrInfo->ai_addrlen);
|
||||
|
||||
fd_set writeSockets;
|
||||
writeSockets.fd_count = 1;
|
||||
writeSockets.fd_array[0] = _socket;
|
||||
#ifdef _WIN32
|
||||
writeSockets.fd_count = 1;
|
||||
writeSockets.fd_array[0] = _socket;
|
||||
#else
|
||||
FD_ZERO(&writeSockets);
|
||||
FD_SET(_socket, &writeSockets);
|
||||
#endif
|
||||
|
||||
//Timeout after 3 seconds
|
||||
TIMEVAL timeout;
|
||||
|
@ -144,12 +182,17 @@ bool Socket::Connect(const char* hostname, uint16_t port)
|
|||
timeout.tv_usec = 0;
|
||||
|
||||
// check if the socket is ready
|
||||
if(select(0, nullptr, &writeSockets, nullptr, &timeout)) {
|
||||
int returnVal = select(_socket+1, nullptr, &writeSockets, nullptr, &timeout);
|
||||
if(returnVal > 0) {
|
||||
result = true;
|
||||
} else {
|
||||
//Could not connect
|
||||
if(returnVal == SOCKET_ERROR) {
|
||||
int nError = WSAGetLastError();
|
||||
//std::cout << "select failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl;
|
||||
}
|
||||
SetConnectionErrorFlag();
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(addrInfo);
|
||||
}
|
||||
|
@ -167,10 +210,15 @@ void Socket::Listen(int backlog)
|
|||
|
||||
shared_ptr<Socket> Socket::Accept()
|
||||
{
|
||||
SOCKET socket = accept(_socket, nullptr, nullptr);
|
||||
uintptr_t socket = accept(_socket, nullptr, nullptr);
|
||||
return shared_ptr<Socket>(new Socket(socket));
|
||||
}
|
||||
|
||||
bool WouldBlock(int nError)
|
||||
{
|
||||
return nError == WSAEWOULDBLOCK || nError == EAGAIN;
|
||||
}
|
||||
|
||||
int Socket::Send(char *buf, int len, int flags)
|
||||
{
|
||||
int retryCount = 15;
|
||||
|
@ -178,39 +226,43 @@ int Socket::Send(char *buf, int len, int flags)
|
|||
int returnVal;
|
||||
do {
|
||||
//Loop until everything has been sent (shouldn't loop at all in the vast majority of cases)
|
||||
if(nError == WSAEWOULDBLOCK) {
|
||||
retryCount--;
|
||||
if(retryCount == 0) {
|
||||
//Connection seems dead, close it.
|
||||
std::cout << "Unable to send data, closing socket." << std::endl;
|
||||
Close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
returnVal = send(_socket, buf, len, flags);
|
||||
|
||||
nError = WSAGetLastError();
|
||||
if(nError != 0) {
|
||||
if(nError != WSAEWOULDBLOCK) {
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
if(returnVal > 0) {
|
||||
//Sent partial data, adjust pointer & length
|
||||
buf += returnVal;
|
||||
len -= returnVal;
|
||||
if(returnVal > 0) {
|
||||
//Sent partial data, adjust pointer & length
|
||||
buf += returnVal;
|
||||
len -= returnVal;
|
||||
} else if(returnVal == SOCKET_ERROR) {
|
||||
nError = WSAGetLastError();
|
||||
if(nError != 0) {
|
||||
if(!WouldBlock(nError)) {
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
retryCount--;
|
||||
if(retryCount == 0) {
|
||||
//Connection seems dead, close it.
|
||||
std::cout << "Unable to send data, closing socket." << std::endl;
|
||||
Close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(10));
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(nError == WSAEWOULDBLOCK);
|
||||
} while(WouldBlock(nError) && len > 0);
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
void Socket::BufferedSend(char *buf, int len)
|
||||
{
|
||||
memcpy(_sendBuffer+_bufferPosition, buf, len);
|
||||
_bufferPosition += len;
|
||||
if(_bufferPosition+len < BUFFER_SIZE) {
|
||||
memcpy(_sendBuffer+_bufferPosition, buf, len);
|
||||
_bufferPosition += len;
|
||||
} else {
|
||||
std::cout << "prevented buffer overflow";
|
||||
}
|
||||
}
|
||||
|
||||
void Socket::SendBuffer()
|
||||
|
@ -222,13 +274,14 @@ void Socket::SendBuffer()
|
|||
int Socket::Recv(char *buf, int len, int flags)
|
||||
{
|
||||
int returnVal = recv(_socket, buf, len, flags);
|
||||
|
||||
int nError = WSAGetLastError();
|
||||
if(nError != WSAEWOULDBLOCK && nError != 0) {
|
||||
SetConnectionErrorFlag();
|
||||
}
|
||||
|
||||
if(returnVal == 0) {
|
||||
|
||||
if(returnVal == SOCKET_ERROR) {
|
||||
int nError = WSAGetLastError();
|
||||
if(nError && !WouldBlock(nError)) {
|
||||
std::cout << "recv failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
}
|
||||
} else if(returnVal == 0) {
|
||||
//Socket closed
|
||||
std::cout << "Socket closed by peer." << std::endl;
|
||||
Close();
|
||||
|
@ -236,83 +289,3 @@ int Socket::Recv(char *buf, int len, int flags)
|
|||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Socket::Socket()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Socket::Socket(uintptr_t socket)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Socket::SetSocketOptions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Socket::SetConnectionErrorFlag()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Socket::Close()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Socket::ConnectionError()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Socket::Bind(uint16_t port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Socket::Connect(const char* hostname, uint16_t port)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Socket::Listen(int backlog)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
shared_ptr<Socket> Socket::Accept()
|
||||
{
|
||||
return shared_ptr<Socket>(new Socket());
|
||||
}
|
||||
|
||||
int Socket::Send(char *buf, int len, int flags)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
void Socket::BufferedSend(char *buf, int len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Socket::SendBuffer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int Socket::Recv(char *buf, int len, int flags)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue