yeah whatever
This commit is contained in:
@@ -116,16 +116,18 @@ void logError(const char_t *message, ...) {
|
||||
|
||||
// PAD_Init is idempotent - safe even if inputInit already called it,
|
||||
// and handles the case where the error occurred before inputInit ran.
|
||||
// logError is used for routine, already-handled errors (e.g. a rejected
|
||||
// network connection) as well as genuine assertion failures, so it must
|
||||
// only pause to let the message be seen, not decide to terminate the
|
||||
// program -- that decision belongs to the caller (assertTrueImpl calls
|
||||
// abort() right after logError returns; a plain errorPrint() just
|
||||
// continues running).
|
||||
PAD_Init();
|
||||
while(SYS_MainLoop()) {
|
||||
PAD_ScanPads();
|
||||
// START button matches the RAGEQUIT bind - allows exit on GC controller
|
||||
// when there is no Wiimote HOME button available.
|
||||
// START button matches the RAGEQUIT bind - allows dismissing the
|
||||
// message on a GC controller when there is no Wiimote HOME button.
|
||||
if(PAD_ButtonsDown(0) & PAD_BUTTON_START) break;
|
||||
VIDEO_WaitVSync();
|
||||
}
|
||||
|
||||
// Exit cleanly to HBC regardless of engine state. engineDispose() is not
|
||||
// called here because the engine may be partially initialized.
|
||||
exit(0);
|
||||
}
|
||||
@@ -7,7 +7,10 @@
|
||||
|
||||
#include "network/network.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
#include "log/log.h"
|
||||
#include <ogc/system.h>
|
||||
|
||||
errorret_t networkDolphinInit() {
|
||||
// s32 ret = net_init();
|
||||
@@ -45,43 +48,86 @@ void networkDolphinRequestConnection(
|
||||
NETWORK.platform.onFailed = onFailed;
|
||||
NETWORK.platform.onConnectedUser = user;
|
||||
|
||||
memoryZero(NETWORK.platform.ip, sizeof(NETWORK.platform.ip));
|
||||
memoryZero(NETWORK.platform.netmask, sizeof(NETWORK.platform.netmask));
|
||||
memoryZero(NETWORK.platform.gateway, sizeof(NETWORK.platform.gateway));
|
||||
// TEMPORARY: static IP instead of DHCP, to isolate whether if_config()'s
|
||||
// DHCP handshake (and the packet-receive/DMA path it triggers in gcif.c)
|
||||
// is what's corrupting memory, vs. link-up/NWAY negotiation alone. These
|
||||
// match Dolphin's Broadband Adapter (Built-In) default subnet. Revert to
|
||||
// DHCP once this is diagnosed.
|
||||
stringCopy(NETWORK.platform.ip, "10.0.1.10", sizeof(NETWORK.platform.ip));
|
||||
stringCopy(
|
||||
NETWORK.platform.netmask, "255.255.255.0",
|
||||
sizeof(NETWORK.platform.netmask)
|
||||
);
|
||||
stringCopy(
|
||||
NETWORK.platform.gateway, "10.0.1.1", sizeof(NETWORK.platform.gateway)
|
||||
);
|
||||
|
||||
// Negotiate DHCP using the Wi-Fi settings saved in Wii System Menu.
|
||||
// This call blocks until the interface is configured or times out.
|
||||
#ifdef DUSK_WII
|
||||
s32 ret = if_config(
|
||||
NETWORK.platform.ip,
|
||||
NETWORK.platform.netmask,
|
||||
NETWORK.platform.gateway,
|
||||
true
|
||||
);
|
||||
#else
|
||||
s32 ret = -1;
|
||||
#endif
|
||||
// Diagnostic: log the live MEM1 arena headroom (assets/heap already
|
||||
// accounted for, since this runs after assetInit()/scene setup) right
|
||||
// around if_config(), to check whether linking `bba` (~400KB+ of new
|
||||
// static lwIP pools, see lwipopts.h) is pushing memory too tight.
|
||||
logDebug(
|
||||
"networkDolphinRequestConnection: MEM1 arena free before if_config(): "
|
||||
"%u bytes (lo=%p hi=%p)\n",
|
||||
(uint32_t)((uint8_t *)SYS_GetArena1Hi() - (uint8_t *)SYS_GetArena1Lo()),
|
||||
SYS_GetArena1Lo(), SYS_GetArena1Hi()
|
||||
);
|
||||
|
||||
// Negotiate DHCP. This call blocks until the interface is configured or
|
||||
// times out. Wii (IOS) and GameCube (bundled lwIP + BBA driver, linked
|
||||
// via `bba` in gamecube.cmake) expose the same if_config()/net_*() API,
|
||||
// so this call is identical on both platforms.
|
||||
logDebug("networkDolphinRequestConnection: calling if_config()\n");
|
||||
s32 ret = if_config(
|
||||
NETWORK.platform.ip,
|
||||
NETWORK.platform.netmask,
|
||||
NETWORK.platform.gateway,
|
||||
false
|
||||
);
|
||||
logDebug(
|
||||
"networkDolphinRequestConnection: if_config() returned %d "
|
||||
"(ip=%s netmask=%s gateway=%s)\n",
|
||||
(int_t)ret,
|
||||
NETWORK.platform.ip,
|
||||
NETWORK.platform.netmask,
|
||||
NETWORK.platform.gateway
|
||||
);
|
||||
logDebug(
|
||||
"networkDolphinRequestConnection: MEM1 arena free after if_config(): "
|
||||
"%u bytes (lo=%p hi=%p)\n",
|
||||
(uint32_t)((uint8_t *)SYS_GetArena1Hi() - (uint8_t *)SYS_GetArena1Lo()),
|
||||
SYS_GetArena1Lo(), SYS_GetArena1Hi()
|
||||
);
|
||||
|
||||
// Rejecting the connection (no cable/AP, DHCP timeout) is a routine,
|
||||
// expected outcome, not a programming error. It must never be able to
|
||||
// bring the whole program down, so this only logs and skips the
|
||||
// callback if it's unexpectedly missing, rather than asserting.
|
||||
if(ret >= 0) {
|
||||
NETWORK.state = NETWORK_STATE_CONNECTED;
|
||||
assertNotNull(
|
||||
NETWORK.platform.onConnected,
|
||||
"Network platform onConnected callback should be set."
|
||||
);
|
||||
NETWORK.platform.onConnected(NETWORK.platform.onConnectedUser);
|
||||
} else {
|
||||
NETWORK.state = NETWORK_STATE_DISCONNECTED;
|
||||
assertNotNull(
|
||||
NETWORK.platform.onFailed,
|
||||
"Network platform onFailed callback should be set."
|
||||
);
|
||||
errorret_t error = errorThrowImpl(
|
||||
&NETWORK.errorState,
|
||||
ERROR_NOT_OK,
|
||||
__FILE__, __func__, __LINE__,
|
||||
"Failed to connect to network"
|
||||
);
|
||||
logDebug("networkDolphinRequestConnection: connected\n");
|
||||
if(NETWORK.platform.onConnected) {
|
||||
NETWORK.platform.onConnected(NETWORK.platform.onConnectedUser);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NETWORK.state = NETWORK_STATE_DISCONNECTED;
|
||||
logDebug(
|
||||
"networkDolphinRequestConnection: failed to connect (if_config "
|
||||
"returned %d)\n",
|
||||
(int_t)ret
|
||||
);
|
||||
errorret_t error = errorThrowImpl(
|
||||
&NETWORK.errorState,
|
||||
ERROR_NOT_OK,
|
||||
__FILE__, __func__, __LINE__,
|
||||
"Failed to connect to network"
|
||||
);
|
||||
if(NETWORK.platform.onFailed) {
|
||||
NETWORK.platform.onFailed(error, NETWORK.platform.onConnectedUser);
|
||||
} else {
|
||||
errorCatch(errorPrint(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,15 @@
|
||||
|
||||
#define NETWORK_DOLPHIN_IP_MAX 16
|
||||
|
||||
#ifdef DUSK_GAMECUBE
|
||||
// No DNS client is implemented for GameCube yet (see
|
||||
// networkSocketDolphinConnect) -- only literal IP addresses work.
|
||||
// A future resolver should query this server.
|
||||
#ifndef NETWORK_DOLPHIN_DNS_SERVER_IP
|
||||
#define NETWORK_DOLPHIN_DNS_SERVER_IP "0.0.0.0"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char_t ip[NETWORK_DOLPHIN_IP_MAX];
|
||||
char_t netmask[NETWORK_DOLPHIN_IP_MAX];
|
||||
@@ -23,37 +32,39 @@ typedef struct {
|
||||
} networkdolphin_t;
|
||||
|
||||
/**
|
||||
* Initializes the Wii network stack via IOS. Does not connect; use
|
||||
* networkDolphinRequestConnection for that.
|
||||
* Initializes the network stack (IOS on Wii, bundled lwIP + BBA driver on
|
||||
* GameCube). Does not connect; use networkDolphinRequestConnection for
|
||||
* that.
|
||||
*
|
||||
* @return Error state (if any).
|
||||
*/
|
||||
errorret_t networkDolphinInit();
|
||||
|
||||
/**
|
||||
* Called each frame. No-op on Wii since connection is synchronous.
|
||||
* Called each frame. No-op since connection is synchronous.
|
||||
*
|
||||
* @return Error state (if any).
|
||||
*/
|
||||
errorret_t networkDolphinUpdate();
|
||||
|
||||
/**
|
||||
* Disposes the Wii network stack.
|
||||
* Disposes the network stack.
|
||||
*
|
||||
* @return Error state (if any).
|
||||
*/
|
||||
errorret_t networkDolphinDispose();
|
||||
|
||||
/**
|
||||
* Returns true if the Wii is connected to a network.
|
||||
* Returns true if connected to a network.
|
||||
*
|
||||
* @return True if connected.
|
||||
*/
|
||||
bool_t networkDolphinIsConnected();
|
||||
|
||||
/**
|
||||
* Requests the Wii to connect to the network using the Wi-Fi settings saved
|
||||
* in the Wii System Menu. Blocks until connected or failed.
|
||||
* Requests a connection to the network: the Wi-Fi settings saved in the
|
||||
* Wii System Menu on Wii, or DHCP over the Broadband Adapter on GameCube.
|
||||
* Blocks until connected or failed.
|
||||
*
|
||||
* @param onConnected Callback on successful connection.
|
||||
* @param onFailed Callback if connection fails.
|
||||
@@ -68,7 +79,7 @@ void networkDolphinRequestConnection(
|
||||
);
|
||||
|
||||
/**
|
||||
* Requests the Wii to disconnect from the network.
|
||||
* Requests to disconnect from the network.
|
||||
*
|
||||
* @param onComplete Callback when disconnection is complete.
|
||||
* @param user User data passed to the callback.
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include "networksocketdolphin.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
#include "log/log.h"
|
||||
|
||||
#ifdef DUSK_WII
|
||||
#if defined(DUSK_WII) || defined(DUSK_GAMECUBE)
|
||||
#include <network.h>
|
||||
#endif
|
||||
|
||||
@@ -21,24 +22,60 @@ errorret_t networkSocketDolphinConnect(
|
||||
assertNotNull(sock, "sock must not be NULL");
|
||||
assertNotNull(host, "host must not be NULL");
|
||||
|
||||
#ifdef DUSK_WII
|
||||
struct hostent *entry = net_gethostbyname(host);
|
||||
if(entry == NULL || entry->h_addr_list[0] == NULL) {
|
||||
errorThrow("Failed to resolve host %s", host);
|
||||
}
|
||||
logDebug(
|
||||
"networkSocketDolphinConnect: resolving %s:%u\n", host, (uint32_t)port
|
||||
);
|
||||
|
||||
#if defined(DUSK_WII) || defined(DUSK_GAMECUBE)
|
||||
struct in_addr resolved;
|
||||
|
||||
#ifdef DUSK_WII
|
||||
struct hostent *entry = net_gethostbyname(host);
|
||||
if(entry == NULL || entry->h_addr_list[0] == NULL) {
|
||||
logDebug(
|
||||
"networkSocketDolphinConnect: net_gethostbyname(%s) failed\n", host
|
||||
);
|
||||
errorThrow("Failed to resolve host %s", host);
|
||||
}
|
||||
memoryCopy(&resolved, entry->h_addr_list[0], sizeof(resolved));
|
||||
#else
|
||||
// GameCube's bundled lwIP stack has no DNS resolver (see
|
||||
// NETWORK_DOLPHIN_DNS_SERVER_IP in networkdolphin.h) -- only
|
||||
// literal IP addresses work until a resolver is written against
|
||||
// that server.
|
||||
if(!inet_aton(host, &resolved)) {
|
||||
logDebug(
|
||||
"networkSocketDolphinConnect: inet_aton(%s) failed\n", host
|
||||
);
|
||||
errorThrow(
|
||||
"Failed to resolve host %s (GameCube requires a literal IP "
|
||||
"address; DNS is not yet supported)", host
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
logDebug(
|
||||
"networkSocketDolphinConnect: resolved %s to %s\n",
|
||||
host, inet_ntoa(resolved)
|
||||
);
|
||||
|
||||
const s32 fd = net_socket(AF_INET, SOCK_STREAM, 0);
|
||||
logDebug(
|
||||
"networkSocketDolphinConnect: net_socket() returned fd=%d\n",
|
||||
(int_t)fd
|
||||
);
|
||||
if(fd < 0) errorThrow("Failed to create socket: %d", (int_t)fd);
|
||||
|
||||
struct sockaddr_in serverAddr;
|
||||
memoryZero(&serverAddr, sizeof(serverAddr));
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_port = htons(port);
|
||||
memoryCopy(
|
||||
&serverAddr.sin_addr, entry->h_addr_list[0], sizeof(serverAddr.sin_addr)
|
||||
);
|
||||
serverAddr.sin_addr = resolved;
|
||||
|
||||
const s32 ret = net_connect(fd, (void *)&serverAddr, sizeof(serverAddr));
|
||||
logDebug(
|
||||
"networkSocketDolphinConnect: net_connect() returned %d\n", (int_t)ret
|
||||
);
|
||||
if(ret < 0) {
|
||||
net_close(fd);
|
||||
errorThrow("Failed to connect to %s:%u: %d", host, port, (int_t)ret);
|
||||
@@ -63,8 +100,12 @@ errorret_t networkSocketDolphinSend(
|
||||
assertNotNull(data, "data must not be NULL");
|
||||
assertNotNull(outSent, "outSent must not be NULL");
|
||||
|
||||
#ifdef DUSK_WII
|
||||
#if defined(DUSK_WII) || defined(DUSK_GAMECUBE)
|
||||
const s32 sent = net_send(sock->fd, data, (s32)length, 0);
|
||||
logDebug(
|
||||
"networkSocketDolphinSend: net_send(fd=%d, len=%u) returned %d\n",
|
||||
sock->fd, (uint32_t)length, (int_t)sent
|
||||
);
|
||||
if(sent < 0) errorThrow("Failed to send data: %d", (int_t)sent);
|
||||
|
||||
*outSent = (size_t)sent;
|
||||
@@ -84,8 +125,12 @@ errorret_t networkSocketDolphinReceive(
|
||||
assertNotNull(buffer, "buffer must not be NULL");
|
||||
assertNotNull(outReceived, "outReceived must not be NULL");
|
||||
|
||||
#ifdef DUSK_WII
|
||||
#if defined(DUSK_WII) || defined(DUSK_GAMECUBE)
|
||||
const s32 received = net_recv(sock->fd, buffer, (s32)bufferSize, 0);
|
||||
logDebug(
|
||||
"networkSocketDolphinReceive: net_recv(fd=%d, max=%u) returned %d\n",
|
||||
sock->fd, (uint32_t)bufferSize, (int_t)received
|
||||
);
|
||||
if(received < 0) errorThrow("Failed to receive data: %d", (int_t)received);
|
||||
|
||||
*outReceived = (size_t)received;
|
||||
@@ -98,7 +143,8 @@ errorret_t networkSocketDolphinReceive(
|
||||
void networkSocketDolphinClose(networksocketdolphin_t *sock) {
|
||||
assertNotNull(sock, "sock must not be NULL");
|
||||
|
||||
#ifdef DUSK_WII
|
||||
#if defined(DUSK_WII) || defined(DUSK_GAMECUBE)
|
||||
logDebug("networkSocketDolphinClose: closing fd=%d\n", sock->fd);
|
||||
if(sock->fd >= 0) net_close(sock->fd);
|
||||
#endif
|
||||
sock->fd = -1;
|
||||
|
||||
@@ -14,8 +14,10 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* Resolves host and opens a blocking TCP connection to host:port.
|
||||
* Always fails under plain DUSK_GAMECUBE -- retail GameCube units have
|
||||
* no network hardware.
|
||||
* On Wii, host may be a hostname (resolved via IOS's DNS resolver) or an
|
||||
* IP address. On GameCube, host must be a literal IP address -- the
|
||||
* bundled lwIP stack has no DNS resolver yet (see
|
||||
* NETWORK_DOLPHIN_DNS_SERVER_IP in networkdolphin.h).
|
||||
*
|
||||
* @param sock The socket structure to initialize.
|
||||
* @param host The hostname or IP address to connect to.
|
||||
|
||||
Reference in New Issue
Block a user