From bbf07fe518226b91545b87d320391f55c3ff3483 Mon Sep 17 00:00:00 2001 From: genxium Date: Sat, 28 Jan 2023 10:52:52 +0800 Subject: [PATCH] Fixed Android segfault on mysterious udp reception callback. --- frontend/assets/scripts/Map.js | 43 +++++++++--------- .../runtime-src/Classes/udp_session.cpp | 44 ++++++++++++------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index 3c5e1a9..06011d2 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -43,30 +43,27 @@ window.onUdpMessage = (args) => { } cc.log(`#1 Js called back by CPP: onUdpMessage: args=${args}, typeof(args)=${typeof (args)}, argslen=${args.length}, ui8Arr=${ui8Arr}`); - if (6 == len) { - cc.log(`#2 Js called back by CPP for peer hole punching`); - } else { - const req = window.pb.protos.WsReq.decode(ui8Arr); - if (req) { - cc.log(`#2 Js called back by CPP for upsync: onUdpMessage: ${JSON.stringify(req)}`); - if (req.act && window.UPSYNC_MSG_ACT_PLAYER_CMD == req.act) { - const renderedInputFrameIdUpper = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId); - const peerJoinIndex = req.joinIndex; - const batch = req.inputFrameUpsyncBatch; - for (let k in batch) { - const inputFrameUpsync = batch[k]; - if (inputFrameUpsync.inputFrameId < renderedInputFrameIdUpper) { - // Avoid obfuscating already rendered history - continue; - } - if (inputFrameUpsync.inputFrameId <= self.lastAllConfirmedInputFrameId) { - continue; - } - self.getOrPrefabInputFrameUpsync(inputFrameUpsync.inputFrameId); // Make sure that inputFrame exists locally - const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameUpsync.inputFrameId); - existingInputFrame.InputList[inputFrameUpsync.joinIndex - 1] = inputFrameUpsync.encoded; // No need to change "confirmedList", leave it to "onInputFrameDownsyncBatch" -- we're just helping prediction here - self.recentInputCache.SetByFrameId(existingInputFrame, inputFrameUpsync.inputFrameId); + cc.log(`#2 Js called back by CPP for upsync: trying to decode by WsReq...`); + const req = window.pb.protos.WsReq.decode(ui8Arr); + if (req) { + cc.log(`#2 Js called back by CPP for upsync: onUdpMessage: ${JSON.stringify(req)}`); + if (req.act && window.UPSYNC_MSG_ACT_PLAYER_CMD == req.act) { + const renderedInputFrameIdUpper = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId); + const peerJoinIndex = req.joinIndex; + const batch = req.inputFrameUpsyncBatch; + for (let k in batch) { + const inputFrameUpsync = batch[k]; + if (inputFrameUpsync.inputFrameId < renderedInputFrameIdUpper) { + // Avoid obfuscating already rendered history + continue; } + if (inputFrameUpsync.inputFrameId <= self.lastAllConfirmedInputFrameId) { + continue; + } + self.getOrPrefabInputFrameUpsync(inputFrameUpsync.inputFrameId); // Make sure that inputFrame exists locally + const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameUpsync.inputFrameId); + existingInputFrame.InputList[inputFrameUpsync.joinIndex - 1] = inputFrameUpsync.encoded; // No need to change "confirmedList", leave it to "onInputFrameDownsyncBatch" -- we're just helping prediction here + self.recentInputCache.SetByFrameId(existingInputFrame, inputFrameUpsync.inputFrameId); } } } diff --git a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp index cc2a6b7..5865a74 100644 --- a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp +++ b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp @@ -14,30 +14,37 @@ struct PeerAddr peerAddrList[maxPeerCnt]; char SRV_IP[256]; int SRV_PORT = 0; -void _onRead(uv_udp_t* req, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { +void _onRead(uv_udp_t* req, ssize_t nread, uv_buf_t const* buf, struct sockaddr const* addr, unsigned flags) { if (nread < 0) { CCLOGERROR("Read error %s", uv_err_name(nread)); uv_close((uv_handle_t*)req, NULL); free(buf->base); return; } - - struct sockaddr_in* sockAddr = (struct sockaddr_in*)addr; - char ip[17] = { 0 }; - uv_ip4_name(sockAddr, ip, sizeof ip); - int port = ntohs(sockAddr->sin_port); - - int const gameThreadMsgSize = 256; - char* const gameThreadMsg = (char* const)malloc(gameThreadMsgSize); - memset(gameThreadMsg, 0, gameThreadMsgSize); - memcpy(gameThreadMsg, buf->base, nread); - - free(buf->base); - //uv_udp_recv_stop(req); - + if (NULL != addr) { + // The null check for "addr" is necessary, on Android there'd be such mysterious call to "_onRead"! + switch (addr->sa_family) { + case AF_INET: { + struct sockaddr_in const* sockAddr = (struct sockaddr_in const*)addr; + char ip[INET_ADDRSTRLEN]; + memset(ip, 0, sizeof ip); + //uv_ip4_name(sockAddr, ip, 16); + uv_inet_ntop(sockAddr->sin_family, &(sockAddr->sin_addr), ip, INET_ADDRSTRLEN); + int port = ntohs(sockAddr->sin_port); + CCLOG("UDP received %d bytes from %s:%d", nread, ip, port); + break; + } + default: + break; + } + } + if (6 != nread) { // Non-holepunching - CCLOG("UDP received %d bytes from %s:%d, converted to %d bytes for the JS callback", nread, ip, port, strlen(gameThreadMsg)); + int const gameThreadMsgSize = 256; + char* const gameThreadMsg = (char* const)malloc(gameThreadMsgSize); + memset(gameThreadMsg, 0, gameThreadMsgSize); + memcpy(gameThreadMsg, buf->base, nread); cocos2d::Application::getInstance()->getScheduler()->performFunctionInCocosThread([=]() { // [WARNING] Use of the "ScriptEngine" is only allowed in "GameThread a.k.a. CocosThread"! se::Value onUdpMessageCb; @@ -55,8 +62,11 @@ void _onRead(uv_udp_t* req, ssize_t nread, const uv_buf_t* buf, const struct soc free(gameThreadMsg); }); } else { - CCLOG("UDP received hole punching from %s:%d", ip, port); + CCLOG("UDP received hole punching"); } + free(buf->base); + //uv_udp_recv_stop(req); + uv_close((uv_handle_t*)req, NULL); } static void _allocBuffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {