Windows recvfrom doesn't support MSG_TRUNC, so we're using dummy buffer with max size as alternative for peeking actual size of the next pending message.

This commit is contained in:
ANR2ME committed 2021-02-11 07:40:35 +07:00
1 parent fc452c0dfd
commit 0ce2c2c6e9
4 files changed
+19 -12

No files matched your search

+3 -6
View File
@@ -60,6 +60,8 @@ uint16_t portOffset;
uint32_t minSocketTimeoutUS;
uint32_t fakePoolSize = 0;
SceNetAdhocMatchingContext * contexts = NULL;
char* dummyPeekBuf64k = NULL;
int dummyPeekBuf64kSize = 65536;
int one = 1;
bool friendFinderRunning = false;
SceNetAdhocctlPeerInfo * friends = NULL;
@@ -1908,12 +1910,7 @@ u_long getAvailToRecv(int sock, int udpBufferSize) {
return 0;
if (udpBufferSize > 0 && n > 0) {
// TODO: Cap number of bytes of full DGRAM message(s) up to buffer size
char buf[8];
// Each recv can only received one message, not sure how to read the next pending msg without actually receiving the first one
err = recvfrom(sock, buf, sizeof(buf), MSG_PEEK | MSG_NOSIGNAL | MSG_TRUNC, NULL, NULL);
if (err >= 0)
return (u_long)err;
// TODO: Cap number of bytes of full DGRAM message(s) up to buffer size, but may cause Warriors Orochi 2 to get FPS drops
}
return n;
}
+2
View File
@@ -917,6 +917,8 @@ extern int defaultWlanChannel; // Default WLAN Channel for Auto, JPCSP uses 11
extern uint32_t fakePoolSize;
extern SceNetAdhocMatchingContext * contexts;
extern char* dummyPeekBuf64k;
extern int dummyPeekBuf64kSize;
extern int one;
extern bool friendFinderRunning;
extern SceNetAdhocctlPeerInfo * friends;
+3
View File
@@ -203,6 +203,7 @@ void __NetInit() {
g_adhocServerIP.in.sin_port = htons(SERVER_PORT); //27312 // Maybe read this from config too
g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE;
dummyPeekBuf64k = (char*)malloc(dummyPeekBuf64kSize);
InitLocalhostIP();
SceNetEtherAddr mac;
@@ -235,6 +236,8 @@ void __NetShutdown() {
// Since PortManager supposed to be general purpose for whatever port forwarding PPSSPP needed, may be we shouldn't clear & restore ports in here? it will be cleared and restored by PortManager's destructor when exiting PPSSPP anyway
__UPnPShutdown();
free(dummyPeekBuf64k);
}
static void __UpdateApctlHandlers(u32 oldState, u32 newState, u32 flag, u32 error) {
+11 -6
View File
@@ -412,9 +412,11 @@ int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) {
memset(&sin, 0, sizeof(sin));
socklen_t sinlen = sizeof(sin);
// On Windows: Using MSG_TRUNC can sometimes getting socket error WSAEOPNOTSUPP, may be the socket wasn't ready to received anything right after created & binded?
int ret = recvfrom(uid, (char*)req.buffer, *req.length, MSG_PEEK | MSG_NOSIGNAL | MSG_TRUNC, (sockaddr*)&sin, &sinlen);
// On Windows: MSG_TRUNC are not supported on recvfrom (socket error WSAEOPNOTSUPP), so we use dummy buffer as an alternative
int ret = recvfrom(uid, dummyPeekBuf64k, dummyPeekBuf64kSize, MSG_PEEK | MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen);
int sockerr = errno;
if (ret > 0 && *req.length > 0)
memcpy(req.buffer, dummyPeekBuf64k, std::min(ret, *req.length));
// Note: UDP must not be received partially, otherwise leftover data in socket's buffer will be discarded
if (ret >= 0 && ret <= *req.length) {
@@ -453,7 +455,7 @@ int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) {
result = 0;
}
// On Windows: recvfrom on UDP can get error WSAECONNRESET when previous sendto's destination is unreachable (or destination port is not bound yet), may need to disable SIO_UDP_CONNRESET error
else if (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ECONNRESET || sockerr == EOPNOTSUPP) {
else if (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ECONNRESET) {
u64 now = (u64)(time_now_d() * 1000000.0);
if (req.timeout == 0 || now - req.startTime <= req.timeout) {
// Try again later
@@ -1691,8 +1693,11 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *
// Receive Data. PDP always sent in full size or nothing(failed), recvfrom will always receive in full size as requested (blocking) or failed (non-blocking). If available UDP data is larger than buffer, excess data is lost.
// Should peek first for the available data size if it's more than len return ERROR_NET_ADHOC_NOT_ENOUGH_SPACE along with required size in len to prevent losing excess data
// On Windows: Using MSG_TRUNC can sometimes getting socket error WSAEOPNOTSUPP, may be the socket wasn't ready to received anything right after created & binded?
received = recvfrom(pdpsocket.id, (char*)buf, *len, MSG_PEEK | MSG_NOSIGNAL | MSG_TRUNC, (sockaddr*)&sin, &sinlen);
// On Windows: MSG_TRUNC are not supported on recvfrom (socket error WSAEOPNOTSUPP), so we use dummy buffer as an alternative
received = recvfrom(pdpsocket.id, dummyPeekBuf64k, dummyPeekBuf64kSize, MSG_PEEK | MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen);
if (received > 0 && *len > 0)
memcpy(buf, dummyPeekBuf64k, std::min(received, *len));
if (received != SOCKET_ERROR && *len < received) {
WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, *len, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
*len = received;
@@ -1722,7 +1727,7 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *
error = errno;
// On Windows: recvfrom on UDP can get error WSAECONNRESET when previous sendto's destination is unreachable (or destination port is not bound), may need to disable SIO_UDP_CONNRESET
if (received == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ECONNRESET || error == EOPNOTSUPP)) {
if (received == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ECONNRESET)) {
if (flag == 0) {
// Simulate blocking behaviour with non-blocking socket
u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | pdpsocket.id;