diff --git a/Core/Config.cpp b/Core/Config.cpp index 5250751855..a61ea02740 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -955,7 +955,10 @@ static ConfigSetting controlSettings[] = { static ConfigSetting networkSettings[] = { ConfigSetting("EnableWlan", &g_Config.bEnableWlan, false, true, true), ConfigSetting("EnableAdhocServer", &g_Config.bEnableAdhocServer, false, true, true), + ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "myneighborsushicat.com", true, true), + ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), ConfigSetting("EnableUPnP", &g_Config.bEnableUPnP, false, true, true), + ConfigSetting("MinTimeout", &g_Config.iMinTimeout, 1, true, true), ConfigSetting("EnableNetworkChat", &g_Config.bEnableNetworkChat, false, true, true), ConfigSetting("ChatButtonPosition",&g_Config.iChatButtonPosition,BOTTOM_LEFT,true,true), @@ -995,9 +998,7 @@ static ConfigSetting systemParamSettings[] = { ReportedConfigSetting("PSPModel", &g_Config.iPSPModel, &DefaultPSPModel, true, true), ReportedConfigSetting("PSPFirmwareVersion", &g_Config.iFirmwareVersion, PSP_DEFAULT_FIRMWARE, true, true), ConfigSetting("NickName", &g_Config.sNickName, "PPSSPP", true, true), - ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "myneighborsushicat.com", true, true), ConfigSetting("MacAddress", &g_Config.sMACAddress, "", true, true), - ConfigSetting("PortOffset", &g_Config.iPortOffset, 0, true, true), ReportedConfigSetting("Language", &g_Config.iLanguage, &DefaultSystemParamLanguage, true, true), ConfigSetting("ParamTimeFormat", &g_Config.iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR, true, true), ConfigSetting("ParamDateFormat", &g_Config.iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD, true, true), diff --git a/Core/Config.h b/Core/Config.h index 077e75ada4..8ef4696b4f 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -396,9 +396,7 @@ public: // SystemParam std::string sNickName; - std::string proAdhocServer; std::string sMACAddress; - int iPortOffset; int iLanguage; int iTimeFormat; int iDateFormat; @@ -410,9 +408,12 @@ public: bool bSavedataUpgrade; // Networking + std::string proAdhocServer; bool bEnableWlan; bool bEnableAdhocServer; bool bEnableUPnP; + int iPortOffset; + int iMinTimeout; int iWlanAdhocChannel; bool bWlanPowerSave; bool bEnableNetworkChat; diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 855f991300..f0d1de9be4 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -42,7 +42,8 @@ #include "proAdhoc.h" #include "i18n/i18n.h" -uint16_t portOffset = g_Config.iPortOffset; +uint16_t portOffset; +uint32_t minSocketTimeoutUS; uint32_t fakePoolSize = 0; SceNetAdhocMatchingContext * contexts = NULL; int one = 1; @@ -215,8 +216,8 @@ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) { void changeBlockingMode(int fd, int nonblocking) { unsigned long on = 1; unsigned long off = 0; -#ifdef _WIN32 - if (nonblocking){ +#if defined(_WIN32) + if (nonblocking) { // Change to Non-Blocking Mode ioctlsocket(fd, FIONBIO, &on); } @@ -224,14 +225,31 @@ void changeBlockingMode(int fd, int nonblocking) { // Change to Blocking Mode ioctlsocket(fd, FIONBIO, &off); } +// If they have O_NONBLOCK, use the POSIX way to do it. On POSIX sockets Error code would be EINPROGRESS instead of EAGAIN +//#elif defined(O_NONBLOCK) #else - if(nonblocking == 1) fcntl(fd, F_SETFL, O_NONBLOCK); + int flags = fcntl(fd, F_GETFL, 0); + // Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. + if (flags == -1) + flags = 0; + if (nonblocking) { + // Set Non-Blocking Flag + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } else { - // Get Flags - int flags = fcntl(fd, F_GETFL); // Remove Non-Blocking Flag fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } +// Otherwise, use the old way of doing it (UNIX way). On UNIX sockets Error code would be EAGAIN instead of EINPROGRESS +/*#else + if (nonblocking) { + // Change to Non - Blocking Mode + ioctl(fd, FIONBIO, (char*)&on); + } + else { + // Change to Blocking Mode + ioctl(fd, FIONBIO, (char*)&off); + }*/ #endif } @@ -1613,6 +1631,16 @@ uint16_t getLocalPort(int sock) { return ntohs(localAddr.sin_port); } +int getSockMaxSize(int udpsock) { +#if !defined(SO_MAX_MSG_SIZE) +#define SO_MAX_MSG_SIZE 0x2003 +#endif + int n = 1500; // Typical MTU size as default + socklen_t m = sizeof(n); + getsockopt(udpsock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*)&n, &m); + return n; +} + int getSockBufferSize(int sock, int opt) { // opt = SO_RCVBUF/SO_SNDBUF int n = 16384; socklen_t m = sizeof(n); @@ -1625,22 +1653,45 @@ int setSockBufferSize(int sock, int opt, int size) { // opt = SO_RCVBUF/SO_SNDBU return setsockopt(sock, SOL_SOCKET, opt, (char *)&n, sizeof(n)); } +int setSockTimeout(int sock, int opt, unsigned long timeout_usec) { // opt = SO_SNDTIMEO/SO_RCVTIMEO + if (timeout_usec > 0 && timeout_usec < minSocketTimeoutUS) timeout_usec = minSocketTimeoutUS; // Override timeout for high latency multiplayer +#if defined(_WIN32) + unsigned long optval = timeout_usec / 1000UL; + if (timeout_usec > 0 && optval == 0) optval = 1; // Since there are games that use 100 usec timeout, we should set it to minimum value on Windows (1 msec) instead of using 0 (0 = indefinitely timeout) +#else + struct timeval optval = { static_cast(timeout_usec) / 1000000L, static_cast(timeout_usec) % 1000000L }; +#endif + return setsockopt(sock, SOL_SOCKET, opt, (char*)&optval, sizeof(optval)); +} + +int getSockNoDelay(int tcpsock) { + int opt = 0; + socklen_t optlen = sizeof(opt); + getsockopt(tcpsock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, &optlen); + return opt; +} + +int setSockNoDelay(int tcpsock, int flag) { + int opt = flag; + return setsockopt(tcpsock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); +} + #if !defined(TCP_KEEPIDLE) #define TCP_KEEPIDLE TCP_KEEPALIVE //TCP_KEEPIDLE on Linux is equivalent to TCP_KEEPALIVE on macOS #endif -int setSockKeepAlive(int sock, bool keepalive, const int keepcnt, const int keepidle, const int keepinvl) { +int setSockKeepAlive(int sock, bool keepalive, const int keepinvl, const int keepcnt, const int keepidle) { int optval = keepalive ? 1 : 0; int optlen = sizeof(optval); int result = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, optlen); if (result == 0 && keepalive) { if (getsockopt(sock, SOL_SOCKET, SO_TYPE, (char*)&optval, (socklen_t*)&optlen) == 0 && optval == SOCK_STREAM) { optlen = sizeof(optval); + optval = keepidle; //180 sec + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&optval, optlen); + optval = keepinvl; //60 sec + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&optval, optlen); optval = keepcnt; //20 setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&optval, optlen); - optval = keepidle; //180 - setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&optval, optlen); - optval = keepinvl; //60 - setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&optval, optlen); } } return result; diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 94518d3cdd..3b0b58b9d0 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -65,6 +65,7 @@ #undef EINPROGRESS #undef EISCONN #undef EALREADY +#undef ETIMEDOUT #define errno WSAGetLastError() #define ECONNABORTED WSAECONNABORTED #define ECONNRESET WSAECONNRESET @@ -73,12 +74,13 @@ #define EINPROGRESS WSAEWOULDBLOCK #define EISCONN WSAEISCONN #define EALREADY WSAEALREADY +#define ETIMEDOUT WSAETIMEDOUT inline bool connectInProgress(int errcode){ return (errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == WSAEALREADY); } #else #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket close -inline bool connectInProgress(int errcode){ return (errcode == EINPROGRESS || errcode == EALREADY); } +inline bool connectInProgress(int errcode){ return (errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EALREADY); } #endif #ifndef POLL_ERR @@ -841,6 +843,7 @@ extern SceNetAdhocPdpStat * pdp[255]; extern SceNetAdhocPtpStat * ptp[255]; extern uint16_t portOffset; +extern uint32_t minSocketTimeoutUS; extern bool isLocalServer; extern sockaddr LocalhostIP; // Used to differentiate localhost IP on multiple-instance extern sockaddr LocalIP; // IP of Network Adapter used to connect to Adhoc Server (LAN/WAN) @@ -1155,6 +1158,11 @@ int getActivePeerCount(const bool excludeTimedout = true); int getLocalIp(sockaddr_in * SocketAddress); uint32_t getLocalIp(int sock); +/* + * Get UDP Socket Max Message Size + */ +int getSockMaxSize(int udpsock); + /* * Get Socket Buffer Size (opt = SO_RCVBUF/SO_SNDBUF) */ @@ -1165,10 +1173,25 @@ int getSockBufferSize(int sock, int opt); */ int setSockBufferSize(int sock, int opt, int size); +/* +* Set Socket TimeOut (opt = SO_SNDTIMEO/SO_RCVTIMEO) +*/ +int setSockTimeout(int sock, int opt, unsigned long timeout_usec); + +/* + * Get TCP Socket TCP_NODELAY (Nagle Algo) + */ +int getSockNoDelay(int tcpsock); + +/* +* Set TCP Socket TCP_NODELAY (Nagle Algo) +*/ +int setSockNoDelay(int tcpsock, int flag); + /* * Set Socket KeepAlive (opt = SO_KEEPALIVE) */ -int setSockKeepAlive(int sock, bool keepalive, const int keepcnt = 20, const int keepidle = 180, const int keepinvl = 60); +int setSockKeepAlive(int sock, bool keepalive, const int keepinvl = 60, const int keepcnt = 20, const int keepidle = 180); /** * Return the Number of Players with the chosen Nickname in the Local Users current Network diff --git a/Core/HLE/proAdhocServer.cpp b/Core/HLE/proAdhocServer.cpp index a385e7d8e5..c8ef8ea79c 100644 --- a/Core/HLE/proAdhocServer.cpp +++ b/Core/HLE/proAdhocServer.cpp @@ -37,6 +37,7 @@ #else #include #include +#include #endif #include @@ -476,6 +477,8 @@ const char * strcpyxml(char * out, const char * in, uint32_t size); // Function Prototypes void interrupt(int sig); void enable_address_reuse(int fd); +void enable_keepalive(int fd); +void change_nodelay_mode(int fd, int flag); void change_blocking_mode(int fd, int nonblocking); int create_listen_socket(uint16_t port); int server_loop(int server); @@ -1743,6 +1746,17 @@ void enable_keepalive(int fd) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); } +/** + * Change TCP Socket TCP_NODELAY (Nagle Algo) mode + * @param fd Socket + * @param nonblocking 1 for Nonblocking, 0 for Blocking + */ +void change_nodelay_mode(int fd, int flag) +{ + int opt = flag; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); +} + /** * Change Socket Blocking Mode * @param fd Socket @@ -1799,6 +1813,9 @@ int create_listen_socket(uint16_t port) // Make Socket Nonblocking change_blocking_mode(fd, 1); + // Make TCP Socket send immediately + change_nodelay_mode(fd, 1); + // Prepare Local Address Information struct sockaddr_in local; memset(&local, 0, sizeof(local)); diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 7b6a5aea78..24bd5fd38b 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -115,7 +115,9 @@ static void __ResetInitNetLib() { } void __NetInit() { + // Windows: Assuming WSAStartup already called beforehand portOffset = g_Config.iPortOffset; + minSocketTimeoutUS = g_Config.iMinTimeout * 1000UL; InitLocalhostIP(); @@ -149,8 +151,6 @@ void __NetShutdown() { g_PortManager.Restore(); g_PortManager.Deinit(); } - - //PPSSPPIDCleanup(); // To make the ID/IP persistent on every reset, we should just let the OS closes all open handles instead of calling PPSSPPIDCleanup() on every reset } static void __UpdateApctlHandlers(int oldState, int newState, int flag, int error) { diff --git a/Core/Util/PortManager.cpp b/Core/Util/PortManager.cpp index cd531043d7..cb518ec275 100644 --- a/Core/Util/PortManager.cpp +++ b/Core/Util/PortManager.cpp @@ -104,6 +104,7 @@ bool PortManager::Init(const unsigned int timeout) { break; } } + m_leaseDuration = "43200"; // 12 hours m_InitState = UPNP_INITSTATE_BUSY; urls = (UPNPUrls*)malloc(sizeof(struct UPNPUrls)); @@ -165,6 +166,7 @@ bool PortManager::Init(const unsigned int timeout) { RefreshPortList(); return true; } + ERROR_LOG(SCENET, "PortManager - upnpDiscover failed (error: %i) or No UPnP device detected", error); auto n = GetI18NCategory("Networking"); host->NotifyUserMessage(n->T("Unable to find UPnP device"), 6.0f, 0x0000ff); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 78d860f234..a7088a829d 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -693,6 +693,7 @@ void GameSettingsScreen::CreateViews() { networkingSettings->Add(new CheckBox(&g_Config.bEnableUPnP, n->T("Enable UPnP", "Enable UPnP (need a few seconds to detect)"))); networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.sMACAddress, n->T("Change Mac Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeMacAddress); networkingSettings->Add(new PopupSliderChoice(&g_Config.iPortOffset, 0, 60000, n->T("Port offset", "Port offset(0 = PSP compatibility)"), 100, screenManager())); + networkingSettings->Add(new PopupSliderChoice(&g_Config.iMinTimeout, 1, 15000, n->T("Minimum Timeout", "Minimum Timeout (override low latency communication in milliseconds)"), 100, screenManager())); networkingSettings->Add(new ItemHeader(n->T("Chat"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableNetworkChat, n->T("Enable network chat", "Enable network chat")));