Fix static analysis reports

This commit is contained in:
Michael Theall 2024-11-03 17:38:51 -06:00
parent 9a73b92497
commit 41e467f47b
18 changed files with 369 additions and 267 deletions

View File

@ -2,6 +2,18 @@ cmake_minimum_required(VERSION 3.12)
project(ftpd VERSION 3.2.0)
if(CMAKE_EXPORT_COMPILE_COMMANDS)
list(APPEND CMAKE_C_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES})
list(APPEND CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
endif()
include(FetchContent)
FetchContent_Declare(gsl
GIT_REPOSITORY https://github.com/microsoft/GSL.git
GIT_TAG v4.0.0
)
FetchContent_Populate(gsl)
option(FTPD_CLASSIC "Build ${PROJECT_NAME} classic" OFF)
if(FTPD_CLASSIC AND (NINTENDO_SWITCH OR NINTENDO_3DS))
@ -12,6 +24,8 @@ endif()
add_executable(${FTPD_TARGET})
target_include_directories(${FTPD_TARGET} PRIVATE ${gsl_SOURCE_DIR}/include)
if(NINTENDO_SWITCH OR NINTENDO_3DS OR NINTENDO_DS)
dkp_target_generate_symbol_list(${FTPD_TARGET})
endif()

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2020 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -22,6 +22,8 @@
#include "ioBuffer.h"
#include <gsl/gsl>
#include <dirent.h>
#include <cstdint>
@ -29,6 +31,7 @@
#include <cstdlib>
#include <memory>
#include <string_view>
#include <vector>
namespace fs
{
@ -69,7 +72,7 @@ public:
/// \brief Open file
/// \param path_ Path to open
/// \param mode_ Access mode (\sa std::fopen)
bool open (char const *path_, char const *mode_ = "rb");
bool open (gsl::not_null<gsl::czstring> path_, gsl::not_null<gsl::czstring> mode_ = "rb");
/// \brief Close file
void close ();
@ -77,13 +80,13 @@ public:
/// \brief Seek to file position
/// \param pos_ File position
/// \param origin_ Reference position (\sa std::fseek)
std::make_signed_t<std::size_t> seek (std::size_t pos_, int origin_);
std::make_signed_t<std::size_t> seek (std::make_signed_t<std::size_t> pos_, int origin_);
/// \brief Read data
/// \param buffer_ Output buffer
/// \param size_ Size to read
/// \note Can return partial reads
std::make_signed_t<std::size_t> read (void *buffer_, std::size_t size_);
std::make_signed_t<std::size_t> read (gsl::not_null<void *> buffer_, std::size_t size_);
/// \brief Read data
/// \param buffer_ Output buffer
@ -97,13 +100,13 @@ public:
/// \param buffer_ Output buffer
/// \param size_ Size to read
/// \note Fails on partial reads and errors
bool readAll (void *buffer_, std::size_t size_);
bool readAll (gsl::not_null<void *> buffer_, std::size_t size_);
/// \brief Write data
/// \param buffer_ Input data
/// \param size_ Size to write
/// \note Can return partial writes
std::make_signed_t<std::size_t> write (void const *buffer_, std::size_t size_);
std::make_signed_t<std::size_t> write (gsl::not_null<void const *> buffer_, std::size_t size_);
/// \brief Write data
/// \param buffer_ Input data
@ -114,20 +117,17 @@ public:
/// \param buffer_ Input data
/// \param size_ Size to write
/// \note Fails on partials writes and errors
bool writeAll (void const *buffer_, std::size_t size_);
bool writeAll (gsl::not_null<void const *> buffer_, std::size_t size_);
private:
/// \brief Underlying std::FILE*
std::unique_ptr<std::FILE, int (*) (std::FILE *)> m_fp{nullptr, nullptr};
/// \brief Buffer
std::unique_ptr<char[]> m_buffer;
/// \brief Buffer size
std::size_t m_bufferSize = 0;
std::vector<char> m_buffer;
/// \brief Line buffer
char *m_lineBuffer = nullptr;
gsl::owner<char *> m_lineBuffer = nullptr;
/// \brief Line buffer size
std::size_t m_lineBufferSize = 0;
@ -161,14 +161,14 @@ public:
/// \brief Open directory
/// \param path_ Path to open
bool open (char const *const path_);
bool open (gsl::not_null<gsl::czstring> path_);
/// \brief Close directory
void close ();
/// \brief Read a directory entry
/// \note Returns nullptr on end-of-directory or error; check errno
struct dirent *read ();
dirent *read ();
private:
/// \brief Underlying DIR*

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2023 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -22,10 +22,13 @@
#include "platform.h"
#include <gsl/gsl>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
class FtpConfig;
using UniqueFtpConfig = std::unique_ptr<FtpConfig>;
@ -41,7 +44,7 @@ public:
/// \brief Load config
/// \param path_ Path to config file
static UniqueFtpConfig load (char const *path_);
static UniqueFtpConfig load (gsl::not_null<gsl::czstring> path_);
#ifndef __NDS__
std::scoped_lock<platform::Mutex> lockGuard ();
@ -49,7 +52,7 @@ public:
/// \brief Save config
/// \param path_ Path to config file
bool save (char const *path_);
bool save (gsl::not_null<gsl::czstring> path_);
/// \brief Get user
std::string const &user () const;
@ -79,15 +82,15 @@ public:
/// \brief Set user
/// \param user_ User
void setUser (std::string const &user_);
void setUser (std::string user_);
/// \brief Set password
/// \param pass_ Password
void setPass (std::string const &pass_);
void setPass (std::string pass_);
/// \brief Set listen port
/// \param port_ Listen port
bool setPort (std::string const &port_);
bool setPort (std::string_view port_);
/// \brief Set listen port
/// \param port_ Listen port
@ -106,11 +109,11 @@ public:
/// \brief Set access point SSID
/// \param ssid_ SSID
void setSSID (std::string const &ssid_);
void setSSID (std::string_view ssid_);
/// \brief Set access point passphrase
/// \param passphrase_ Passphrase
void setPassphrase (std::string const &passphrase_);
void setPassphrase (std::string_view passphrase_);
#endif
private:

View File

@ -117,7 +117,7 @@ private:
std::vector<UniqueFtpSession> m_sessions;
/// \brief Whether thread should quit
std::atomic<bool> m_quit;
std::atomic_bool m_quit = false;
#ifndef CLASSIC
/// \brief Log upload cURL context
@ -152,7 +152,7 @@ private:
std::string m_passSetting;
/// \brief Port setting
std::uint16_t m_portSetting;
std::uint16_t m_portSetting = 0;
#ifdef __3DS__
/// \brief getMTime setting
@ -161,7 +161,7 @@ private:
#ifdef __SWITCH__
/// \brief Whether an error occurred enabling access point
std::atomic<bool> m_apError = false;
std::atomic_bool m_apError = false;
/// \brief Enable access point setting
bool m_enableAPSetting;

View File

@ -27,10 +27,12 @@
#include "socket.h"
#include <sys/stat.h>
using stat_t = struct stat;
#include <chrono>
#include <ctime>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include <vector>
@ -165,18 +167,18 @@ private:
/// \brief Perform stat and apply tz offset to mtime
/// \param path_ Path to stat
/// \param st_ Output stat
int tzStat (char const *const path_, struct stat *st_);
int tzStat (char const *const path_, stat_t *st_);
/// \brief Perform lstat and apply tz offset to mtime
/// \param path_ Path to lstat
/// \param st_ Output stat
int tzLStat (char const *const path_, struct stat *st_);
int tzLStat (char const *const path_, stat_t *st_);
/// \brief Fill directory entry
/// \param st_ Entry status
/// \param path_ Path name
/// \param type_ MLST type
int fillDirent (struct stat const &st_, std::string_view path_, char const *type_ = nullptr);
int fillDirent (stat_t const &st_, std::string_view path_, char const *type_ = nullptr);
/// \brief Fill directory entry
/// \param path_ Path name

View File

@ -58,44 +58,46 @@ public:
SockAddr &operator= (SockAddr &&that_);
/// \brief Parameterized constructor
/// \param addr_ Address
SockAddr (struct sockaddr_in const &addr_);
/// \param addr_ Address (network byte order)
SockAddr (sockaddr_in const &addr_);
#ifndef NO_IPV6
/// \brief Parameterized constructor
/// \param addr_ Address
SockAddr (struct sockaddr_in6 const &addr_);
/// \param addr_ Address (network byte order)
SockAddr (sockaddr_in6 const &addr_);
#endif
/// \brief Parameterized constructor
/// \param addr_ Address
SockAddr (struct sockaddr_storage const &addr_);
/// \param addr_ Address (network byte order)
SockAddr (sockaddr_storage const &addr_);
/// \brief sockaddr_in cast operator
operator struct sockaddr_in const & () const;
/// \brief sockaddr_in cast operator (network byte order)
operator sockaddr_in const & () const;
#ifndef NO_IPV6
/// \brief sockaddr_in6 cast operator
operator struct sockaddr_in6 const & () const;
/// \brief sockaddr_in6 cast operator (network byte order)
operator sockaddr_in6 const & () const;
#endif
/// \brief sockaddr_storage cast operator
operator struct sockaddr_storage const & () const;
/// \brief sockaddr_storage cast operator (network byte order)
operator sockaddr_storage const & () const;
/// \brief sockaddr* cast operator (network byte order)
operator sockaddr * ();
/// \brief sockaddr const* cast operator (network byte order)
operator sockaddr const * () const;
/// \brief sockaddr* cast operator
operator struct sockaddr * ();
/// \brief sockaddr const* cast operator
operator struct sockaddr const * () const;
/// \brief sockaddr size
socklen_t size () const;
/// \brief Address port
/// \brief Address port (host byte order)
std::uint16_t port () const;
/// \brief Set address port
/// \param port_ Port to set
bool setPort (std::uint16_t port_);
/// \param port_ Port to set (host byte order)
void setPort (std::uint16_t port_);
/// \brief Address name
/// \param buffer_ Buffer to hold name
@ -110,6 +112,6 @@ public:
char const *name () const;
private:
/// \brief Address storage
struct sockaddr_storage m_addr = {};
/// \brief Address storage (network byte order)
sockaddr_storage m_addr = {};
};

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2023 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -37,7 +37,7 @@ struct pollfd
using socklen_t = int;
using nfds_t = unsigned int;
extern "C" int poll (struct pollfd *fds_, nfds_t nfds_, int timeout_);
extern "C" int poll (pollfd *fds_, nfds_t nfds_, int timeout_);
#define POLLIN (1 << 0)
#define POLLPRI (1 << 1)

View File

@ -70,7 +70,7 @@ static_assert (SOCU_BUFFERSIZE % SOCU_ALIGN == 0);
bool s_ndmuLocked = false;
/// \brief Whether soc:u is active
std::atomic<bool> s_socuActive = false;
std::atomic_bool s_socuActive = false;
/// \brief soc:u buffer
u32 *s_socuBuffer = nullptr;
/// \brief ac:u fence
@ -569,7 +569,7 @@ bool platform::networkVisible ()
bool platform::networkAddress (SockAddr &addr_)
{
struct sockaddr_in addr;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = gethostid ();

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2023 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -19,11 +19,24 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "fs.h"
#include "ioBuffer.h"
#include <gsl/pointers>
#include <gsl/util>
#include <array>
#include <cassert>
#include <cerrno>
#include <cinttypes>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <dirent.h>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#if defined(__NDS__) || defined(__3DS__) || defined(__SWITCH__)
#define getline __getline
@ -38,7 +51,7 @@ std::string fs::printSize (std::uint64_t const size_)
constexpr std::uint64_t const PiB = 1024 * TiB;
constexpr std::uint64_t const EiB = 1024 * PiB;
char buffer[64] = {};
std::array<char, 64> buffer{};
for (auto const &[name, bin] : {
// clang-format off
@ -56,30 +69,32 @@ std::string fs::printSize (std::uint64_t const size_)
if (size_ >= 100 * bin)
{
// >= 100, print xxxXiB
std::sprintf (buffer, "%" PRIu64 "%s", whole, name);
return buffer;
std::size_t const size = std::sprintf (buffer.data (), "%" PRIu64 "%s", whole, name);
return {buffer.data (), size};
}
// get the fractional portion of the number
auto const frac = size_ - whole * bin;
auto const frac = size_ - (whole * bin);
if (size_ >= 10 * bin)
{
// >= 10, print xx.xXiB
std::sprintf (buffer, "%" PRIu64 ".%" PRIu64 "%s", whole, frac * 10 / bin, name);
return buffer;
std::size_t const size = std::sprintf (
buffer.data (), "%" PRIu64 ".%" PRIu64 "%s", whole, frac * 10 / bin, name);
return {buffer.data (), size};
}
if (size_ >= 1000 * (bin / KiB))
{
// >= 1000 of lesser bin, print x.xxXiB
std::sprintf (buffer, "%" PRIu64 ".%02" PRIu64 "%s", whole, frac * 100 / bin, name);
return buffer;
std::size_t const size = std::sprintf (
buffer.data (), "%" PRIu64 ".%02" PRIu64 "%s", whole, frac * 100 / bin, name);
return {buffer.data (), size};
}
}
// < 1KiB, just print the number
std::sprintf (buffer, "%" PRIu64 "B", size_);
return buffer;
std::size_t const size = std::sprintf (buffer.data (), "%" PRIu64 "B", size_);
return {buffer.data (), size};
}
///////////////////////////////////////////////////////////////////////////
@ -106,26 +121,24 @@ fs::File::operator FILE * () const
void fs::File::setBufferSize (std::size_t const size_)
{
if (m_bufferSize != size_)
{
m_buffer = std::make_unique<char[]> (size_);
m_bufferSize = size_;
}
if (m_buffer.size () != size_)
m_buffer.resize (size_);
if (m_fp)
std::setvbuf (m_fp.get (), m_buffer.get (), _IOFBF, m_bufferSize);
(void)std::setvbuf (m_fp.get (), m_buffer.data (), _IOFBF, m_buffer.size ());
}
bool fs::File::open (char const *const path_, char const *const mode_)
bool fs::File::open (gsl::not_null<char const *> const path_,
gsl::not_null<char const *> const mode_)
{
auto const fp = std::fopen (path_, mode_);
gsl::owner<FILE *> fp = std::fopen (path_, mode_);
if (!fp)
return false;
m_fp = std::unique_ptr<std::FILE, int (*) (std::FILE *)> (fp, &std::fclose);
if (m_buffer)
std::setvbuf (m_fp.get (), m_buffer.get (), _IOFBF, m_bufferSize);
if (!m_buffer.empty ())
(void)std::setvbuf (m_fp.get (), m_buffer.data (), _IOFBF, m_buffer.size ());
return true;
}
@ -135,17 +148,27 @@ void fs::File::close ()
m_fp.reset ();
}
std::make_signed_t<std::size_t> fs::File::seek (std::size_t const pos_, int const origin_)
std::make_signed_t<std::size_t> fs::File::seek (std::make_signed_t<std::size_t> const pos_,
int const origin_)
{
return std::fseek (m_fp.get (), pos_, origin_);
}
std::make_signed_t<std::size_t> fs::File::read (void *const buffer_, std::size_t const size_)
std::make_signed_t<std::size_t> fs::File::read (gsl::not_null<void *> const buffer_,
std::size_t const size_)
{
assert (buffer_);
assert (size_ > 0);
return std::fread (buffer_, 1, size_, m_fp.get ());
auto const rc = std::fread (buffer_, 1, size_, m_fp.get ());
if (rc == 0)
{
if (std::feof (m_fp.get ()))
return 0;
return -1;
}
return gsl::narrow_cast<std::make_signed_t<std::size_t>> (rc);
}
std::make_signed_t<std::size_t> fs::File::read (IOBuffer &buffer_)
@ -176,37 +199,41 @@ std::string_view fs::File::readLine ()
}
if (rc > 0)
return std::string_view (m_lineBuffer, rc);
return {m_lineBuffer, gsl::narrow_cast<std::size_t> (rc)};
}
}
bool fs::File::readAll (void *const buffer_, std::size_t const size_)
bool fs::File::readAll (gsl::not_null<void *> const buffer_, std::size_t const size_)
{
assert (buffer_);
assert (size_ > 0);
auto p = static_cast<char *> (buffer_);
auto const p = static_cast<char *> (buffer_.get ());
std::size_t bytes = 0;
while (bytes < size_)
{
auto const rc = read (p, size_ - bytes);
auto const rc = read (p + bytes, size_ - bytes);
if (rc <= 0)
return false;
p += rc;
bytes += rc;
}
return true;
}
std::make_signed_t<std::size_t> fs::File::write (void const *const buffer_, std::size_t const size_)
std::make_signed_t<std::size_t> fs::File::write (gsl::not_null<void const *> const buffer_,
std::size_t const size_)
{
assert (buffer_);
assert (size_ > 0);
return std::fwrite (buffer_, 1, size_, m_fp.get ());
auto const rc = std::fwrite (buffer_, 1, size_, m_fp.get ());
if (rc == 0)
return -1;
return gsl::narrow_cast<std::make_signed_t<std::size_t>> (rc);
}
std::make_signed_t<std::size_t> fs::File::write (IOBuffer &buffer_)
@ -220,21 +247,20 @@ std::make_signed_t<std::size_t> fs::File::write (IOBuffer &buffer_)
return rc;
}
bool fs::File::writeAll (void const *const buffer_, std::size_t const size_)
bool fs::File::writeAll (gsl::not_null<void const *> const buffer_, std::size_t const size_)
{
assert (buffer_);
assert (size_ > 0);
auto p = static_cast<char const *> (buffer_);
auto const p = static_cast<char const *> (buffer_.get ());
std::size_t bytes = 0;
while (bytes < size_)
{
auto const rc = write (p, size_ - bytes);
auto const rc = write (p + bytes, size_ - bytes);
if (rc <= 0)
return false;
p += rc;
bytes += rc;
}
@ -260,7 +286,7 @@ fs::Dir::operator DIR * () const
return m_dp.get ();
}
bool fs::Dir::open (char const *const path_)
bool fs::Dir::open (gsl::not_null<char const *> const path_)
{
auto const dp = ::opendir (path_);
if (!dp)
@ -275,7 +301,7 @@ void fs::Dir::close ()
m_dp.reset ();
}
struct dirent *fs::Dir::read ()
dirent *fs::Dir::read ()
{
errno = 0;
return ::readdir (m_dp.get ());

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2023 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -22,24 +22,36 @@
#include "fs.h"
#include "log.h"
#include "platform.h"
#include <gsl/pointers>
#include <sys/stat.h>
using stat_t = struct stat;
#include <limits>
#include <cctype>
#include <cerrno>
#include <charconv>
#include <cstdint>
#include <cstdio>
#include <mutex>
#include <string>
#include <string_view>
#include <system_error>
#include <utility>
namespace
{
constexpr std::uint16_t DEFAULT_PORT = 5000;
bool mkdirParent (std::string const &path_)
bool mkdirParent (std::string_view const path_)
{
auto pos = path_.find_first_of ('/');
while (pos != std::string::npos)
{
auto const dir = path_.substr (0, pos);
auto const dir = std::string (path_.substr (0, pos));
struct stat st;
stat_t st{};
auto const rc = ::stat (dir.c_str (), &st);
if (rc < 0 && errno != ENOENT)
return false;
@ -57,14 +69,13 @@ bool mkdirParent (std::string const &path_)
return true;
}
std::string strip (std::string const &str_)
std::string_view strip (std::string_view const str_)
{
auto const start = str_.find_first_not_of (" \t");
if (start == std::string::npos)
return {};
auto const end = str_.find_last_not_of (" \t");
if (end == std::string::npos)
return str_.substr (start);
@ -72,37 +83,21 @@ std::string strip (std::string const &str_)
}
template <typename T>
bool parseInt (T &out_, std::string const &val_)
bool parseInt (T &out_, std::string_view const val_)
{
T val = 0;
for (auto const &c : val_)
auto const rc = std::from_chars (val_.data (), val_.data () + val_.size (), out_);
if (rc.ec != std::errc{})
{
if (!std::isdigit (c))
{
errno = EINVAL;
return false;
}
if (std::numeric_limits<T>::max () / 10 < val)
{
errno = EOVERFLOW;
return false;
}
val *= 10;
auto const v = c - '0';
if (std::numeric_limits<T>::max () - v < val)
{
errno = EOVERFLOW;
return false;
}
val += v;
errno = static_cast<int> (rc.ec);
return false;
}
if (rc.ptr != val_.data () + val_.size ())
{
errno = EINVAL;
return false;
}
out_ = val;
return true;
}
}
@ -119,7 +114,7 @@ UniqueFtpConfig FtpConfig::create ()
return UniqueFtpConfig (new FtpConfig ());
}
UniqueFtpConfig FtpConfig::load (char const *const path_)
UniqueFtpConfig FtpConfig::load (gsl::not_null<gsl::czstring> const path_)
{
auto config = create ();
@ -139,8 +134,8 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
continue;
}
auto const key = strip (line.substr (0, pos));
auto const val = strip (line.substr (pos + 1));
auto const key = strip (std::string_view (line).substr (0, pos));
auto const val = strip (std::string_view (line).substr (pos + 1));
if (key.empty () || val.empty ())
{
error ("Ignoring '%s'\n", line.c_str ());
@ -161,7 +156,9 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
else if (val == "1")
config->m_getMTime = true;
else
error ("Invalid value for mtime: %s\n", val.c_str ());
error ("Invalid value for mtime: %.*s\n",
gsl::narrow_cast<int> (val.size ()),
val.data ());
}
#endif
#ifdef __SWITCH__
@ -172,7 +169,9 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
else if (val == "1")
config->m_enableAP = true;
else
error ("Invalid value for ap: %s\n", val.c_str ());
error ("Invalid value for ap: %.*s\n",
gsl::narrow_cast<int> (val.size ()),
val.data ());
}
else if (key == "ssid")
config->m_ssid = val;
@ -193,9 +192,9 @@ std::scoped_lock<platform::Mutex> FtpConfig::lockGuard ()
}
#endif
bool FtpConfig::save (char const *const path_)
bool FtpConfig::save (gsl::not_null<gsl::czstring> const path_)
{
if (!mkdirParent (path_))
if (!mkdirParent (path_.get ()))
return false;
auto fp = fs::File ();
@ -203,21 +202,21 @@ bool FtpConfig::save (char const *const path_)
return false;
if (!m_user.empty ())
std::fprintf (fp, "user=%s\n", m_user.c_str ());
(void)std::fprintf (fp, "user=%s\n", m_user.c_str ());
if (!m_pass.empty ())
std::fprintf (fp, "pass=%s\n", m_pass.c_str ());
std::fprintf (fp, "port=%u\n", m_port);
(void)std::fprintf (fp, "pass=%s\n", m_pass.c_str ());
(void)std::fprintf (fp, "port=%u\n", m_port);
#ifdef __3DS__
std::fprintf (fp, "mtime=%u\n", m_getMTime);
(void)std::fprintf (fp, "mtime=%u\n", m_getMTime);
#endif
#ifdef __SWITCH__
std::fprintf (fp, "ap=%u\n", m_enableAP);
(void)std::fprintf (fp, "ap=%u\n", m_enableAP);
if (!m_ssid.empty ())
std::fprintf (fp, "ssid=%s\n", m_ssid.c_str ());
(void)std::fprintf (fp, "ssid=%s\n", m_ssid.c_str ());
if (!m_passphrase.empty ())
std::fprintf (fp, "passphrase=%s\n", m_passphrase.c_str ());
(void)std::fprintf (fp, "passphrase=%s\n", m_passphrase.c_str ());
#endif
return true;
@ -262,19 +261,19 @@ std::string const &FtpConfig::passphrase () const
}
#endif
void FtpConfig::setUser (std::string const &user_)
void FtpConfig::setUser (std::string user_)
{
m_user = user_.substr (0, user_.find_first_of ('\0'));
m_user = std::move (user_);
}
void FtpConfig::setPass (std::string const &pass_)
void FtpConfig::setPass (std::string pass_)
{
m_pass = pass_.substr (0, pass_.find_first_of ('\0'));
m_pass = std::move (pass_);
}
bool FtpConfig::setPort (std::string const &port_)
bool FtpConfig::setPort (std::string_view const port_)
{
std::uint16_t parsed;
std::uint16_t parsed{};
if (!parseInt (parsed, port_))
return false;
@ -317,12 +316,12 @@ void FtpConfig::setEnableAP (bool const enable_)
m_enableAP = enable_;
}
void FtpConfig::setSSID (std::string const &ssid_)
void FtpConfig::setSSID (std::string_view const ssid_)
{
m_ssid = ssid_.substr (0, ssid_.find_first_of ('\0'));
}
void FtpConfig::setPassphrase (std::string const &passphrase_)
void FtpConfig::setPassphrase (std::string_view const passphrase_)
{
m_passphrase = passphrase_.substr (0, passphrase_.find_first_of ('\0'));
}

View File

@ -21,9 +21,12 @@
#include "ftpServer.h"
#include "fs.h"
#include "ftpConfig.h"
#include "ftpSession.h"
#include "licenses.h"
#include "log.h"
#include "platform.h"
#include "sockAddr.h"
#include "socket.h"
#include "imgui.h"
@ -32,22 +35,38 @@
#include <dswifi9.h>
#endif
#ifndef CLASSIC
#include <jansson.h>
#ifdef __3DS__
#include <citro3d.h>
#endif
#ifndef CLASSIC
#include <jansson.h>
#include <curl/easy.h>
#include <curl/multi.h>
#ifndef NDEBUG
#include <curl/curl.h>
#endif
#endif
#include <arpa/inet.h>
#include <sys/statvfs.h>
#include <unistd.h>
using statvfs_t = struct statvfs;
#include <algorithm>
#include <array>
#include <atomic>
#include <cctype>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <functional>
#include <mutex>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>
using namespace std::chrono_literals;
#ifdef __NDS__
@ -81,21 +100,33 @@ std::string s_freeSpace;
#ifndef CLASSIC
#ifndef NDEBUG
std::string printable (char *const data_, std::size_t const size_)
std::string printable (std::string_view const data_)
{
std::string result;
result.reserve (size_);
for (std::size_t i = 0; i < size_; ++i)
unsigned count = 0;
for (auto const &c : data_)
{
if (std::isprint (data_[i]) || std::isspace (data_[i]))
result.push_back (data_[i]);
if (c != '%' && (std::isprint (c) || std::isspace (c)))
++count;
else
count += 3;
}
std::string result;
result.reserve (count);
for (auto const &c : data_)
{
if (c != '%' && (std::isprint (c) || std::isspace (c)))
result.push_back (c);
else
{
char buffer[5];
std::snprintf (
buffer, sizeof (buffer), "%%%02u", static_cast<unsigned char> (data_[i]));
result += buffer;
result.push_back ('%');
auto const upper = (static_cast<unsigned char> (c) >> 4u) & 0xF;
auto const lower = (static_cast<unsigned char> (c) >> 0u) & 0xF;
result.push_back (gsl::narrow_cast<char> (upper < 10 ? upper + '0' : upper + 'A' - 10));
result.push_back (gsl::narrow_cast<char> (lower < 10 ? lower + '0' : lower + 'A' - 10));
}
}
@ -111,7 +142,7 @@ int curlDebug (CURL *const handle_,
(void)handle_;
(void)user_;
auto const text = printable (data_, size_);
auto const text = printable (std::string_view (data_, size_));
switch (type_)
{
@ -190,7 +221,8 @@ FtpServer::~FtpServer ()
#endif
}
FtpServer::FtpServer (UniqueFtpConfig config_) : m_config (std::move (config_)), m_quit (false)
FtpServer::FtpServer (UniqueFtpConfig config_)
: m_config (std::move (config_))
{
#ifndef __NDS__
m_thread = platform::Thread (std::bind (&FtpServer::threadFunc, this));
@ -279,17 +311,17 @@ void FtpServer::draw ()
ImGui::SetNextWindowSize (ImVec2 (width, height));
#endif
{
char title[64];
std::array<char, 64> title{};
{
auto const serverLock = std::scoped_lock (m_lock);
std::snprintf (title,
sizeof (title),
std::snprintf (title.data (),
title.size (),
STATUS_STRING " %s###ftpd",
m_socket ? m_name.c_str () : "Waiting for WiFi...");
}
ImGui::Begin (title,
ImGui::Begin (title.data (),
nullptr,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
#ifndef __3DS__
@ -361,7 +393,7 @@ std::string FtpServer::getFreeSpace ()
void FtpServer::updateFreeSpace ()
{
struct statvfs st;
statvfs_t st = {};
#if defined(__NDS__) || defined(__3DS__) || defined(__SWITCH__)
if (::statvfs ("sdmc:/", &st) != 0)
#else
@ -440,8 +472,9 @@ void FtpServer::handleNetworkLost ()
}
{
// destroy command socket
UniqueSocket sock;
// destroy command socket
LOCKED (sock = std::move (m_socket));
}

View File

@ -38,6 +38,7 @@
#include <cstring>
#include <ctime>
#include <mutex>
#include <string>
using namespace std::chrono_literals;
#if defined(__NDS__) || defined(__3DS__) || defined(__SWITCH__)
@ -60,6 +61,33 @@ namespace
/// \brief Idle timeout
constexpr auto IDLE_TIMEOUT = 60;
/// \brief Check if string view is a C string
/// \param str_ String to check
bool isCString (std::string_view const str_)
{
return str_.find_first_of ('\0') != std::string_view::npos;
}
/// \brief Case-insensitive string compare
/// \param lhs_ Left string
/// \param rhs_ Right string
int compare (std::string_view const lhs_, std::string_view const rhs_)
{
if (isCString (lhs_) && isCString (rhs_))
return ::strcasecmp (lhs_.data (), rhs_.data ());
auto const maxLen = std::min (lhs_.size (), rhs_.size ());
for (unsigned i = 0; i < maxLen; ++i)
{
auto const l = std::tolower (lhs_[i]);
auto const r = std::tolower (rhs_[i]);
if (l != r)
return l - r;
}
return gsl::narrow_cast<int> (lhs_.size ()) - gsl::narrow_cast<int> (rhs_.size ());
}
/// \brief Parse command
/// \param buffer_ Buffer to parse
/// \param size_ Size of buffer
@ -171,7 +199,7 @@ std::string resolvePath (std::string_view const path_)
assert (path_[0] == '/');
// make sure parent is a directory
struct stat st;
stat_t st;
if (::stat (dirName (path_).c_str (), &st) != 0)
return {};
@ -385,7 +413,8 @@ void FtpSession::draw ()
auto const timeDiff = now - m_filePositionTime;
m_filePositionTime = now;
auto const rate = diff / std::chrono::duration<float> (timeDiff).count ();
auto const rate =
gsl::narrow_cast<float> (diff) / std::chrono::duration<float> (timeDiff).count ();
auto const alpha = 0.01f;
m_xferRate = alpha * rate + (1.0f - alpha) * m_xferRate;
}
@ -469,7 +498,7 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
for (auto &pending : session->m_pendingCloseSocket)
{
assert (pending.unique ());
pollInfo.emplace_back (Socket::PollInfo{*pending, POLLIN, 0});
pollInfo.emplace_back (*pending, POLLIN, 0);
}
}
@ -513,8 +542,7 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
{
if (session->m_commandSocket)
{
pollInfo.emplace_back (
Socket::PollInfo{*session->m_commandSocket, POLLIN | POLLPRI, 0});
pollInfo.emplace_back (*session->m_commandSocket, POLLIN | POLLPRI, 0);
if (session->m_responseBuffer.usedSize () != 0)
pollInfo.back ().events |= POLLOUT;
}
@ -530,12 +558,12 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
{
assert (!session->m_port);
// we are waiting for a PASV connection
pollInfo.emplace_back (Socket::PollInfo{*session->m_pasvSocket, POLLIN, 0});
pollInfo.emplace_back (*session->m_pasvSocket, POLLIN, 0);
}
else
{
// we are waiting to complete a PORT connection
pollInfo.emplace_back (Socket::PollInfo{*session->m_dataSocket, POLLOUT, 0});
pollInfo.emplace_back (*session->m_dataSocket, POLLOUT, 0);
}
break;
@ -544,12 +572,12 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
if (session->m_recv)
{
assert (!session->m_send);
pollInfo.emplace_back (Socket::PollInfo{*session->m_dataSocket, POLLIN, 0});
pollInfo.emplace_back (*session->m_dataSocket, POLLIN, 0);
}
else
{
assert (session->m_send);
pollInfo.emplace_back (Socket::PollInfo{*session->m_dataSocket, POLLOUT, 0});
pollInfo.emplace_back (*session->m_dataSocket, POLLOUT, 0);
}
break;
}
@ -751,7 +779,7 @@ bool FtpSession::changeDir (char const *const args_)
if (path.empty ())
return false;
struct stat st;
stat_t st;
if (tzStat (path.c_str (), &st) != 0)
return false;
@ -834,7 +862,7 @@ bool FtpSession::dataConnect ()
return true;
}
int FtpSession::tzStat (char const *const path_, struct stat *st_)
int FtpSession::tzStat (char const *const path_, stat_t *st_)
{
auto const rc = ::stat (path_, st_);
if (rc != 0)
@ -855,7 +883,7 @@ int FtpSession::tzStat (char const *const path_, struct stat *st_)
return 0;
}
int FtpSession::tzLStat (char const *const path_, struct stat *st_)
int FtpSession::tzLStat (char const *const path_, stat_t *st_)
{
auto const rc = ::lstat (path_, st_);
if (rc != 0)
@ -876,7 +904,7 @@ int FtpSession::tzLStat (char const *const path_, struct stat *st_)
return 0;
}
int FtpSession::fillDirent (struct stat const &st_, std::string_view const path_, char const *type_)
int FtpSession::fillDirent (stat_t const &st_, std::string_view const path_, char const *type_)
{
auto const buffer = m_xferBuffer.freeArea ();
auto const size = m_xferBuffer.freeSize ();
@ -1162,7 +1190,7 @@ int FtpSession::fillDirent (struct stat const &st_, std::string_view const path_
int FtpSession::fillDirent (std::string const &path_, char const *type_)
{
struct stat st;
stat_t st;
if (tzStat (path_.c_str (), &st) != 0)
return errno;
@ -1189,7 +1217,7 @@ void FtpSession::xferFile (char const *const args_, XferFileMode const mode_)
else if (mode_ == XferFileMode::RETR)
{
// stat the file
struct stat st;
stat_t st;
if (tzStat (path.c_str (), &st) != 0)
{
sendResponse ("450 %s\r\n", std::strerror (errno));
@ -1321,7 +1349,7 @@ void FtpSession::xferDir (char const *const args_, XferDirMode const mode_, bool
return;
}
struct stat st;
stat_t st;
if (tzStat (path.c_str (), &st) != 0)
{
if (needWorkaround)
@ -1600,12 +1628,10 @@ void FtpSession::readCommand (int const events_)
auto const it = std::lower_bound (std::begin (handlers),
std::end (handlers),
command,
[] (auto const &lhs_, auto const &rhs_) {
return ::strcasecmp (lhs_.first.data (), rhs_) < 0;
});
[] (auto const &lhs_, auto const &rhs_) { return compare (lhs_.first, rhs_) < 0; });
m_timestamp = std::time (nullptr);
if (it == std::end (handlers) || ::strcasecmp (it->first.data (), command) != 0)
if (it == std::end (handlers) || compare (it->first, command) != 0)
{
std::string response = "502 Invalid command \"";
response += encodePath (command);
@ -1623,9 +1649,9 @@ void FtpSession::readCommand (int const events_)
else if (m_state != State::COMMAND)
{
// only some commands are available during data transfer
if (::strcasecmp (command, "ABOR") != 0 && ::strcasecmp (command, "NOOP") != 0 &&
::strcasecmp (command, "PWD") != 0 && ::strcasecmp (command, "QUIT") != 0 &&
::strcasecmp (command, "STAT") != 0 && ::strcasecmp (command, "XPWD") != 0)
if (compare (command, "ABOR") != 0 && compare (command, "NOOP") != 0 &&
compare (command, "PWD") != 0 && compare (command, "QUIT") != 0 &&
compare (command, "STAT") != 0 && compare (command, "XPWD") != 0)
{
sendResponse ("503 Invalid command during transfer\r\n");
setState (State::COMMAND, true, true);
@ -1640,7 +1666,7 @@ void FtpSession::readCommand (int const events_)
else
{
// clear rename for all commands except RNTO
if (::strcasecmp (command, "RNTO") != 0)
if (compare (command, "RNTO") != 0)
m_rename.clear ();
auto const handler = it->second;
@ -1791,7 +1817,7 @@ bool FtpSession::listTransfer ()
{
// build the path
auto const fullPath = buildPath (m_lwd, dent->d_name);
struct stat st;
stat_t st;
#ifdef __3DS__
// the sdmc directory entry already has the type and size, so no need to do a slow stat
@ -2220,7 +2246,7 @@ void FtpSession::MODE (char const *args_)
setState (State::COMMAND, false, false);
// we only accept S (stream) mode
if (::strcasecmp (args_, "S") == 0)
if (compare (args_, "S") == 0)
{
sendResponse ("200 OK\r\n");
return;
@ -2254,8 +2280,8 @@ void FtpSession::OPTS (char const *args_)
setState (State::COMMAND, false, false);
// check UTF8 options
if (::strcasecmp (args_, "UTF8") == 0 || ::strcasecmp (args_, "UTF8 ON") == 0 ||
::strcasecmp (args_, "UTF8 NLST") == 0)
if (compare (args_, "UTF8") == 0 || compare (args_, "UTF8 ON") == 0 ||
compare (args_, "UTF8 NLST") == 0)
{
sendResponse ("200 OK\r\n");
return;
@ -2371,7 +2397,7 @@ void FtpSession::PASV (char const *args_)
m_pasvSocket->setSendBufferSize (SOCK_BUFFERSIZE);
// create an address to bind
struct sockaddr_in addr = m_commandSocket->sockName ();
sockaddr_in addr = m_commandSocket->sockName ();
#if defined(__NDS__) || defined(__3DS__)
static std::uint16_t ephemeralPort = 5001;
if (ephemeralPort > 10000)
@ -2455,7 +2481,7 @@ void FtpSession::PORT (char const *args_)
return;
}
struct sockaddr_in addr = {};
sockaddr_in addr{};
// parse the address
if (!inet_aton (addrString.data (), &addr.sin_addr))
@ -2630,7 +2656,7 @@ void FtpSession::RNFR (char const *args_)
}
// make sure the path exists
struct stat st;
stat_t st;
if (tzLStat (path.c_str (), &st) != 0)
{
sendResponse ("450 %s\r\n", std::strerror (errno));
@ -2687,13 +2713,13 @@ void FtpSession::SITE (char const *args_)
{
setState (State::COMMAND, false, false);
auto const str = std::string (args_);
auto const str = std::string_view (args_);
auto const pos = str.find_first_of (' ');
auto const command = str.substr (0, pos);
auto const arg = pos == std::string::npos ? std::string () : str.substr (pos + 1);
auto const arg = pos == std::string::npos ? std::string_view () : str.substr (pos + 1);
if (::strcasecmp (command.c_str (), "HELP") == 0)
if (compare (command.data (), "HELP") == 0)
{
sendResponse ("211-\r\n"
" Show this help: SITE HELP\r\n"
@ -2714,31 +2740,31 @@ void FtpSession::SITE (char const *args_)
return;
}
if (::strcasecmp (command.c_str (), "USER") == 0)
if (compare (command, "USER") == 0)
{
{
#ifndef __NDS__
auto const lock = m_config.lockGuard ();
#endif
m_config.setUser (arg);
m_config.setUser (std::string (arg));
}
sendResponse ("200 OK\r\n");
return;
}
else if (::strcasecmp (command.c_str (), "PASS") == 0)
else if (compare (command, "PASS") == 0)
{
{
#ifndef __NDS__
auto const lock = m_config.lockGuard ();
#endif
m_config.setPass (arg);
m_config.setPass (std::string (arg));
}
sendResponse ("200 OK\r\n");
return;
}
else if (::strcasecmp (command.c_str (), "PORT") == 0)
else if (compare (command, "PORT") == 0)
{
bool error = false;
@ -2759,7 +2785,7 @@ void FtpSession::SITE (char const *args_)
return;
}
#ifdef __3DS__
else if (::strcasecmp (command.c_str (), "MTIME") == 0)
else if (compare (command, "MTIME") == 0)
{
if (arg == "0")
{
@ -2782,7 +2808,7 @@ void FtpSession::SITE (char const *args_)
}
}
#endif
else if (::strcasecmp (command.c_str (), "SAVE") == 0)
else if (compare (command, "SAVE") == 0)
{
bool error;
@ -2825,7 +2851,7 @@ void FtpSession::SIZE (char const *args_)
}
// stat the path
struct stat st;
stat_t st;
if (tzStat (path.c_str (), &st) != 0)
{
sendResponse ("550 %s\r\n", std::strerror (errno));
@ -2915,7 +2941,7 @@ void FtpSession::STRU (char const *args_)
setState (State::COMMAND, false, false);
// we only support F (no structure) mode
if (::strcasecmp (args_, "F") == 0)
if (compare (args_, "F") == 0)
{
sendResponse ("200 OK\r\n");
return;

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2023 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -29,7 +29,10 @@
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <memory>
#include <mutex>
#include <thread>
@ -193,7 +196,7 @@ bool platform::networkVisible ()
bool platform::networkAddress (SockAddr &addr_)
{
struct sockaddr_in addr;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);

View File

@ -3,7 +3,7 @@
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
//
// Copyright (C) 2020 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -40,7 +40,7 @@ PrintConsole g_sessionConsole;
namespace
{
/// \brief Host address
struct in_addr s_addr = {0};
in_addr s_addr = {0};
/// \brief Which side of double-buffer we're on
bool s_backBuffer = false;
/// \brief Whether to power backlight
@ -75,7 +75,7 @@ bool platform::networkVisible ()
bool platform::networkAddress (SockAddr &addr_)
{
struct sockaddr_in addr;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);

View File

@ -39,83 +39,80 @@ SockAddr &SockAddr::operator= (SockAddr const &that_) = default;
SockAddr &SockAddr::operator= (SockAddr &&that_) = default;
SockAddr::SockAddr (struct sockaddr_in const &addr_)
SockAddr::SockAddr (sockaddr_in const &addr_)
{
assert (addr_.sin_family == AF_INET);
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in));
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in));
}
#ifndef NO_IPV6
SockAddr::SockAddr (struct sockaddr_in6 const &addr_)
SockAddr::SockAddr (sockaddr_in6 const &addr_)
{
assert (addr_.sin6_family == AF_INET6);
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in6));
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in6));
}
#endif
SockAddr::SockAddr (struct sockaddr_storage const &addr_)
SockAddr::SockAddr (sockaddr_storage const &addr_)
{
switch (addr_.ss_family)
{
case AF_INET:
assert (addr_.ss_family == AF_INET);
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in));
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in));
break;
#ifndef NO_IPV6
case AF_INET6:
assert (addr_.ss_family == AF_INET6);
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in6));
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in6));
break;
#endif
default:
std::abort ();
break;
}
}
SockAddr::operator struct sockaddr_in const & () const
SockAddr::operator sockaddr_in const & () const
{
assert (m_addr.ss_family == AF_INET);
return reinterpret_cast<struct sockaddr_in const &> (m_addr);
return reinterpret_cast<sockaddr_in const &> (m_addr);
}
#ifndef NO_IPV6
SockAddr::operator struct sockaddr_in6 const & () const
SockAddr::operator sockaddr_in6 const & () const
{
assert (m_addr.ss_family == AF_INET6);
return reinterpret_cast<struct sockaddr_in6 const &> (m_addr);
return reinterpret_cast<sockaddr_in6 const &> (m_addr);
}
#endif
SockAddr::operator struct sockaddr_storage const & () const
SockAddr::operator sockaddr_storage const & () const
{
return m_addr;
}
SockAddr::operator struct sockaddr * ()
SockAddr::operator sockaddr * ()
{
return reinterpret_cast<struct sockaddr *> (&m_addr);
return reinterpret_cast<sockaddr *> (&m_addr);
}
SockAddr::operator struct sockaddr const * () const
SockAddr::operator sockaddr const * () const
{
return reinterpret_cast<struct sockaddr const *> (&m_addr);
return reinterpret_cast<sockaddr const *> (&m_addr);
}
bool SockAddr::setPort (std::uint16_t const port_)
void 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;
break;
#ifndef NO_IPV6
case AF_INET6:
reinterpret_cast<struct sockaddr_in6 *> (&m_addr)->sin6_port = htons (port_);
return true;
break;
#endif
default:
@ -146,11 +143,11 @@ std::uint16_t SockAddr::port () const
switch (m_addr.ss_family)
{
case AF_INET:
return ntohs (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_port);
return ntohs (reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_port);
#ifndef NO_IPV6
case AF_INET6:
return ntohs (reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_port);
return ntohs (reinterpret_cast<sockaddr_in6 const *> (&m_addr)->sin6_port);
#endif
default:
@ -167,32 +164,27 @@ char const *SockAddr::name (char *buffer_, std::size_t size_) const
#ifdef __NDS__
(void)buffer_;
(void)size_;
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
return inet_ntoa (reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_addr);
#else
return inet_ntop (AF_INET,
&reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr,
buffer_,
size_);
return inet_ntop (
AF_INET, &reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_addr, buffer_, size_);
#endif
#ifndef NO_IPV6
case AF_INET6:
return inet_ntop (AF_INET6,
&reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_addr,
buffer_,
size_);
return inet_ntop (
AF_INET6, &reinterpret_cast<sockaddr_in6 const *> (&m_addr)->sin6_addr, buffer_, size_);
#endif
default:
std::abort ();
break;
}
}
char const *SockAddr::name () const
{
#ifdef __NDS__
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
return inet_ntoa (reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_addr);
#else
#ifdef NO_IPV6
thread_local static char buffer[INET_ADDRSTRLEN];

View File

@ -23,6 +23,7 @@
#include "log.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
@ -65,7 +66,7 @@ Socket::Socket (int const fd_, SockAddr const &sockName_, SockAddr const &peerNa
UniqueSocket Socket::accept ()
{
SockAddr addr;
socklen_t addrLen = sizeof (struct sockaddr_storage);
socklen_t addrLen = sizeof (sockaddr_storage);
auto const fd = ::accept (m_fd, addr, &addrLen);
if (fd < 0)
@ -104,7 +105,7 @@ bool Socket::bind (SockAddr const &addr_)
if (addr_.port () == 0)
{
// get socket name due to request for ephemeral port
socklen_t addrLen = sizeof (struct sockaddr_storage);
socklen_t addrLen = sizeof (sockaddr_storage);
if (::getsockname (m_fd, m_sockName, &addrLen) != 0)
error ("getsockname: %s\n", std::strerror (errno));
}
@ -166,7 +167,7 @@ bool Socket::setLinger (bool const enable_, std::chrono::seconds const time_)
errno = ENOSYS;
return -1;
#else
struct linger linger;
linger linger;
linger.l_onoff = enable_;
linger.l_linger = time_.count ();
@ -330,7 +331,7 @@ int Socket::poll (PollInfo *const info_,
if (count_ == 0)
return 0;
auto const pfd = std::make_unique<struct pollfd[]> (count_);
auto const pfd = std::make_unique<pollfd[]> (count_);
for (std::size_t i = 0; i < count_; ++i)
{
pfd[i].fd = info_[i].socket.get ().m_fd;
@ -352,7 +353,7 @@ int Socket::poll (PollInfo *const info_,
}
#ifdef __NDS__
extern "C" int poll (struct pollfd *const fds_, nfds_t const nfds_, int const timeout_)
extern "C" int poll (pollfd *const fds_, nfds_t const nfds_, int const timeout_)
{
fd_set readFds;
fd_set writeFds;
@ -370,7 +371,7 @@ extern "C" int poll (struct pollfd *const fds_, nfds_t const nfds_, int const ti
FD_SET (fds_[i].fd, &writeFds);
}
struct timeval tv;
timeval tv;
tv.tv_sec = timeout_ / 1000;
tv.tv_usec = (timeout_ % 1000) * 1000;
auto const rc = ::select (nfds_, &readFds, &writeFds, &exceptFds, &tv);

View File

@ -5,7 +5,7 @@
//
// The MIT License (MIT)
//
// Copyright (C) 2023 Michael Theall
// Copyright (C) 2024 Michael Theall
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -42,6 +42,7 @@
#include <sys/stat.h>
#include <unistd.h>
using stat_t = struct stat;
#include <array>
#include <cerrno>
@ -123,7 +124,7 @@ void loadShaders (dk::UniqueDevice &device_)
/// \param path_ Path to file
static std::size_t getSize (char const *const path_)
{
struct stat st;
stat_t st;
auto const rc = ::stat (path_, &st);
if (rc != 0)
{

View File

@ -339,7 +339,7 @@ void loadTextures ()
unsigned imageOffset = 0;
for (auto const &textureInfo : textureInfos)
{
struct stat st;
stat_t st;
if (::stat (textureInfo.path, &st) != 0)
{
std::fprintf (stderr, "stat(%s): %s\n", textureInfo.path, std::strerror (errno));
@ -618,14 +618,14 @@ bool platform::init ()
return true;
}
bool platform::enableAP (bool const enableAP_,
bool platform::enableAP (bool const enable_,
std::string const &ssid_,
std::string const &passphrase_)
{
if (s_activeAP == enableAP_)
if (s_activeAP == enable_)
return true;
if (enableAP_)
if (enable_)
{
auto const ssidError = validateSSID (ssid_);
if (ssidError)
@ -781,11 +781,11 @@ bool platform::networkAddress (SockAddr &addr_)
return false;
}
addr_ = *reinterpret_cast<struct sockaddr_in *> (ipConfig.ip_addr);
addr_ = *reinterpret_cast<sockaddr_in *> (ipConfig.ip_addr);
return true;
}
struct sockaddr_in addr;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = gethostid ();