Linux: Implemented sockets/netplay + fixed uninitialized variable crash

This commit is contained in:
Souryo 2016-12-17 18:46:46 -05:00
parent 2c8c1be648
commit a6579fbfdb
4 changed files with 121 additions and 143 deletions

View file

@ -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);
}

View file

@ -12,6 +12,7 @@ unique_ptr<GameServer> GameServer::Instance;
GameServer::GameServer(uint16_t listenPort, string hostPlayerName)
{
_stop = false;
_port = listenPort;
_hostPlayerName = hostPlayerName;
_hostControllerPort = 0;

View file

@ -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()

View file

@ -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