Merge pull request #13432 from ANR2ME/adhoc_socket

Fix an issue of major performance drops when using accepted PTP Sockets.
This commit is contained in:
Henrik Rydgård 2020-09-14 22:08:50 +02:00 committed by GitHub
commit 68735b4e52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 21 deletions

View file

@ -244,7 +244,7 @@ int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode, int timeout
tval.tv_sec = timeoutUS / 1000000;
tval.tv_usec = timeoutUS % 1000000;
int ret = select(fd + 1, &readfds, &writefds, nullptr, &tval);
int ret = select(fd + 1, readfd? &readfds: nullptr, writefd? &writefds: nullptr, nullptr, &tval);
if (errorcode != nullptr)
*errorcode = errno;
@ -1990,13 +1990,13 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
if (iResult == SOCKET_ERROR && errorcode != EISCONN) {
u64 startTime = (u64)(real_time_now() * 1000.0);
while (IsSocketReady(metasocket, true, true) <= 0) {
while (IsSocketReady(metasocket, false, true) <= 0) {
u64 now = (u64)(real_time_now() * 1000.0);
if (coreState == CORE_POWERDOWN) return iResult;
if (now - startTime > adhocDefaultTimeout) break;
sleep_ms(10);
}
if (IsSocketReady(metasocket, true, true) <= 0) {
if (IsSocketReady(metasocket, false, true) <= 0) {
ERROR_LOG(SCENET, "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), inet_ntoa(g_adhocServerIP.in.sin_addr), ntohs(g_adhocServerIP.in.sin_port));
host->NotifyUserMessage(n->T("Failed to connect to Adhoc Server"), 1.0f, 0x0000ff);
return iResult;

View file

@ -96,7 +96,7 @@ inline bool connectInProgress(int errcode){ return (errcode == EAGAIN || errcode
#endif
#ifndef SD_BOTH
#define SD_BOTH 0x02
#define SD_BOTH SHUT_RDWR //0x02
#endif
#define IsMatch(buf1, buf2) (memcmp(&buf1, &buf2, sizeof(buf1)) == 0)
@ -326,11 +326,12 @@ typedef struct SceNetAdhocPtpStat {
// PDP & PTP Socket Union (Internal use only)
typedef struct AdhocSocket {
s32_le type;
s32_le type; // SOCK_PDP/SOCK_PTP
s32_le flags; // Socket Alert Flags
u32 send_timeout;
u32 recv_timeout;
s32 connectCount;
u32 send_timeout; // default connect timeout
u32 recv_timeout; // default accept timeout
s32 retry_count; // combined with timeout to be used on keepalive
s32 attemptCount; // connect/accept attempts
union {
SceNetAdhocPdpStat pdp;
SceNetAdhocPtpStat ptp;

View file

@ -440,10 +440,15 @@ int DoBlockingPtpAccept(int uid, AdhocSocketRequest& req, s64& result) {
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
socklen_t sinlen = sizeof(sin);
int ret, sockerr;
// Accept Connection
int ret = accept(uid, (sockaddr*)&sin, &sinlen);
int sockerr = errno;
// Check if listening socket is ready to accept
ret = IsSocketReady(uid, true, false, &sockerr);
if (ret > 0) {
// Accept Connection
ret = accept(uid, (sockaddr*)&sin, &sinlen);
sockerr = errno;
}
// Accepted New Connection
if (ret > 0) {
@ -451,7 +456,7 @@ int DoBlockingPtpAccept(int uid, AdhocSocketRequest& req, s64& result) {
if (newid > 0)
result = newid;
}
else if (ret == SOCKET_ERROR && connectInProgress(sockerr)) {
else if (ret == 0 || (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK || sockerr == ETIMEDOUT))) {
u64 now = (u64)(real_time_now() * 1000000.0);
if (sock->flags & ADHOC_F_ALERTACCEPT) {
result = ERROR_NET_ADHOC_SOCKET_ALERTED;
@ -479,7 +484,7 @@ int DoBlockingPtpConnect(int uid, AdhocSocketRequest& req, s64& result) {
int sockerr;
// Wait for Connection (assuming "connect" has been called before)
int ret = IsSocketReady(uid, true, true, &sockerr);
int ret = IsSocketReady(uid, false, true, &sockerr);
// Connection is ready
if (ret > 0) {
@ -2669,6 +2674,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac,
// Socket Type
internal->type = SOCK_PTP;
internal->send_timeout = rexmt_int;
internal->retry_count = rexmt_cnt;
// Copy Infrastructure Socket ID
internal->data.ptp.id = tcpsocket;
@ -2737,6 +2743,9 @@ int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEther
// Enable Port Re-use
setSockReuseAddrPort(newsocket);
// Enable KeepAlive
setSockKeepAlive(newsocket, true, socket->recv_timeout / 1000000L, socket->retry_count);
// Disable Nagle Algo to send immediately. Or may be we shouldn't disable Nagle since there is PtpFlush function?
if (g_Config.bTCPNoDelay)
setSockNoDelay(newsocket, 1);
@ -2801,6 +2810,9 @@ int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEther
//sceNetPortOpen("TCP", internal->lport);
//g_PortManager.Add(IP_PROTOCOL_TCP, internal->lport + portOffset);
// Switch to non-blocking for futher usage
changeBlockingMode(newsocket, 1);
INFO_LOG(SCENET, "sceNetAdhocPtpAccept[%i->%i:%u]: Established (%s:%u)", ptpId, i + 1, internal->data.ptp.lport, inet_ntoa(peeraddr.sin_addr), internal->data.ptp.pport);
// Return Socket
@ -2864,16 +2876,22 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int
sockaddr_in peeraddr;
memset(&peeraddr, 0, sizeof(peeraddr));
socklen_t peeraddrlen = sizeof(peeraddr);
int error;
// Accept Connection
int newsocket = accept(ptpsocket.id, (sockaddr*)&peeraddr, &peeraddrlen);
int error = errno;
// Check if listening socket is ready to accept
int newsocket = IsSocketReady(ptpsocket.id, true, false, &error);
if (newsocket > 0) {
// Accept Connection
newsocket = accept(ptpsocket.id, (sockaddr*)&peeraddr, &peeraddrlen);
error = errno;
}
if (newsocket == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK)) {
if (newsocket == 0 || (newsocket == SOCKET_ERROR && (error == EAGAIN || error == EWOULDBLOCK || error == ETIMEDOUT))) {
socket->attemptCount++;
if (flag == 0) {
// Simulate blocking behaviour with non-blocking socket
u64 threadSocketId = ((u64)__KernelGetCurThread()) << 32 | ptpsocket.id;
return WaitBlockingAdhocSocket(threadSocketId, PTP_ACCEPT, id, nullptr, nullptr, timeout, addr, port, "ptp accept");
return WaitBlockingAdhocSocket(threadSocketId, PTP_ACCEPT, id, nullptr, nullptr, (flag) ? socket->recv_timeout : timeout, addr, port, "ptp accept");
}
// Prevent spamming Debug Log with retries of non-bocking socket
else {
@ -2883,6 +2901,7 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int
// Accepted New Connection
if (newsocket > 0) {
socket->attemptCount++;
int newid = AcceptPtpSocket(id, newsocket, peeraddr, addr, port);
if (newid >= 0)
return newid;
@ -2971,7 +2990,7 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) {
// Instant Connection (Lucky!)
if (connectresult != SOCKET_ERROR || errorcode == EISCONN) {
socket->connectCount++;
socket->attemptCount++;
// Set Connected State
ptpsocket.state = ADHOC_PTP_STATE_ESTABLISHED;
@ -2982,9 +3001,9 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) {
// Connection in Progress
else if (connectresult == SOCKET_ERROR && connectInProgress(errorcode)) {
socket->connectCount++;
socket->attemptCount++;
// Nonblocking Mode. First attempt need to be blocking for GvG Next Plus to work, even though it used non-blocking flag but only try to connect once per socket, which mean treating it just like blocking socket instead of non-blocking :(
if (flag && socket->connectCount > 1) {
if (flag && socket->attemptCount > 1) {
//if (errorcode == EALREADY) return ERROR_NET_ADHOC_BUSY;
return ERROR_NET_ADHOC_WOULD_BLOCK;
}
@ -3166,6 +3185,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int
// Socket Type
internal->type = SOCK_PTP;
internal->recv_timeout = rexmt_int;
internal->retry_count = rexmt_cnt;
// Copy Infrastructure Socket ID
internal->data.ptp.id = tcpsocket;