Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
bin
.vscode
*.txt
*.cfg
digitalocean.py
__pycache__
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

31 changes: 19 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Build options #
#################

OSX_INTEL ?= 0
OSX_ARM ?= 0
OSX_BUILD ?= 0
LOGGING ?= 0

Expand Down Expand Up @@ -35,20 +37,25 @@ ifeq ($(OS),Windows_NT)
LIB_DIR := lib/win32
CXXFLAGS += -Wno-error=format
endif
else ifeq ($(OSX_BUILD),1)
# macOS defines sprintf as unsafe, and refuses to compile further, so add this flag to ignore it
CXXFLAGS += -DOSX_BUILD=1 -Wno-error=deprecated-declarations
ifeq ($(shell arch),arm64)
LIB_DIR := lib/mac-arm
else
ifeq ($(OSX_BUILD),1)
ifeq ($(OSX_ARM),1)
LIB_DIR := ./lib/mac_arm
CXXFLAGS += -arch arm64
LDFLAGS += -arch arm64
else
LIB_DIR := ./lib/mac_intel
CXXFLAGS += -arch x86_64
LDFLAGS += -arch x86_64
endif
CXXFLAGS += -DOSX_BUILD=1
DYNLIB_NAME := libcoopnet.dylib
LIBS := -l juice.1.6.2
LDFLAGS += -rpath . -dynamiclib -install_name @rpath/$(DYNLIB_NAME)
else
LIB_DIR := lib/mac-intel
CXXFLAGS += -Wno-nonnull-compare
LIB_DIR := lib/linux
endif
DYNLIB_NAME := libcoopnet.dylib
LIBS := -ljuice
LDFLAGS += -rpath . -dynamiclib -install_name @rpath/$(DYNLIB_NAME)
else
CXXFLAGS += -Wno-nonnull-compare
LIB_DIR := lib/linux
endif

ifeq ($(LOGGING),1)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Signaling server / lobby manager for P2P connections
131 changes: 83 additions & 48 deletions client/cmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@

std::thread sThreadRecv;

static uint64_t sLastLobbyId = 0;

static void sOnDisconnected(bool aIntentional) { exit(0); }
static void sOnReceive(uint64_t aFromUserId, const uint8_t* aData, uint64_t aSize) {
std::string msg((const char*)aData, (size_t)aSize);
LOG_INFO("Received from %" PRIu64 ": %s", aFromUserId, msg.c_str());
}

static void sOnLobbyListGot(uint64_t aLobbyId, uint64_t aOwnerId, uint16_t aConnections, uint16_t aMaxConnections, const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, const char* aDescription) {
sLastLobbyId = aLobbyId;
}

static void sReceive(void) {
while (coopnet_is_connected()) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
coopnet_update();
}
}
Expand All @@ -26,9 +36,61 @@ static uint64_t stru64(const char* s) {
return strtoull(s, &end, 10);
}

static void process_command(const std::vector<std::string>& words) {
if (words[0] == "create" || words[0] == "c") {
if (words.size() == 2) {
coopnet_lobby_create("sm64coopdx2", "beta 34", "Host's Name", "Super Mario 64", 16, words[1].c_str(), "description!");
} else if (words.size() == 6) {
coopnet_lobby_create(words[1].c_str(), words[2].c_str(), words[3].c_str(), words[4].c_str(), (uint16_t)atoi(words[5].c_str()), "", "description!");
} else if (words.size() == 7) {
coopnet_lobby_create(words[1].c_str(), words[2].c_str(), words[3].c_str(), words[4].c_str(), (uint16_t)atoi(words[5].c_str()), words[6].c_str(), "description!");
} else {
coopnet_lobby_create("sm64coopdx2", "beta 34", "Host's Name", "Super Mario 64", 16, "", "description!");
}
} else if (words[0] == "join" || words[0] == "j") {
if (words.size() == 1 && sLastLobbyId != 0) {
coopnet_lobby_join(sLastLobbyId, "");
} else if (words.size() == 2) {
coopnet_lobby_join((uint64_t)stru64(words[1].c_str()), "");
} else if (words.size() == 3) {
coopnet_lobby_join((uint64_t)stru64(words[1].c_str()), words[2].c_str());
}
} else if (words[0] == "leave" || words[0] == "l") {
if (words.size() == 2) {
coopnet_lobby_leave((uint64_t)stru64(words[1].c_str()));
}
} else if (words[0] == "list" || words[0] == "ls") {
if (words.size() == 3) {
coopnet_lobby_list_get(words[1].c_str(), words[2].c_str());
} else if (words.size() == 2) {
coopnet_lobby_list_get("sm64coopdx2", words[1].c_str());
} else {
coopnet_lobby_list_get("sm64coopdx2", "");
}
} else if (words[0] == "send" || words[0] == "s") {
if (words.size() == 2) {
coopnet_send((const uint8_t*)words[1].c_str(), words[1].length() + 1);
}
} else if (words[0] == "connect") {
gCoopNetCallbacks.OnDisconnected = sOnDisconnected;
coopnet_begin(HOST, PORT, "example", 0);
sThreadRecv = std::thread(sReceive);
sThreadRecv.detach();
} else if (words[0] == "disconnect") {
gCoopNetCallbacks.OnDisconnected = nullptr;
coopnet_shutdown();
} else if (words[0] == "unpeer") {
if (words.size() == 2) {
coopnet_unpeer((uint64_t)stru64(words[1].c_str()));
}
}
}

int main(int argc, char const *argv[]) {
// setup callbacks
gCoopNetCallbacks.OnDisconnected = sOnDisconnected;
gCoopNetCallbacks.OnReceive = sOnReceive;
gCoopNetCallbacks.OnLobbyListGot = sOnLobbyListGot;

if (coopnet_begin(HOST, PORT, "example", 999) != COOPNET_OK) {
LOG_ERROR("Failed to begin client");
Expand All @@ -38,6 +100,23 @@ int main(int argc, char const *argv[]) {
sThreadRecv = std::thread(sReceive);
sThreadRecv.detach();

std::vector<std::string> words;
words.push_back("list");
process_command(words);
words.clear();

if (argc > 1) {
for(int i = 1; i < argc; ++i) {
words.push_back(argv[i]);
}
if (words[0][0] == 'j') {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
process_command(words);
}

//coopnet_lobby_create("sm64coopdx2", "beta 34", "Host's Name", "Super Mario 64", 16, "", "description!");

while (true) {
std::string input;
std::getline(std::cin, input);
Expand All @@ -50,56 +129,12 @@ int main(int argc, char const *argv[]) {
words.push_back(word);
}

if (words.size() == 0) {
if (words.empty()) {
continue;
}

if (words[0] == "create" || words[0] == "c") {
if (words.size() == 2) {
coopnet_lobby_create("sm64ex-coop", "beta 34", "Host's Name", "Super Mario 64", 16, words[1].c_str(), "description!");
} else if (words.size() == 6) {
coopnet_lobby_create(words[1].c_str(), words[2].c_str(), words[3].c_str(), words[4].c_str(), (uint16_t)atoi(words[5].c_str()), "", "description!");
} else if (words.size() == 7) {
coopnet_lobby_create(words[1].c_str(), words[2].c_str(), words[3].c_str(), words[4].c_str(), (uint16_t)atoi(words[5].c_str()), words[6].c_str(), "description!");
} else {
coopnet_lobby_create("sm64ex-coop", "beta 34", "Host's Name", "Super Mario 64", 16, "", "description!");
}
} else if (words[0] == "join" || words[0] == "j") {
if (words.size() == 2) {
coopnet_lobby_join((uint64_t)stru64(words[1].c_str()), "");
} else if (words.size() == 3) {
coopnet_lobby_join((uint64_t)stru64(words[1].c_str()), words[2].c_str());
}
} else if (words[0] == "leave" || words[0] == "l") {
if (words.size() == 2) {
coopnet_lobby_leave((uint64_t)stru64(words[1].c_str()));
}
} else if (words[0] == "list" || words[0] == "ls") {
if (words.size() == 3) {
coopnet_lobby_list_get(words[1].c_str(), words[2].c_str());
} else if (words.size() == 2) {
coopnet_lobby_list_get("sm64ex-coop", words[1].c_str());
} else {
coopnet_lobby_list_get("sm64ex-coop", "");
}
} else if (words[0] == "send" || words[0] == "s") {
if (words.size() == 2) {
coopnet_send((const uint8_t*)words[1].c_str(), words[1].length() + 1);
}
} else if (words[0] == "connect") {
gCoopNetCallbacks.OnDisconnected = sOnDisconnected;
coopnet_begin(HOST, PORT, "example", 0);
sThreadRecv = std::thread(sReceive);
sThreadRecv.detach();
} else if (words[0] == "disconnect") {
gCoopNetCallbacks.OnDisconnected = nullptr;
coopnet_shutdown();
} else if (words[0] == "unpeer") {
if (words.size() == 2) {
coopnet_unpeer((uint64_t)stru64(words[1].c_str()));
}
}
process_command(words);

}
return 0;
}
}
2 changes: 1 addition & 1 deletion common/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ bool Client::Begin(std::string aHost, uint32_t aPort, std::string aName, uint64_
if (rc == EINPROGRESS || rc == 0) {
// Setup the timeout duration
struct timeval timeout;
timeout.tv_sec = 3;
timeout.tv_sec = 6;
timeout.tv_usec = 0;

// Setup the file descriptors to watch for write readiness
Expand Down
50 changes: 48 additions & 2 deletions common/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
#include "libcoopnet.h"
#include "logging.hpp"
#include "mpacket.hpp"

#define CONNECTION_KEEP_ALIVE_SECS (60 * 3)
#include "peer.hpp"
#include "server.hpp"

Connection::Connection(uint64_t id) {
mId = id;
Expand Down Expand Up @@ -44,6 +44,7 @@ void Connection::Begin(uint64_t (*aDestIdFunction)(uint64_t aInput)) {
std::chrono::system_clock::time_point nowTp = std::chrono::system_clock::now();
uint64_t now = std::chrono::system_clock::to_time_t(nowTp);
mLastSendTime = now;
mLastReceiveTime = now;

LOG_INFO("[%" PRIu64 "] Connection accepted: %s :: %" PRIu64 "", mId, mAddressStr.c_str(), mDestinationId);
}
Expand Down Expand Up @@ -71,6 +72,25 @@ void Connection::Update() {
if ((mLastSendTime + CONNECTION_KEEP_ALIVE_SECS) < now) {
MPacketKeepAlive({ 0 }).Send(*this);
}

// check up on peers
if (mActive && gServer) {
if (!mLobby) {
mPeerTimeouts.clear();
} else {
for (auto it = mPeerTimeouts.begin(); it != mPeerTimeouts.end();) {
uint64_t peerId = it->first;
uint64_t timeout = it->second;
if (now <= timeout) { ++it; continue; }
it = mPeerTimeouts.erase(it);

Connection* other = gServer->ConnectionGet(peerId);
if (!other || !other->mActive) { continue; }
if (!mLobby || mLobby != other->mLobby) { continue; }
gServer->ReputationIncrease(mDestinationId);
}
}
}
}

void Connection::Receive() {
Expand Down Expand Up @@ -124,6 +144,32 @@ void Connection::Receive() {
}
printf("\n");*/

if (ret > 0) {
std::chrono::system_clock::time_point nowTp = std::chrono::system_clock::now();
uint64_t now = std::chrono::system_clock::to_time_t(nowTp);
mLastReceiveTime = now;
}

mDataSize += ret;
MPacket::Read(this, mData, &mDataSize, MPACKET_MAX_SIZE);
}

void Connection::PeerBegin(uint64_t aPeerId) {
if (mPeerTimeouts.count(aPeerId) > 0) { return; }
if (aPeerId == mDestinationId) { return; }
std::chrono::system_clock::time_point nowTp = std::chrono::system_clock::now();
uint64_t now = std::chrono::system_clock::to_time_t(nowTp);
mPeerTimeouts[aPeerId] = now + PEER_TIMEOUT * 2;
}

void Connection::PeerFail(uint64_t aPeerId) {
if (mPeerTimeouts.count(aPeerId) > 0) {
mPeerTimeouts.erase(aPeerId);
}
if (gServer && mActive) {
Connection* other = gServer->ConnectionGet(aPeerId);
if (!other || !other->mActive) { return; }
if (!mLobby || mLobby != other->mLobby) { return; }
gServer->ReputationDecrease(mDestinationId);
}
}
10 changes: 10 additions & 0 deletions common/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
#include "socket.hpp"
#include "mpacket.hpp"
#include "lobby.hpp"
#include <map>

class Lobby;

#define CONNECTION_KEEP_ALIVE_SECS (60 * 3)
#define CONNECTION_DEAD_SECS (60 * 4)

class Connection {
private:
uint8_t mData[MPACKET_MAX_SIZE] = { 0 };
int64_t mDataSize = 0;
std::map<uint64_t, uint64_t> mPeerTimeouts;

public:
bool mActive = false;
Expand All @@ -24,12 +29,17 @@ class Connection {
Lobby* mLobby = nullptr;
uint32_t mPriority = 0;
uint64_t mLastSendTime = 0;
uint64_t mLastReceiveTime = 0;
std::string mAddressStr;
uint64_t mHash;

Connection(uint64_t id);
~Connection();
void Begin(uint64_t (*aDestIdFunction)(uint64_t aInput));
void Disconnect(bool aIntentional);
void Update();
void Receive();

void PeerBegin(uint64_t aPeerId);
void PeerFail(uint64_t aPeerId);
};
2 changes: 1 addition & 1 deletion common/libcoopnet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ CoopNetRc coopnet_begin(const char* aHost, uint32_t aPort, const char* aName, ui

gClient = new Client();
bool ret = gClient->Begin(aHost, aPort, aName, aDestId);

if (!ret) {
coopnet_shutdown();
coopnet_update();
Expand Down
4 changes: 3 additions & 1 deletion common/libcoopnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <cstdint>
extern "C" {
class Connection;
class Lobby;
#endif

#include <stdbool.h>
Expand Down Expand Up @@ -43,7 +44,8 @@ typedef struct {
uint64_t (*DestIdFunction)(uint64_t aInput);
#if defined(__cplusplus)
bool (*ConnectionIsAllowed)(Connection*, bool);
void (*OnReceiveInfoBits)(Connection* aConnection, uint64_t aDestId, uint64_t aInfoBits, const char* aName);
bool (*LobbyConnectionIsAllowed)(Connection*, Lobby*);
void (*OnReceiveInfoBits)(Connection* aConnection, uint64_t aDestId, uint64_t aInfoBits, uint64_t aHash, const char* aName);
#endif
} CoopNetCallbacks;

Expand Down
Loading