Commits

Kari Vatjus-Anttila  committed 50a266a

Fixed problems with SCTP, Merge bomb destroyed the code a little bit

  • Participants
  • Parent commits fd9a1ba

Comments (0)

Files changed (13)

File CMakeLists.txt

    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
    add_definitions(-DKNET_MEMORY_LEAK_CHECK)
    
-   set(kNetLinkLibraries ${kNetLinkLibraries} ws2_32.lib)
+   set(kNetLinkLibraries ${kNetLinkLibraries} ws2_32.lib )
    
 elseif (UNIX)
    file(GLOB kNetUnixSourceFiles ./src/unix/*.cpp)
    set(kNetLinkLibraries ${kNetLinkLibraries} ${Boost_LIBRARIES})   
 endif()
 
-target_link_libraries(kNet ${kNetLinkLibraries})
+target_link_libraries(kNet ${kNetLinkLibraries} sctp)
 
 set(KNET_OUT_DIR ${CMAKE_SOURCE_DIR}/lib)
 

File include/kNet/MessageConnection.h

 #include "Thread.h"
 #include "Types.h"
 
+#define KNET_HAS_SCTP 1
+
 namespace kNet
 {
 

File include/kNet/Network.h

 	NetworkServer *StartServer(unsigned short port, SocketTransportLayer transport, INetworkServerListener *serverListener, bool allowAddressReuse);
 
 	/// Starts a network server that listens to multiple local ports.
-	/// This version of the function is given a list of pairs (port, UDP|TCP) values
+    /// This version of the function is given a list of pairs (port, UDP|TCP|SCTP) values
 	/// and the server will start listening on each of them.
 	/// @param allowAddressReuse If true, kNet passes the SO_REUSEADDR parameter to the server listen socket before binding 
 	///        the socket to a local port (== before starting the server). This allows the same port to be forcibly reused
 	/// Closes the given MessageConnection object. 
 	void CloseConnection(MessageConnection *connection);
 
-	/** Connects to the given address:port using kNet over UDP or TCP. When you are done with the connection,
+    /** Connects to the given address:port using kNet over UDP, TCP or SCTP. When you are done with the connection,
 		free it by letting the refcount go to 0. */
 	Ptr(MessageConnection) Connect(const char *address, unsigned short port, SocketTransportLayer transport, IMessageHandler *messageHandler, Datagram *connectMessage = 0);
 

File include/kNet/NetworkMessage.h

 	friend struct FragmentedSendManager::FragmentedTransfer;
 
 	/// A temporary storage area to remember the UDP packet ID this messages was received in.
-	/// For TCP messages, this field is always zero.
+    /// For TCP and SCTP messages, this field is always zero.
 	/// When sending out messages, this field is not used.
 	packet_id_t receivedPacketID;
 

File include/kNet/NetworkServer.h

 	NetworkServer(Network *owner, std::vector<Socket *> listenSockets);
 
 	/// We store possibly multiple listening sockets so that the server
-	/// can listen on several sockets (UDP or TCP) at once, making it
-	/// possible for clients to bypass firewalls and/or mix UDP and TCP use.
+    /// can listen on several sockets (UDP, TCP or SCTP) at once, making it
+    /// possible for clients to bypass firewalls and/or mix UDP, TCP or SCTP use.
 	std::vector<Socket *> listenSockets;
 
 	/// The list of active client connections.

File include/kNet/Socket.h

 /// Converts the given string (case-insensitive parsing) to the corresponding SocketTransportLayer enum.
 /// "tcp" & "socketovertcp" -> SocketOverTCP.
 /// "udp" & "socketoverudp" -> SocketOverUDP.
+/// "sctp" & "socketoversctp" -> SocketOverSCTP.
 /// Other strings -> InvalidTransportLayer.
 SocketTransportLayer StringToSocketTransportLayer(const char *str);
 
 	/// Returns the event object that will be notified whenever data is available to be read from the socket.
 	Event GetOverlappedReceiveEvent(); // [worker thread]
 
-	/// Returns which transport layer the connection is using. This value is either SocketOverUDP or SocketOverTCP.
+    /// Returns which transport layer the connection is using. This value is either SocketOverUDP, SocketOverTCP or SocketOverSCTP.
 	SocketTransportLayer TransportLayer() const { return transport; }
 
 	/// Returns the type of this socket object.
 	/// remote IP address. If SocketType == ServerListenSocket, this field is empty.
 	std::string remoteHostName;
 
-	/// Specifies the underlying transport protocol that this Socket is using (TCP or UDP).
+    /// Specifies the underlying transport protocol that this Socket is using (TCP, SCTP or UDP).
 	SocketTransportLayer transport;
 
 	/// Specifies the type of this SOCKET object.

File include/kNetFwd.h

 	class Socket;
 	class StatsEventHierarchyNode;
 	class TCPMessageConnection;
+    class SCTPMessageConnection;
 	class Thread;
 	class UDPMessageConnection;
 }

File src/MessageConnection.cpp

 		statsRefreshTimer.StartMSecs(statsRefreshIntervalMSecs);
 	}
 
-	// Perform the TCP/UDP -specific connection update.
+    // Perform the SCTP/TCP/UDP -specific connection update.
 	DoUpdateConnection();
 }
 
 	sprintf(str, "messageIn.%u", (unsigned int)messageID);
 	ADDEVENT(str, (float)reader.BytesLeft(), "bytes");
 
-	// Pass the message to TCP/UDP -specific message handler.
+    // Pass the message to SCTP/TCP/UDP -specific message handler.
 	bool childHandledMessage = HandleMessage(packetID, messageID, data + reader.BytePos(), reader.BytesLeft());
 	if (childHandledMessage)
 		return; // If the derived class handled the message, no need to propagate it further.

File src/Network.cpp

    limitations under the License. */
 
 /** @file Network.cpp
-	@brief */
+    @brief */
 
 #include <string>
 #include <sstream>
 std::string Network::GetErrorString(int error)
 {
 #ifdef WIN32
-	void *lpMsgBuf = 0;
+    void *lpMsgBuf = 0;
 
-	HRESULT hresult = HRESULT_FROM_WIN32(error);
-	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-		0, hresult, 0 /*Default language*/, (LPTSTR) &lpMsgBuf, 0, 0);
+    HRESULT hresult = HRESULT_FROM_WIN32(error);
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+        0, hresult, 0 /*Default language*/, (LPTSTR) &lpMsgBuf, 0, 0);
 
-	// Copy message to C++ -style string, since the data need to be freed before return.
-	std::stringstream ss;
-	ss << (LPCSTR)lpMsgBuf << "(" << error << ")"; ///\todo Bug: The cast to LPCSTR converts wstr -> str if UNICODE is defined, which will cut out text.
-	LocalFree(lpMsgBuf);
-	return ss.str();
+    // Copy message to C++ -style string, since the data need to be freed before return.
+    std::stringstream ss;
+    ss << (LPCSTR)lpMsgBuf << "(" << error << ")"; ///\todo Bug: The cast to LPCSTR converts wstr -> str if UNICODE is defined, which will cut out text.
+    LocalFree(lpMsgBuf);
+    return ss.str();
 #else
-	std::stringstream ss;
-	ss << strerror(error) << "(" << error << ")";
-	return ss.str();
+    std::stringstream ss;
+    ss << strerror(error) << "(" << error << ")";
+    return ss.str();
 #endif
 }
 
 int Network::GetLastError()
 {
 #ifdef WIN32
-	return WSAGetLastError();
+    return WSAGetLastError();
 #else
-	return errno;
+    return errno;
 #endif
 }
 
 std::string Network::GetLastErrorString()
 {
-	return GetErrorString(GetLastError());
+    return GetErrorString(GetLastError());
 }
 
 std::string FormatBytes(u64 numBytes)
 {
-	return FormatBytes((double)numBytes);
+    return FormatBytes((double)numBytes);
 }
 
 std::string FormatBytes(double numBytes)
 {
-	char str[256];
-	if (numBytes >= 1000.0 * 1000.0 * 1000.0)
-		sprintf(str, "%.3f GB", (float)(numBytes / (1024.0 * 1024.0 * 1024.0)));
-	else if (numBytes >= 1000.0 * 1000.0)
-		sprintf(str, "%.3f MB", (float)(numBytes / (1024.0 * 1024.0)));
-	else if (numBytes >= 200.0)
-		sprintf(str, "%.3f KB", (float)(numBytes / 1024.0));
-	else
-		sprintf(str, "%.2f B", (float)numBytes);
-	return std::string(str);
+    char str[256];
+    if (numBytes >= 1000.0 * 1000.0 * 1000.0)
+        sprintf(str, "%.3f GB", (float)(numBytes / (1024.0 * 1024.0 * 1024.0)));
+    else if (numBytes >= 1000.0 * 1000.0)
+        sprintf(str, "%.3f MB", (float)(numBytes / (1024.0 * 1024.0)));
+    else if (numBytes >= 200.0)
+        sprintf(str, "%.3f KB", (float)(numBytes / 1024.0));
+    else
+        sprintf(str, "%.2f B", (float)numBytes);
+    return std::string(str);
 }
 
 Network::Network()
 {
 #ifdef WIN32
-	memset(&wsaData, 0, sizeof(wsaData));
+    memset(&wsaData, 0, sizeof(wsaData));
 #endif
-	Init();
+    Init();
 }
 
 Network::~Network()
 {
-	StopServer();
-	DeInit();
+    StopServer();
+    DeInit();
 }
 
 void PrintLocalIP()
 {
-	char ac[80];
-	if (gethostname(ac, sizeof(ac)) == KNET_SOCKET_ERROR)
-	{
-		LOG(LogError, "Error getting local host name!");
-		return;
-	}
-	LOG(LogInfo, "Host name is %s", ac);
-
-	struct hostent *phe = gethostbyname(ac);
-	if (phe == 0)
-	{
-		LOG(LogError, "Bad host lookup.");
-		return;
-	}
-
-	for (int i = 0; phe->h_addr_list[i] != 0; ++i)
-	{
-		struct in_addr addr;
-		memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
-		LOG(LogInfo, "Address %d: %s", i, inet_ntoa(addr)); ///\todo inet_ntoa is deprecated! doesn't handle IPv6!
-	}
+    char ac[80];
+    if (gethostname(ac, sizeof(ac)) == KNET_SOCKET_ERROR)
+    {
+        LOG(LogError, "Error getting local host name!");
+        return;
+    }
+    LOG(LogInfo, "Host name is %s", ac);
+
+    struct hostent *phe = gethostbyname(ac);
+    if (phe == 0)
+    {
+        LOG(LogError, "Bad host lookup.");
+        return;
+    }
+
+    for (int i = 0; phe->h_addr_list[i] != 0; ++i)
+    {
+        struct in_addr addr;
+        memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
+        LOG(LogInfo, "Address %d: %s", i, inet_ntoa(addr)); ///\todo inet_ntoa is deprecated! doesn't handle IPv6!
+    }
 }
 
 void Network::PrintAddrInfo(const addrinfo *ptr)
 {
         printf("\n");
-	if (!ptr)
-	{
-		LOG(LogError, "Null pointer passed to Network::PrintAddrInfo!");
-		return;
-	}
-
-	LOG(LogInfo, "\tFlags: 0x%x\n", ptr->ai_flags);
-	LOG(LogInfo, "\tFamily: ");
-	switch(ptr->ai_family)
-	{
-	case AF_UNSPEC:
-		LOG(LogInfo, "Unspecified\n");
-		break;
-	case AF_INET:
-		LOG(LogInfo, "AF_INET (IPv4)\n");
-		break;
-	case AF_INET6:
-		LOG(LogInfo, "AF_INET6 (IPv6)\n");
-		break;
+    if (!ptr)
+    {
+        LOG(LogError, "Null pointer passed to Network::PrintAddrInfo!");
+        return;
+    }
+
+    LOG(LogInfo, "\tFlags: 0x%x\n", ptr->ai_flags);
+    LOG(LogInfo, "\tFamily: ");
+    switch(ptr->ai_family)
+    {
+    case AF_UNSPEC:
+        LOG(LogInfo, "Unspecified\n");
+        break;
+    case AF_INET:
+        LOG(LogInfo, "AF_INET (IPv4)\n");
+        break;
+    case AF_INET6:
+        LOG(LogInfo, "AF_INET6 (IPv6)\n");
+        break;
 #ifdef WIN32
-	case AF_NETBIOS:
-		LOG(LogInfo, "AF_NETBIOS (NetBIOS)\n");
-		break;
+    case AF_NETBIOS:
+        LOG(LogInfo, "AF_NETBIOS (NetBIOS)\n");
+        break;
 #endif
-	default:
-		LOG(LogInfo, "Other %u\n", ptr->ai_family);
-		break;
-	}
-	LOG(LogInfo, "\tSocket type: ");
-	switch(ptr->ai_socktype)
-	{
-	case 0:
-		LOG(LogInfo, "Unspecified\n");
-		break;
-	case SOCK_STREAM:
-		LOG(LogInfo, "SOCK_STREAM (stream)\n");
-		break;
-	case SOCK_DGRAM:
-		LOG(LogInfo, "SOCK_DGRAM (datagram) \n");
-		break;
-	case SOCK_RAW:
-		LOG(LogInfo, "SOCK_RAW (raw) \n");
-		break;
-	case SOCK_RDM:
-		LOG(LogInfo, "SOCK_RDM (reliable message datagram)\n");
-		break;
-	case SOCK_SEQPACKET:
-		LOG(LogInfo, "SOCK_SEQPACKET (pseudo-stream packet)\n");
-		break;
-	default:
-		LOG(LogInfo, "Other %u\n", ptr->ai_socktype);
-		break;
-	}
-	LOG(LogInfo, "\tProtocol: ");
-	switch(ptr->ai_protocol)
-	{
-	case 0:
-		LOG(LogInfo, "Unspecified\n");
-		break;
-	case IPPROTO_TCP:
-		LOG(LogInfo, "IPPROTO_TCP (TCP)\n");
-		break;
-	case IPPROTO_UDP:
-		LOG(LogInfo, "IPPROTO_UDP (UDP) \n");
-		break;
-	default:
-		LOG(LogInfo, "Other %u\n", ptr->ai_protocol);
-		break;
-	}
-	LOG(LogInfo, "\tLength of this sockaddr: %d\n", (int)ptr->ai_addrlen);
-	LOG(LogInfo, "\tCanonical name: %s\n", ptr->ai_canonname);
-
-	char address[256];
-	sprintf(address, "%d.%d.%d.%d",
-		(unsigned int)(unsigned char)ptr->ai_addr->sa_data[2], (unsigned int)(unsigned char)ptr->ai_addr->sa_data[3],
-		(unsigned int)(unsigned char)ptr->ai_addr->sa_data[4], (unsigned int)(unsigned char)ptr->ai_addr->sa_data[5]);
-
-	LOG(LogInfo, "Address of this sockaddr: %s.\n", address);
+    default:
+        LOG(LogInfo, "Other %u\n", ptr->ai_family);
+        break;
+    }
+    LOG(LogInfo, "\tSocket type: ");
+    switch(ptr->ai_socktype)
+    {
+    case 0:
+        LOG(LogInfo, "Unspecified\n");
+        break;
+    case SOCK_STREAM:
+        LOG(LogInfo, "SOCK_STREAM (stream)\n");
+        break;
+    case SOCK_DGRAM:
+        LOG(LogInfo, "SOCK_DGRAM (datagram) \n");
+        break;
+    case SOCK_RAW:
+        LOG(LogInfo, "SOCK_RAW (raw) \n");
+        break;
+    case SOCK_RDM:
+        LOG(LogInfo, "SOCK_RDM (reliable message datagram)\n");
+        break;
+    case SOCK_SEQPACKET:
+        LOG(LogInfo, "SOCK_SEQPACKET (pseudo-stream packet)\n");
+        break;
+    default:
+        LOG(LogInfo, "Other %u\n", ptr->ai_socktype);
+        break;
+    }
+    LOG(LogInfo, "\tProtocol: ");
+    switch(ptr->ai_protocol)
+    {
+    case 0:
+        LOG(LogInfo, "Unspecified\n");
+        break;
+    case IPPROTO_TCP:
+        LOG(LogInfo, "IPPROTO_TCP (TCP)\n");
+        break;
+    case IPPROTO_UDP:
+        LOG(LogInfo, "IPPROTO_UDP (UDP) \n");
+        break;
+    case IPPROTO_SCTP:
+        LOG(LogInfo, "IPPROTO_SCTP (SCTP) \n");
+        break;
+    default:
+        LOG(LogInfo, "Other %u\n", ptr->ai_protocol);
+        break;
+    }
+    LOG(LogInfo, "\tLength of this sockaddr: %d\n", (int)ptr->ai_addrlen);
+    LOG(LogInfo, "\tCanonical name: %s\n", ptr->ai_canonname);
+
+    char address[256];
+    sprintf(address, "%d.%d.%d.%d",
+        (unsigned int)(unsigned char)ptr->ai_addr->sa_data[2], (unsigned int)(unsigned char)ptr->ai_addr->sa_data[3],
+        (unsigned int)(unsigned char)ptr->ai_addr->sa_data[4], (unsigned int)(unsigned char)ptr->ai_addr->sa_data[5]);
+
+    LOG(LogInfo, "Address of this sockaddr: %s.\n", address);
 }
 
 void Network::PrintHostNameInfo(const char *hostname, const char *port)
 {
-	addrinfo hints;
-
-	//--------------------------------
-	// Setup the hints address info structure
-	// which is passed to the getaddrinfo() function
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_UNSPEC;
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_protocol = IPPROTO_TCP;
-
-	//--------------------------------
-	// Call getaddrinfo(). If the call succeeds,
-	// the result variable will hold a linked list
-	// of addrinfo structures containing response
-	// information
-	addrinfo *result = NULL;
-	unsigned long dwRetval = (unsigned long)getaddrinfo(hostname, port, &hints, &result);
-	if (dwRetval != 0)
-	{
-		LOG(LogError, "getaddrinfo failed with error: %d\n", (int)dwRetval);
-		return;
-	}
-
-	LOG(LogInfo, "getaddrinfo returned success\n");
-
-	int i = 1;
-
-	// Retrieve each address and print out the hex bytes
-	for (addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
-	{
-		LOG(LogInfo, "getaddrinfo response %d\n", i++);
-		PrintAddrInfo(ptr);
-	}
-
-	freeaddrinfo(result);
-
-	PrintLocalIP();
+    addrinfo hints;
+
+    //--------------------------------
+    // Setup the hints address info structure
+    // which is passed to the getaddrinfo() function
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+
+    //--------------------------------
+    // Call getaddrinfo(). If the call succeeds,
+    // the result variable will hold a linked list
+    // of addrinfo structures containing response
+    // information
+    addrinfo *result = NULL;
+    unsigned long dwRetval = (unsigned long)getaddrinfo(hostname, port, &hints, &result);
+    if (dwRetval != 0)
+    {
+        LOG(LogError, "getaddrinfo failed with error: %d\n", (int)dwRetval);
+        return;
+    }
+
+    LOG(LogInfo, "getaddrinfo returned success\n");
+
+    int i = 1;
+
+    // Retrieve each address and print out the hex bytes
+    for (addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
+    {
+        LOG(LogInfo, "getaddrinfo response %d\n", i++);
+        PrintAddrInfo(ptr);
+    }
+
+    freeaddrinfo(result);
+
+    PrintLocalIP();
 }
 
 void Network::Init()
 {
 #ifdef WIN32
-	// Initialize Winsock
-	int result = WSAStartup(MAKEWORD(2,2), &wsaData);
-	if (result != 0)
-	{
-		LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).c_str());
-		return;
-	}
+    // Initialize Winsock
+    int result = WSAStartup(MAKEWORD(2,2), &wsaData);
+    if (result != 0)
+    {
+        LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).c_str());
+        return;
+    }
 #endif
 
-	// Fetch the local system host name for later use. The local address is cached here 
-	// to avoid multiple queries to namespace providers.
-	char str[256];
-	int ret = gethostname(str, 256); // For more information, see http://msdn.microsoft.com/en-us/library/ms738527(VS.85).aspx .
-	if (ret == 0)
-	{
-		localHostName = str;
-		LOG(LogInfo, "Network::Init successful. gethostname returned %s", str);
-	}
-	else
-	{
-		LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().c_str());
-		localHostName = "localhost";
-	}
+    // Fetch the local system host name for later use. The local address is cached here
+    // to avoid multiple queries to namespace providers.
+    char str[256];
+    int ret = gethostname(str, 256); // For more information, see http://msdn.microsoft.com/en-us/library/ms738527(VS.85).aspx .
+    if (ret == 0)
+    {
+        localHostName = str;
+        LOG(LogInfo, "Network::Init successful. gethostname returned %s", str);
+    }
+    else
+    {
+        LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().c_str());
+        localHostName = "localhost";
+    }
 }
 
 NetworkWorkerThread *Network::GetOrCreateWorkerThread()
 {
-	static const int maxConnectionsPerThread = 8;
-
-	// Find an existing thread with sufficiently low load.
-	for(size_t i = 0; i < workerThreads.size(); ++i)
-		if (workerThreads[i]->NumConnections() + workerThreads[i]->NumServers() < maxConnectionsPerThread)
-			return workerThreads[i];
-
-	// No appropriate thread found. Create a new one.
-	NetworkWorkerThread *workerThread = new NetworkWorkerThread();
-	workerThread->StartThread();
-	workerThreads.push_back(workerThread);
-	LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.size());
-	return workerThread;
+    static const int maxConnectionsPerThread = 8;
+
+    // Find an existing thread with sufficiently low load.
+    for(size_t i = 0; i < workerThreads.size(); ++i)
+        if (workerThreads[i]->NumConnections() + workerThreads[i]->NumServers() < maxConnectionsPerThread)
+            return workerThreads[i];
+
+    // No appropriate thread found. Create a new one.
+    NetworkWorkerThread *workerThread = new NetworkWorkerThread();
+    workerThread->StartThread();
+    workerThreads.push_back(workerThread);
+    LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.size());
+    return workerThread;
 }
 
 void Network::AssignConnectionToWorkerThread(MessageConnection *connection)
 {
-	NetworkWorkerThread *workerThread = GetOrCreateWorkerThread();
-	connection->SetWorkerThread(workerThread);
-	workerThread->AddConnection(connection);
+    NetworkWorkerThread *workerThread = GetOrCreateWorkerThread();
+    connection->SetWorkerThread(workerThread);
+    workerThread->AddConnection(connection);
 }
 
 void Network::AssignServerToWorkerThread(NetworkServer *server)
 {
-	NetworkWorkerThread *workerThread = GetOrCreateWorkerThread();
-	server->SetWorkerThread(workerThread);
-	workerThread->AddServer(server);
+    NetworkWorkerThread *workerThread = GetOrCreateWorkerThread();
+    server->SetWorkerThread(workerThread);
+    workerThread->AddServer(server);
 }
 
 void Network::RemoveConnectionFromItsWorkerThread(MessageConnection *connection)
 {
-	if (!connection)
-		return;
-
-	NetworkWorkerThread *workerThread = connection->WorkerThread();
-	if (workerThread)
-	{
-		workerThread->RemoveConnection(connection);
-		connection->SetWorkerThread(0);
-
-		if (workerThread->NumConnections() + workerThread->NumServers() == 0)
-			CloseWorkerThread(workerThread);
-	}
+    if (!connection)
+        return;
+
+    NetworkWorkerThread *workerThread = connection->WorkerThread();
+    if (workerThread)
+    {
+        workerThread->RemoveConnection(connection);
+        connection->SetWorkerThread(0);
+
+        if (workerThread->NumConnections() + workerThread->NumServers() == 0)
+            CloseWorkerThread(workerThread);
+    }
 }
 
 void Network::RemoveServerFromItsWorkerThread(NetworkServer *server)
 {
-	if (!server)
-		return;
-
-	NetworkWorkerThread *workerThread = server->WorkerThread();
-	if (workerThread)
-	{
-		workerThread->RemoveServer(server);
-		server->SetWorkerThread(0);
-
-		if (workerThread->NumConnections() + workerThread->NumServers() == 0)
-			CloseWorkerThread(workerThread);
-	}
+    if (!server)
+        return;
+
+    NetworkWorkerThread *workerThread = server->WorkerThread();
+    if (workerThread)
+    {
+        workerThread->RemoveServer(server);
+        server->SetWorkerThread(0);
+
+        if (workerThread->NumConnections() + workerThread->NumServers() == 0)
+            CloseWorkerThread(workerThread);
+    }
 }
 
 void Network::CloseWorkerThread(NetworkWorkerThread *workerThread)
 {
-	if (!workerThread)
-		return;
-
-	// We (should) never close a worker thread until we have first removed all the connections and servers it handles.
-	if (workerThread->NumConnections() + workerThread->NumServers() > 0)
-		LOG(LogError, "Warning: Closing a worker thread %p when it still has %d connections and %d servers to handle.", workerThread, workerThread->NumConnections(), workerThread->NumServers());
-
-	for(size_t i = 0; i < workerThreads.size(); ++i)
-		if (workerThreads[i] == workerThread)
-		{
-			// Remove the thread pointer from internal list.
-			std::swap(workerThreads[i], workerThreads[workerThreads.size()-1]);
-			workerThreads.pop_back();
-
-			workerThread->StopThread();
-			LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.size());
-			delete workerThread;
-			return;
-		}
-
-	LOG(LogError, "Network::CloseWorkerThread: Asked to close worker thread %p, but no such thread is tracked by this Network object! Ignoring the request.", workerThread);
+    if (!workerThread)
+        return;
+
+    // We (should) never close a worker thread until we have first removed all the connections and servers it handles.
+    if (workerThread->NumConnections() + workerThread->NumServers() > 0)
+        LOG(LogError, "Warning: Closing a worker thread %p when it still has %d connections and %d servers to handle.", workerThread, workerThread->NumConnections(), workerThread->NumServers());
+
+    for(size_t i = 0; i < workerThreads.size(); ++i)
+        if (workerThreads[i] == workerThread)
+        {
+            // Remove the thread pointer from internal list.
+            std::swap(workerThreads[i], workerThreads[workerThreads.size()-1]);
+            workerThreads.pop_back();
+
+            workerThread->StopThread();
+            LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.size());
+            delete workerThread;
+            return;
+        }
+
+    LOG(LogError, "Network::CloseWorkerThread: Asked to close worker thread %p, but no such thread is tracked by this Network object! Ignoring the request.", workerThread);
 }
 
 NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer transport, INetworkServerListener *serverListener, bool allowAddressReuse)
 {
-	Socket *listenSock = OpenListenSocket(port, transport, allowAddressReuse);
-	if (listenSock == 0)
-	{
-		LOG(LogError, "Failed to start server. Could not open listen port to %d using %s.", (int)port, 
-			transport == SocketOverTCP ? "TCP" : "UDP");
-		return 0;
-	}
+    Socket *listenSock = OpenListenSocket(port, transport, allowAddressReuse);
 
-	std::vector<Socket *> listenSockets;
-	listenSockets.push_back(listenSock);
+    if (listenSock == 0)
+    {
+        LOG(LogError, "Failed to start server. Could not open listen port to %d using %s.", (int)port,
+            transport == SocketOverTCP ? "TCP" : (transport == SocketOverUDP) ? "UDP" : "SCTP");
+        return 0;
+    }
 
-	server = new NetworkServer(this, listenSockets);
-	server->RegisterServerListener(serverListener);
+    std::vector<Socket *> listenSockets;
+    listenSockets.push_back(listenSock);
 
-	AssignServerToWorkerThread(server);
+    server = new NetworkServer(this, listenSockets);
+    server->RegisterServerListener(serverListener);
 
-	LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().c_str());
+    AssignServerToWorkerThread(server);
 
-	return server;
+    LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().c_str());
+
+    return server;
 }
 
-NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short, SocketTransportLayer> > &listenPorts, 
-	INetworkServerListener *serverListener, bool allowAddressReuse)
+NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short, SocketTransportLayer> > &listenPorts,
+    INetworkServerListener *serverListener, bool allowAddressReuse)
 {
-	if (listenPorts.size() == 0)
-	{
-		LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
-		return 0;
-	}
-
-	std::vector<Socket *> listenSockets;
-
-	for(size_t i = 0; i < listenPorts.size(); ++i)
-	{
-		Socket *listenSock = OpenListenSocket(listenPorts[i].first, listenPorts[i].second, allowAddressReuse);
-		if (listenSock)
-			listenSockets.push_back(listenSock);
-	}
-
-	if (listenSockets.size() == 0)
-	{
-		LOG(LogError, "Failed to start server. No ports to listen to!");
-		return 0;
-	}
-
-	server = new NetworkServer(this, listenSockets);
-	server->RegisterServerListener(serverListener);
-
-	AssignServerToWorkerThread(server);
-
-	LOG(LogInfo, "Server up and listening on the following ports: ");
-	{
-		std::stringstream ss;
-		ss << "UDP ";
-		for(size_t i = 0; i < listenSockets.size(); ++i)
-			if (listenSockets[i]->TransportLayer() == SocketOverUDP)
-				ss << listenSockets[i]->LocalPort() << " ";
-		LOG(LogInfo, ss.str().c_str());
-	}
-	{
-		std::stringstream ss;
-		ss << "TCP ";
-		for(size_t i = 0; i < listenSockets.size(); ++i)
-			if (listenSockets[i]->TransportLayer() == SocketOverTCP)
-				ss << listenSockets[i]->LocalPort() << " ";
-		LOG(LogInfo, ss.str().c_str());
-	}
-
-	return server;
+    if (listenPorts.size() == 0)
+    {
+        LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
+        return 0;
+    }
+
+    std::vector<Socket *> listenSockets;
+
+    for(size_t i = 0; i < listenPorts.size(); ++i)
+    {
+        Socket *listenSock = OpenListenSocket(listenPorts[i].first, listenPorts[i].second, allowAddressReuse);
+        if (listenSock)
+            listenSockets.push_back(listenSock);
+    }
+
+    if (listenSockets.size() == 0)
+    {
+        LOG(LogError, "Failed to start server. No ports to listen to!");
+        return 0;
+    }
+
+    server = new NetworkServer(this, listenSockets);
+    server->RegisterServerListener(serverListener);
+
+    AssignServerToWorkerThread(server);
+
+    LOG(LogInfo, "Server up and listening on the following ports: ");
+    {
+        std::stringstream ss;
+        ss << "UDP ";
+        for(size_t i = 0; i < listenSockets.size(); ++i)
+            if (listenSockets[i]->TransportLayer() == SocketOverUDP)
+                ss << listenSockets[i]->LocalPort() << " ";
+        LOG(LogInfo, ss.str().c_str());
+    }
+    {
+        std::stringstream ss;
+        ss << "TCP ";
+        for(size_t i = 0; i < listenSockets.size(); ++i)
+            if (listenSockets[i]->TransportLayer() == SocketOverTCP)
+                ss << listenSockets[i]->LocalPort() << " ";
+        LOG(LogInfo, ss.str().c_str());
+    }
+    {
+        std::stringstream ss;
+        ss << "SCTP ";
+        for(size_t i = 0; i < listenSockets.size(); ++i)
+            if (listenSockets[i]->TransportLayer() == SocketOverSCTP)
+                ss << listenSockets[i]->LocalPort() << " ";
+        LOG(LogInfo, ss.str().c_str());
+    }
+    return server;
 }
 
 void Network::StopServer()
 {
-	if (!server)
-		return;
+    if (!server)
+        return;
 
-	RemoveServerFromItsWorkerThread(server);
+    RemoveServerFromItsWorkerThread(server);
 
-	///\todo This is a forceful stop. Perhaps have a benign teardown as well?
-	server = 0;
-	LOG(LogVerbose, "Network::StopServer: Deinitialized NetworkServer.");
+    ///\todo This is a forceful stop. Perhaps have a benign teardown as well?
+    server = 0;
+    LOG(LogVerbose, "Network::StopServer: Deinitialized NetworkServer.");
 }
 
 void Network::DeleteSocket(Socket *socket)
 {
-	if (!socket)
-	{
-		LOG(LogError, "Network::DeleteSocket() called with a null socket pointer!");
-		return;
-	}
-
-	for(std::list<Socket>::iterator iter = sockets.begin(); iter != sockets.end(); ++iter)
-		if (&*iter == socket)
-		{
-			socket->Close();
-			// The Socket pointers MessageConnection objects have are pointers to this list,
-			// so after calling this function with a Socket pointer, the Socket is deleted for good.
-			sockets.erase(iter);
-			LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
-			return;
-		}
-	LOG(LogError, "Network::DeleteSocket: Tried to free a nonexisting socket %p!", socket);
+    if (!socket)
+    {
+        LOG(LogError, "Network::DeleteSocket() called with a null socket pointer!");
+        return;
+    }
+
+    for(std::list<Socket>::iterator iter = sockets.begin(); iter != sockets.end(); ++iter)
+        if (&*iter == socket)
+        {
+            socket->Close();
+            // The Socket pointers MessageConnection objects have are pointers to this list,
+            // so after calling this function with a Socket pointer, the Socket is deleted for good.
+            sockets.erase(iter);
+            LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
+            return;
+        }
+    LOG(LogError, "Network::DeleteSocket: Tried to free a nonexisting socket %p!", socket);
 }
 
 void Network::CloseConnection(MessageConnection *connection)
 {
-	LOG(LogVerbose, "Network::CloseConnection: Closing down connection %p.", connection);
-	if (!connection)
-		return;
-
-	RemoveConnectionFromItsWorkerThread(connection);
-	DeleteSocket(connection->socket);
-	connection->socket = 0;
-	connection->owner = 0;
-	connection->ownerServer = 0;
-	connections.erase(connection);
+    LOG(LogVerbose, "Network::CloseConnection: Closing down connection %p.", connection);
+    if (!connection)
+        return;
+
+    RemoveConnectionFromItsWorkerThread(connection);
+    DeleteSocket(connection->socket);
+    connection->socket = 0;
+    connection->owner = 0;
+    connection->ownerServer = 0;
+    connections.erase(connection);
 }
 
 void Network::DeInit()
 {
-	LOG(LogVerbose, "Network::DeInit: Closing down.");
-	PolledTimer timer;
-
-	// Kill all connections.
-	while(connections.size() > 0)
-	{
-		MessageConnection *connection = *connections.begin();
-		CloseConnection(connection); // CloseConnection erases connection from the connections list, so this loop terminates.
-	}
-
-	// Kill the server, if it's running.
-	StopServer();
-
-	// Kill all worker threads.
-	while(workerThreads.size() > 0)
-		CloseWorkerThread(workerThreads.front()); // Erases the item from workerThreads, so this loop terminates.
-
-	// Clean up any sockets that might be remaining.
-	while(sockets.size() > 0)
-	{
-		sockets.front().Close();
-		sockets.pop_front();
-	}
-
-	// Deinitialize network subsystem.
+    LOG(LogVerbose, "Network::DeInit: Closing down.");
+    PolledTimer timer;
+
+    // Kill all connections.
+    while(connections.size() > 0)
+    {
+        MessageConnection *connection = *connections.begin();
+        CloseConnection(connection); // CloseConnection erases connection from the connections list, so this loop terminates.
+    }
+
+    // Kill the server, if it's running.
+    StopServer();
+
+    // Kill all worker threads.
+    while(workerThreads.size() > 0)
+        CloseWorkerThread(workerThreads.front()); // Erases the item from workerThreads, so this loop terminates.
+
+    // Clean up any sockets that might be remaining.
+    while(sockets.size() > 0)
+    {
+        sockets.front().Close();
+        sockets.pop_front();
+    }
+
+    // Deinitialize network subsystem.
 #ifdef WIN32
-	WSACleanup();
+    WSACleanup();
 #endif
 
-	LOG(LogWaits, "Network::DeInit: Deinitialized kNet Network object, took %f msecs.", timer.MSecsElapsed());
+    LOG(LogWaits, "Network::DeInit: Deinitialized kNet Network object, took %f msecs.", timer.MSecsElapsed());
 }
 
 void Network::NewMessageConnectionCreated(MessageConnection *connection)
 {
-	connections.insert(connection);
+    connections.insert(connection);
 }
 
 Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer transport, bool allowAddressReuse)
 {
-	addrinfo *result = NULL;
-	addrinfo *ptr = NULL;
-	addrinfo hints;
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_INET;
-	hints.ai_flags = AI_PASSIVE;
-	hints.ai_socktype = (transport == SocketOverTCP) ? SOCK_STREAM : SOCK_DGRAM;
-	hints.ai_protocol = (transport == SocketOverTCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
-	char strPort[256];
-	sprintf(strPort, "%d", (unsigned int)port);
-
-	int ret = getaddrinfo(NULL, strPort, &hints, &result);
-	if (ret != 0)
-	{
-		LOG(LogError, "getaddrinfo failed: %s", GetErrorString(ret).c_str());
-		return 0;
-	}
-
-	SOCKET listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
-	LOG(LogInfo, "Network::OpenListenSocket: Created listenSocket 0x%8X.", (unsigned int)listenSocket);
-
-	if (listenSocket == INVALID_SOCKET)
-	{
-		LOG(LogError, "Error at socket(): %s", GetLastErrorString().c_str());
-		freeaddrinfo(result);
-		return 0;
-	}
-
-	if (allowAddressReuse)
-	{
-		// Allow other sockets to be bound to this address after this. 
-		// (Possibly unsecure, only enable for development purposes - to avoid having to wait for the server listen socket 
-		//  to time out if the server crashes.)
-#ifdef WIN32
-		BOOL val = TRUE;
-		ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-#else
-		int val = 1;
-		ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
-#endif
-		if (ret != 0)
-			LOG(LogError, "setsockopt to SO_REUSEADDR failed: %s", GetLastErrorString().c_str());
-	}
-
-	// It is safe to cast to a sockaddr_in, since we've specifically queried for AF_INET addresses.
-	sockaddr_in localAddress = *(sockaddr_in*)&result->ai_addr;
-
-	// Setup the listening socket - bind it to a local port.
-	// If we are setting up a TCP socket, the socket will be only for listening and accepting incoming connections.
-	// If we are setting up an UDP socket, all connection initialization and data transfers will be managed through this socket.
-	ret = bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);
-	if (ret == KNET_SOCKET_ERROR)
-	{
-		LOG(LogError, "bind failed: %s when trying to bind to port %d with transport %s", 
-			GetLastErrorString().c_str(), (int)port, transport == SocketOverTCP ? "TCP" : "UDP");
-		closesocket(listenSocket);
-		freeaddrinfo(result);
-		return 0;
-	}
-
-	freeaddrinfo(result);
-
-	// For a reliable TCP socket, start the server with a call to listen().
-	if (transport == SocketOverTCP)
-	{
-		// Transition the bound socket to a listening state.
-		ret = listen(listenSocket, SOMAXCONN);
-		if (ret == KNET_SOCKET_ERROR)
-		{
-			LOG(LogError, "Error at listen(): %s", GetLastErrorString().c_str());
-			closesocket(listenSocket);
-			return 0;
-		}
-	}
-
-	EndPoint localEndPoint = EndPoint::FromSockAddrIn(localAddress);
-
-	// We are starting up a server listen socket, which is not bound to an address. Use null address for the remote endpoint.
-	EndPoint remoteEndPoint;
-	remoteEndPoint.Reset();
-
-	const size_t maxSendSize = (transport == SocketOverTCP ? cMaxTCPSendSize : cMaxUDPSendSize);
-	sockets.push_back(Socket(listenSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, "", transport, ServerListenSocket, maxSendSize));
-	Socket *listenSock = &sockets.back();
-	listenSock->SetBlocking(false);
-
-	return listenSock;
+    addrinfo                *result = NULL;
+    addrinfo                *ptr = NULL;
+    addrinfo                hints;
+
+    sctp_initmsg            initmsg;
+    sctp_event_subscribe    events;
+    sctp_paddrparams        heartbeat;
+    sctp_rtoinfo            rtoinfo;
+
+    sockaddr_in             *laddr[5];
+    sockaddr_in             addr;
+    sockaddr_in             localAddress;
+
+    int                     ret;
+    int                     addr_count;
+    char                    strPort[256];
+
+    SOCKET listenSocket = INVALID_SOCKET;
+
+/* This is for SCTP */
+    memset(&hints,      0, sizeof(hints));
+    memset(&initmsg,    0, sizeof(initmsg));
+    memset(&events,         1, sizeof(events) );
+    memset(&heartbeat,  0, sizeof(heartbeat));
+    memset(&rtoinfo,    0, sizeof(rtoinfo));
+
+    addr.sin_family         = AF_INET;
+    addr.sin_addr.s_addr    = htonl(INADDR_ANY);
+    addr.sin_port           = htons(port);
+
+    /* This is for TCP & UDP */
+    hints.ai_family = AF_INET;
+    hints.ai_flags = AI_PASSIVE;
+    hints.ai_socktype = (transport == SocketOverTCP) ? SOCK_STREAM : (transport == SocketOverSCTP) ? SOCK_STREAM : SOCK_DGRAM;
+    hints.ai_protocol = (transport == SocketOverTCP) ? IPPROTO_TCP : (transport == SocketOverSCTP) ? IPPROTO_SCTP : IPPROTO_UDP;
+
+    sprintf(strPort, "%d", (unsigned int)port);
+
+    if(getaddrinfo(NULL, strPort, &hints, &result) != 0)
+    {
+            LOG(LogError, "getaddrinfo failed: %s", GetErrorString(ret).c_str());
+            return 0;
+    }
+
+    ptr = result;
+    //PrintAddrInfo(ptr);
+
+    listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
+
+    if (listenSocket == INVALID_SOCKET)
+    {
+            LOG(LogError, "Error at socket(): %s", GetLastErrorString().c_str());
+            if(result != NULL)
+                freeaddrinfo(result);
+            return 0;
+    }
+
+    LOG(LogInfo, "\tNetwork::OpenListenSocket: Created listenSocket 0x%X.\n", (unsigned int)listenSocket);
+
+    if(transport == SocketOverSCTP)
+    {
+            /* Specify that a maximum of 2 streams will be available per socket */
+            initmsg.sinit_num_ostreams  = 2;
+            initmsg.sinit_max_instreams = 2;
+            initmsg.sinit_max_attempts  = 5;
+
+            /* Configure SCTP Heartbeats */
+            heartbeat.spp_flags = SPP_HB_ENABLE;
+            heartbeat.spp_hbinterval = 5000;
+            heartbeat.spp_pathmaxrxt = 2;
+
+            /*Configure RTOInfo*/
+            rtoinfo.srto_max = 2000;
+
+            /*Initialize SCTP*/
+            if((ret = setsockopt(listenSocket, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg))) != 0)
+                perror("setsockopt");
+
+            /*Set SCTP Heartbeats*/
+            if((ret = setsockopt(listenSocket, SOL_SCTP, SCTP_PEER_ADDR_PARAMS , &heartbeat, sizeof(heartbeat))) != 0)
+                perror("setsockopt");
+
+            /*Set SCTP Rtoinfo*/
+            if((ret = setsockopt(listenSocket, SOL_SCTP, SCTP_RTOINFO , &rtoinfo, sizeof(rtoinfo))) != 0)
+                perror("setsockopt");
+
+            /*Set SCTP Events*/
+            if((ret = setsockopt(listenSocket, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events))) != 0)
+                perror("setsockopt");
+    }
+
+    if (allowAddressReuse)
+    {
+            // Allow other sockets to be bound to this address after this.
+            // (Possibly unsecure, only enable for development purposes - to avoid having to wait for the server listen socket
+            //  to time out if the server crashes.)
+    #ifdef WIN32
+            BOOL val = TRUE;
+            ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+    #else
+            int val = 1;
+            ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+    #endif
+            if (ret != 0)
+                LOG(LogError, "setsockopt to SO_REUSEADDR failed: %s", GetLastErrorString().c_str());
+    }
+
+    // It is safe to cast to a sockaddr_in, since we've specifically queried for AF_INET addresses.
+    localAddress = *(sockaddr_in*)&result->ai_addr;
+    // Setup the listening socket - bind it to a local port.
+    // If we are setting up a TCP socket, the socket will be only for listening and accepting incoming connections.
+    // If we are setting up an UDP socket, all connection initialization and data transfers will be managed through this socket.
+
+    if(transport == SocketOverSCTP)
+    {
+            if((ret = bind(listenSocket, (struct sockaddr*)&addr, sizeof(struct sockaddr))) < 0)
+                perror("bind");
+
+            addr_count = sctp_getladdrs(listenSocket, 0, (struct sockaddr**)laddr);
+            LOG(LogInfo, "\tAddresses binded: %d", addr_count);
+            for(int i = 0; i < addr_count; i++)
+                LOG(LogInfo, "\tAddress %d: %s:%d", i +1, inet_ntoa((*laddr)[i].sin_addr), (*laddr)[i].sin_port);
+            sctp_freeladdrs((struct sockaddr*)*laddr);
+            printf("\n");
+    }
+
+    else ret = bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);
+
+    if(ret == KNET_SOCKET_ERROR)
+    {
+            LOG(LogError, "bind failed: %s when trying to bind to port %d with transport %s",
+            GetLastErrorString().c_str(), (int)port, transport == SocketOverTCP ? "TCP" : transport == SocketOverSCTP ? "SCTP" : "UDP");
+            closesocket(listenSocket);
+            freeaddrinfo(result);
+            return 0;
+    }
+
+    if(result != NULL) freeaddrinfo(result);
+
+    // For a reliable TCP or SCTP socket, start the server with a call to listen().
+    if(transport == SocketOverTCP || transport == SocketOverSCTP)
+    {
+            // Transition the bound socket to a listening state.
+            ret = listen(listenSocket, SOMAXCONN);
+            if (ret == KNET_SOCKET_ERROR)
+            {
+                    LOG(LogError, "Error at listen(): %s", GetLastErrorString().c_str());
+                    closesocket(listenSocket);
+                    return 0;
+            }
+    }
+
+    EndPoint localEndPoint = EndPoint::FromSockAddrIn(localAddress);
+
+    // We are starting up a server listen socket, which is not bound to an address. Use null address for the remote endpoint.
+    EndPoint remoteEndPoint;
+    remoteEndPoint.Reset();
+
+    const size_t maxSendSize = (transport == SocketOverTCP) ? cMaxTCPSendSize : (transport == SocketOverSCTP) ? cMaxTCPSendSize : cMaxUDPSendSize;
+    sockets.push_back(Socket(listenSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, "", transport, ServerListenSocket, maxSendSize));
+    Socket *listenSock = &sockets.back();
+
+    listenSock->SetBlocking(false);
+
+    return listenSock;
 }
 
 Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketTransportLayer transport)
 {
-	addrinfo *result = NULL;
-	addrinfo *ptr = NULL;
-	addrinfo hints;
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_INET;
-	hints.ai_socktype = (transport == SocketOverTCP) ? SOCK_STREAM : SOCK_DGRAM;
-	hints.ai_protocol = (transport == SocketOverTCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
-	char strPort[256];
-	sprintf(strPort, "%d", (unsigned int)port);
-	int ret = getaddrinfo(address, strPort, &hints, &result);
-	if (ret != 0)
-	{
-		LOG(LogError, "Network::Connect: getaddrinfo failed: %s", GetErrorString(ret).c_str());
-		return 0;
-	}
+    sctp_initmsg            initmsg;
+    sctp_event_subscribe    events;
+    sctp_status             status;
+    sctp_paddrparams        heartbeat;
+    sctp_rtoinfo            rtoinfo;
+
+    sockaddr_in             *paddrs[5];
+
+    SOCKET                  connectSocket;
+
+    addrinfo                *result = NULL;
+    addrinfo                *ptr = NULL;
+    addrinfo                hints;
+
+    int                     ret;
+    int                     in;
+    int                     addr_count;
+    char                    strPort[256];
+
+    /* Initialize variables */
+    connectSocket = INVALID_SOCKET;
+    memset(&events,     1, sizeof(events));
+    memset(&hints,      0, sizeof(hints));
+    memset(&initmsg,    0, sizeof(initmsg));
+    memset(&heartbeat,  0, sizeof(heartbeat));
+    memset(&rtoinfo,    0, sizeof(rtoinfo));
+
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = (transport == SocketOverTCP) ? SOCK_STREAM : (transport == SocketOverSCTP) ? SOCK_STREAM : SOCK_DGRAM;
+    hints.ai_protocol = (transport == SocketOverTCP) ? IPPROTO_TCP : (transport == SocketOverSCTP) ? IPPROTO_SCTP : IPPROTO_UDP;
+
+    sprintf(strPort, "%d", (unsigned int)port);
+
+    if((getaddrinfo(address, strPort, &hints, &result)) != 0)
+    {
+            LOG(LogError, "Network::Connect: getaddrinfo failed: %s", GetErrorString(ret).c_str());
+            return 0;
+    }
+
+    ptr = result;
+    PrintAddrInfo(ptr);
 
 #ifdef WIN32
-	SOCKET connectSocket = WSASocket(result->ai_family, result->ai_socktype, result->ai_protocol,
-		NULL, 0, WSA_FLAG_OVERLAPPED);
-#else
-	SOCKET connectSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
-	LOG(LogInfo, "A call to socket() returned a new socket 0x%8X.", (unsigned int)connectSocket);
-#endif
-	if (connectSocket == INVALID_SOCKET)
-	{
-		LOG(LogError, "Network::Connect: Error at socket(): %s", GetLastErrorString().c_str());
-		freeaddrinfo(result);
-		return 0;
-	}
-
-	// Connect to server.
-#ifdef WIN32
-	ret = WSAConnect(connectSocket, result->ai_addr, (int)result->ai_addrlen, 0, 0, 0, 0);
+    connectSocket = WSASocket(result->ai_family, result->ai_socktype, result->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
 #else
-	ret = connect(connectSocket, result->ai_addr, (int)result->ai_addrlen);
+    connectSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
 #endif
 
-	if (ret == KNET_SOCKET_ERROR)
-	{
-		closesocket(connectSocket);
-		connectSocket = INVALID_SOCKET;
-	}
-
-	freeaddrinfo(result);
-
-	if (connectSocket == INVALID_SOCKET)
-	{
-		LOG(LogError, "Unable to connect to server!");
-		return 0;
-	}
-
-	EndPoint localEndPoint;
-	sockaddr_in sockname;
-	socklen_t socknamelen = sizeof(sockname);
-	ret = getsockname(connectSocket, (sockaddr*)&sockname, &socknamelen);
-	if (ret == 0)
-		 localEndPoint = EndPoint::FromSockAddrIn(sockname);
-	else
-		LOG(LogError, "Network::ConnectSocket: getsockname failed: %s!", Network::GetLastErrorString().c_str());
-
-	EndPoint remoteEndPoint;
-	sockaddr_in peername;
-	socklen_t peernamelen = sizeof(peername);
-	ret = getpeername(connectSocket, (sockaddr*)&peername, &peernamelen);
-	if (ret == 0)
-		remoteEndPoint = EndPoint::FromSockAddrIn(peername);
-	else
-		LOG(LogError, "Network::ConnectSocket: getpeername failed: %s!", Network::GetLastErrorString().c_str());
-
-	std::string remoteHostName = remoteEndPoint.IPToString();
-
-	const size_t maxSendSize = (transport == SocketOverTCP) ? cMaxTCPSendSize : cMaxUDPSendSize;
-	Socket socket(connectSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, remoteHostName.c_str(), transport, ClientSocket, maxSendSize);
-
-	socket.SetBlocking(false);
-	sockets.push_back(socket);
-
-	Socket *sock = &sockets.back();
-
-	return sock;
+    if (connectSocket == INVALID_SOCKET)
+    {
+            LOG(LogError, "Network::Connect: Error at socket(): %s", GetLastErrorString().c_str());
+            freeaddrinfo(result);
+            return 0;
+    }
+
+    LOG(LogInfo, "\tA call to socket() returned a new socket 0x%X.\n", (unsigned int)connectSocket);
+
+    if(transport == SocketOverSCTP) /*Configure SCTP*/
+    {
+            /* Specify that a maximum of 2 streams will be available per socket */
+            initmsg.sinit_num_ostreams = 2;
+            initmsg.sinit_max_instreams = 2;
+            initmsg.sinit_max_attempts = 5;
+
+            /* Configure SCTP Heartbeats */
+            heartbeat.spp_flags = SPP_HB_ENABLE;
+            heartbeat.spp_hbinterval = 5000;
+            heartbeat.spp_pathmaxrxt = 2;
+
+            /*Configure RTOInfo*/
+            rtoinfo.srto_max = 2000;
+
+            if((setsockopt(connectSocket, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg))) != 0)
+                    perror("setsockopt");
+
+            if((ret = setsockopt(connectSocket, SOL_SCTP, SCTP_PEER_ADDR_PARAMS , &heartbeat, sizeof(heartbeat))) != 0)
+                perror("setsockopt");
+
+            if((ret = setsockopt(connectSocket, SOL_SCTP, SCTP_RTOINFO , &rtoinfo, sizeof(rtoinfo))) != 0)
+                perror("setsockopt");
+
+            if((setsockopt(connectSocket, SOL_SCTP, SCTP_EVENTS, &events, sizeof(events))) != 0)
+                    perror("setsockopt");
+    }
+
+    #ifdef WIN32
+        ret = WSAConnect(connectSocket, result->ai_addr, (int)result->ai_addrlen, 0, 0, 0, 0);
+    #else
+        if(transport == SocketOverSCTP)
+        {
+                addresses addr;
+
+                addr.addr_count = SCTPMessageConnection::GetIPAddresses(connectSocket, addr);
+
+                if(sctp_bindx(connectSocket, (struct sockaddr*)addr.addrs, addr.addr_count, SCTP_BINDX_ADD_ADDR) < 0)   // we try to bind all addresses in the beginning manually.
+                    LOG(LogError, "Can't bind addresses for the SCTP association.");                    // SCTP is able to do this automatically, but then you won't
+        }                                                                                               // be able to change addresses in the lifetime of the association
+        puts("connceting");
+        if((ret = connect(connectSocket, result->ai_addr, (int)result->ai_addrlen)) == KNET_SOCKET_ERROR)
+        {
+                closesocket(connectSocket);
+                connectSocket = INVALID_SOCKET;
+        }
+    #endif
+
+    freeaddrinfo(result);
+
+    if (connectSocket == INVALID_SOCKET)
+    {
+            LOG(LogError, "Unable to connect to server!");
+            return 0;
+    }
+    puts("asdasd");
+    if(transport == SocketOverSCTP) /* Print out some statistics about SCTP */
+    {
+            /*Get Peer Addresses*/
+            addr_count = sctp_getpaddrs(connectSocket, 0, (struct sockaddr**)paddrs);
+            LOG(LogInfo, "\tPeer addresses: %d", addr_count);
+
+            /*Print Out Addresses*/
+            for(int i = 0; i < addr_count; i++)
+                   LOG(LogInfo, "\tAddress %d: %s:%d", i +1, inet_ntoa((*paddrs)[i].sin_addr), (*paddrs)[i].sin_port);
+
+            printf("\n");
+            sctp_freepaddrs((struct sockaddr*)*paddrs);
+
+            in = sizeof(status);
+            if((ret = getsockopt(connectSocket, SOL_SCTP, SCTP_STATUS, (void *)&status, (socklen_t *)&in)) != 0)
+                perror("getsockopt");
+
+            LOG(LogInfo, "\tSCTP Status:");
+            LOG(LogInfo, "\t--------");
+            LOG(LogInfo, "\tassoc id  = %d", status.sstat_assoc_id);
+            LOG(LogInfo, "\tstate     = %d", status.sstat_state);
+            LOG(LogInfo, "\tinstrms   = %d", status.sstat_instrms);
+            LOG(LogInfo, "\toutstrms  = %d", status.sstat_outstrms);
+            LOG(LogInfo, "\t--------\n");
+    }
+
+    EndPoint localEndPoint;
+    sockaddr_in sockname;
+    socklen_t socknamelen = sizeof(sockname);
+
+    if((ret = getsockname(connectSocket, (sockaddr*)&sockname, &socknamelen)) == 0)
+            localEndPoint = EndPoint::FromSockAddrIn(sockname);
+    else
+            LOG(LogError, "Network::ConnectSocket: getsockname failed: %s!", Network::GetLastErrorString().c_str());
+
+    EndPoint remoteEndPoint;
+    sockaddr_in peername;
+    socklen_t peernamelen = sizeof(peername);
+
+    if((ret = getpeername(connectSocket, (sockaddr*)&peername, &peernamelen)) == 0)
+            remoteEndPoint = EndPoint::FromSockAddrIn(peername);
+    else
+            LOG(LogError, "Network::ConnectSocket: getpeername failed: %s!", Network::GetLastErrorString().c_str());
+
+    std::string remoteHostName = remoteEndPoint.IPToString();
+
+    const size_t maxSendSize = (transport == SocketOverTCP) ? cMaxTCPSendSize : (transport == SocketOverSCTP) ? cMaxTCPSendSize : cMaxUDPSendSize;
+
+    Socket socket(connectSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, remoteHostName.c_str(), transport, ClientSocket, maxSendSize);
+
+    socket.SetBlocking(false);
+
+    sockets.push_back(socket);
+
+    Socket *sock = &sockets.back();
+
+    return sock;
 }
 
-Ptr(MessageConnection) Network::Connect(const char *address, unsigned short port, 
-	SocketTransportLayer transport, IMessageHandler *messageHandler, Datagram *connectMessage)
+Ptr(MessageConnection) Network::Connect(const char *address, unsigned short port,
+    SocketTransportLayer transport, IMessageHandler *messageHandler, Datagram *connectMessage)
 {
-	Socket *socket = ConnectSocket(address, port, transport);
-	if (!socket)
-		return 0;
-
-	if (transport == SocketOverUDP)
-	{
-		SendUDPConnectDatagram(*socket, connectMessage);
-		LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().c_str());
-	}
-	else
-		LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().c_str());
-
-	Ptr(MessageConnection) connection;
-	if (transport == SocketOverTCP)
-		connection = new TCPMessageConnection(this, 0, socket, ConnectionOK);
-	else
-		connection = new UDPMessageConnection(this, 0, socket, ConnectionPending);
-
-	connection->RegisterInboundMessageHandler(messageHandler);
-	AssignConnectionToWorkerThread(connection);
-
-	connections.insert(connection);
-	return connection;
+    Socket *socket = ConnectSocket(address, port, transport);
+    if (!socket)
+        return 0;
+
+    if (transport == SocketOverUDP)
+    {
+        SendUDPConnectDatagram(*socket, connectMessage);
+        LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().c_str());
+    }
+    else if (transport == SocketOverTCP)
+        LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().c_str());
+    else
+        LOG(LogInfo, "Network::Connect: Connected a SCTP socket to %s.", socket->ToString().c_str());
+
+    Ptr(MessageConnection) connection;
+
+    if (transport == SocketOverTCP)
+        connection = new TCPMessageConnection(this, 0, socket, ConnectionOK);
+    else if (transport == SocketOverSCTP)
+        connection = new SCTPMessageConnection(this, 0, socket, ConnectionOK);
+    else
+        connection = new UDPMessageConnection(this, 0, socket, ConnectionPending);
+
+    connection->RegisterInboundMessageHandler(messageHandler);
+    AssignConnectionToWorkerThread(connection);
+
+    connections.insert(connection);
+    return connection;
 }
 
 Socket *Network::CreateUDPSlaveSocket(Socket *serverListenSocket, const EndPoint &remoteEndPoint, const char *remoteHostName)
 {
-	if (!serverListenSocket)
-	{
-		LOG(LogError, "Network::CreateUDPSlaveSocket called with null serverListenSocket handle!");
-		return 0;
-	}
-
-	SOCKET udpSocket = serverListenSocket->GetSocketHandle();
-	if (udpSocket == INVALID_SOCKET)
-	{
-		LOG(LogError, "Network::CreateUDPSlaveSocket called with a UDP server socket with invalid internal socket handle!");
-		return 0;
-	}
-
-	sockets.push_back(Socket(udpSocket, serverListenSocket->LocalEndPoint(),
-		serverListenSocket->LocalAddress(), remoteEndPoint, remoteHostName, SocketOverUDP, ServerClientSocket, cMaxUDPSendSize));
-	Socket *socket = &sockets.back();
-	socket->SetBlocking(false);
-
-	LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().c_str());
-	return socket;
+    if (!serverListenSocket)
+    {
+        LOG(LogError, "Network::CreateUDPSlaveSocket called with null serverListenSocket handle!");
+        return 0;
+    }
+
+    SOCKET udpSocket = serverListenSocket->GetSocketHandle();
+    if (udpSocket == INVALID_SOCKET)
+    {
+        LOG(LogError, "Network::CreateUDPSlaveSocket called with a UDP server socket with invalid internal socket handle!");
+        return 0;
+    }
+
+    sockets.push_back(Socket(udpSocket, serverListenSocket->LocalEndPoint(),
+        serverListenSocket->LocalAddress(), remoteEndPoint, remoteHostName, SocketOverUDP, ServerClientSocket, cMaxUDPSendSize));
+    Socket *socket = &sockets.back();
+    socket->SetBlocking(false);
+
+    LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().c_str());
+    return socket;
 }
 
 Socket *Network::StoreSocket(const Socket &cp)
 {
-	sockets.push_back(cp);
-	return &sockets.back();
+    sockets.push_back(cp);
+    return &sockets.back();
 }
 
 void Network::SendUDPConnectDatagram(Socket &socket, Datagram *connectMessage)
 {
     const int connectMessageSize = connectMessage ? connectMessage->size : 8;
-	OverlappedTransferBuffer *sendData = socket.BeginSend(connectMessageSize);
-	if (!sendData)
-	{
-		LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
-		return;
-	}
-	sendData->bytesContains = connectMessageSize;
-	if (connectMessage)
-	{
-		///\todo Craft the proper connection attempt datagram.
-		memcpy(sendData->buffer.buf, connectMessage->data, sendData->buffer.len);
-		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
-	}
-	else
-	{
-		///\todo Craft the proper connection attempt datagram.
-		memset(sendData->buffer.buf, 0, sendData->buffer.len);
-		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
-	}
-	socket.EndSend(sendData);
+    OverlappedTransferBuffer *sendData = socket.BeginSend(connectMessageSize);
+    if (!sendData)
+    {
+        LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
+        return;
+    }
+    sendData->bytesContains = connectMessageSize;
+    if (connectMessage)
+    {
+        ///\todo Craft the proper connection attempt datagram.
+        memcpy(sendData->buffer.buf, connectMessage->data, sendData->buffer.len);
+        LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
+    }
+    else
+    {
+        ///\todo Craft the proper connection attempt datagram.
+        memset(sendData->buffer.buf, 0, sendData->buffer.len);
+        LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
+    }
+    socket.EndSend(sendData);
 }
 
 } // ~kNet

File src/NetworkServer.cpp

 				networkServerListener->ClientDisconnected(iter->second);
 			if (iter->second->GetSocket() && iter->second->GetSocket()->TransportLayer() == SocketOverTCP)
 				owner->CloseConnection(iter->second);
+            else if (iter->second->GetSocket() && iter->second->GetSocket()->TransportLayer() == SocketOverSCTP)
+                owner->CloseConnection(iter->second);
 
 			{
 				Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();

File src/SCTPMessageConnection.cpp

 
     if (!socket || !socket->IsWriteOpen())
     {
-        LOG(LogVerbose, "TCPMessageConnection::SendOutPacket: Socket is not write open %p!", socket);
+        LOG(LogVerbose, "SCTPMessageConnection::SendOutPacket: Socket is not write open %p!", socket);
         if (connectionState == ConnectionOK) ///\todo This is slightly annoying to manually update the state here,
             connectionState = ConnectionPeerClosed; /// reorganize to be able to have this automatically apply.
         if (connectionState == ConnectionDisconnecting)
             overlappedTransfer = socket->BeginSend(std::max<size_t>(socket->MaxSendSize(), totalMessageSize));
             if (!overlappedTransfer)
             {
-                LOG(LogError, "TCPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
+                LOG(LogError, "SCTPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
                 assert(serializedMessages.size() == 0);
                 return PacketSendSocketClosed;
             }
 #endif
 //		assert(ContainerUniqueAndNoNullElements(outboundQueue));
 
-        LOG(LogError, "TCPMessageConnection::SendOutPacket() failed: Could not initiate overlapped transfer!");
+        LOG(LogError, "SCTPMessageConnection::SendOutPacket() failed: Could not initiate overlapped transfer!");
 
         return PacketSendSocketFull;
     }
 
-    LOG(LogData, "TCPMessageConnection::SendOutPacket: Sent %d bytes (%d messages) to peer %s.", (int)writer.BytesFilled(), (int)serializedMessages.size(), socket->ToString().c_str());
+    LOG(LogData, "SCTPMessageConnection::SendOutPacket: Sent %d bytes (%d messages) to peer %s.", (int)writer.BytesFilled(), (int)serializedMessages.size(), socket->ToString().c_str());
     AddOutboundStats(writer.BytesFilled(), 1, numMessagesPacked);
-    ADDEVENT("tcpDataOut", (float)writer.BytesFilled(), "bytes");
+    ADDEVENT("sctpDataOut", (float)writer.BytesFilled(), "bytes");
 
-    // The messages in serializedMessages array are now in the TCP driver to handle. It will guarantee
+    // The messages in serializedMessages array are now in the SCTP driver to handle. It will guarantee
     // delivery if possible, so we can free the messages already.
     for(size_t i = 0; i < serializedMessages.size(); ++i)
     {

File src/Socket.cpp

 		return false;
 	}
 
-	// Server listen sockets are *not* for sending data. They only accept incoming connections.
+    // Server listen sockets are *not* for sending data. They only accept incoming connections.
 	if (type == ServerListenSocket)
 	{
 		LOG(LogError, "Trying to send data through a server listen socket!");
 
 	int bytesSent = 0;
 	// sendto() to a connected socket causes EISCONN on OSX, so avoid it for client UDP sockets
+
 	if (transport == SocketOverUDP && type != ClientSocket)
 		bytesSent = sendto(connectSocket, data, numBytes, 0, (sockaddr*)&udpPeerAddress, sizeof(udpPeerAddress));
 	else if(transport == SocketOverTCP)
 		bytesSent = send(connectSocket, data, numBytes, 0);
-
     else
     {
         sctp_sndrcvinfo sinfo;
             ret = setsockopt(connectSocket, IPPROTO_SCTP, SCTP_NODELAY, &nagleEnabled, sizeof(nagleEnabled));
 #endif
 	if (ret != 0)
-		LOG(LogError, "Setting TCP_NODELAY=%s for socket %d failed. Reason: %s.",
+        LOG(LogError, "Setting %s=%s for socket %d failed. Reason: %s.", (transport == SocketOverTCP) ? "TCP_NODELAY" : "SCTP_NODELAY",
 			enabled ? "true" : "false", (int)connectSocket, Network::GetLastErrorString().c_str());
 }
 
 
         switch(notification->sn_header.sn_type)
         {
-
-                case SCTP_ASSOC_CHANGE:
-                case SCTP_PEER_ADDR_CHANGE:
-                case SCTP_REMOTE_ERROR:
-                case SCTP_SEND_FAILED:
-                case SCTP_SHUTDOWN_EVENT:
-                case SCTP_ADAPTATION_INDICATION:
-                case SCTP_PARTIAL_DELIVERY_EVENT:
-                case SCTP_AUTHENTICATION_INDICATION:
-                default:
-                    break;
+            case SCTP_ASSOC_CHANGE:
+            case SCTP_PEER_ADDR_CHANGE:
+            case SCTP_REMOTE_ERROR:
+            case SCTP_SEND_FAILED:
+            case SCTP_SHUTDOWN_EVENT:
+            case SCTP_ADAPTATION_INDICATION:
+            case SCTP_PARTIAL_DELIVERY_EVENT:
+            case SCTP_AUTHENTICATION_INDICATION:
+            default:
+                break;
         }
 }
 

File src/TCPMessageConnection.cpp

    limitations under the License. */
 
 /** @file TCPMessageConnection.cpp
-	@brief */
+    @brief */
 
 #include <sstream>
 
 
 TCPMessageConnection::~TCPMessageConnection()
 {
-	if (owner)
-		owner->CloseConnection(this);
+    if (owner)
+        owner->CloseConnection(this);
 }
 
 MessageConnection::SocketReadResult TCPMessageConnection::ReadSocket(size_t &totalBytesRead)
 {
-	AssertInWorkerThreadContext();
-
-	totalBytesRead = 0;
-
-	if (!socket || !socket->IsReadOpen())
-		return SocketReadError;
-
-	using namespace std;
-
-	// This is a limit on how many messages we keep in the inbound application buffer at maximum.
-	// If we receive data from the TCP socket faster than this limit, we stop reading until
-	// the application handles the previous messages first.
-	const int arbitraryInboundMessageCapacityLimit = 2048;
-
-	if (inboundMessageQueue.CapacityLeft() < arbitraryInboundMessageCapacityLimit) 
-	{
-		LOG(LogVerbose, "TCPMessageConnection::ReadSocket: Read throttled! Application cannot consume data fast enough.");
-		return SocketReadThrottled; // Can't read in new data, since the client app can't process it so fast.
-	}
-
-	// This is an arbitrary throttle limit on how much data we read in this function at once. Without this limit, 
-	// a slow computer with a fast network connection and a fast sender at the other end could flood this end 
-	// with so many messages that we wouldn't ever return from the loop below until the sender stops. This would
-	// starve the processing of all other connections this worker thread has to manage.
-	const size_t maxBytesToRead = 1024 * 1024;
-
-	// Pump the socket's receiving end until it's empty or can't process any more for now.
-	while(totalBytesRead < maxBytesToRead)
-	{
-		assert(socket);
-
-		// If we don't have enough free space in the ring buffer (even after compacting), throttle the reading of data.
-		if (tcpInboundSocketData.ContiguousFreeBytesLeft() < 16384 && tcpInboundSocketData.Capacity() > 1048576)
-		{
-			tcpInboundSocketData.Compact();
-			if (tcpInboundSocketData.ContiguousFreeBytesLeft() < 16384)
-				return SocketReadThrottled;
-		}
-
-		OverlappedTransferBuffer *buffer = socket->BeginReceive();
-		if (!buffer)
-			break; // Nothing to receive.
-
-		// If we can't fit the data we got, compact the ring buffer.
-		if (buffer->bytesContains > tcpInboundSocketData.ContiguousFreeBytesLeft())
-		{
-			tcpInboundSocketData.Compact();
-			if (buffer->bytesContains > tcpInboundSocketData.ContiguousFreeBytesLeft())
-			{
-				// Even compacting didn't get enough space to fit the message, so resize the ring buffer to be able to contain the message.
-				// At least always double the capacity of the buffer, so that we don't waste effort incrementing the capacity by too small amounts at a time.
-				tcpInboundSocketData.Resize(max(tcpInboundSocketData.Capacity()*2, tcpInboundSocketData.Capacity() + buffer->bytesContains - tcpInboundSocketData.ContiguousFreeBytesLeft()));
-				LOG(LogWaits, "TCPMessageConnection::ReadSocket: Performance warning! Resized the capacity of the receive ring buffer to %d bytes to accommodate a message of size %d (now have %d bytes of free space)",
-					tcpInboundSocketData.Capacity(), buffer->bytesContains, tcpInboundSocketData.ContiguousFreeBytesLeft());
-			}
-		}
-
-		LOG(LogData, "TCPMessageConnection::ReadSocket: Received %d bytes from the network from peer %s.", 
-			buffer->bytesContains, socket->ToString().c_str());
-
-		assert((size_t)buffer->bytesContains <= (size_t)tcpInboundSocketData.ContiguousFreeBytesLeft());
-		///\todo For performance, this memcpy can be optimized away. We can parse the message directly
-		/// from this buffer without copying it to a temporary working buffer. Detect if message straddles
-		/// two OverlappedTransferBuffers and only in that case memcpy that message to form a
-		/// single contiguous memory area.
-		memcpy(tcpInboundSocketData.End(), buffer->buffer.buf, buffer->bytesContains);
-		tcpInboundSocketData.Inserted(buffer->bytesContains); // Mark the memory area in the ring buffer as used.
-
-		totalBytesRead += buffer->bytesContains;
-		socket->EndReceive(buffer);
-	}
-
-	// Update statistics about the connection.
-	if (totalBytesRead > 0)
-	{
-		lastHeardTime = Clock::Tick();
-		ADDEVENT("tcpDataIn", (float)totalBytesRead, "bytes");
-		AddInboundStats(totalBytesRead, 1, 0);
-	}
-
-	// Finally, try to parse any bytes we received to complete messages. Any bytes consisting a partial
-	// message will be left into the tcpInboundSocketData partial buffer to wait for more bytes to be received later.
-	ExtractMessages();
-
-	if (totalBytesRead >= maxBytesToRead)
-		return SocketReadThrottled;
-	else
-		return SocketReadOK;
+    AssertInWorkerThreadContext();
+
+    totalBytesRead = 0;
+
+    if (!socket || !socket->IsReadOpen())
+        return SocketReadError;
+
+    using namespace std;
+
+    // This is a limit on how many messages we keep in the inbound application buffer at maximum.
+    // If we receive data from the TCP socket faster than this limit, we stop reading until
+    // the application handles the previous messages first.
+    const int arbitraryInboundMessageCapacityLimit = 2048;
+
+    if (inboundMessageQueue.CapacityLeft() < arbitraryInboundMessageCapacityLimit)
+    {
+        LOG(LogVerbose, "TCPMessageConnection::ReadSocket: Read throttled! Application cannot consume data fast enough.");
+        return SocketReadThrottled; // Can't read in new data, since the client app can't process it so fast.
+    }
+
+    // This is an arbitrary throttle limit on how much data we read in this function at once. Without this limit,
+    // a slow computer with a fast network connection and a fast sender at the other end could flood this end
+    // with so many messages that we wouldn't ever return from the loop below until the sender stops. This would
+    // starve the processing of all other connections this worker thread has to manage.
+    const size_t maxBytesToRead = 1024 * 1024;
+
+    // Pump the socket's receiving end until it's empty or can't process any more for now.
+    while(totalBytesRead < maxBytesToRead)
+    {
+        assert(socket);
+
+        // If we don't have enough free space in the ring buffer (even after compacting), throttle the reading of data.
+        if (tcpInboundSocketData.ContiguousFreeBytesLeft() < 16384 && tcpInboundSocketData.Capacity() > 1048576)
+        {
+            tcpInboundSocketData.Compact();
+            if (tcpInboundSocketData.ContiguousFreeBytesLeft() < 16384)
+                return SocketReadThrottled;
+        }
+
+        OverlappedTransferBuffer *buffer = socket->BeginReceive();
+        if (!buffer)
+            break; // Nothing to receive.
+
+        // If we can't fit the data we got, compact the ring buffer.
+        if (buffer->bytesContains > tcpInboundSocketData.ContiguousFreeBytesLeft())
+        {
+            tcpInboundSocketData.Compact();
+            if (buffer->bytesContains > tcpInboundSocketData.ContiguousFreeBytesLeft())
+            {
+                // Even compacting didn't get enough space to fit the message, so resize the ring buffer to be able to contain the message.
+                // At least always double the capacity of the buffer, so that we don't waste effort incrementing the capacity by too small amounts at a time.
+                tcpInboundSocketData.Resize(max(tcpInboundSocketData.Capacity()*2, tcpInboundSocketData.Capacity() + buffer->bytesContains - tcpInboundSocketData.ContiguousFreeBytesLeft()));
+                LOG(LogWaits, "TCPMessageConnection::ReadSocket: Performance warning! Resized the capacity of the receive ring buffer to %d bytes to accommodate a message of size %d (now have %d bytes of free space)",
+                    tcpInboundSocketData.Capacity(), buffer->bytesContains, tcpInboundSocketData.ContiguousFreeBytesLeft());
+            }
+        }
+
+        LOG(LogData, "TCPMessageConnection::ReadSocket: Received %d bytes from the network from peer %s.",
+            buffer->bytesContains, socket->ToString().c_str());
+
+        assert((size_t)buffer->bytesContains <= (size_t)tcpInboundSocketData.ContiguousFreeBytesLeft());
+        ///\todo For performance, this memcpy can be optimized away. We can parse the message directly
+        /// from this buffer without copying it to a temporary working buffer. Detect if message straddles
+        /// two OverlappedTransferBuffers and only in that case memcpy that message to form a
+        /// single contiguous memory area.
+        memcpy(tcpInboundSocketData.End(), buffer->buffer.buf, buffer->bytesContains);
+        tcpInboundSocketData.Inserted(buffer->bytesContains); // Mark the memory area in the ring buffer as used.
+
+        totalBytesRead += buffer->bytesContains;
+        socket->EndReceive(buffer);
+    }
+
+    // Update statistics about the connection.
+    if (totalBytesRead > 0)
+    {
+        lastHeardTime = Clock::Tick();
+        ADDEVENT("tcpDataIn", (float)totalBytesRead, "bytes");
+        AddInboundStats(totalBytesRead, 1, 0);
+    }
+
+    // Finally, try to parse any bytes we received to complete messages. Any bytes consisting a partial
+    // message will be left into the tcpInboundSocketData partial buffer to wait for more bytes to be received later.
+    ExtractMessages();
+
+    if (totalBytesRead >= maxBytesToRead)
+        return SocketReadThrottled;
+    else
+        return SocketReadOK;
 }
 
 /// Checks that the specified conditions for the container apply.
 template<typename T>
 bool ContainerUniqueAndNoNullElements(const std::vector<T> &cont)
 {
-	for(size_t i = 0; i < cont.size(); ++i)
-		for(size_t j = i+1; j < cont.size(); ++j)
-			if (cont[i] == cont[j] || cont[i] == 0)
-				return false;
-	return true;
+    for(size_t i = 0; i < cont.size(); ++i)
+        for(size_t j = i+1; j < cont.size(); ++j)
+            if (cont[i] == cont[j] || cont[i] == 0)
+                return false;
+    return true;
 }
 
 /// Packs several messages from the outbound priority queue into a single packet and sends it out the wire.
 /// @return False if the send was a failure and sending should not be tried again at this time, true otherwise.
 MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 {
-	AssertInWorkerThreadContext();
+    AssertInWorkerThreadContext();
 
-	if (bOutboundSendsPaused || outboundQueue.Size() == 0)
-		return PacketSendNoMessages;
+    if (bOutboundSendsPaused || outboundQueue.Size() == 0)
+        return PacketSendNoMessages;
 
-	if (!socket || !socket->IsWriteOpen())
-	{
-		LOG(LogVerbose, "TCPMessageConnection::SendOutPacket: Socket is not write open %p!", socket);
-		if (connectionState == ConnectionOK) ///\todo This is slightly annoying to manually update the state here,
-			connectionState = ConnectionPeerClosed; /// reorganize to be able to have this automatically apply.
-		if (connectionState == ConnectionDisconnecting)
-			connectionState = ConnectionClosed;
-		return PacketSendSocketClosed;
-	}
+    if (!socket || !socket->IsWriteOpen())
+    {
+        LOG(LogVerbose, "TCPMessageConnection::SendOutPacket: Socket is not write open %p!", socket);
+        if (connectionState == ConnectionOK) ///\todo This is slightly annoying to manually update the state here,
+            connectionState = ConnectionPeerClosed; /// reorganize to be able to have this automatically apply.
+        if (connectionState == ConnectionDisconnecting)
+            connectionState = ConnectionClosed;
+        return PacketSendSocketClosed;
+    }
 
     // 'serializedMessages' is a temporary data structure used only by this member function.
     // It caches a list of all the messages we are pushing out during this call.
-	serializedMessages.clear();
+    serializedMessages.clear();
 
-	// In the following, we start coalescing multiple messages into a single socket send() calls.
-	// Get the maximum number of bytes we can coalesce for the send() call. This is only a soft limit
-	// in the sense that if we encounter a single message that is larger than this limit, then we try
-	// to send that through in one send() call.
+    // In the following, we start coalescing multiple messages into a single socket send() calls.
+    // Get the maximum number of bytes we can coalesce for the send() call. This is only a soft limit
+    // in the sense that if we encounter a single message that is larger than this limit, then we try
+    // to send that through in one send() call.
 //	const size_t maxSendSize = socket->MaxSendSize();
 
-	// Push out all the pending data to the socket.
-	OverlappedTransferBuffer *overlappedTransfer = 0;
+    // Push out all the pending data to the socket.
+    OverlappedTransferBuffer *overlappedTransfer = 0;
 
-	int numMessagesPacked = 0;
-	DataSerializer writer;
+    int numMessagesPacked = 0;
+    DataSerializer writer;
 //	assert(ContainerUniqueAndNoNullElements(outboundQueue)); // This precondition should always hold (but very heavy to test, uncomment to debug)
-	while(outboundQueue.Size() > 0)
-	{
+    while(outboundQueue.Size() > 0)
+    {
 #ifdef KNET_NO_MAXHEAP
-		NetworkMessage *msg = *outboundQueue.Front();
+        NetworkMessage *msg = *outboundQueue.Front();
 #else
-		NetworkMessage *msg = outboundQueue.Front();
+        NetworkMessage *msg = outboundQueue.Front();
 #endif
 
-		if (msg->obsolete)
-		{
-			ClearOutboundMessageWithContentID(msg);
-			FreeMessage(msg);
-			outboundQueue.PopFront();
-			continue;
-		}
+        if (msg->obsolete)
+        {
+            ClearOutboundMessageWithContentID(msg);
+            FreeMessage(msg);
+            outboundQueue.PopFront();
+            continue;
+        }
 
-		const int encodedMsgIdLength = VLE8_16_32::GetEncodedBitLength(msg->id) / 8;
-		const size_t messageContentSize = msg->dataSize + encodedMsgIdLength; // 1 byte: Message ID. X bytes: Content.
-		const int encodedMsgSizeLength = VLE8_16_32::GetEncodedBitLength(messageContentSize) / 8;
-		const size_t totalMessageSize = messageContentSize + encodedMsgSizeLength; // 2 bytes: Content length. X bytes: Content.
+        const int encodedMsgIdLength = VLE8_16_32::GetEncodedBitLength(msg->id) / 8;
+        const size_t messageContentSize = msg->dataSize + encodedMsgIdLength; // 1 byte: Message ID. X bytes: Content.
+        const int encodedMsgSizeLength = VLE8_16_32::GetEncodedBitLength(messageContentSize) / 8;
+        const size_t totalMessageSize = messageContentSize + encodedMsgSizeLength; // 2 bytes: Content length. X bytes: Content.
 
         if (!overlappedTransfer)
         {
             overlappedTransfer = socket->BeginSend(std::max<size_t>(socket->MaxSendSize(), totalMessageSize));
-	        if (!overlappedTransfer)
-	        {
-		        LOG(LogError, "TCPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
+            if (!overlappedTransfer)
+            {
+                LOG(LogError, "TCPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
                 assert(serializedMessages.size() == 0);
-		        return PacketSendSocketClosed;