1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <charconv>
#include <cstring>
#include <string>
#include <string_view>
#include "common/logging/log.h"
#include "core/hle/service/sockets/bsd.h"
#include "core/hle/service/sockets/socket_utils.h"
namespace Service::Sockets::nn::socket {
bool InetAton(const char* ip, in_addr* addr) {
if (ip == nullptr || addr == nullptr) {
return false;
}
std::string_view ip_view(ip);
// Count the number of dots to validate IPv4 format
size_t dots = std::count(ip_view.begin(), ip_view.end(), '.');
if (dots != 3) {
return false;
}
// Parse the IP address in standard dotted-decimal notation
u32 result = 0;
size_t pos = 0;
for (int i = 0; i < 4; i++) {
size_t next_dot = ip_view.find('.', pos);
std::string_view octet_view;
if (i < 3) {
if (next_dot == std::string_view::npos) {
return false;
}
octet_view = ip_view.substr(pos, next_dot - pos);
pos = next_dot + 1;
} else {
octet_view = ip_view.substr(pos);
}
u32 octet;
auto [ptr, ec] = std::from_chars(octet_view.data(), octet_view.data() + octet_view.size(), octet);
if (ec != std::errc() || octet > 255 || (ptr != octet_view.data() + octet_view.size())) {
return false;
}
result = (result << 8) | octet;
}
addr->s_addr = result;
return true;
}
s32 Connect(s32 socket, const sockaddr* addr, u32 addr_len) {
if (addr == nullptr || addr_len < sizeof(sockaddr)) {
LOG_ERROR(Service_BSD, "Invalid address pointer or length");
// Set errno to EINVAL (Invalid argument)
errno = static_cast<u32>(Errno::INVAL);
return -1;
}
// Create a BSD-compliant sockaddr_in from our sockaddr
SockAddrIn bsd_addr{};
bsd_addr.len = sizeof(SockAddrIn);
// Cast explicitly with a mask to ensure valid range conversion
bsd_addr.family = static_cast<u8>(addr->sa_family & 0xFF);
if (addr->sa_family == 2) { // AF_INET
const auto* addr_in = reinterpret_cast<const sockaddr_in*>(addr);
bsd_addr.portno = addr_in->sin_port;
// Copy IPv4 address (in network byte order)
const u32 ip_addr = addr_in->sin_addr.s_addr;
bsd_addr.ip[0] = static_cast<u8>((ip_addr >> 24) & 0xFF);
bsd_addr.ip[1] = static_cast<u8>((ip_addr >> 16) & 0xFF);
bsd_addr.ip[2] = static_cast<u8>((ip_addr >> 8) & 0xFF);
bsd_addr.ip[3] = static_cast<u8>(ip_addr & 0xFF);
} else {
LOG_ERROR(Service_BSD, "Unsupported address family: {}", addr->sa_family);
// Set errno to EAFNOSUPPORT (Address family not supported)
errno = static_cast<u32>(Errno::INVAL); // Using INVAL as a substitute for EAFNOSUPPORT
return -1;
}
// Forward to the BSD socket implementation
return BSD::Connect(socket, bsd_addr);
}
} // namespace Service::Sockets::nn::socket
|