diff --git a/nx/include/switch/services/bsd.h b/nx/include/switch/services/bsd.h index ff306166..f21fbd10 100644 --- a/nx/include/switch/services/bsd.h +++ b/nx/include/switch/services/bsd.h @@ -9,7 +9,6 @@ #include "../types.h" #include "../kernel/tmem.h" -#include // for ssize_t, etc. #include // for socklen_t #include // for fd_set #include // for struct pollfd, ndfs_t diff --git a/nx/include/switch/services/sfdnsres.h b/nx/include/switch/services/sfdnsres.h new file mode 100644 index 00000000..4a2f001f --- /dev/null +++ b/nx/include/switch/services/sfdnsres.h @@ -0,0 +1,40 @@ +#pragma once +#include "../types.h" + +#include // For socklen_t, etc. + +/// Configuration structure for sfdnsres. +typedef struct { + size_t serialized_out_addrinfos_max_size; ///< For getaddrinfo. + size_t serialized_out_hostent_max_size; ///< For gethostbyname/gethostbyaddr. + bool bypass_nsd; ///< For DNS requests: bypass the Name Server Daemon. + int timeout; ///< For DNS requests: timeout or 0. +} SfdnsresConfig; + +/// Result values returned by the DNS request commands. +typedef struct { + int ret; ///< Return value (error code). + int errno_; ///< Errno. + ssize_t out_serialized_size; ///< Size of the serialized output buffer or -1 (?). +} SfdnsresRequestResults; + +// SetDnsAddressesPrivate & GetDnsAddressPrivate are stubbed + +Result sfdnsresGetHostByName(SfdnsresRequestResults *ret, const SfdnsresConfig *config, void *out_he_serialized, const char *name); +Result sfdnsresGetHostByAddr(SfdnsresRequestResults *ret, const SfdnsresConfig *config, void *out_he_serialized, const void *addr, socklen_t len, int type); + +Result sfdnsresGetHostStringError(char *str, size_t str_size); +Result sfdnsresGetGaiStringError(char *str, size_t str_size); + +Result sfdnsresGetAddrInfo(SfdnsresRequestResults *ret, const SfdnsresConfig *config, const char *node, const char *service, + const void *hints_serialized, size_t hints_serialized_size, void *res_serialized); +Result sfdnsresGetNameInfo(SfdnsresRequestResults *ret, const SfdnsresConfig *config, + const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, + char *serv, size_t servlen, int flags); + +Result sfdnsresRequestCancelHandle(u32 *out_handle); +/// Bug: always sets errno ? +Result sfdnsresCancelSocketCall(SfdnsresRequestResults *ret, u32 handle); +/// Bug: always sets errno ? +Result sfdnsresCancelAllSocketCalls(SfdnsresRequestResults *ret); +Result sfdnsresClearDnsIpServerAddressArray(void); diff --git a/nx/include/sys/socket.h b/nx/include/sys/socket.h index ef8c15e4..6b50e8f9 100644 --- a/nx/include/sys/socket.h +++ b/nx/include/sys/socket.h @@ -53,7 +53,7 @@ */ // Stripped some of them - +#include // for ssize_t, etc. #include #ifndef _SA_FAMILY_T_DECLARED diff --git a/nx/source/services/sfdnsres.c b/nx/source/services/sfdnsres.c new file mode 100644 index 00000000..8c6d2474 --- /dev/null +++ b/nx/source/services/sfdnsres.c @@ -0,0 +1,282 @@ +#include "types.h" +#include "result.h" +#include "ipc.h" +#include "services/sm.h" +#include "services/sfdnsres.h" + +#include + +static Result _sfdnsresDispatchCommand(IpcParsedCommand *r, IpcCommand *c, const void *raw, size_t raw_size) { + Service sfdnsres; + + Result rc = smGetService(&sfdnsres, "sfdnsres"); + if(R_FAILED(rc)) goto cleanup; + + memcpy(ipcPrepareHeader(c, raw_size), raw, raw_size); + + rc = serviceIpcDispatch(&sfdnsres); + if(R_FAILED(rc)) goto cleanup; + + ipcParse(r); + +cleanup: + serviceClose(&sfdnsres); + return rc; +} + +static Result _sfdnsresDnsRequestCommand(IpcCommand *c, u64 cmd_id, SfdnsresRequestResults *ret, const SfdnsresConfig *config, bool has_serialized_data_out, int *arg) { + Result rc; + IpcParsedCommand r; + struct { + u64 magic; + u64 cmd_id; + int arg; + int timeout; + u64 pid_placeholder; + } raw; + + ipcSendPid(c); + + raw.magic = SFCI_MAGIC; + raw.cmd_id = cmd_id; + raw.arg = arg == NULL ? (config->bypass_nsd ? 0 : 1) : *arg; + raw.timeout = config->timeout; + raw.pid_placeholder = 0; + + rc = _sfdnsresDispatchCommand(&r, c, &raw, sizeof(raw)); + if(R_FAILED(rc)) return rc; + + struct { + u64 magic; + u64 result; + int ret; + int errno_; + int out_serialized_size; // OOB if !has_serialized_data + } *resp = r.Raw; + + rc = resp->result; + if(R_FAILED(rc)) return rc; + + ret->ret = resp->ret; + ret->errno_ = resp->errno_; + ret->out_serialized_size = has_serialized_data_out ? resp->out_serialized_size : 0; + + return rc; +} + +static Result _sfdnsresErrorStringGetterCommand(u64 cmd_id, char *str, size_t str_size) { + IpcCommand c; + Result rc; + IpcParsedCommand r; + + ipcInitialize(&c); + ipcAddRecvBuffer(&c, str, str_size, 0); + + struct { + u64 magic; + u64 cmd_id; + } raw; + + raw.magic = SFCI_MAGIC; + raw.cmd_id = cmd_id; + + rc = _sfdnsresDispatchCommand(&r, &c, &raw, sizeof(raw)); + if(R_FAILED(rc)) return rc; + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + return rc; +} + +Result sfdnsresGetHostByName(SfdnsresRequestResults *ret, const SfdnsresConfig *config, void *out_he_serialized, const char *name) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, name, strlen(name) + 1, 0); + + ipcAddRecvBuffer(&c, out_he_serialized, config->serialized_out_hostent_max_size, 0); + + return _sfdnsresDnsRequestCommand(&c, 2, ret, config, true, NULL); +} + +Result sfdnsresGetHostByAddr(SfdnsresRequestResults *ret, const SfdnsresConfig *config, void *out_he_serialized, const void *addr, socklen_t len, int type) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, out_he_serialized, config->serialized_out_hostent_max_size, 0); + + return _sfdnsresDnsRequestCommand(&c, 3, ret, config, true, &type); +} + +Result sfdnsresGetHostStringError(char *str, size_t str_size) { + return _sfdnsresErrorStringGetterCommand(4, str, str_size); +} + +Result sfdnsresGetGaiStringError(char *str, size_t str_size) { + return _sfdnsresErrorStringGetterCommand(5, str, str_size); +} + +Result sfdnsresGetAddrInfo(SfdnsresRequestResults *ret, const SfdnsresConfig *config, const char *node, const char *service, + const void *hints_serialized, size_t hints_serialized_size, void *res_serialized) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, node, strlen(node) + 1, 0); + ipcAddSendBuffer(&c, node, strlen(service) + 1, 0); + ipcAddSendBuffer(&c, hints_serialized, hints_serialized_size, 0); + + ipcAddRecvBuffer(&c, res_serialized, config->serialized_out_hostent_max_size, 0); + + return _sfdnsresDnsRequestCommand(&c, 6, ret, config, true, NULL); +} + +Result sfdnsresGetNameInfo(SfdnsresRequestResults *ret, const SfdnsresConfig *config, + const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, + char *serv, size_t servlen, int flags) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, sa, salen, 0); + + ipcAddRecvBuffer(&c, host, hostlen, 0); + ipcAddRecvBuffer(&c, serv, servlen, 0); + + return _sfdnsresDnsRequestCommand(&c, 7, ret, config, false, &flags); +} + +Result sfdnsresRequestCancelHandle(u32 *out_handle) { + Result rc; + IpcCommand c; + IpcParsedCommand r; + struct { + u64 magic; + u64 cmd_id; + u64 pid_placeholder; + } raw; + + ipcInitialize(&c); + ipcSendPid(&c); + + raw.magic = SFCI_MAGIC; + raw.cmd_id = 8; + raw.pid_placeholder = 0; + + rc = _sfdnsresDispatchCommand(&r, &c, &raw, sizeof(raw)); + if(R_FAILED(rc)) return rc; + + struct { + u64 magic; + u64 result; + u32 handle; + } *resp = r.Raw; + + rc = resp->result; + if(R_FAILED(rc)) return rc; + + *out_handle = resp->handle; + + return rc; +} + +/// Bug: always sets errno ? +Result sfdnsresCancelSocketCall(SfdnsresRequestResults *ret, u32 handle) { + Result rc; + IpcCommand c; + IpcParsedCommand r; + struct { + u64 magic; + u64 cmd_id; + u32 handle; + u64 pid_placeholder; + } raw; + + ipcInitialize(&c); + ipcSendPid(&c); + + raw.magic = SFCI_MAGIC; + raw.cmd_id = 9; + raw.handle = handle; + raw.pid_placeholder = 0; + + rc = _sfdnsresDispatchCommand(&r, &c, &raw, sizeof(raw)); + if(R_FAILED(rc)) return rc; + + struct { + u64 magic; + u64 result; + int ret; + int errno_; + } *resp = r.Raw; + + rc = resp->result; + if(R_FAILED(rc)) return rc; + + ret->ret = resp->ret; + ret->errno_ = resp->errno_; + + return rc; +} + +/// Bug: always sets errno ? +Result sfdnsresCancelAllSocketCalls(SfdnsresRequestResults *ret) { + Result rc; + IpcCommand c; + IpcParsedCommand r; + struct { + u64 magic; + u64 cmd_id; + u64 pid_placeholder; + } raw; + + ipcInitialize(&c); + ipcSendPid(&c); + + raw.magic = SFCI_MAGIC; + raw.cmd_id = 10; + raw.pid_placeholder = 0; + + rc = _sfdnsresDispatchCommand(&r, &c, &raw, sizeof(raw)); + if(R_FAILED(rc)) return rc; + + struct { + u64 magic; + u64 result; + int ret; + int errno_; + } *resp = r.Raw; + + rc = resp->result; + if(R_FAILED(rc)) return rc; + + ret->ret = resp->ret; + ret->errno_ = resp->errno_; + + return rc; +} + +Result sfdnsresClearDnsIpServerAddressArray(void) { + Result rc; + IpcCommand c; + IpcParsedCommand r; + struct { + u64 magic; + u64 cmd_id; + } raw; + + ipcInitialize(&c); + + raw.magic = SFCI_MAGIC; + raw.cmd_id = 11; + + rc = _sfdnsresDispatchCommand(&r, &c, &raw, sizeof(raw)); + if(R_FAILED(rc)) return rc; + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + return rc; +}