diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2024-12-18 14:13:39 -0500 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2024-12-18 14:13:39 -0500 |
commit | 62f2eb908c6771f9ac89aa518c55fbc101df3447 (patch) | |
tree | 5e2410248dcbba40625c271a857549140f7b9e56 | |
parent | 2844eecb65501f7dafa4de15d7377bfb810e1158 (diff) | |
download | lingo-ap-tracker-62f2eb908c6771f9ac89aa518c55fbc101df3447.tar.gz lingo-ap-tracker-62f2eb908c6771f9ac89aa518c55fbc101df3447.tar.bz2 lingo-ap-tracker-62f2eb908c6771f9ac89aa518c55fbc101df3447.zip |
Handle exceptions when starting IPC connection
Also fixes bug where the IPC thread would double-lock the state mutex if the connection timed out and reached the maximum backoff interval.
-rw-r--r-- | src/ipc_state.cpp | 68 |
1 files changed, 41 insertions, 27 deletions
diff --git a/src/ipc_state.cpp b/src/ipc_state.cpp index 24d0115..62b1828 100644 --- a/src/ipc_state.cpp +++ b/src/ipc_state.cpp | |||
@@ -112,8 +112,6 @@ struct IPCState { | |||
112 | private: | 112 | private: |
113 | void Thread() { | 113 | void Thread() { |
114 | for (;;) { | 114 | for (;;) { |
115 | SetStatusMessage("Disconnected from game."); | ||
116 | |||
117 | // initialized is definitely true because it is set to true when the thread | 115 | // initialized is definitely true because it is set to true when the thread |
118 | // is created and only set to false within this block, when the thread is | 116 | // is created and only set to false within this block, when the thread is |
119 | // killed. Thus, a call to Connect would always at most set | 117 | // killed. Thus, a call to Connect would always at most set |
@@ -127,6 +125,8 @@ struct IPCState { | |||
127 | { | 125 | { |
128 | std::lock_guard state_guard(state_mutex); | 126 | std::lock_guard state_guard(state_mutex); |
129 | 127 | ||
128 | SetStatusMessage("Disconnected from game."); | ||
129 | |||
130 | should_disconnect = false; | 130 | should_disconnect = false; |
131 | 131 | ||
132 | slot_matches = false; | 132 | slot_matches = false; |
@@ -142,34 +142,49 @@ struct IPCState { | |||
142 | } | 142 | } |
143 | 143 | ||
144 | ipc_address = address; | 144 | ipc_address = address; |
145 | |||
146 | SetStatusMessage("Connecting to game..."); | ||
145 | } | 147 | } |
146 | 148 | ||
147 | int backoff_amount = 0; | 149 | int backoff_amount = 0; |
148 | 150 | ||
149 | SetStatusMessage("Connecting to game..."); | ||
150 | TrackerLog(fmt::format("Looking for game over IPC ({})...", ipc_address)); | 151 | TrackerLog(fmt::format("Looking for game over IPC ({})...", ipc_address)); |
151 | 152 | ||
152 | while (!TryConnect(ipc_address) || !connected) { | 153 | while (!connected) { |
153 | int backoff_limit = (backoff_amount + 1) * 10; | 154 | if (TryConnect(ipc_address)) { |
154 | 155 | int backoff_limit = (backoff_amount + 1) * 10; | |
155 | for (int i = 0; i < backoff_limit && !connected; i++) { | 156 | |
156 | // If Connect is called right before this block, we will see and handle | 157 | for (int i = 0; i < backoff_limit && !connected; i++) { |
157 | // should_disconnect. If it is called right after, we will do one bad | 158 | // If Connect is called right before this block, we will see and |
158 | // poll, one sleep, and then grab the mutex again right after. | 159 | // handle should_disconnect. If it is called right after, we will do |
159 | { | 160 | // one bad poll, one sleep, and then grab the mutex again right |
160 | std::lock_guard state_guard(state_mutex); | 161 | // after. |
161 | if (should_disconnect) { | 162 | { |
162 | break; | 163 | std::lock_guard state_guard(state_mutex); |
164 | if (should_disconnect) { | ||
165 | break; | ||
166 | } | ||
163 | } | 167 | } |
168 | |||
169 | ws->poll(); | ||
170 | |||
171 | // Back off | ||
172 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
164 | } | 173 | } |
165 | 174 | ||
166 | ws->poll(); | 175 | backoff_amount++; |
176 | } else { | ||
177 | std::lock_guard state_guard(state_mutex); | ||
167 | 178 | ||
168 | // Back off | 179 | if (!should_disconnect) { |
169 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); | 180 | should_disconnect = true; |
170 | } | 181 | address.clear(); |
171 | 182 | ||
172 | backoff_amount++; | 183 | SetStatusMessage("Disconnected from game."); |
184 | } | ||
185 | |||
186 | break; | ||
187 | } | ||
173 | 188 | ||
174 | // If Connect is called right before this block, we will see and handle | 189 | // If Connect is called right before this block, we will see and handle |
175 | // should_disconnect. If it is called right after, and the connection | 190 | // should_disconnect. If it is called right after, and the connection |
@@ -236,6 +251,8 @@ struct IPCState { | |||
236 | [this](const std::string& s) { OnError(s); }); | 251 | [this](const std::string& s) { OnError(s); }); |
237 | return true; | 252 | return true; |
238 | } catch (const std::exception& ex) { | 253 | } catch (const std::exception& ex) { |
254 | TrackerLog(fmt::format("Error connecting to Lingo: {}", ex.what())); | ||
255 | wxMessageBox(ex.what(), "Error connecting to Lingo", wxOK | wxICON_ERROR); | ||
239 | ws.reset(); | 256 | ws.reset(); |
240 | return false; | 257 | return false; |
241 | } | 258 | } |
@@ -303,26 +320,23 @@ struct IPCState { | |||
303 | 320 | ||
304 | void OnError(const std::string& s) {} | 321 | void OnError(const std::string& s) {} |
305 | 322 | ||
323 | // Assumes mutex is locked. | ||
306 | void CheckIfSlotMatches() { | 324 | void CheckIfSlotMatches() { |
307 | slot_matches = (tracker_ap_server == game_ap_server && | 325 | slot_matches = (tracker_ap_server == game_ap_server && |
308 | tracker_ap_user == game_ap_user); | 326 | tracker_ap_user == game_ap_user); |
309 | 327 | ||
310 | if (slot_matches) { | 328 | if (slot_matches) { |
311 | status_message = "Connected to game."; | 329 | SetStatusMessage("Connected to game."); |
312 | 330 | ||
313 | Sync(); | 331 | Sync(); |
314 | } else if (connected) { | 332 | } else if (connected) { |
315 | status_message = "Local game doesn't match AP slot."; | 333 | SetStatusMessage("Local game doesn't match AP slot."); |
316 | } | 334 | } |
317 | |||
318 | tracker_frame->UpdateStatusMessage(); | ||
319 | } | 335 | } |
320 | 336 | ||
337 | // Assumes mutex is locked. | ||
321 | void SetStatusMessage(std::optional<std::string> msg) { | 338 | void SetStatusMessage(std::optional<std::string> msg) { |
322 | { | 339 | status_message = msg; |
323 | std::lock_guard state_guard(state_mutex); | ||
324 | status_message = msg; | ||
325 | } | ||
326 | 340 | ||
327 | tracker_frame->UpdateStatusMessage(); | 341 | tracker_frame->UpdateStatusMessage(); |
328 | } | 342 | } |