Awoo-Installer/source/netInstall.cpp

243 lines
7.6 KiB
C++
Raw Normal View History

#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sstream>
#include <curl/curl.h>
#include <switch.h>
#include "util/network_util.hpp"
#include "install/install_nsp_remote.hpp"
#include "install/http_nsp.hpp"
#include "install/install.hpp"
#include "error.hpp"
#include "netInstall.hpp"
#include "ui/MainApplication.hpp"
#include "netInstall.hpp"
const unsigned int MAX_URL_SIZE = 1024;
const unsigned int MAX_URLS = 256;
const int REMOTE_INSTALL_PORT = 2000;
static int m_serverSocket = 0;
static int m_clientSocket = 0;
std::vector<std::string> m_urls;
FsStorageId m_destStorageId = FsStorageId_SdCard;
namespace inst::ui {
extern MainApplication *mainApp;
void setInfoText(std::string ourText){
mainApp->netinstPage->pageInfoText->SetText(ourText);
mainApp->CallForRender();
}
void loadMainMenu(){
mainApp->LoadLayout(mainApp->mainPage);
}
}
2019-10-18 19:01:51 +00:00
namespace netInstStuff{
2019-10-18 19:01:51 +00:00
void InitializeServerSocket() try
{
2019-10-18 19:01:51 +00:00
// Create a socket
m_serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
2019-10-18 19:01:51 +00:00
if (m_serverSocket < -1)
{
inst::ui::setInfoText("Failed to create a server socket.");
2019-10-18 19:01:51 +00:00
THROW_FORMAT("Failed to create a server socket. Error code: %u\n", errno);
}
2019-10-18 19:01:51 +00:00
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(REMOTE_INSTALL_PORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
2019-10-18 19:01:51 +00:00
if (bind(m_serverSocket, (struct sockaddr*) &server, sizeof(server)) < 0)
{
inst::ui::setInfoText("Failed to bind server socket.");
2019-10-18 19:01:51 +00:00
THROW_FORMAT("Failed to bind server socket. Error code: %u\n", errno);
}
// Set as non-blocking
fcntl(m_serverSocket, F_SETFL, fcntl(m_serverSocket, F_GETFL, 0) | O_NONBLOCK);
2019-10-18 19:01:51 +00:00
if (listen(m_serverSocket, 5) < 0)
{
inst::ui::setInfoText("Failed to listen on server socket.");
2019-10-18 19:01:51 +00:00
THROW_FORMAT("Failed to listen on server socket. Error code: %u\n", errno);
}
}
catch (std::exception& e)
{
inst::ui::setInfoText("Failed to initialize server socket!");
2019-10-18 19:01:51 +00:00
printf("Failed to initialize server socket!\n");
fprintf(stdout, "%s", e.what());
if (m_serverSocket != 0)
{
close(m_serverSocket);
m_serverSocket = 0;
}
}
2019-10-18 19:01:51 +00:00
void OnUnwound()
{
2019-10-18 19:01:51 +00:00
printf("unwinding view\n");
if (m_clientSocket != 0)
{
close(m_clientSocket);
m_clientSocket = 0;
}
curl_global_cleanup();
}
2019-10-18 19:01:51 +00:00
bool OnDestinationSelected(int ourStorage)
{
2019-10-18 19:01:51 +00:00
if (ourStorage == 0) m_destStorageId = FsStorageId_NandUser;
else m_destStorageId = FsStorageId_SdCard;
for (auto& url : m_urls)
{
tin::install::nsp::HTTPNSP httpNSP(url);
printf("%s %s\n", "NSP_INSTALL_FROM", url.c_str());
// second var is ignoring required version
tin::install::nsp::RemoteNSPInstall install(m_destStorageId, true, &httpNSP);
printf("%s\n", "NSP_INSTALL_PREPARING");
install.Prepare();
printf("Pre Install Records: \n");
// These crash sometimes, if they're not needed then don't worry about em
//install.DebugPrintInstallData();
inst::ui::setInfoText("Installing NSP for real right now. Figure out how to get percentages");
2019-10-18 19:01:51 +00:00
install.Begin();
printf("Post Install Records: \n");
//install.DebugPrintInstallData();
2019-10-18 19:01:51 +00:00
printf("\n");
}
printf("%s\n", "NSP_INSTALL_NETWORK_SENDING_ACK");
// Send 1 byte ack to close the server
u8 ack = 0;
tin::network::WaitSendNetworkData(m_clientSocket, &ack, sizeof(u8));
printf("Clearing url vector\n");
2019-10-18 19:01:51 +00:00
m_urls.clear();
return true;
}
2019-10-18 19:01:51 +00:00
bool OnNSPSelected(std::string ourUrl, int ourStorage)
{
2019-10-18 19:01:51 +00:00
m_urls.push_back(ourUrl);
return OnDestinationSelected(ourStorage);
}
2019-10-18 19:01:51 +00:00
std::vector<std::string> OnSelected()
{
2019-10-18 19:01:51 +00:00
OnUnwound();
try
{
2019-10-18 19:01:51 +00:00
ASSERT_OK(curl_global_init(CURL_GLOBAL_ALL), "Curl failed to initialized");
2019-10-18 19:01:51 +00:00
// Initialize the server socket if it hasn't already been
if (m_serverSocket == 0)
{
2019-10-18 19:01:51 +00:00
InitializeServerSocket();
2019-10-18 19:01:51 +00:00
if (m_serverSocket <= 0)
{
inst::ui::setInfoText("Server socket failed to initialize.");
2019-10-18 19:01:51 +00:00
THROW_FORMAT("Server socket failed to initialize.\n");
}
}
2019-10-18 19:01:51 +00:00
struct in_addr addr = {(in_addr_t) gethostid()};
std::string ourIPAddr(inet_ntoa(addr));
inst::ui::setInfoText(ourIPAddr + " - Waiting for connect... Press B to cancel.");
2019-10-18 19:01:51 +00:00
printf("%s %s\n", "Switch IP is ", inet_ntoa(addr));
printf("%s\n", "Waiting for network");
printf("%s\n", "B to cancel");
std::vector<std::string> urls;
2019-10-18 19:01:51 +00:00
while (true)
{
2019-10-18 19:01:51 +00:00
// Break on input pressed
hidScanInput();
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
2019-10-18 19:01:51 +00:00
//consoleUpdate(NULL);
2019-10-18 19:01:51 +00:00
if (kDown & KEY_B)
{
inst::ui::loadMainMenu();
2019-10-18 19:01:51 +00:00
break;
}
2019-10-18 19:01:51 +00:00
struct sockaddr_in client;
socklen_t clientLen = sizeof(client);
2019-10-18 19:01:51 +00:00
m_clientSocket = accept(m_serverSocket, (struct sockaddr*)&client, &clientLen);
2019-10-18 19:01:51 +00:00
if (m_clientSocket >= 0)
{
2019-10-18 19:01:51 +00:00
printf("%s\n", "NSP_INSTALL_NETWORK_ACCEPT");
u32 size = 0;
tin::network::WaitReceiveNetworkData(m_clientSocket, &size, sizeof(u32));
size = ntohl(size);
printf("Received url buf size: 0x%x\n", size);
2019-10-18 19:01:51 +00:00
if (size > MAX_URL_SIZE * MAX_URLS)
{
inst::ui::setInfoText("URL size is too large!");
2019-10-18 19:01:51 +00:00
THROW_FORMAT("URL size %x is too large!\n", size);
}
2019-10-18 19:01:51 +00:00
// Make sure the last string is null terminated
auto urlBuf = std::make_unique<char[]>(size+1);
memset(urlBuf.get(), 0, size+1);
2019-10-18 19:01:51 +00:00
tin::network::WaitReceiveNetworkData(m_clientSocket, urlBuf.get(), size);
2019-10-18 19:01:51 +00:00
// Split the string up into individual URLs
std::stringstream urlStream(urlBuf.get());
std::string segment;
std::string nspExt = ".nsp";
while (std::getline(urlStream, segment, '\n'))
{
if (segment.compare(segment.size() - nspExt.size(), nspExt.size(), nspExt) == 0)
urls.push_back(segment);
}
break;
}
else if (errno != EAGAIN)
{
inst::ui::setInfoText("Failed to open client socket");
2019-10-18 19:01:51 +00:00
THROW_FORMAT("Failed to open client socket with code %u\n", errno);
}
}
2019-10-18 19:01:51 +00:00
return urls;
}
catch (std::runtime_error& e)
{
inst::ui::setInfoText("Failed to perform remote install!");
2019-10-18 19:01:51 +00:00
printf("Failed to perform remote install!\n");
printf("%s", e.what());
fprintf(stdout, "%s", e.what());
return {};
}
}
}