libgui 2.01
libgui is a GUI library for the GameCube, Wii, and Wii U
 
Loading...
Searching...
No Matches
WiiNetwork.cpp
1/****************************************************************************
2 * Platform Abstraction Layer (OGC driver)
3 * Daryl Borth 2026
4 * WiiNetwork.cpp
5 ***************************************************************************/
6#include "WiiNetwork.h"
7
8#include <unistd.h>
9#include <errno.h>
10#include <network.h>
11
12#include "../../ThreadDriver.h"
13#include "../../Time.h"
14
15#define NETWORK_THREAD_STACKSIZE (8 * 1024)
16#define NETWORK_BRINGUP_TIMEOUT_SECS 10 // don't block forever if the network never comes up
17
18static ThreadSync & NetSync() { static ThreadSync s; return s; }
19static Thread networkThread;
20static bool networkIdle = false; // protected by NetSync().mutex - true once the current bring-up attempt has finished (success or exhausted retries)
21static bool networkUp = false; // protected by NetSync().mutex - result of that attempt
22static bool netPrevInit = false; // true once net_init_async has succeeded at least once; drives the teardown-before-retry dance below
23static void (*onUpCallback)() = nullptr; // protected by NetSync().mutex - armed by notifyWhenUp(), fired once (then cleared) on the first successful bring-up
24
25static void WakeNetworkThread()
26{
27 MutexLock guard(NetSync().mutex);
28 NetSync().workCond.signal();
29}
30
31/****************************************************************************
32 * NetworkThreadEntry
33 *
34 * Brings the network up (net_init_async, with its own bounded internal
35 * retry) and goes idle until ensureUp()/notifyWhenUp() wakes it for
36 * another try, or JoinAll()/requestStop() tears it down at app exit.
37 ***************************************************************************/
38static void * NetworkThreadEntry(void *)
39{
40 NetSync().mutex.lock();
41 while(!networkThread.stopRequested())
42 {
43 NetSync().mutex.unlock();
44
45 // Already up
46 bool success = (net_gethostip() > 0);
47
48 if(!success)
49 {
50 s32 res = -1;
51 int retry = 5;
52
53 while(retry > 0 && !networkThread.stopRequested())
54 {
55 if(netPrevInit)
56 {
57 net_deinit();
58 for(int i = 0; i < 400 && !networkThread.stopRequested(); i++) // up to 10 seconds to let the old connection tear down
59 {
60 res = net_get_status();
61 if(res != -EBUSY) // not still busy tearing down the old connection
62 {
63 usleep(2000);
64 net_wc24cleanup();
65 netPrevInit = false; // net_wc24cleanup only needs to run once per net_init_async success
66 usleep(20000);
67 break;
68 }
69 usleep(20000);
70 }
71 }
72
73 usleep(2000);
74 res = net_init_async(NULL, NULL);
75
76 if(res != 0)
77 {
78 sleep(1);
79 retry--;
80 continue;
81 }
82
83 res = net_get_status();
84 int wait = 400; // ~8 sec
85 while(res == -EBUSY && wait > 0 && !networkThread.stopRequested())
86 {
87 usleep(20000);
88 res = net_get_status();
89 wait--;
90 }
91
92 if(res == 0)
93 break;
94
95 retry--;
96 usleep(2000);
97 }
98
99 if(res == 0)
100 {
101 struct in_addr hostip;
102 hostip.s_addr = net_gethostip();
103 if(hostip.s_addr)
104 {
105 success = true;
106 netPrevInit = true;
107 }
108 }
109 }
110
111 void (*firedCallback)() = nullptr;
112
113 NetSync().mutex.lock();
114 networkUp = success;
115 networkIdle = true;
116 NetSync().idleCond.signal(); // wake anything blocked in ensureUp()
117
118 if(success && onUpCallback)
119 {
120 firedCallback = onUpCallback;
121 onUpCallback = nullptr;
122 }
123
124 if(firedCallback)
125 {
126 NetSync().mutex.unlock();
127 firedCallback();
128 NetSync().mutex.lock();
129 }
130
131 while(networkIdle && !networkThread.stopRequested())
132 NetSync().workCond.wait(NetSync().mutex);
133 }
134 NetSync().mutex.unlock();
135 return nullptr;
136}
137
139{
140 return net_gethostip() > 0;
141}
142
143bool WiiNetwork::ensureUp(bool (*cancel)(void))
144{
145 // The network can go stale (cable pulled, AP dropped, IOS reload) even
146 // after a prior successful bring-up, so re-check liveness every call
147 // rather than trusting a cached "we succeeded once" flag. This is a
148 // cheap call - only fall through to a full (re-)init if it fails.
149 if(net_gethostip() > 0)
150 return true;
151
152 if(!networkThread.isRunning())
153 {
154 {
155 MutexLock guard(NetSync().mutex);
156 networkIdle = false;
157 }
158 networkThread.start(NetworkThreadEntry, nullptr, NETWORK_THREAD_STACKSIZE, ThreadPriority::Low, WakeNetworkThread);
159 }
160 else
161 {
162 MutexLock guard(NetSync().mutex);
163 networkIdle = false;
164 NetSync().workCond.signal();
165 }
166
167 Ticks start = SystemTime::now();
168 while(SystemTime::diffSecs(start, SystemTime::now()) <= NETWORK_BRINGUP_TIMEOUT_SECS)
169 {
170 bool idle, up;
171 {
172 MutexLock guard(NetSync().mutex);
173 idle = networkIdle;
174 up = networkUp;
175 }
176
177 if(idle)
178 return up && net_gethostip() > 0;
179
180 if(cancel && cancel())
181 return false;
182
183 usleep(50 * 1000);
184 }
185 return false;
186}
187
188void WiiNetwork::notifyWhenUp(void (*callback)())
189{
190 {
191 MutexLock guard(NetSync().mutex);
192 onUpCallback = callback;
193 networkIdle = false;
194 }
195
196 if(!networkThread.isRunning())
197 networkThread.start(NetworkThreadEntry, nullptr, NETWORK_THREAD_STACKSIZE, ThreadPriority::Low, WakeNetworkThread);
198 else
199 WakeNetworkThread();
200}
201
203{
204 {
205 MutexLock guard(NetSync().mutex);
206 onUpCallback = nullptr;
207 }
208 networkThread.requestStop();
209 networkThread.join();
210}
RAII lock guard - locks on construction, unlocks on destruction.
Definition Mutex.h:37
static Ticks now()
Definition Time.h:28
static uint32_t diffSecs(Ticks start, Ticks end)
Definition Time.h:40
A platform thread.
Definition Thread.h:40
static void notifyWhenUp(void(*callback)())
Registers callback to run exactly once.
static void shutdown()
Stops and joins the background bring-up thread.
static bool isUp()
Non-blocking: true if the console currently has a usable IP.
static bool ensureUp(bool(*cancel)(void)=nullptr)
Brings the network interface up if it isn't already, or confirms it's still alive if it is.
Bundles the mutex and pair of condition variables used by the common producer/consumer handshake betw...
Definition Thread.h:141