Add access point for Switch

This commit is contained in:
Michael Theall 2020-12-11 19:15:33 -06:00
parent 852669818d
commit 709e24d458
15 changed files with 600 additions and 87 deletions

View File

@ -86,7 +86,7 @@ LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) \
CC := `which ccache 2>/dev/null` $(CC) CC := `which ccache 2>/dev/null` $(CC)
CXX := `which ccache 2>/dev/null` $(CXX) CXX := `which ccache 2>/dev/null` $(CXX)
LIBS := `$(PREFIX)pkg-config --libs libzstd` -ldeko3dd -lnx LIBS := `$(PREFIX)pkg-config --libs libzstd` -ldeko3d -lnx
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing # list of directories containing libraries, this must be the top level containing

View File

@ -20,8 +20,11 @@
#pragma once #pragma once
#include "platform.h"
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <mutex>
#include <string> #include <string>
class FtpConfig; class FtpConfig;
@ -40,6 +43,10 @@ public:
/// \param path_ Path to config file /// \param path_ Path to config file
static UniqueFtpConfig load (char const *path_); static UniqueFtpConfig load (char const *path_);
#ifndef NDS
std::lock_guard<platform::Mutex> lockGuard ();
#endif
/// \brief Save config /// \brief Save config
/// \param path_ Path to config file /// \param path_ Path to config file
bool save (char const *path_); bool save (char const *path_);
@ -59,6 +66,17 @@ public:
bool getMTime () const; bool getMTime () const;
#endif #endif
#ifdef __SWITCH__
/// \brief Whether to enable access point
bool enableAP () const;
/// \brief Access point SSID
std::string const &ssid () const;
/// \brief Access point passphrase
std::string const &passphrase () const;
#endif
/// \brief Set user /// \brief Set user
/// \param user_ User /// \param user_ User
void setUser (std::string const &user_); void setUser (std::string const &user_);
@ -81,9 +99,28 @@ public:
void setGetMTime (bool getMTime_); void setGetMTime (bool getMTime_);
#endif #endif
#ifdef __SWITCH__
/// \brief Set whether to enable access point
/// \param enable_ Whether to enable access point
void setEnableAP (bool enable_);
/// \brief Set access point SSID
/// \param ssid_ SSID
void setSSID (std::string const &ssid_);
/// \brief Set access point passphrase
/// \param passphrase_ Passphrase
void setPassphrase (std::string const &passphrase_);
#endif
private: private:
FtpConfig (); FtpConfig ();
#ifndef NDS
/// \brief Mutex
mutable platform::Mutex m_lock;
#endif
/// \brief Username /// \brief Username
std::string m_user; std::string m_user;
@ -97,4 +134,15 @@ private:
/// \brief Whether to get mtime /// \brief Whether to get mtime
bool m_getMTime = true; bool m_getMTime = true;
#endif #endif
#ifdef __SWITCH__
/// \brief Whether to enable access point
bool m_enableAP = false;
/// \brief Access point SSID
std::string m_ssid = "ftpd";
/// \brief Access point passphrase
std::string m_passphrase;
#endif
}; };

View File

@ -67,6 +67,7 @@ private:
/// \brief Handle when network is lost /// \brief Handle when network is lost
void handleNetworkLost (); void handleNetworkLost ();
#ifndef CLASSIC
/// \brief Show menu in the current window /// \brief Show menu in the current window
void showMenu (); void showMenu ();
@ -75,6 +76,7 @@ private:
/// \brief Show about window /// \brief Show about window
void showAbout (); void showAbout ();
#endif
/// \brief Server loop /// \brief Server loop
void loop (); void loop ();
@ -108,6 +110,12 @@ private:
#ifndef CLASSIC #ifndef CLASSIC
/// \brief Whether to show settings menu /// \brief Whether to show settings menu
bool m_showSettings = false; bool m_showSettings = false;
#ifdef __SWITCH__
/// \brief Whether to show access point menu
bool m_showAP = false;
#endif
/// \brief Whether to show about window /// \brief Whether to show about window
bool m_showAbout = false; bool m_showAbout = false;
@ -124,5 +132,19 @@ private:
/// \brief getMTime setting /// \brief getMTime setting
bool m_getMTimeSetting; bool m_getMTimeSetting;
#endif #endif
#ifdef __SWITCH__
/// \brief Whether an error occurred enabling access point
std::atomic<bool> m_apError = false;
/// \brief Enable access point setting
bool m_enableAPSetting;
/// \brief Access point SSID setting
std::string m_ssidSetting;
/// \brief Access point passphrase setting
std::string m_passphraseSetting;
#endif
#endif #endif
}; };

View File

@ -20,6 +20,8 @@
#pragma once #pragma once
#include "sockAddr.h"
#if defined(NDS) #if defined(NDS)
#include <nds.h> #include <nds.h>
#elif defined(_3DS) #elif defined(_3DS)
@ -44,9 +46,31 @@ namespace platform
/// \brief Initialize platform /// \brief Initialize platform
bool init (); bool init ();
#ifdef __SWITCH__
/// \brief Enable access point
/// \param enable_ Whether to enable access point
/// \param ssid_ SSID
/// \param passphrase_ Passphrase
bool enableAP (bool enable_, std::string const &ssid_, std::string const &passphrase_);
/// \brief Check if SSID is valid
/// \param ssid_ SSID to check
/// \returns empty string on success, error message on failure
char const *validateSSID (std::string const &ssid_);
/// \brief Check if passphrase is valid
/// \param passphrase_ Passphrase to check
/// \returns empty string on success, error message on failure
char const *validatePassphrase (std::string const &passphrase_);
#endif
/// \brief Whether network is visible /// \brief Whether network is visible
bool networkVisible (); bool networkVisible ();
/// \brief Get network address
/// \param[out] addr_ Network address
bool networkAddress (SockAddr &addr_);
/// \brief Platform loop /// \brief Platform loop
bool loop (); bool loop ();

View File

@ -94,8 +94,12 @@ public:
/// \brief Address port /// \brief Address port
std::uint16_t port () const; std::uint16_t port () const;
/// \brief Set address port
/// \param port_ Port to set
bool setPort (std::uint16_t port_);
/// \brief Address name /// \brief Address name
/// \param buffer_ /// \param buffer_ Buffer to hold name
/// \param size_ Size of buffer_ /// \param size_ Size of buffer_
/// \retval buffer_ success /// \retval buffer_ success
/// \retval nullptr failure /// \retval nullptr failure

View File

@ -165,7 +165,7 @@ void handleAPTHook (APT_HookType const type_, void *const param_)
bool getNetworkVisibility () bool getNetworkVisibility ()
{ {
// serialize ac:u access from multiple threads // serialize ac:u access from multiple threads
auto lock = std::scoped_lock (s_acuFence); auto lock = std::lock_guard (s_acuFence);
// get wifi status // get wifi status
std::uint32_t wifi = 0; std::uint32_t wifi = 0;
@ -428,6 +428,16 @@ bool platform::networkVisible ()
return getNetworkVisibility (); return getNetworkVisibility ();
} }
bool platform::networkAddress (SockAddr &addr_)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = gethostid ();
addr_ = addr;
return true;
}
bool platform::loop () bool platform::loop ()
{ {
if (!aptMainLoop ()) if (!aptMainLoop ())

View File

@ -26,6 +26,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <limits> #include <limits>
#include <mutex>
namespace namespace
{ {
@ -162,6 +163,21 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
else else
error ("Invalid value for mtime: %s\n", val.c_str ()); error ("Invalid value for mtime: %s\n", val.c_str ());
} }
#endif
#ifdef __SWITCH__
else if (key == "ap")
{
if (val == "0")
config->m_enableAP = false;
else if (val == "1")
config->m_enableAP = true;
else
error ("Invalid value for ap: %s\n", val.c_str ());
}
else if (key == "ssid")
config->m_ssid = val;
else if (key == "passphrase")
config->m_passphrase = val;
#endif #endif
} }
@ -170,6 +186,13 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
return config; return config;
} }
#ifndef NDS
std::lock_guard<platform::Mutex> FtpConfig::lockGuard ()
{
return std::lock_guard<platform::Mutex> (m_lock);
}
#endif
bool FtpConfig::save (char const *const path_) bool FtpConfig::save (char const *const path_)
{ {
if (!mkdirParent (path_)) if (!mkdirParent (path_))
@ -189,6 +212,14 @@ bool FtpConfig::save (char const *const path_)
std::fprintf (fp, "mtime=%u\n", m_getMTime); std::fprintf (fp, "mtime=%u\n", m_getMTime);
#endif #endif
#ifdef __SWITCH__
std::fprintf (fp, "ap=%u\n", m_enableAP);
if (!m_ssid.empty ())
std::fprintf (fp, "ssid=%s\n", m_ssid.c_str ());
if (!m_passphrase.empty ())
std::fprintf (fp, "passphrase=%s\n", m_passphrase.c_str ());
#endif
return true; return true;
} }
@ -214,6 +245,23 @@ bool FtpConfig::getMTime () const
} }
#endif #endif
#ifdef __SWITCH__
bool FtpConfig::enableAP () const
{
return m_enableAP;
}
std::string const &FtpConfig::ssid () const
{
return m_ssid;
}
std::string const &FtpConfig::passphrase () const
{
return m_passphrase;
}
#endif
void FtpConfig::setUser (std::string const &user_) void FtpConfig::setUser (std::string const &user_)
{ {
m_user = user_.substr (0, user_.find_first_of ('\0')); m_user = user_.substr (0, user_.find_first_of ('\0'));
@ -255,3 +303,20 @@ void FtpConfig::setGetMTime (bool const getMTime_)
m_getMTime = getMTime_; m_getMTime = getMTime_;
} }
#endif #endif
#ifdef __SWITCH__
void FtpConfig::setEnableAP (bool const enable_)
{
m_enableAP = enable_;
}
void FtpConfig::setSSID (std::string const &ssid_)
{
m_ssid = ssid_.substr (0, ssid_.find_first_of ('\0'));
}
void FtpConfig::setPassphrase (std::string const &passphrase_)
{
m_passphrase = passphrase_.substr (0, passphrase_.find_first_of ('\0'));
}
#endif

View File

@ -36,10 +36,12 @@
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <unistd.h> #include <unistd.h>
#include <cctype>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <mutex> #include <mutex>
#include <string_view>
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -49,7 +51,7 @@ using namespace std::chrono_literals;
#define LOCKED(x) \ #define LOCKED(x) \
do \ do \
{ \ { \
auto const lock = std::scoped_lock (m_lock); \ auto const lock = std::lock_guard (m_lock); \
x; \ x; \
} while (0) } while (0)
#endif #endif
@ -95,7 +97,7 @@ void FtpServer::draw ()
{ {
char port[7]; char port[7];
#ifndef NDS #ifndef NDS
auto lock = std::scoped_lock (m_lock); auto const lock = std::lock_guard (m_lock);
#endif #endif
if (m_socket) if (m_socket)
std::sprintf (port, ":%u", m_socket->sockName ().port ()); std::sprintf (port, ":%u", m_socket->sockName ().port ());
@ -120,7 +122,7 @@ void FtpServer::draw ()
{ {
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (s_lock); auto const lock = std::lock_guard (s_lock);
#endif #endif
if (!s_freeSpace.empty ()) if (!s_freeSpace.empty ())
{ {
@ -134,7 +136,7 @@ void FtpServer::draw ()
{ {
#ifndef NDS #ifndef NDS
auto lock = std::scoped_lock (m_lock); auto const lock = std::lock_guard (m_lock);
#endif #endif
consoleSelect (&g_sessionConsole); consoleSelect (&g_sessionConsole);
std::fputs ("\x1b[2J", stdout); std::fputs ("\x1b[2J", stdout);
@ -164,7 +166,7 @@ void FtpServer::draw ()
char title[64]; char title[64];
{ {
auto const serverLock = std::scoped_lock (m_lock); auto const serverLock = std::lock_guard (m_lock);
std::snprintf (title, std::snprintf (title,
sizeof (title), sizeof (title),
STATUS_STRING " %s###ftpd", STATUS_STRING " %s###ftpd",
@ -210,7 +212,7 @@ void FtpServer::draw ()
#endif #endif
{ {
auto lock = std::scoped_lock (m_lock); auto const lock = std::lock_guard (m_lock);
for (auto &session : m_sessions) for (auto &session : m_sessions)
session->draw (); session->draw ();
} }
@ -231,7 +233,7 @@ UniqueFtpServer FtpServer::create ()
std::string FtpServer::getFreeSpace () std::string FtpServer::getFreeSpace ()
{ {
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (s_lock); auto const lock = std::lock_guard (s_lock);
#endif #endif
return s_freeSpace; return s_freeSpace;
} }
@ -249,7 +251,7 @@ void FtpServer::updateFreeSpace ()
auto freeSpace = fs::printSize (static_cast<std::uint64_t> (st.f_bsize) * st.f_bfree); auto freeSpace = fs::printSize (static_cast<std::uint64_t> (st.f_bsize) * st.f_bfree);
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (s_lock); auto const lock = std::lock_guard (s_lock);
#endif #endif
if (freeSpace != s_freeSpace) if (freeSpace != s_freeSpace)
s_freeSpace = std::move (freeSpace); s_freeSpace = std::move (freeSpace);
@ -262,22 +264,26 @@ std::time_t FtpServer::startTime ()
void FtpServer::handleNetworkFound () void FtpServer::handleNetworkFound ()
{ {
struct sockaddr_in addr; SockAddr addr;
addr.sin_family = AF_INET; if (!platform::networkAddress (addr))
#if defined(NDS) return;
addr.sin_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
#elif defined(_3DS) || defined(__SWITCH__) std::uint16_t port;
addr.sin_addr.s_addr = gethostid ();
#else {
addr.sin_addr.s_addr = INADDR_ANY; #ifndef NDS
auto const lock = m_config->lockGuard ();
#endif #endif
addr.sin_port = htons (m_config->port ()); port = m_config->port ();
}
addr.setPort (port);
auto socket = Socket::create (); auto socket = Socket::create ();
if (!socket) if (!socket)
return; return;
if (m_config->port () != 0 && !socket->setReuseAddress (true)) if (port != 0 && !socket->setReuseAddress (true))
return; return;
if (!socket->bind (addr)) if (!socket->bind (addr))
@ -290,7 +296,7 @@ void FtpServer::handleNetworkFound ()
auto const name = sockName.name (); auto const name = sockName.name ();
m_name.resize (std::strlen (name) + 3 + 5); m_name.resize (std::strlen (name) + 3 + 5);
m_name.resize (std::sprintf (&m_name[0], "[%s]:%u", name, sockName.port ())); m_name.resize (std::sprintf (m_name.data (), "[%s]:%u", name, sockName.port ()));
info ("Started server at %s\n", m_name.c_str ()); info ("Started server at %s\n", m_name.c_str ());
@ -314,9 +320,9 @@ void FtpServer::handleNetworkLost ()
info ("Stopped server at %s\n", m_name.c_str ()); info ("Stopped server at %s\n", m_name.c_str ());
} }
#ifndef CLASSIC
void FtpServer::showMenu () void FtpServer::showMenu ()
{ {
#ifndef CLASSIC
auto const prevShowSettings = m_showSettings; auto const prevShowSettings = m_showSettings;
auto const prevShowAbout = m_showAbout; auto const prevShowAbout = m_showAbout;
@ -343,6 +349,10 @@ void FtpServer::showMenu ()
{ {
if (!prevShowSettings) if (!prevShowSettings)
{ {
#ifndef NDS
auto const lock = m_config->lockGuard ();
#endif
m_userSetting = m_config->user (); m_userSetting = m_config->user ();
m_userSetting.resize (32); m_userSetting.resize (32);
@ -355,7 +365,16 @@ void FtpServer::showMenu ()
m_getMTimeSetting = m_config->getMTime (); m_getMTimeSetting = m_config->getMTime ();
#endif #endif
info ("Open \"Settings\" popup\n"); #ifdef __SWITCH__
m_enableAPSetting = m_config->enableAP ();
m_ssidSetting = m_config->ssid ();
m_ssidSetting.resize (19);
m_passphraseSetting = m_config->passphrase ();
m_passphraseSetting.resize (63);
#endif
ImGui::OpenPopup ("Settings"); ImGui::OpenPopup ("Settings");
} }
@ -373,7 +392,6 @@ void FtpServer::showMenu ()
void FtpServer::showSettings () void FtpServer::showSettings ()
{ {
#ifndef CLASSIC
#ifdef _3DS #ifdef _3DS
auto const &io = ImGui::GetIO (); auto const &io = ImGui::GetIO ();
auto const width = io.DisplaySize.x; auto const width = io.DisplaySize.x;
@ -388,11 +406,13 @@ void FtpServer::showSettings ()
if (ImGui::BeginPopupModal ("Settings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) if (ImGui::BeginPopupModal ("Settings", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
#endif #endif
{ {
ImGui::InputText ( ImGui::InputText ("User",
"User", &m_userSetting[0], m_userSetting.size (), ImGuiInputTextFlags_AutoSelectAll); m_userSetting.data (),
m_userSetting.size (),
ImGuiInputTextFlags_AutoSelectAll);
ImGui::InputText ("Pass", ImGui::InputText ("Pass",
&m_passSetting[0], m_passSetting.data (),
m_passSetting.size (), m_passSetting.size (),
ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_Password); ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_Password);
@ -408,6 +428,26 @@ void FtpServer::showSettings ()
ImGui::Checkbox ("Get mtime", &m_getMTimeSetting); ImGui::Checkbox ("Get mtime", &m_getMTimeSetting);
#endif #endif
#ifdef __SWITCH__
ImGui::Checkbox ("Enable Access Point", &m_enableAPSetting);
ImGui::InputText ("SSID",
m_ssidSetting.data (),
m_ssidSetting.size (),
ImGuiInputTextFlags_AutoSelectAll);
auto const ssidError = platform::validateSSID (m_ssidSetting);
if (ssidError)
ImGui::TextColored (ImVec4 (1.0f, 0.4f, 0.4f, 1.0f), ssidError);
ImGui::InputText ("Passphrase",
m_passphraseSetting.data (),
m_passphraseSetting.size (),
ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_Password);
auto const passphraseError = platform::validatePassphrase (m_passphraseSetting);
if (passphraseError)
ImGui::TextColored (ImVec4 (1.0f, 0.4f, 0.4f, 1.0f), passphraseError);
#endif
auto const apply = ImGui::Button ("Apply", ImVec2 (100, 0)); auto const apply = ImGui::Button ("Apply", ImVec2 (100, 0));
ImGui::SameLine (); ImGui::SameLine ();
auto const save = ImGui::Button ("Save", ImVec2 (100, 0)); auto const save = ImGui::Button ("Save", ImVec2 (100, 0));
@ -419,6 +459,10 @@ void FtpServer::showSettings ()
m_showSettings = false; m_showSettings = false;
ImGui::CloseCurrentPopup (); ImGui::CloseCurrentPopup ();
#ifndef NDS
auto const lock = m_config->lockGuard ();
#endif
m_config->setUser (m_userSetting); m_config->setUser (m_userSetting);
m_config->setPass (m_passSetting); m_config->setPass (m_passSetting);
m_config->setPort (m_portSetting); m_config->setPort (m_portSetting);
@ -427,12 +471,24 @@ void FtpServer::showSettings ()
m_config->setGetMTime (m_getMTimeSetting); m_config->setGetMTime (m_getMTimeSetting);
#endif #endif
#ifdef __SWITCH__
m_config->setEnableAP (m_enableAPSetting);
m_config->setSSID (m_ssidSetting);
m_config->setPassphrase (m_passphraseSetting);
m_apError = false;
#endif
UniqueSocket socket; UniqueSocket socket;
LOCKED (socket = std::move (m_socket)); LOCKED (socket = std::move (m_socket));
} }
{
#ifndef NDS
auto const lock = m_config->lockGuard ();
#endif
if (save && !m_config->save (FTPDCONFIG)) if (save && !m_config->save (FTPDCONFIG))
error ("Failed to save config\n"); error ("Failed to save config\n");
}
if (apply || save || cancel) if (apply || save || cancel)
{ {
@ -442,13 +498,10 @@ void FtpServer::showSettings ()
ImGui::EndPopup (); ImGui::EndPopup ();
} }
#endif
#endif
} }
void FtpServer::showAbout () void FtpServer::showAbout ()
{ {
#ifndef CLASSIC
auto const &io = ImGui::GetIO (); auto const &io = ImGui::GetIO ();
auto const width = io.DisplaySize.x; auto const width = io.DisplaySize.x;
auto const height = io.DisplaySize.y; auto const height = io.DisplaySize.y;
@ -539,13 +592,31 @@ void FtpServer::showAbout ()
ImGui::EndPopup (); ImGui::EndPopup ();
} }
#endif
} }
#endif
void FtpServer::loop () void FtpServer::loop ()
{ {
if (!m_socket) if (!m_socket)
{ {
#ifdef __SWITCH__
if (!m_apError)
{
bool enable;
std::string ssid;
std::string passphrase;
{
auto const lock = m_config->lockGuard ();
enable = m_config->enableAP ();
ssid = m_config->ssid ();
passphrase = m_config->passphrase ();
}
m_apError = !platform::enableAP (enable, ssid, passphrase);
}
#endif
if (platform::networkVisible ()) if (platform::networkVisible ())
handleNetworkFound (); handleNetworkFound ();
} }
@ -582,7 +653,7 @@ void FtpServer::loop ()
{ {
// remove dead sessions // remove dead sessions
#ifndef NDS #ifndef NDS
auto lock = std::scoped_lock (m_lock); auto const lock = std::lock_guard (m_lock);
#endif #endif
auto it = std::begin (m_sessions); auto it = std::begin (m_sessions);
while (it != std::end (m_sessions)) while (it != std::end (m_sessions))

View File

@ -50,7 +50,7 @@ using namespace std::chrono_literals;
#define LOCKED(x) \ #define LOCKED(x) \
do \ do \
{ \ { \
auto const lock = std::scoped_lock (m_lock); \ auto const lock = std::lock_guard (m_lock); \
x; \ x; \
} while (0) } while (0)
#endif #endif
@ -293,10 +293,15 @@ FtpSession::FtpSession (FtpConfig &config_, UniqueSocket commandSocket_)
m_mlstUnixMode (false), m_mlstUnixMode (false),
m_devZero (false) m_devZero (false)
{ {
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
if (m_config.user ().empty ()) if (m_config.user ().empty ())
m_authorizedUser = true; m_authorizedUser = true;
if (m_config.pass ().empty ()) if (m_config.pass ().empty ())
m_authorizedPass = true; m_authorizedPass = true;
}
char buffer[32]; char buffer[32];
std::sprintf (buffer, "Session#%p", this); std::sprintf (buffer, "Session#%p", this);
@ -313,7 +318,7 @@ FtpSession::FtpSession (FtpConfig &config_, UniqueSocket commandSocket_)
bool FtpSession::dead () bool FtpSession::dead ()
{ {
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (m_lock); auto const lock = std::lock_guard (m_lock);
#endif #endif
if (m_commandSocket || m_pasvSocket || m_dataSocket) if (m_commandSocket || m_pasvSocket || m_dataSocket)
return false; return false;
@ -324,7 +329,7 @@ bool FtpSession::dead ()
void FtpSession::draw () void FtpSession::draw ()
{ {
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (m_lock); auto const lock = std::lock_guard (m_lock);
#endif #endif
#ifdef CLASSIC #ifdef CLASSIC
@ -610,7 +615,7 @@ void FtpSession::setState (State const state_, bool const closePasv_, bool const
{ {
{ {
#ifndef NDS #ifndef NDS
auto lock = std::scoped_lock (m_lock); auto lock = std::lock_guard (m_lock);
#endif #endif
m_restartPosition = 0; m_restartPosition = 0;
@ -1673,7 +1678,13 @@ bool FtpSession::listTransfer ()
else if (m_xferDirMode == XferDirMode::NLST) else if (m_xferDirMode == XferDirMode::NLST)
getmtime = false; getmtime = false;
if (getmtime && m_config.getMTime ()) {
auto const lock = m_config.lockGuard ();
if (!m_config.getMTime ())
getmtime = false;
}
if (getmtime)
{ {
std::uint64_t mtime = 0; std::uint64_t mtime = 0;
auto const rc = archive_getmtime (fullPath.c_str (), &mtime); auto const rc = archive_getmtime (fullPath.c_str (), &mtime);
@ -2159,13 +2170,24 @@ void FtpSession::PASS (char const *args_)
m_authorizedPass = false; m_authorizedPass = false;
if (!m_config.user ().empty () && !m_authorizedUser) std::string user;
std::string pass;
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
user = m_config.user ();
pass = m_config.pass ();
}
if (!user.empty () && !m_authorizedUser)
{ {
sendResponse ("430 User not authorized\r\n"); sendResponse ("430 User not authorized\r\n");
return; return;
} }
if (m_config.pass ().empty () || m_config.pass () == args_) if (pass.empty () || pass == args_)
{ {
m_authorizedPass = true; m_authorizedPass = true;
sendResponse ("230 OK\r\n"); sendResponse ("230 OK\r\n");
@ -2544,19 +2566,40 @@ void FtpSession::SITE (char const *args_)
if (::strcasecmp (command.c_str (), "USER") == 0) if (::strcasecmp (command.c_str (), "USER") == 0)
{ {
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
m_config.setUser (arg); m_config.setUser (arg);
}
sendResponse ("200 OK\r\n"); sendResponse ("200 OK\r\n");
return; return;
} }
else if (::strcasecmp (command.c_str (), "PASS") == 0) else if (::strcasecmp (command.c_str (), "PASS") == 0)
{ {
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
m_config.setPass (arg); m_config.setPass (arg);
}
sendResponse ("200 OK\r\n"); sendResponse ("200 OK\r\n");
return; return;
} }
else if (::strcasecmp (command.c_str (), "PORT") == 0) else if (::strcasecmp (command.c_str (), "PORT") == 0)
{ {
if (!m_config.setPort (arg)) bool error = false;
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
error = !m_config.setPort (arg);
}
if (error)
{ {
sendResponse ("550 %s\r\n", std::strerror (errno)); sendResponse ("550 %s\r\n", std::strerror (errno));
return; return;
@ -2569,9 +2612,19 @@ void FtpSession::SITE (char const *args_)
else if (::strcasecmp (command.c_str (), "MTIME") == 0) else if (::strcasecmp (command.c_str (), "MTIME") == 0)
{ {
if (arg == "0") if (arg == "0")
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
m_config.setGetMTime (false); m_config.setGetMTime (false);
}
else if (arg == "1") else if (arg == "1")
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
m_config.setGetMTime (true); m_config.setGetMTime (true);
}
else else
{ {
sendResponse ("550 %s\r\n", std::strerror (EINVAL)); sendResponse ("550 %s\r\n", std::strerror (EINVAL));
@ -2581,7 +2634,16 @@ void FtpSession::SITE (char const *args_)
#endif #endif
else if (::strcasecmp (command.c_str (), "SAVE") == 0) else if (::strcasecmp (command.c_str (), "SAVE") == 0)
{ {
if (!m_config.save (FTPDCONFIG)) bool error;
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
error = !m_config.save (FTPDCONFIG);
}
if (error)
{ {
sendResponse ("550 %s\r\n", std::strerror (errno)); sendResponse ("550 %s\r\n", std::strerror (errno));
return; return;
@ -2730,10 +2792,21 @@ void FtpSession::USER (char const *args_)
m_authorizedUser = false; m_authorizedUser = false;
if (m_config.user ().empty () || m_config.user () == args_) std::string user;
std::string pass;
{
#ifndef NDS
auto const lock = m_config.lockGuard ();
#endif
user = m_config.user ();
pass = m_config.pass ();
}
if (user.empty () || user == args_)
{ {
m_authorizedUser = true; m_authorizedUser = true;
if (m_config.pass ().empty ()) if (pass.empty ())
{ {
sendResponse ("230 OK\r\n"); sendResponse ("230 OK\r\n");
return; return;

View File

@ -169,6 +169,16 @@ bool platform::networkVisible ()
return true; return true;
} }
bool platform::networkAddress (SockAddr &addr_)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr_ = addr;
return true;
}
bool platform::loop () bool platform::loop ()
{ {
bool inactive; bool inactive;

View File

@ -79,7 +79,7 @@ platform::Mutex s_lock;
void drawLog () void drawLog ()
{ {
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (s_lock); auto const lock = std::lock_guard (s_lock);
#endif #endif
#ifdef CLASSIC #ifdef CLASSIC
@ -211,7 +211,7 @@ void addLog (LogLevel const level_, char const *const fmt_, va_list ap_)
std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_); std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_);
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (s_lock); auto const lock = std::lock_guard (s_lock);
#endif #endif
#ifndef NDEBUG #ifndef NDEBUG
// std::fprintf (stderr, "%s", s_prefix[level_]); // std::fprintf (stderr, "%s", s_prefix[level_]);
@ -239,7 +239,7 @@ void addLog (LogLevel const level_, std::string_view const message_)
} }
#ifndef NDS #ifndef NDS
auto const lock = std::scoped_lock (s_lock); auto const lock = std::lock_guard (s_lock);
#endif #endif
#ifndef NDEBUG #ifndef NDEBUG
// std::fprintf (stderr, "%s", s_prefix[level_]); // std::fprintf (stderr, "%s", s_prefix[level_]);

View File

@ -73,6 +73,16 @@ bool platform::networkVisible ()
return false; return false;
} }
bool platform::networkAddress (SockAddr &addr_)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
addr_ = addr;
return true;
}
bool platform::init () bool platform::init ()
{ {
sassert (fatInitDefault (), "Failed to initialize fat"); sassert (fatInitDefault (), "Failed to initialize fat");

View File

@ -107,6 +107,26 @@ SockAddr::operator struct sockaddr const * () const
return reinterpret_cast<struct sockaddr const *> (&m_addr); return reinterpret_cast<struct sockaddr const *> (&m_addr);
} }
bool SockAddr::setPort (std::uint16_t const port_)
{
switch (m_addr.ss_family)
{
case AF_INET:
reinterpret_cast<struct sockaddr_in *> (&m_addr)->sin_port = htons (port_);
return true;
#ifndef NO_IPV6
case AF_INET6:
reinterpret_cast<struct sockaddr_in6 *> (&m_addr)->sin6_port = htons (port_);
return true;
#endif
default:
std::abort ();
break;
}
}
std::uint16_t SockAddr::port () const std::uint16_t SockAddr::port () const
{ {
switch (m_addr.ss_family) switch (m_addr.ss_family)

View File

@ -1372,7 +1372,7 @@ void updateKeyboard (HidKeyboardState const &kbState_, ImGuiIO &io_)
io_.KeySuper = kbState_.modifiers & HidKeyboardModifier_Gui; io_.KeySuper = kbState_.modifiers & HidKeyboardModifier_Gui;
for (int i = 0; i < 256; ++i) for (int i = 0; i < 256; ++i)
io_.KeysDown[i] = kbState_.keys[i / 64] & (1 << (i % 64)); io_.KeysDown[i] = kbState_.keys[i / 64] & (1ul << (i % 64));
static enum { static enum {
INACTIVE, INACTIVE,

View File

@ -53,13 +53,16 @@ namespace
/// \brief Whether to power backlight /// \brief Whether to power backlight
bool s_backlight = true; bool s_backlight = true;
/// \brief Whether access point is active
bool s_activeAP = false;
/// \brief Access point SSID
std::string s_ssid;
/// \brief Applet hook cookie /// \brief Applet hook cookie
AppletHookCookie s_appletHookCookie; AppletHookCookie s_appletHookCookie;
#ifdef CLASSIC #ifndef CLASSIC
/// \brief Host address
in_addr_t s_addr = 0;
#else
/// \brief Texture index /// \brief Texture index
enum TextureIndex enum TextureIndex
{ {
@ -503,6 +506,10 @@ void drawStatus ()
{ {
TextureIndex netIcon = AIRPLANE_ICON; TextureIndex netIcon = AIRPLANE_ICON;
if (s_activeAP)
netIcon = WIFI3_ICON;
else
{
NifmInternetConnectionType type; NifmInternetConnectionType type;
std::uint32_t wifiStrength; std::uint32_t wifiStrength;
NifmInternetConnectionStatus status; NifmInternetConnectionStatus status;
@ -527,6 +534,7 @@ void drawStatus ()
netIcon = WIFI_NONE_ICON; netIcon = WIFI_NONE_ICON;
} }
} }
}
// draw network icon // draw network icon
pos.x -= ICON_WIDTH + style.FramePadding.x; pos.x -= ICON_WIDTH + style.FramePadding.x;
@ -547,6 +555,15 @@ void drawStatus ()
pos, ImGui::GetColorU32 (ImGuiCol_Text), freeSpace.c_str ()); pos, ImGui::GetColorU32 (ImGuiCol_Text), freeSpace.c_str ());
} }
if (s_activeAP)
{
auto const size = ImGui::CalcTextSize (s_ssid.c_str ());
auto const ssidPos = ImVec2 (
io.DisplaySize.x - style.FramePadding.x - size.x, 3 * style.FramePadding.y + size.y);
ImGui::GetForegroundDrawList ()->AddText (
ssidPos, ImGui::GetColorU32 (ImGuiCol_Text), s_ssid.c_str ());
}
{ {
// get current timestamp // get current timestamp
char timeBuffer[16]; char timeBuffer[16];
@ -598,22 +615,154 @@ bool platform::init ()
return true; return true;
} }
bool platform::enableAP (bool const enableAP_,
std::string const &ssid_,
std::string const &passphrase_)
{
if (s_activeAP == enableAP_)
return true;
if (enableAP_)
{
auto const ssidError = validateSSID (ssid_);
if (ssidError)
{
error ("Access Point: %s\n", ssidError);
return false;
}
auto const passphraseError = validatePassphrase (passphrase_);
if (passphraseError)
{
error ("Access Point: %s\n", passphraseError);
return false;
}
auto rc = lp2pInitialize (Lp2pServiceType_App);
if (R_FAILED (rc))
{
error ("lp2pInitialize: 0x%x\n", rc);
return false;
}
Lp2pGroupInfo groupInfo;
lp2pCreateGroupInfo (&groupInfo);
// set SSID
lp2pGroupInfoSetServiceName (&groupInfo, ssid_.c_str ());
// enable WPA2-PSK
s8 flags = 0;
lp2pGroupInfoSetFlags (&groupInfo, &flags, 1);
// passphrase
rc = lp2pGroupInfoSetPassphrase (&groupInfo, passphrase_.c_str ());
if (R_FAILED (rc))
{
error ("lp2pGroupInfoSetPassphrase: 0x%x\n", rc);
lp2pExit ();
return false;
}
// create group
rc = lp2pCreateGroup (&groupInfo);
if (R_FAILED (rc))
{
error ("lp2pCreateGroup: 0x%x\n", rc);
lp2pExit ();
return false;
}
rc = lp2pGetGroupInfo (&groupInfo);
if (R_FAILED (rc))
{
error ("lp2pGetGroupInfo: 0x%x\n", rc);
lp2pDestroyGroup ();
lp2pExit ();
return false;
}
s_ssid = std::string ("SSID: ") + groupInfo.service_name;
s_activeAP = true;
}
else
{
lp2pDestroyGroup ();
lp2pExit ();
s_activeAP = false;
}
return true;
}
char const *platform::validateSSID (std::string const &ssid_)
{
auto const ssid = std::string_view (ssid_).substr (0, ssid_.find_first_of ('\0'));
if (ssid.size () > 19)
return "SSID too long";
for (auto const &c : ssid)
{
if (!std::isalnum (c) && c != '-')
return "SSID can only contain alphanumeric and -";
}
return nullptr;
}
char const *platform::validatePassphrase (std::string const &passphrase_)
{
auto const passphrase =
std::string_view (passphrase_).substr (0, passphrase_.find_first_of ('\0'));
if (passphrase.size () < 8)
return "Passphrase too short";
else if (passphrase.size () > 63)
return "Passphrase too long";
return nullptr;
}
bool platform::networkVisible () bool platform::networkVisible ()
{ {
if (s_activeAP)
return true;
NifmInternetConnectionType type; NifmInternetConnectionType type;
std::uint32_t wifi; std::uint32_t wifi;
NifmInternetConnectionStatus status; NifmInternetConnectionStatus status;
if (R_FAILED (nifmGetInternetConnectionStatus (&type, &wifi, &status))) if (R_FAILED (nifmGetInternetConnectionStatus (&type, &wifi, &status)))
return false; return false;
#ifdef CLASSIC
if (!s_addr)
s_addr = gethostid ();
#endif
return status == NifmInternetConnectionStatus_Connected; return status == NifmInternetConnectionStatus_Connected;
} }
bool platform::networkAddress (SockAddr &addr_)
{
if (s_activeAP)
{
Lp2pIpConfig ipConfig;
auto const rc = lp2pGetIpConfig (&ipConfig);
if (R_FAILED (rc))
{
error ("lp2pGetIpConfig: 0x%x\n", rc);
return false;
}
addr_ = *reinterpret_cast<struct sockaddr_in *> (ipConfig.ip_addr);
return true;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = gethostid ();
addr_ = addr;
return true;
}
bool platform::loop () bool platform::loop ()
{ {
if (!appletMainLoop ()) if (!appletMainLoop ())
@ -672,7 +821,7 @@ void platform::render ()
#else #else
ImGui::Render (); ImGui::Render ();
auto &io = ImGui::GetIO (); auto const &io = ImGui::GetIO ();
if (s_width != io.DisplaySize.x || s_height != io.DisplaySize.y) if (s_width != io.DisplaySize.x || s_height != io.DisplaySize.y)
{ {
@ -726,6 +875,13 @@ void platform::exit ()
if (!s_backlight) if (!s_backlight)
appletSetLcdBacklightOffEnabled (false); appletSetLcdBacklightOffEnabled (false);
if (s_activeAP)
{
lp2pDestroyGroup ();
lp2pExit ();
s_activeAP = false;
}
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////