diff --git a/Makefile.switch b/Makefile.switch index af88bca..953cbfc 100644 --- a/Makefile.switch +++ b/Makefile.switch @@ -86,7 +86,7 @@ LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) \ CC := `which ccache 2>/dev/null` $(CC) 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 diff --git a/include/ftpConfig.h b/include/ftpConfig.h index 58df89e..1aabab1 100644 --- a/include/ftpConfig.h +++ b/include/ftpConfig.h @@ -20,8 +20,11 @@ #pragma once +#include "platform.h" + #include #include +#include #include class FtpConfig; @@ -40,6 +43,10 @@ public: /// \param path_ Path to config file static UniqueFtpConfig load (char const *path_); +#ifndef NDS + std::lock_guard lockGuard (); +#endif + /// \brief Save config /// \param path_ Path to config file bool save (char const *path_); @@ -59,6 +66,17 @@ public: bool getMTime () const; #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 /// \param user_ User void setUser (std::string const &user_); @@ -81,9 +99,28 @@ public: void setGetMTime (bool getMTime_); #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: FtpConfig (); +#ifndef NDS + /// \brief Mutex + mutable platform::Mutex m_lock; +#endif + /// \brief Username std::string m_user; @@ -97,4 +134,15 @@ private: /// \brief Whether to get mtime bool m_getMTime = true; #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 }; diff --git a/include/ftpServer.h b/include/ftpServer.h index c455c12..c4389e0 100644 --- a/include/ftpServer.h +++ b/include/ftpServer.h @@ -67,6 +67,7 @@ private: /// \brief Handle when network is lost void handleNetworkLost (); +#ifndef CLASSIC /// \brief Show menu in the current window void showMenu (); @@ -75,6 +76,7 @@ private: /// \brief Show about window void showAbout (); +#endif /// \brief Server loop void loop (); @@ -108,6 +110,12 @@ private: #ifndef CLASSIC /// \brief Whether to show settings menu bool m_showSettings = false; + +#ifdef __SWITCH__ + /// \brief Whether to show access point menu + bool m_showAP = false; +#endif + /// \brief Whether to show about window bool m_showAbout = false; @@ -124,5 +132,19 @@ private: /// \brief getMTime setting bool m_getMTimeSetting; #endif + +#ifdef __SWITCH__ + /// \brief Whether an error occurred enabling access point + std::atomic 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 }; diff --git a/include/platform.h b/include/platform.h index 3e28020..7c6b5bc 100644 --- a/include/platform.h +++ b/include/platform.h @@ -20,6 +20,8 @@ #pragma once +#include "sockAddr.h" + #if defined(NDS) #include #elif defined(_3DS) @@ -44,9 +46,31 @@ namespace platform /// \brief Initialize platform 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 bool networkVisible (); +/// \brief Get network address +/// \param[out] addr_ Network address +bool networkAddress (SockAddr &addr_); + /// \brief Platform loop bool loop (); diff --git a/include/sockAddr.h b/include/sockAddr.h index 07e151a..9b7793b 100644 --- a/include/sockAddr.h +++ b/include/sockAddr.h @@ -94,8 +94,12 @@ public: /// \brief Address port std::uint16_t port () const; + /// \brief Set address port + /// \param port_ Port to set + bool setPort (std::uint16_t port_); + /// \brief Address name - /// \param buffer_ + /// \param buffer_ Buffer to hold name /// \param size_ Size of buffer_ /// \retval buffer_ success /// \retval nullptr failure diff --git a/source/3ds/platform.cpp b/source/3ds/platform.cpp index d8daade..7c92438 100644 --- a/source/3ds/platform.cpp +++ b/source/3ds/platform.cpp @@ -165,7 +165,7 @@ void handleAPTHook (APT_HookType const type_, void *const param_) bool getNetworkVisibility () { // serialize ac:u access from multiple threads - auto lock = std::scoped_lock (s_acuFence); + auto lock = std::lock_guard (s_acuFence); // get wifi status std::uint32_t wifi = 0; @@ -428,6 +428,16 @@ bool platform::networkVisible () 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 () { if (!aptMainLoop ()) diff --git a/source/ftpConfig.cpp b/source/ftpConfig.cpp index 7f768f2..ba938d3 100644 --- a/source/ftpConfig.cpp +++ b/source/ftpConfig.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace { @@ -162,6 +163,21 @@ UniqueFtpConfig FtpConfig::load (char const *const path_) else 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 } @@ -170,6 +186,13 @@ UniqueFtpConfig FtpConfig::load (char const *const path_) return config; } +#ifndef NDS +std::lock_guard FtpConfig::lockGuard () +{ + return std::lock_guard (m_lock); +} +#endif + bool FtpConfig::save (char const *const path_) { if (!mkdirParent (path_)) @@ -189,6 +212,14 @@ bool FtpConfig::save (char const *const path_) std::fprintf (fp, "mtime=%u\n", m_getMTime); #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; } @@ -214,6 +245,23 @@ bool FtpConfig::getMTime () const } #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_) { m_user = user_.substr (0, user_.find_first_of ('\0')); @@ -255,3 +303,20 @@ void FtpConfig::setGetMTime (bool const getMTime_) m_getMTime = getMTime_; } #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 diff --git a/source/ftpServer.cpp b/source/ftpServer.cpp index 5f63e80..1638612 100644 --- a/source/ftpServer.cpp +++ b/source/ftpServer.cpp @@ -36,10 +36,12 @@ #include #include +#include #include #include #include #include +#include #include using namespace std::chrono_literals; @@ -49,7 +51,7 @@ using namespace std::chrono_literals; #define LOCKED(x) \ do \ { \ - auto const lock = std::scoped_lock (m_lock); \ + auto const lock = std::lock_guard (m_lock); \ x; \ } while (0) #endif @@ -95,7 +97,7 @@ void FtpServer::draw () { char port[7]; #ifndef NDS - auto lock = std::scoped_lock (m_lock); + auto const lock = std::lock_guard (m_lock); #endif if (m_socket) std::sprintf (port, ":%u", m_socket->sockName ().port ()); @@ -120,7 +122,7 @@ void FtpServer::draw () { #ifndef NDS - auto const lock = std::scoped_lock (s_lock); + auto const lock = std::lock_guard (s_lock); #endif if (!s_freeSpace.empty ()) { @@ -134,7 +136,7 @@ void FtpServer::draw () { #ifndef NDS - auto lock = std::scoped_lock (m_lock); + auto const lock = std::lock_guard (m_lock); #endif consoleSelect (&g_sessionConsole); std::fputs ("\x1b[2J", stdout); @@ -164,7 +166,7 @@ void FtpServer::draw () char title[64]; { - auto const serverLock = std::scoped_lock (m_lock); + auto const serverLock = std::lock_guard (m_lock); std::snprintf (title, sizeof (title), STATUS_STRING " %s###ftpd", @@ -210,7 +212,7 @@ void FtpServer::draw () #endif { - auto lock = std::scoped_lock (m_lock); + auto const lock = std::lock_guard (m_lock); for (auto &session : m_sessions) session->draw (); } @@ -231,7 +233,7 @@ UniqueFtpServer FtpServer::create () std::string FtpServer::getFreeSpace () { #ifndef NDS - auto const lock = std::scoped_lock (s_lock); + auto const lock = std::lock_guard (s_lock); #endif return s_freeSpace; } @@ -249,7 +251,7 @@ void FtpServer::updateFreeSpace () auto freeSpace = fs::printSize (static_cast (st.f_bsize) * st.f_bfree); #ifndef NDS - auto const lock = std::scoped_lock (s_lock); + auto const lock = std::lock_guard (s_lock); #endif if (freeSpace != s_freeSpace) s_freeSpace = std::move (freeSpace); @@ -262,22 +264,26 @@ std::time_t FtpServer::startTime () void FtpServer::handleNetworkFound () { - struct sockaddr_in addr; - addr.sin_family = AF_INET; -#if defined(NDS) - addr.sin_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr); -#elif defined(_3DS) || defined(__SWITCH__) - addr.sin_addr.s_addr = gethostid (); -#else - addr.sin_addr.s_addr = INADDR_ANY; + SockAddr addr; + if (!platform::networkAddress (addr)) + return; + + std::uint16_t port; + + { +#ifndef NDS + auto const lock = m_config->lockGuard (); #endif - addr.sin_port = htons (m_config->port ()); + port = m_config->port (); + } + + addr.setPort (port); auto socket = Socket::create (); if (!socket) return; - if (m_config->port () != 0 && !socket->setReuseAddress (true)) + if (port != 0 && !socket->setReuseAddress (true)) return; if (!socket->bind (addr)) @@ -290,7 +296,7 @@ void FtpServer::handleNetworkFound () auto const name = sockName.name (); 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 ()); @@ -314,9 +320,9 @@ void FtpServer::handleNetworkLost () info ("Stopped server at %s\n", m_name.c_str ()); } +#ifndef CLASSIC void FtpServer::showMenu () { -#ifndef CLASSIC auto const prevShowSettings = m_showSettings; auto const prevShowAbout = m_showAbout; @@ -343,6 +349,10 @@ void FtpServer::showMenu () { if (!prevShowSettings) { +#ifndef NDS + auto const lock = m_config->lockGuard (); +#endif + m_userSetting = m_config->user (); m_userSetting.resize (32); @@ -355,7 +365,16 @@ void FtpServer::showMenu () m_getMTimeSetting = m_config->getMTime (); #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"); } @@ -373,7 +392,6 @@ void FtpServer::showMenu () void FtpServer::showSettings () { -#ifndef CLASSIC #ifdef _3DS auto const &io = ImGui::GetIO (); auto const width = io.DisplaySize.x; @@ -388,11 +406,13 @@ void FtpServer::showSettings () if (ImGui::BeginPopupModal ("Settings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) #endif { - ImGui::InputText ( - "User", &m_userSetting[0], m_userSetting.size (), ImGuiInputTextFlags_AutoSelectAll); + ImGui::InputText ("User", + m_userSetting.data (), + m_userSetting.size (), + ImGuiInputTextFlags_AutoSelectAll); ImGui::InputText ("Pass", - &m_passSetting[0], + m_passSetting.data (), m_passSetting.size (), ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_Password); @@ -408,6 +428,26 @@ void FtpServer::showSettings () ImGui::Checkbox ("Get mtime", &m_getMTimeSetting); #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)); ImGui::SameLine (); auto const save = ImGui::Button ("Save", ImVec2 (100, 0)); @@ -419,6 +459,10 @@ void FtpServer::showSettings () m_showSettings = false; ImGui::CloseCurrentPopup (); +#ifndef NDS + auto const lock = m_config->lockGuard (); +#endif + m_config->setUser (m_userSetting); m_config->setPass (m_passSetting); m_config->setPort (m_portSetting); @@ -427,12 +471,24 @@ void FtpServer::showSettings () m_config->setGetMTime (m_getMTimeSetting); #endif +#ifdef __SWITCH__ + m_config->setEnableAP (m_enableAPSetting); + m_config->setSSID (m_ssidSetting); + m_config->setPassphrase (m_passphraseSetting); + m_apError = false; +#endif + UniqueSocket socket; LOCKED (socket = std::move (m_socket)); } - if (save && !m_config->save (FTPDCONFIG)) - error ("Failed to save config\n"); + { +#ifndef NDS + auto const lock = m_config->lockGuard (); +#endif + if (save && !m_config->save (FTPDCONFIG)) + error ("Failed to save config\n"); + } if (apply || save || cancel) { @@ -442,13 +498,10 @@ void FtpServer::showSettings () ImGui::EndPopup (); } -#endif -#endif } void FtpServer::showAbout () { -#ifndef CLASSIC auto const &io = ImGui::GetIO (); auto const width = io.DisplaySize.x; auto const height = io.DisplaySize.y; @@ -539,13 +592,31 @@ void FtpServer::showAbout () ImGui::EndPopup (); } -#endif } +#endif void FtpServer::loop () { 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 ()) handleNetworkFound (); } @@ -582,7 +653,7 @@ void FtpServer::loop () { // remove dead sessions #ifndef NDS - auto lock = std::scoped_lock (m_lock); + auto const lock = std::lock_guard (m_lock); #endif auto it = std::begin (m_sessions); while (it != std::end (m_sessions)) diff --git a/source/ftpSession.cpp b/source/ftpSession.cpp index 5ea27ee..78afa1e 100644 --- a/source/ftpSession.cpp +++ b/source/ftpSession.cpp @@ -50,7 +50,7 @@ using namespace std::chrono_literals; #define LOCKED(x) \ do \ { \ - auto const lock = std::scoped_lock (m_lock); \ + auto const lock = std::lock_guard (m_lock); \ x; \ } while (0) #endif @@ -293,10 +293,15 @@ FtpSession::FtpSession (FtpConfig &config_, UniqueSocket commandSocket_) m_mlstUnixMode (false), m_devZero (false) { - if (m_config.user ().empty ()) - m_authorizedUser = true; - if (m_config.pass ().empty ()) - m_authorizedPass = true; + { +#ifndef NDS + auto const lock = m_config.lockGuard (); +#endif + if (m_config.user ().empty ()) + m_authorizedUser = true; + if (m_config.pass ().empty ()) + m_authorizedPass = true; + } char buffer[32]; std::sprintf (buffer, "Session#%p", this); @@ -313,7 +318,7 @@ FtpSession::FtpSession (FtpConfig &config_, UniqueSocket commandSocket_) bool FtpSession::dead () { #ifndef NDS - auto const lock = std::scoped_lock (m_lock); + auto const lock = std::lock_guard (m_lock); #endif if (m_commandSocket || m_pasvSocket || m_dataSocket) return false; @@ -324,7 +329,7 @@ bool FtpSession::dead () void FtpSession::draw () { #ifndef NDS - auto const lock = std::scoped_lock (m_lock); + auto const lock = std::lock_guard (m_lock); #endif #ifdef CLASSIC @@ -610,7 +615,7 @@ void FtpSession::setState (State const state_, bool const closePasv_, bool const { { #ifndef NDS - auto lock = std::scoped_lock (m_lock); + auto lock = std::lock_guard (m_lock); #endif m_restartPosition = 0; @@ -1673,7 +1678,13 @@ bool FtpSession::listTransfer () else if (m_xferDirMode == XferDirMode::NLST) 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; auto const rc = archive_getmtime (fullPath.c_str (), &mtime); @@ -2159,13 +2170,24 @@ void FtpSession::PASS (char const *args_) 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"); return; } - if (m_config.pass ().empty () || m_config.pass () == args_) + if (pass.empty () || pass == args_) { m_authorizedPass = true; sendResponse ("230 OK\r\n"); @@ -2544,19 +2566,40 @@ void FtpSession::SITE (char const *args_) if (::strcasecmp (command.c_str (), "USER") == 0) { - m_config.setUser (arg); + { +#ifndef NDS + auto const lock = m_config.lockGuard (); +#endif + m_config.setUser (arg); + } + sendResponse ("200 OK\r\n"); return; } else if (::strcasecmp (command.c_str (), "PASS") == 0) { - m_config.setPass (arg); + { +#ifndef NDS + auto const lock = m_config.lockGuard (); +#endif + m_config.setPass (arg); + } + sendResponse ("200 OK\r\n"); return; } 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)); return; @@ -2569,9 +2612,19 @@ void FtpSession::SITE (char const *args_) else if (::strcasecmp (command.c_str (), "MTIME") == 0) { if (arg == "0") + { +#ifndef NDS + auto const lock = m_config.lockGuard (); +#endif m_config.setGetMTime (false); + } else if (arg == "1") + { +#ifndef NDS + auto const lock = m_config.lockGuard (); +#endif m_config.setGetMTime (true); + } else { sendResponse ("550 %s\r\n", std::strerror (EINVAL)); @@ -2581,7 +2634,16 @@ void FtpSession::SITE (char const *args_) #endif 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)); return; @@ -2730,10 +2792,21 @@ void FtpSession::USER (char const *args_) 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; - if (m_config.pass ().empty ()) + if (pass.empty ()) { sendResponse ("230 OK\r\n"); return; diff --git a/source/linux/platform.cpp b/source/linux/platform.cpp index 546b016..2511f8c 100644 --- a/source/linux/platform.cpp +++ b/source/linux/platform.cpp @@ -169,6 +169,16 @@ bool platform::networkVisible () 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 inactive; diff --git a/source/log.cpp b/source/log.cpp index 1e486b6..f7d8cb6 100644 --- a/source/log.cpp +++ b/source/log.cpp @@ -79,7 +79,7 @@ platform::Mutex s_lock; void drawLog () { #ifndef NDS - auto const lock = std::scoped_lock (s_lock); + auto const lock = std::lock_guard (s_lock); #endif #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_); #ifndef NDS - auto const lock = std::scoped_lock (s_lock); + auto const lock = std::lock_guard (s_lock); #endif #ifndef NDEBUG // std::fprintf (stderr, "%s", s_prefix[level_]); @@ -239,7 +239,7 @@ void addLog (LogLevel const level_, std::string_view const message_) } #ifndef NDS - auto const lock = std::scoped_lock (s_lock); + auto const lock = std::lock_guard (s_lock); #endif #ifndef NDEBUG // std::fprintf (stderr, "%s", s_prefix[level_]); diff --git a/source/nds/platform.cpp b/source/nds/platform.cpp index bd88276..259ec5c 100644 --- a/source/nds/platform.cpp +++ b/source/nds/platform.cpp @@ -73,6 +73,16 @@ bool platform::networkVisible () 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 () { sassert (fatInitDefault (), "Failed to initialize fat"); diff --git a/source/sockAddr.cpp b/source/sockAddr.cpp index b3b7e58..c840063 100644 --- a/source/sockAddr.cpp +++ b/source/sockAddr.cpp @@ -107,6 +107,26 @@ SockAddr::operator struct sockaddr const * () const return reinterpret_cast (&m_addr); } +bool SockAddr::setPort (std::uint16_t const port_) +{ + switch (m_addr.ss_family) + { + case AF_INET: + reinterpret_cast (&m_addr)->sin_port = htons (port_); + return true; + +#ifndef NO_IPV6 + case AF_INET6: + reinterpret_cast (&m_addr)->sin6_port = htons (port_); + return true; +#endif + + default: + std::abort (); + break; + } +} + std::uint16_t SockAddr::port () const { switch (m_addr.ss_family) diff --git a/source/switch/imgui_nx.cpp b/source/switch/imgui_nx.cpp index ab4febc..b861d47 100644 --- a/source/switch/imgui_nx.cpp +++ b/source/switch/imgui_nx.cpp @@ -1372,7 +1372,7 @@ void updateKeyboard (HidKeyboardState const &kbState_, ImGuiIO &io_) io_.KeySuper = kbState_.modifiers & HidKeyboardModifier_Gui; 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 { INACTIVE, diff --git a/source/switch/platform.cpp b/source/switch/platform.cpp index 24a4c34..7ddbb63 100644 --- a/source/switch/platform.cpp +++ b/source/switch/platform.cpp @@ -53,13 +53,16 @@ namespace /// \brief Whether to power backlight 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 AppletHookCookie s_appletHookCookie; -#ifdef CLASSIC -/// \brief Host address -in_addr_t s_addr = 0; -#else +#ifndef CLASSIC /// \brief Texture index enum TextureIndex { @@ -294,7 +297,7 @@ void loadTextures () }; TextureInfo textureInfos[] = { - // clang-format off + // clang-format off TextureInfo ( "romfs:/deko3d.12x12.astc.zst", DkImageFormat_RGBA_ASTC_12x12, LOGO_WIDTH, LOGO_HEIGHT), TextureInfo ( @@ -315,7 +318,7 @@ void loadTextures () "romfs:/wifi2_icon.rgba.zst", DkImageFormat_RGBA8_Unorm, ICON_WIDTH, ICON_HEIGHT), TextureInfo ( "romfs:/wifi3_icon.rgba.zst", DkImageFormat_RGBA8_Unorm, ICON_WIDTH, ICON_HEIGHT) - // clang-format on + // clang-format on }; // create memblock for transfer (large enough for the largest source file) @@ -503,28 +506,33 @@ void drawStatus () { TextureIndex netIcon = AIRPLANE_ICON; - NifmInternetConnectionType type; - std::uint32_t wifiStrength; - NifmInternetConnectionStatus status; - if (R_SUCCEEDED (nifmGetInternetConnectionStatus (&type, &wifiStrength, &status))) + if (s_activeAP) + netIcon = WIFI3_ICON; + else { - if (type == NifmInternetConnectionType_Ethernet) + NifmInternetConnectionType type; + std::uint32_t wifiStrength; + NifmInternetConnectionStatus status; + if (R_SUCCEEDED (nifmGetInternetConnectionStatus (&type, &wifiStrength, &status))) { - if (status == NifmInternetConnectionStatus_Connected) - netIcon = ETH_ICON; + if (type == NifmInternetConnectionType_Ethernet) + { + if (status == NifmInternetConnectionStatus_Connected) + netIcon = ETH_ICON; + else + netIcon = ETH_NONE_ICON; + } else - netIcon = ETH_NONE_ICON; - } - else - { - if (wifiStrength >= 3) - netIcon = WIFI3_ICON; - else if (wifiStrength == 2) - netIcon = WIFI3_ICON; - else if (wifiStrength == 1) - netIcon = WIFI3_ICON; - else if (wifiStrength == 0) - netIcon = WIFI_NONE_ICON; + { + if (wifiStrength >= 3) + netIcon = WIFI3_ICON; + else if (wifiStrength == 2) + netIcon = WIFI3_ICON; + else if (wifiStrength == 1) + netIcon = WIFI3_ICON; + else if (wifiStrength == 0) + netIcon = WIFI_NONE_ICON; + } } } @@ -547,6 +555,15 @@ void drawStatus () 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 char timeBuffer[16]; @@ -598,22 +615,154 @@ bool platform::init () 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 () { + if (s_activeAP) + return true; + NifmInternetConnectionType type; std::uint32_t wifi; NifmInternetConnectionStatus status; if (R_FAILED (nifmGetInternetConnectionStatus (&type, &wifi, &status))) return false; -#ifdef CLASSIC - if (!s_addr) - s_addr = gethostid (); -#endif - 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 (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 () { if (!appletMainLoop ()) @@ -672,7 +821,7 @@ void platform::render () #else ImGui::Render (); - auto &io = ImGui::GetIO (); + auto const &io = ImGui::GetIO (); if (s_width != io.DisplaySize.x || s_height != io.DisplaySize.y) { @@ -726,6 +875,13 @@ void platform::exit () if (!s_backlight) appletSetLcdBacklightOffEnabled (false); + + if (s_activeAP) + { + lp2pDestroyGroup (); + lp2pExit (); + s_activeAP = false; + } } ///////////////////////////////////////////////////////////////////////////