Merge branch 'master' into jgrpp

# Conflicts:
#	.gitignore
#	CMakeLists.txt
#	src/3rdparty/optional/optional.hpp
#	src/group_cmd.cpp
#	src/industry_cmd.cpp
#	src/misc_gui.cpp
#	src/video/sdl2_v.cpp
This commit is contained in:
Jonathan G Rennison
2021-01-29 17:45:15 +00:00
68 changed files with 2084 additions and 1978 deletions

View File

@@ -265,6 +265,18 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
this->address_length = (int)runp->ai_addrlen;
assert(sizeof(this->address) >= runp->ai_addrlen);
memcpy(&this->address, runp->ai_addr, runp->ai_addrlen);
#ifdef __EMSCRIPTEN__
/* Emscripten doesn't zero sin_zero, but as we compare addresses
* to see if they are the same address, we need them to be zero'd.
* Emscripten is, as far as we know, the only OS not doing this.
*
* https://github.com/emscripten-core/emscripten/issues/12998
*/
if (this->address.ss_family == AF_INET) {
sockaddr_in *address_ipv4 = (sockaddr_in *)&this->address;
memset(address_ipv4->sin_zero, 0, sizeof(address_ipv4->sin_zero));
}
#endif
break;
}
@@ -297,7 +309,15 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type);
if (connect(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) {
int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen);
#ifdef __EMSCRIPTEN__
/* Emscripten is asynchronous, and as such a connect() is still in
* progress by the time the call returns. */
if (err != 0 && errno != EINPROGRESS)
#else
if (err != 0)
#endif
{
DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno));
closesocket(sock);
return INVALID_SOCKET;

View File

@@ -99,6 +99,16 @@ typedef unsigned long in_addr_t;
# include <errno.h>
# include <sys/time.h>
# include <netdb.h>
# if defined(__EMSCRIPTEN__)
/* Emscripten doesn't support AI_ADDRCONFIG and errors out on it. */
# undef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
/* Emscripten says it supports FD_SETSIZE fds, but it really only supports 64.
* https://github.com/emscripten-core/emscripten/issues/1711 */
# undef FD_SETSIZE
# define FD_SETSIZE 64
# endif
#endif /* UNIX */
/* OS/2 stuff */
@@ -160,6 +170,28 @@ typedef unsigned long in_addr_t;
#endif /* OS/2 */
#ifdef __EMSCRIPTEN__
/**
* Emscripten doesn't set 'addrlen' for accept(), getsockname(), getpeername()
* and recvfrom(), which confuses other functions and causes them to crash.
* This function needs to be called after these four functions to make sure
* 'addrlen' is patched up.
*
* https://github.com/emscripten-core/emscripten/issues/12996
*
* @param address The address returned by those four functions.
* @return The correct value for addrlen.
*/
static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address)
{
switch (address.ss_family) {
case AF_INET6: return sizeof(struct sockaddr_in6);
case AF_INET: return sizeof(struct sockaddr_in);
default: NOT_REACHED();
}
}
#endif
/**
* Try to set the socket into non-blocking mode.
* @param d The socket to set the non-blocking more for.
@@ -167,12 +199,16 @@ typedef unsigned long in_addr_t;
*/
static inline bool SetNonBlocking(SOCKET d)
{
#ifdef _WIN32
u_long nonblocking = 1;
#ifdef __EMSCRIPTEN__
return true;
#else
# ifdef _WIN32
u_long nonblocking = 1;
# else
int nonblocking = 1;
#endif
# endif
return ioctlsocket(d, FIONBIO, &nonblocking) == 0;
#endif
}
/**
@@ -197,10 +233,14 @@ static inline bool SetBlocking(SOCKET d)
*/
static inline bool SetNoDelay(SOCKET d)
{
#ifdef __EMSCRIPTEN__
return true;
#else
/* XXX should this be done at all? */
int b = 1;
/* The (const char*) cast is needed for windows */
return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0;
#endif
}

View File

@@ -42,6 +42,9 @@ public:
socklen_t sin_len = sizeof(sin);
SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
if (s == INVALID_SOCKET) return;
#ifdef __EMSCRIPTEN__
sin_len = FixAddrLenForEmscripten(sin);
#endif
SetNonBlocking(s); // XXX error handling?

View File

@@ -164,6 +164,9 @@ void NetworkUDPSocketHandler::ReceivePackets()
/* Did we get the bytes for the base header of the packet? */
if (nbytes <= 0) break; // No data, i.e. no packet
if (nbytes <= 2) continue; // Invalid data; try next packet
#ifdef __EMSCRIPTEN__
client_len = FixAddrLenForEmscripten(client_addr);
#endif
NetworkAddress address(client_addr, client_len);
p.PrepareToRead();

View File

@@ -1122,3 +1122,14 @@ bool IsNetworkCompatibleVersion(const char *other, bool extended)
{
return strncmp(_openttd_revision, other, (extended ? NETWORK_LONG_REVISION_LENGTH : NETWORK_REVISION_LENGTH) - 1) == 0;
}
#ifdef __EMSCRIPTEN__
extern "C" {
void CDECL em_openttd_add_server(const char *host, int port)
{
NetworkUDPQueryServer(NetworkAddress(host, port), true);
}
}
#endif

View File

@@ -23,6 +23,10 @@
#include <zlib.h>
#endif
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
#endif
#include "../safeguards.h"
extern bool HasScenario(const ContentInfo *ci, bool md5sum);
@@ -296,6 +300,13 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
{
bytes = 0;
#ifdef __EMSCRIPTEN__
/* Emscripten is loaded via an HTTPS connection. As such, it is very
* difficult to make HTTP connections. So always use the TCP method of
* downloading content. */
fallback = true;
#endif
ContentIDList content;
for (const ContentInfo *ci : this->infos) {
if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue;
@@ -542,6 +553,10 @@ void ClientNetworkContentSocketHandler::AfterDownload()
unlink(GetFullFilename(this->curInfo, false));
}
#ifdef __EMSCRIPTEN__
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
#endif
this->OnDownloadComplete(this->curInfo->id);
} else {
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);

View File

@@ -41,6 +41,9 @@
#include "../safeguards.h"
#ifdef __EMSCRIPTEN__
# include <emscripten.h>
#endif
static void ShowNetworkStartServerWindow();
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
@@ -490,6 +493,14 @@ public:
this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
this->SetFocusedWidget(WID_NG_FILTER);
/* As the master-server doesn't support "websocket" servers yet, we
* let "os/emscripten/pre.js" hardcode a list of servers people can
* join. This means the serverlist is curated for now, but it is the
* best we can offer. */
#ifdef __EMSCRIPTEN__
EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
#endif
this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
this->server = this->last_joined;
if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address);
@@ -630,6 +641,12 @@ public:
this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr);
this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible);
#ifdef __EMSCRIPTEN__
this->SetWidgetDisabledState(WID_NG_FIND, true);
this->SetWidgetDisabledState(WID_NG_ADD, true);
this->SetWidgetDisabledState(WID_NG_START, true);
#endif
this->DrawWidgets();
}