yeah whatever
This commit is contained in:
@@ -6,7 +6,7 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
# bba
|
||||
bba
|
||||
)
|
||||
|
||||
# ISO post-build: produce NTSC-J, NTSC-U and PAL disc images
|
||||
|
||||
+1
-153
@@ -12,20 +12,15 @@
|
||||
#include "locale/localemanager.h"
|
||||
#include "display/display.h"
|
||||
#include "scene/scene.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
#include "display/color.h"
|
||||
#include "asset/asset.h"
|
||||
#include "ui/ui.h"
|
||||
#include "assert/assert.h"
|
||||
#include "network/network.h"
|
||||
#include "network/http/networkhttprequest.h"
|
||||
#include "system/system.h"
|
||||
#include "console/console.h"
|
||||
#include "save/save.h"
|
||||
#include "save/savesettings.h"
|
||||
#include "log/log.h"
|
||||
|
||||
engine_t ENGINE;
|
||||
|
||||
@@ -51,85 +46,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(networkInit());
|
||||
errorChain(sceneInit());
|
||||
|
||||
// Test: three colored cubes falling onto each other and a static floor,
|
||||
// viewed by a static camera.
|
||||
ENGINE.testSceneId = sceneCreate();
|
||||
sceneSetActive(ENGINE.testSceneId);
|
||||
entitymanager_t *testEntities = sceneGetEntities(ENGINE.testSceneId);
|
||||
|
||||
entityid_t testCamera = entityManagerAdd(testEntities);
|
||||
componentid_t testCameraPosition = entityAddComponent(
|
||||
testEntities, testCamera, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityAddComponent(testEntities, testCamera, COMPONENT_TYPE_CAMERA);
|
||||
entityPositionLookAt(
|
||||
testEntities, testCamera, testCameraPosition,
|
||||
(vec3){ 4.0f, 3.0f, 4.0f },
|
||||
(vec3){ 0.0f, 0.0f, 0.0f },
|
||||
(vec3){ 0.0f, 1.0f, 0.0f }
|
||||
);
|
||||
|
||||
// Static floor: a wide, thin box. Its render scale matches its physics
|
||||
// half-extents exactly, since CUBE_MESH_SIMPLE and PHYSICS_SHAPE_CUBE are
|
||||
// both centered on the entity's position.
|
||||
entityid_t floorEntity = entityManagerAdd(testEntities);
|
||||
componentid_t floorPosition = entityAddComponent(
|
||||
testEntities, floorEntity, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionSetLocalPosition(
|
||||
testEntities, floorEntity, floorPosition, (vec3){ 0.0f, -1.0f, 0.0f }
|
||||
);
|
||||
entityPositionSetLocalScale(
|
||||
testEntities, floorEntity, floorPosition, (vec3){ 10.0f, 1.0f, 10.0f }
|
||||
);
|
||||
componentid_t floorPhysics = entityAddComponent(
|
||||
testEntities, floorEntity, COMPONENT_TYPE_PHYSICS
|
||||
);
|
||||
entityPhysicsSetBodyType(
|
||||
testEntities, floorEntity, floorPhysics, PHYSICS_BODY_STATIC
|
||||
);
|
||||
entityPhysicsSetShape(testEntities, floorEntity, floorPhysics, (physicsshape_t){
|
||||
.type = PHYSICS_SHAPE_CUBE,
|
||||
.data.cube.halfExtents = { 5.0f, 0.5f, 5.0f }
|
||||
});
|
||||
componentid_t floorRenderable = entityAddComponent(
|
||||
testEntities, floorEntity, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
entityRenderableSetColor(testEntities, floorEntity, floorRenderable, COLOR_GRAY);
|
||||
|
||||
// Three dynamic cubes, staggered above the floor with slight offsets so
|
||||
// they tumble and land on each other instead of falling in perfect sync.
|
||||
vec3 cubeStartPositions[3] = {
|
||||
{ -0.3f, 1.5f, 0.1f },
|
||||
{ 0.1f, 3.0f, -0.2f },
|
||||
{ -0.1f, 4.5f, 0.2f },
|
||||
};
|
||||
color_t cubeColors[3] = { COLOR_RED, COLOR_GREEN, COLOR_BLUE };
|
||||
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
entityid_t cubeEntity = entityManagerAdd(testEntities);
|
||||
componentid_t cubePosition = entityAddComponent(
|
||||
testEntities, cubeEntity, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionSetLocalPosition(
|
||||
testEntities, cubeEntity, cubePosition, cubeStartPositions[i]
|
||||
);
|
||||
entityAddComponent(testEntities, cubeEntity, COMPONENT_TYPE_PHYSICS);
|
||||
componentid_t cubeRenderable = entityAddComponent(
|
||||
testEntities, cubeEntity, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
entityRenderableSetColor(
|
||||
testEntities, cubeEntity, cubeRenderable, cubeColors[i]
|
||||
);
|
||||
}
|
||||
|
||||
networkRequestConnection(
|
||||
engineNetworkOnConnected,
|
||||
engineNetworkOnFailed,
|
||||
engineNetworkOnDisconnect,
|
||||
NULL
|
||||
);
|
||||
|
||||
consolePrint("Engine initialized");
|
||||
|
||||
#ifdef DUSK_ASSERTIONS_FAKED
|
||||
@@ -148,14 +64,6 @@ errorret_t engineUpdate(void) {
|
||||
errorChain(networkUpdate());
|
||||
timeUpdate();
|
||||
|
||||
if(
|
||||
ENGINE.networkDisconnectTestPending &&
|
||||
TIME.time >= ENGINE.networkDisconnectTestAt
|
||||
) {
|
||||
ENGINE.networkDisconnectTestPending = false;
|
||||
networkRequestDisconnection(engineNetworkDisconnectTestOnComplete, NULL);
|
||||
}
|
||||
|
||||
const systemdialogtype_t dialogType = systemGetActiveDialogType();
|
||||
if(dialogType == SYSTEM_DIALOG_TYPE_NONE) {
|
||||
inputUpdate();
|
||||
@@ -193,63 +101,3 @@ errorret_t engineDispose(void) {
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void engineHttpTestOnComplete(void *params, void *user) {
|
||||
networkhttprequest_t *request = (networkhttprequest_t *)params;
|
||||
const networkhttpresponse_t *response = &request->response;
|
||||
|
||||
consolePrint("frogfind.com response status: %d", response->status);
|
||||
|
||||
for(uint32_t i = 0; i < response->headers.count; i++) {
|
||||
const networkhttpheader_t *header = &response->headers.headers[i];
|
||||
consolePrint("frogfind.com header: %s: %s", header->name, header->value);
|
||||
}
|
||||
|
||||
consolePrint("frogfind.com body length: %d", (int32_t)response->bodyLength);
|
||||
|
||||
const size_t chunkMax = CONSOLE_LINE_MAX - 32;
|
||||
for(size_t offset = 0; offset < response->bodyLength; offset += chunkMax) {
|
||||
size_t chunkLength = response->bodyLength - offset;
|
||||
if(chunkLength > chunkMax) chunkLength = chunkMax;
|
||||
|
||||
consolePrint("frogfind.com body: %.*s",
|
||||
(int32_t)chunkLength, (const char_t *)response->body + offset);
|
||||
}
|
||||
}
|
||||
|
||||
void engineHttpTestOnError(void *params, void *user) {
|
||||
consolePrint("frogfind.com request failed");
|
||||
}
|
||||
|
||||
void engineNetworkOnConnected(void *user) {
|
||||
consolePrint("Network connected");
|
||||
|
||||
errorret_t ret = networkHttpRequest(
|
||||
NETWORK_HTTP_METHOD_GET,
|
||||
"http://frogfind.com",
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
engineHttpTestOnComplete,
|
||||
engineHttpTestOnError,
|
||||
NULL
|
||||
);
|
||||
errorCatch(errorPrint(ret));
|
||||
|
||||
ENGINE.networkDisconnectTestAt = TIME.time + 10.0f;
|
||||
ENGINE.networkDisconnectTestPending = true;
|
||||
}
|
||||
|
||||
void engineNetworkOnFailed(errorret_t error, void *user) {
|
||||
consolePrint("Network connection failed");
|
||||
errorCatch(errorPrint(error));
|
||||
}
|
||||
|
||||
void engineNetworkOnDisconnect(errorret_t error, void *user) {
|
||||
consolePrint("Network disconnected");
|
||||
errorCatch(errorPrint(error));
|
||||
}
|
||||
|
||||
void engineNetworkDisconnectTestOnComplete(void *user) {
|
||||
consolePrint("Network disconnect test complete");
|
||||
}
|
||||
|
||||
@@ -10,22 +10,12 @@
|
||||
// Important to be included first:
|
||||
#include "display/display.h"
|
||||
#include "error/error.h"
|
||||
#include "scene/scenebase.h"
|
||||
#include "entity/entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
bool_t running;
|
||||
int32_t argc;
|
||||
const char_t **argv;
|
||||
const char_t *version;
|
||||
|
||||
// Test: disconnects the network 10 seconds after it connects.
|
||||
bool_t networkDisconnectTestPending;
|
||||
float_t networkDisconnectTestAt;
|
||||
|
||||
// Test: three colored cubes falling onto each other and a static floor,
|
||||
// viewed by a static camera.
|
||||
sceneid_t testSceneId;
|
||||
} engine_t;
|
||||
|
||||
extern engine_t ENGINE;
|
||||
@@ -47,52 +37,3 @@ errorret_t engineUpdate(void);
|
||||
* Shuts down the engine.
|
||||
*/
|
||||
errorret_t engineDispose(void);
|
||||
|
||||
/**
|
||||
* Logs the response status, headers and body of the frogfind.com test
|
||||
* request to the console.
|
||||
*
|
||||
* @param params The completed networkhttprequest_t.
|
||||
* @param user Unused.
|
||||
*/
|
||||
void engineHttpTestOnComplete(void *params, void *user);
|
||||
|
||||
/**
|
||||
* Logs that the frogfind.com test request failed.
|
||||
*
|
||||
* @param params The failed networkhttprequest_t.
|
||||
* @param user Unused.
|
||||
*/
|
||||
void engineHttpTestOnError(void *params, void *user);
|
||||
|
||||
/**
|
||||
* Fires the frogfind.com test request once the network connection is
|
||||
* up (some platforms, such as PSP, only bring the network stack up
|
||||
* asynchronously after networkRequestConnection is called).
|
||||
*
|
||||
* @param user Unused.
|
||||
*/
|
||||
void engineNetworkOnConnected(void *user);
|
||||
|
||||
/**
|
||||
* Logs that the network connection could not be established.
|
||||
*
|
||||
* @param error The error describing why the connection failed.
|
||||
* @param user Unused.
|
||||
*/
|
||||
void engineNetworkOnFailed(errorret_t error, void *user);
|
||||
|
||||
/**
|
||||
* Logs that the network connection was lost after having connected.
|
||||
*
|
||||
* @param error The error describing why the connection was lost.
|
||||
* @param user Unused.
|
||||
*/
|
||||
void engineNetworkOnDisconnect(errorret_t error, void *user);
|
||||
|
||||
/**
|
||||
* Logs that the 10-second test disconnect completed.
|
||||
*
|
||||
* @param user Unused.
|
||||
*/
|
||||
void engineNetworkDisconnectTestOnComplete(void *user);
|
||||
|
||||
@@ -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