Skip to content

Commit

Permalink
refactor: low level socket tidyups and removal of punning (#1282)
Browse files Browse the repository at this point in the history
  • Loading branch information
braindigitalis authored Oct 16, 2024
1 parent b720cc6 commit 4965b5c
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 128 deletions.
3 changes: 2 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@
"nullopt",
"chrono",
"ciphersuite",
"rmap"
"rmap",
"WSAPOLLFD"
],
"flagWords": [
"hte"
Expand Down
7 changes: 7 additions & 0 deletions include/dpp/discordvoiceclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,13 @@ class DPP_EXPORT discord_voice_client : public websocket_client
*/
dave_version_t dave_version;

/**
* @brief Destination address for where packets go
* on the UDP socket
*/
address_t destination{};


/**
* @brief Send data to UDP socket immediately.
*
Expand Down
37 changes: 29 additions & 8 deletions include/dpp/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <sys/types.h>
#include <string>
#include <unordered_map>
#include <cstring>
#include <dpp/socket.h>

namespace dpp {

Expand All @@ -40,23 +42,42 @@ namespace dpp {
*/
struct dns_cache_entry {
/**
* @brief Resolved address information
* @brief Resolved address metadata
*/
addrinfo addr;

/**
* @brief Socket address.
* Discord only supports ipv4, but sockaddr_in6 is larger
* than sockaddr_in, sockaddr_storage will hold either. This
* means that if discord ever do support ipv6 we just flip
* one value in dns.cpp and that should be all that is needed.
* @brief Resolved address as string.
* The metadata is needed to know what type of address it is.
* Do not do silly stuff like just looking to see if '.' is in it!
*/
sockaddr_storage ai_addr;
std::string resolved_addr;

/**
* @brief Time at which this cache entry is invalidated
*/
time_t expire_timestamp;

/**
* @brief Get address length
* @return address length
*/
[[nodiscard]] int size() const;

/**
* @brief Get the address_t that corresponds to this cache entry
* for use when connecting with ::connect()
* @param port Port number to connect to
* @return address_t prefilled with the IP and port number
*/
[[nodiscard]] const address_t get_connecting_address(uint16_t port) const;

/**
* @brief Allocate a socket file descriptor for the given dns address
* @return File descriptor ready for calling connect(), or INVALID_SOCKET
* on failure.
*/
[[nodiscard]] socket make_connecting_socket() const;
};

/**
Expand All @@ -73,4 +94,4 @@ namespace dpp {
* @throw dpp::connection_exception On failure to resolve hostname
*/
const dns_cache_entry* resolve_hostname(const std::string& hostname, const std::string& port);
} // namespace dpp
}
135 changes: 130 additions & 5 deletions include/dpp/socket.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,53 @@
/************************************************************************************
*
* D++, A Lightweight C++ library for Discord
*
* SPDX-License-Identifier: Apache-2.0
* Copyright 2021 Craig Edwards and D++ contributors
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
************************************************************************************/
#pragma once

#include <dpp/export.h>
#ifdef _WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <io.h>
#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
#define pollfd WSAPOLLFD
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif
#include <string_view>
#include <cstdint>


namespace dpp
{
/**
* @brief Represents a socket file descriptor.
* This is used to ensure parity between windows and unix-like systems.
*/
/**
* @brief Represents a socket file descriptor.
* This is used to ensure parity between windows and unix-like systems.
*/
#ifndef _WIN32
using socket = int;
#else
using socket = SOCKET;
#endif
} // namespace dpp

#ifndef SOCKET_ERROR
/**
Expand All @@ -26,3 +62,92 @@ namespace dpp
*/
#define INVALID_SOCKET ~0
#endif

/**
* @brief Represents an IPv4 address for use with socket functions such as
* bind().
*
* Avoids type punning with C style casts from sockaddr_in to sockaddr pointers.
*/
class DPP_EXPORT address_t {
/**
* @brief Internal sockaddr struct
*/
sockaddr socket_addr{};

public:

/**
* @brief Create a new address_t
* @param ip IPv4 address
* @param port Port number
* @note Leave both as defaults to create a default bind-to-any setting
*/
address_t(const std::string_view ip = "0.0.0.0", uint16_t port = 0);

/**
* @brief Get sockaddr
* @return sockaddr pointer
*/
[[nodiscard]] sockaddr *get_socket_address();

/**
* @brief Returns size of sockaddr_in
* @return sockaddr_in size
* @note It is important the size this returns is sizeof(sockaddr_in) not
* sizeof(sockaddr), this is NOT a bug but requirement of C socket functions.
*/
[[nodiscard]] size_t size();

/**
* @brief Get the port bound to a file descriptor
* @param fd File descriptor
* @return Port number, or 0 if no port bound
*/
[[nodiscard]] uint16_t get_port(socket fd);
};

/**
* @brief Allocates a dpp::socket, closing it on destruction
*/
struct DPP_EXPORT raii_socket {
/**
* @brief File descriptor
*/
socket fd;

/**
* @brief Construct a socket.
* Calls socket() and returns a new file descriptor
*/
raii_socket();

/**
* @brief Non-copyable
*/
raii_socket(raii_socket&) = delete;

/**
* @brief Non-movable
*/
raii_socket(raii_socket&&) = delete;

/**
* @brief Non-copyable
*/
raii_socket operator=(raii_socket&) = delete;

/**
* @brief Non-movable
*/
raii_socket operator=(raii_socket&&) = delete;

/**
* @brief Destructor
* Frees the socket by closing it
*/
~raii_socket();
};


}
Loading

0 comments on commit 4965b5c

Please sign in to comment.