mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-11-04 07:38:47 +00:00 
			
		
		
		
	Merge pull request #4632 from zhaowenlan1779/socu
service/soc_u: Implement getaddrinfo and getnameinfo
This commit is contained in:
		
						commit
						5f10cc412f
					
				
					 2 changed files with 126 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -10,6 +10,7 @@
 | 
			
		|||
#include "common/common_types.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/scope_exit.h"
 | 
			
		||||
#include "common/swap.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/ipc_helpers.h"
 | 
			
		||||
#include "core/hle/kernel/shared_memory.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -320,6 +321,35 @@ union CTRSockAddr {
 | 
			
		|||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CTRAddrInfo {
 | 
			
		||||
    s32_le ai_flags;
 | 
			
		||||
    s32_le ai_family;
 | 
			
		||||
    s32_le ai_socktype;
 | 
			
		||||
    s32_le ai_protocol;
 | 
			
		||||
    s32_le ai_addrlen;
 | 
			
		||||
    char ai_canonname[256];
 | 
			
		||||
    CTRSockAddr ai_addr;
 | 
			
		||||
 | 
			
		||||
    /// Converts a platform-specific addrinfo to a 3ds addrinfo.
 | 
			
		||||
    static CTRAddrInfo FromPlatform(const addrinfo& addr) {
 | 
			
		||||
        CTRAddrInfo ctr_addr{};
 | 
			
		||||
 | 
			
		||||
        ctr_addr.ai_flags = addr.ai_flags;
 | 
			
		||||
        ctr_addr.ai_family = addr.ai_family;
 | 
			
		||||
        ctr_addr.ai_socktype = addr.ai_socktype;
 | 
			
		||||
        ctr_addr.ai_protocol = addr.ai_protocol;
 | 
			
		||||
        if (addr.ai_canonname)
 | 
			
		||||
            std::strncpy(ctr_addr.ai_canonname, addr.ai_canonname, sizeof(ctr_addr.ai_canonname));
 | 
			
		||||
 | 
			
		||||
        ctr_addr.ai_addr = CTRSockAddr::FromPlatform(*addr.ai_addr);
 | 
			
		||||
        ctr_addr.ai_addrlen = ctr_addr.ai_addr.raw.len;
 | 
			
		||||
 | 
			
		||||
        return ctr_addr;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(CTRAddrInfo) == 0x130, "Size of CTRAddrInfo is not correct");
 | 
			
		||||
 | 
			
		||||
void SOC_U::CleanupSockets() {
 | 
			
		||||
    for (auto sock : open_sockets)
 | 
			
		||||
        closesocket(sock.second.socket_fd);
 | 
			
		||||
| 
						 | 
				
			
			@ -858,6 +888,95 @@ void SOC_U::SetSockOpt(Kernel::HLERequestContext& ctx) {
 | 
			
		|||
    rb.Push(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SOC_U::GetAddrInfoImpl(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x0F, 4, 6);
 | 
			
		||||
    u32 node_length = rp.Pop<u32>();
 | 
			
		||||
    u32 service_length = rp.Pop<u32>();
 | 
			
		||||
    u32 hints_size = rp.Pop<u32>();
 | 
			
		||||
    u32 out_size = rp.Pop<u32>();
 | 
			
		||||
    auto node = rp.PopStaticBuffer();
 | 
			
		||||
    auto service = rp.PopStaticBuffer();
 | 
			
		||||
    auto hints_buff = rp.PopStaticBuffer();
 | 
			
		||||
 | 
			
		||||
    const char* node_data = node_length > 0 ? reinterpret_cast<const char*>(node.data()) : nullptr;
 | 
			
		||||
    const char* service_data =
 | 
			
		||||
        service_length > 0 ? reinterpret_cast<const char*>(service.data()) : nullptr;
 | 
			
		||||
 | 
			
		||||
    s32 ret = -1;
 | 
			
		||||
    addrinfo* out = nullptr;
 | 
			
		||||
    if (hints_size > 0) {
 | 
			
		||||
        CTRAddrInfo ctr_hints;
 | 
			
		||||
        std::memcpy(&ctr_hints, hints_buff.data(), hints_size);
 | 
			
		||||
        // Only certain fields are meaningful in hints, copy them manually
 | 
			
		||||
        addrinfo hints = {};
 | 
			
		||||
        hints.ai_flags = ctr_hints.ai_flags;
 | 
			
		||||
        hints.ai_family = ctr_hints.ai_family;
 | 
			
		||||
        hints.ai_socktype = ctr_hints.ai_socktype;
 | 
			
		||||
        hints.ai_protocol = ctr_hints.ai_protocol;
 | 
			
		||||
        ret = getaddrinfo(node_data, service_data, &hints, &out);
 | 
			
		||||
    } else {
 | 
			
		||||
        ret = getaddrinfo(node_data, service_data, nullptr, &out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<u8> out_buff(out_size);
 | 
			
		||||
    u32 count = 0;
 | 
			
		||||
 | 
			
		||||
    if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		||||
        ret = TranslateError(GET_ERRNO);
 | 
			
		||||
        out_buff.resize(0);
 | 
			
		||||
    } else {
 | 
			
		||||
        std::size_t pos = 0;
 | 
			
		||||
        addrinfo* cur = out;
 | 
			
		||||
        while (cur != nullptr) {
 | 
			
		||||
            if (pos <= out_size - sizeof(CTRAddrInfo)) {
 | 
			
		||||
                // According to 3dbrew, this function fills whatever it can and does not error even
 | 
			
		||||
                // if the buffer is not big enough. However the count returned is always correct.
 | 
			
		||||
                CTRAddrInfo ctr_addr = CTRAddrInfo::FromPlatform(*cur);
 | 
			
		||||
                std::memcpy(out_buff.data() + pos, &ctr_addr, sizeof(ctr_addr));
 | 
			
		||||
            }
 | 
			
		||||
            cur = cur->ai_next;
 | 
			
		||||
            count++;
 | 
			
		||||
        }
 | 
			
		||||
        if (out != nullptr)
 | 
			
		||||
            freeaddrinfo(out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    rb.Push(ret);
 | 
			
		||||
    rb.Push(count);
 | 
			
		||||
    rb.PushStaticBuffer(out_buff, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SOC_U::GetNameInfoImpl(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x10, 4, 2);
 | 
			
		||||
    u32 socklen = rp.Pop<u32>();
 | 
			
		||||
    u32 hostlen = rp.Pop<u32>();
 | 
			
		||||
    u32 servlen = rp.Pop<u32>();
 | 
			
		||||
    s32 flags = rp.Pop<s32>();
 | 
			
		||||
    auto sa_buff = rp.PopStaticBuffer();
 | 
			
		||||
 | 
			
		||||
    CTRSockAddr ctr_sa;
 | 
			
		||||
    std::memcpy(&ctr_sa, sa_buff.data(), socklen);
 | 
			
		||||
    sockaddr sa = CTRSockAddr::ToPlatform(ctr_sa);
 | 
			
		||||
 | 
			
		||||
    std::vector<u8> host(hostlen);
 | 
			
		||||
    std::vector<u8> serv(servlen);
 | 
			
		||||
    char* host_data = hostlen > 0 ? reinterpret_cast<char*>(host.data()) : nullptr;
 | 
			
		||||
    char* serv_data = servlen > 0 ? reinterpret_cast<char*>(serv.data()) : nullptr;
 | 
			
		||||
 | 
			
		||||
    s32 ret = getnameinfo(&sa, sizeof(sa), host_data, hostlen, serv_data, servlen, flags);
 | 
			
		||||
    if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		||||
        ret = TranslateError(GET_ERRNO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(2, 4);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    rb.Push(ret);
 | 
			
		||||
    rb.PushStaticBuffer(host, 0);
 | 
			
		||||
    rb.PushStaticBuffer(serv, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SOC_U::SOC_U() : ServiceFramework("soc:U") {
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0x00010044, &SOC_U::InitializeSockets, "InitializeSockets"},
 | 
			
		||||
| 
						 | 
				
			
			@ -874,8 +993,8 @@ SOC_U::SOC_U() : ServiceFramework("soc:U") {
 | 
			
		|||
        {0x000C0082, &SOC_U::Shutdown, "Shutdown"},
 | 
			
		||||
        {0x000D0082, nullptr, "GetHostByName"},
 | 
			
		||||
        {0x000E00C2, nullptr, "GetHostByAddr"},
 | 
			
		||||
        {0x000F0106, nullptr, "GetAddrInfo"},
 | 
			
		||||
        {0x00100102, nullptr, "GetNameInfo"},
 | 
			
		||||
        {0x000F0106, &SOC_U::GetAddrInfoImpl, "GetAddrInfo"},
 | 
			
		||||
        {0x00100102, &SOC_U::GetNameInfoImpl, "GetNameInfo"},
 | 
			
		||||
        {0x00110102, &SOC_U::GetSockOpt, "GetSockOpt"},
 | 
			
		||||
        {0x00120104, &SOC_U::SetSockOpt, "SetSockOpt"},
 | 
			
		||||
        {0x001300C2, &SOC_U::Fcntl, "Fcntl"},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,11 @@ private:
 | 
			
		|||
    void GetSockOpt(Kernel::HLERequestContext& ctx);
 | 
			
		||||
    void SetSockOpt(Kernel::HLERequestContext& ctx);
 | 
			
		||||
 | 
			
		||||
    // Some platforms seem to have GetAddrInfo and GetNameInfo defined as macros,
 | 
			
		||||
    // so we have to use a different name here.
 | 
			
		||||
    void GetAddrInfoImpl(Kernel::HLERequestContext& ctx);
 | 
			
		||||
    void GetNameInfoImpl(Kernel::HLERequestContext& ctx);
 | 
			
		||||
 | 
			
		||||
    /// Close all open sockets
 | 
			
		||||
    void CleanupSockets();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue