mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
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:
commit
68735b4e52
3 changed files with 42 additions and 21 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue