summaryrefslogtreecommitdiff
path: root/src/network/core/tcp_connect.cpp
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-01-20 11:28:18 +0000
committerrubidium <rubidium@openttd.org>2009-01-20 11:28:18 +0000
commit28a641066e2e9963f6662366281079b7d00ac835 (patch)
tree6b344cc0bfeff2bffba2764265342a0ed65238d2 /src/network/core/tcp_connect.cpp
parentc9436c8d88961032ab66f4d06892615d239014ab (diff)
downloadopenttd-28a641066e2e9963f6662366281079b7d00ac835.tar.xz
(svn r15163) -Change/Fix: use a non-blocking method to resolve the hostname and connect to game servers.
Diffstat (limited to 'src/network/core/tcp_connect.cpp')
-rw-r--r--src/network/core/tcp_connect.cpp99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp
new file mode 100644
index 000000000..88501b260
--- /dev/null
+++ b/src/network/core/tcp_connect.cpp
@@ -0,0 +1,99 @@
+/* $Id$ */
+
+/**
+ * @file tcp_connect.cpp Basic functions to create connections without blocking.
+ */
+
+#ifdef ENABLE_NETWORK
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "../../core/smallvec_type.hpp"
+#include "../../thread.h"
+
+#include "tcp.h"
+
+/** List of connections that are currently being created */
+static SmallVector<TCPConnecter *, 1> _tcp_connecters;
+
+TCPConnecter::TCPConnecter(const NetworkAddress &address) :
+ connected(false),
+ aborted(false),
+ killed(false),
+ sock(INVALID_SOCKET),
+ address(address)
+{
+ *_tcp_connecters.Append() = this;
+ if (!ThreadObject::New(TCPConnecter::ThreadEntry, this, &this->thread)) {
+ this->Connect();
+ }
+}
+
+void TCPConnecter::Connect()
+{
+ DEBUG(net, 1, "Connecting to %s %d", address.GetHostname(), address.GetPort());
+
+ this->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (this->sock == INVALID_SOCKET) {
+ this->aborted = true;
+ return;
+ }
+
+ if (!SetNoDelay(this->sock)) DEBUG(net, 1, "Setting TCP_NODELAY failed");
+
+ struct sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = address.GetIP();
+ sin.sin_port = htons(address.GetPort());
+
+ /* We failed to connect for which reason what so ever */
+ if (connect(this->sock, (struct sockaddr*) &sin, sizeof(sin)) != 0) {
+ closesocket(this->sock);
+ this->sock = INVALID_SOCKET;
+ this->aborted = true;
+ return;
+ }
+
+ if (!SetNonBlocking(this->sock)) DEBUG(net, 0, "Setting non-blocking mode failed");
+
+ this->connected = true;
+}
+
+
+/* static */ void TCPConnecter::ThreadEntry(void *param)
+{
+ static_cast<TCPConnecter*>(param)->Connect();
+}
+
+/* static */ void TCPConnecter::CheckCallbacks()
+{
+ for (TCPConnecter **iter = _tcp_connecters.Begin(); iter < _tcp_connecters.End(); /* nothing */) {
+ TCPConnecter *cur = *iter;
+ if ((cur->connected || cur->aborted) && cur->killed) {
+ _tcp_connecters.Erase(iter);
+ if (cur->sock != INVALID_SOCKET) closesocket(cur->sock);
+ delete cur;
+ continue;
+ }
+ if (cur->connected) {
+ _tcp_connecters.Erase(iter);
+ cur->OnConnect(cur->sock);
+ delete cur;
+ continue;
+ }
+ if (cur->aborted) {
+ _tcp_connecters.Erase(iter);
+ cur->OnFailure();
+ delete cur;
+ continue;
+ }
+ iter++;
+ }
+}
+
+/* static */ void TCPConnecter::KillAll()
+{
+ for (TCPConnecter **iter = _tcp_connecters.Begin(); iter != _tcp_connecters.End(); iter++) (*iter)->killed = true;
+}
+
+#endif /* ENABLE_NETWORK */