Skip to content

Commit

Permalink
scan for open tcp ports for js api
Browse files Browse the repository at this point in the history
  • Loading branch information
p2r3 committed Oct 22, 2024
1 parent 0058c06 commit b7bb14c
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 16 deletions.
4 changes: 2 additions & 2 deletions globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ const std::filesystem::path REPO_PATH = APP_DIR / "repositories.txt";

// Holds the current package installation state
int SPPLICE_INSTALL_STATE = 0; // 0 - idle; 1 - installing; 2 - installed
// TCP communication port between Portal 2 and Spplice
const int SPPLICE_NETCON_PORT = 22333;
// TCP communication port between Portal 2 and Spplice (set during runtime)
int SPPLICE_NETCON_PORT = -1;
2 changes: 1 addition & 1 deletion globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ extern bool CACHE_ENABLE;
extern const std::filesystem::path APP_DIR;
extern const std::filesystem::path REPO_PATH;
extern int SPPLICE_INSTALL_STATE;
extern const int SPPLICE_NETCON_PORT;
extern int SPPLICE_NETCON_PORT;

#endif
48 changes: 38 additions & 10 deletions tools/install.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "../globals.h" // Project globals
#include "curl.h" // ToolsCURL
#include "netcon.h" // ToolsNetCon
#include "qt.h" // ToolsQT
#include "js.h" // ToolsJS

Expand Down Expand Up @@ -201,8 +202,12 @@ bool startPortal2 (const std::vector<std::string> extraArgs) {
args.push_back("-applaunch");
args.push_back("620");
args.push_back("-tempcontent");
args.push_back("-netconport");
args.push_back(std::to_string(SPPLICE_NETCON_PORT).c_str());

// If a valid port has been established, enable TCP console server
if (SPPLICE_NETCON_PORT != -1) {
args.push_back("-netconport");
args.push_back(std::to_string(SPPLICE_NETCON_PORT).c_str());
}

// Append any additional package-specific arguments
for (const std::string &arg : extraArgs) {
Expand All @@ -216,7 +221,9 @@ bool startPortal2 (const std::vector<std::string> extraArgs) {
std::cerr << "Failed to call Steam binary from fork." << std::endl;

// If the above failed, revert to using the Steam browser protocol
std::string command = "xdg-open steam://run/620//-tempcontent -netconport " + std::to_string(SPPLICE_NETCON_PORT);
std::string command = "xdg-open steam://run/620//-tempcontent";
if (SPPLICE_NETCON_PORT != -1) command += " -netconport " + std::to_string(SPPLICE_NETCON_PORT);

for (const std::string &arg : extraArgs) {
command += " " + arg;
}
Expand Down Expand Up @@ -251,7 +258,10 @@ bool startPortal2 (const std::vector<std::string> extraArgs) {
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; // Hide the window for the detached process

std::wstring args = L"-applaunch 620 -tempcontent -netconport " + std::to_wstring(SPPLICE_NETCON_PORT);
std::wstring args = L"-applaunch 620 -tempcontent";
if (SPPLICE_NETCON_PORT != -1) {
args += L" -netconport " + std::to_wstring(SPPLICE_NETCON_PORT);
}

// Append any additional package-specific arguments
for (const std::string &arg : extraArgs) {
Expand Down Expand Up @@ -499,6 +509,26 @@ std::pair<bool, std::wstring> ToolsInstall::installPackageFile (const std::files
std::filesystem::create_directories(tmpPackageDirectory / "maps");
std::filesystem::create_directories(tmpPackageDirectory / "maps" / "soundcache");

// Find the JS API entry point
const std::filesystem::path jsEntryPoint = tmpPackageDirectory / "main.js";
bool jsEntryPointExists = std::filesystem::exists(jsEntryPoint);

// Disable the TCP console server by default
SPPLICE_NETCON_PORT = -1;

// If the JS API is in use, enable the TCP console server
if (jsEntryPointExists) {
// Find an open TCP port
SPPLICE_NETCON_PORT = ToolsNetCon::findOpenPort(1024, 49151);
if (SPPLICE_NETCON_PORT == -1) {
#ifndef TARGET_WINDOWS
return std::pair<bool, std::string> (false, "Failed to find an open port for the JS API.");
#else
return std::pair<bool, std::wstring> (false, L"Failed to find an open port for the JS API.");
#endif
}
}

// Start Portal 2
if (!startPortal2(args)) {
std::filesystem::remove_all(tmpPackageDirectory);
Expand Down Expand Up @@ -565,13 +595,11 @@ std::pair<bool, std::wstring> ToolsInstall::installPackageFile (const std::files
std::filesystem::copy_file(soundcacheSourcePath, soundcacheDestPath);
}

// Run the JavaScript entrypoint (if one exists) on a detached thread
const std::filesystem::path jsEntryPoint = tmpPackageDirectory / "main.js";
if (std::filesystem::exists(jsEntryPoint)) {
std::thread jsThread([jsEntryPoint]() {
// Run the JS API entrypoint (if one exists) on a detached thread
if (jsEntryPointExists) {
std::thread ([jsEntryPoint]() {
ToolsJS::runFile(jsEntryPoint);
});
jsThread.detach();
}).detach();
}

// Report install success to the UI
Expand Down
63 changes: 60 additions & 3 deletions tools/netcon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
// Definitions for this source file
#include "netcon.h"

// Counts the amount of open netcon sockets for setup and cleanup
// I have absolutely no idea why you'd ever need more than one, but oh well...
#ifdef TARGET_WINDOWS
// Counts the amount of open netcon sockets for Winsock setup and cleanup
int openSockets = 0;
#endif

// Closes the given socket
void ToolsNetCon::disconnect (int sockfd)
Expand All @@ -33,6 +34,62 @@ void ToolsNetCon::disconnect (int sockfd)
}
#endif

// Finds an open TCP port in the given range (inclusive)
int ToolsNetCon::findOpenPort (const int start, const int end) {

#ifdef TARGET_WINDOWS
// If no sockets are open, set up Winsock
if (++openSockets == 1) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed." << std::endl;
return -1;
}
}
#endif

for (int port = start; port <= end; port ++) {

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
std::cerr << "Socket creation failed on port " << port << " when scanning for open ports." << std::endl;
break;
}

struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);

int result = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if (result == 0) {
// Successfully bound to the port, close the socket and return the port
ToolsNetCon::disconnect(sockfd);
return port;
}

#ifdef TARGET_WINDOWS
// Increment openSockets to prevent Winsock from being cleaned up
openSockets ++;
#endif

// Port is in use, try the next one
ToolsNetCon::disconnect(sockfd);

}

#ifdef TARGET_WINDOWS
// Reset openSockets and clean up Winsock manually
openSockets --;
WSACleanup();
#endif

// No open port found in the range
return -1;

}

// Attempts to connect to the game's TCP console on SPPLICE_NETCON_PORT
int ToolsNetCon::attemptConnection () {

Expand Down Expand Up @@ -70,7 +127,7 @@ int ToolsNetCon::attemptConnection () {

}

// Sends a command to the TCP consoleserver on the given socket
// Sends a command to the TCP console server on the given socket
bool ToolsNetCon::sendCommand (int sockfd, std::string command) {

// Commands are only processed upon line termination
Expand Down
1 change: 1 addition & 0 deletions tools/netcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class ToolsNetCon {
public:
static int attemptConnection ();
static void disconnect (int sockfd);
static int findOpenPort (const int start, const int end);
static bool sendCommand (int sockfd, std::string command);
static std::string readConsole (int sockfd, size_t size);
};
Expand Down

0 comments on commit b7bb14c

Please sign in to comment.