mirror of
https://github.com/SWG-Source/src.git
synced 2026-07-31 00:15:55 -04:00
Added sharedNetwork library
This commit is contained in:
@@ -8,6 +8,7 @@ add_subdirectory(sharedLog)
|
||||
add_subdirectory(sharedMath)
|
||||
add_subdirectory(sharedMemoryManager)
|
||||
add_subdirectory(sharedMessageDispatch)
|
||||
add_subdirectory(sharedNetwork)
|
||||
add_subdirectory(sharedNetworkMessages)
|
||||
add_subdirectory(sharedRandom)
|
||||
add_subdirectory(sharedSynchronization)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(sharedNetwork)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
|
||||
|
||||
add_subdirectory(src)
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../../src/shared/ConnectionHandler.h"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../../src/shared/ManagerHandler.h"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../../src/shared/UdpLibraryMT/UdpHandlerMT.h"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../../src/shared/UdpLibraryMT/UdpLibraryMT.h"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Address.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/BroadcastSock.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/ConfigSharedNetwork.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Connection.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/FirstSharedNetwork.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/NetworkHandler.h"
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../../src/shared/NetworkSetupData.h"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/Service.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/SetupSharedNetwork.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
#if defined(PLATFORM_WIN32)
|
||||
#include "../../src/win32/Sock.h"
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
#include "../../src/linux/Sock.h"
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/UdpLibraryMT/UdpConnectionMT.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../src/shared/UdpSock.h"
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
set(SHARED_SOURCES
|
||||
shared/Address.h
|
||||
shared/BroadcastSock.cpp
|
||||
shared/BroadcastSock.h
|
||||
shared/ConfigSharedNetwork.cpp
|
||||
shared/ConfigSharedNetwork.h
|
||||
shared/Connection.cpp
|
||||
shared/Connection.h
|
||||
shared/ConnectionHandler.cpp
|
||||
shared/ConnectionHandler.h
|
||||
shared/FirstSharedNetwork.h
|
||||
shared/ManagerHandler.cpp
|
||||
shared/ManagerHandler.h
|
||||
shared/NetworkHandler.cpp
|
||||
shared/NetworkHandler.h
|
||||
shared/NetworkSetupData.cpp
|
||||
shared/NetworkSetupData.h
|
||||
shared/Service.cpp
|
||||
shared/Service.h
|
||||
shared/SetupSharedNetwork.cpp
|
||||
shared/SetupSharedNetwork.h
|
||||
shared/UdpSock.h
|
||||
|
||||
shared/UdpLibraryMT/Events.cpp
|
||||
shared/UdpLibraryMT/Events.h
|
||||
shared/UdpLibraryMT/UdpConnectionHandlerMT.cpp
|
||||
shared/UdpLibraryMT/UdpConnectionHandlerMT.h
|
||||
shared/UdpLibraryMT/UdpConnectionMT.cpp
|
||||
shared/UdpLibraryMT/UdpConnectionMT.h
|
||||
shared/UdpLibraryMT/UdpHandlerMT.h
|
||||
shared/UdpLibraryMT/UdpLibraryMT.cpp
|
||||
shared/UdpLibraryMT/UdpLibraryMT.h
|
||||
shared/UdpLibraryMT/UdpManagerHandlerMT.cpp
|
||||
shared/UdpLibraryMT/UdpManagerHandlerMT.h
|
||||
shared/UdpLibraryMT/UdpManagerMT.cpp
|
||||
shared/UdpLibraryMT/UdpManagerMT.h
|
||||
shared/UdpLibraryMT/UdpMiscMT.cpp
|
||||
shared/UdpLibraryMT/UdpMiscMT.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(PLATFORM_SOURCES
|
||||
win32/Address.cpp
|
||||
win32/FirstSharedNetwork.cpp
|
||||
win32/NetworkGetHostName.cpp
|
||||
win32/OverlappedTcp.cpp
|
||||
win32/OverlappedTcp.h
|
||||
win32/Sock.cpp
|
||||
win32/Sock.h
|
||||
win32/TcpClient.cpp
|
||||
win32/TcpClient.h
|
||||
win32/TcpServer.cpp
|
||||
win32/TcpServer.h
|
||||
win32/UdpSock.cpp
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
|
||||
else()
|
||||
set(PLATFORM_SOURCES
|
||||
linux/Address.cpp
|
||||
linux/NetworkGetHostName.cpp
|
||||
linux/Sock.cpp
|
||||
linux/Sock.h
|
||||
linux/TcpClient.cpp
|
||||
linux/TcpClient.h
|
||||
linux/TcpServer.cpp
|
||||
linux/TcpServer.h
|
||||
linux/UdpSock.cpp
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shared
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
|
||||
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
|
||||
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include
|
||||
)
|
||||
|
||||
add_library(sharedNetwork STATIC
|
||||
${SHARED_SOURCES}
|
||||
${PLATFORM_SOURCES}
|
||||
)
|
||||
@@ -0,0 +1,372 @@
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include "Address.h"
|
||||
#include <cassert>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstdio>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address() :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress("0.0.0.0")
|
||||
{
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_family = AF_INET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address(const std::string & newHostAddress, unsigned short newHostPort) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(newHostAddress)
|
||||
{
|
||||
struct hostent * h;
|
||||
unsigned long u;
|
||||
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_port = htons(newHostPort);
|
||||
addr4->sin_family = AF_INET;
|
||||
// was an address supplied?
|
||||
if(hostAddress.size() > 0)
|
||||
{
|
||||
// Is the first byte a number? (IP names begin with an alpha)
|
||||
if(!isdigit(hostAddress[0]))
|
||||
{
|
||||
// The first byte is a letter, resolve it
|
||||
if( (h = gethostbyname(hostAddress.c_str())) != 0)
|
||||
{
|
||||
memcpy(&addr4->sin_addr, h->h_addr_list[0], sizeof(addr4->sin_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// boom! grab the entry from the h_addr member instead!
|
||||
if( (h = gethostbyname(hostAddress.c_str())) != 0)
|
||||
{
|
||||
memcpy(&addr4->sin_addr, h->h_addr, sizeof(addr4->sin_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// no resolution, INADDR_ANY
|
||||
memset(&addr4->sin_addr, 0, sizeof(addr4->sin_addr));
|
||||
|
||||
// in debug, fail, something is wrong.
|
||||
// potential problems - an insanely bogus address was
|
||||
// passed or the host system is misconfigured and cannot
|
||||
// resolve the name
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
char addrbuf[17] = {"\0"};
|
||||
unsigned char * a = (unsigned char *)&addr4->sin_addr;
|
||||
snprintf(addrbuf, sizeof(addrbuf), "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
|
||||
hostAddress = addrbuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A dotted decimal ip number string was supplied. Convert for sin_addr
|
||||
u = inet_addr(hostAddress.c_str());
|
||||
memcpy(&addr4->sin_addr, &u, sizeof(addr4->sin_addr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing was supplied, assign INADDR_ANY
|
||||
addr4->sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address(const Address & source) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(source.hostAddress)
|
||||
{
|
||||
*addr4 = *source.addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::Address(const struct sockaddr_in & ipv4addr) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress("")
|
||||
{
|
||||
convertFromSockAddr(ipv4addr);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address::~Address()
|
||||
{
|
||||
delete addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address & Address::operator = (const Address & rhs)
|
||||
{
|
||||
if(this != &rhs)
|
||||
{
|
||||
hostAddress = rhs.hostAddress;
|
||||
*addr4 = *rhs.addr4;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Address & Address::operator = (const struct sockaddr_in & rhs)
|
||||
{
|
||||
convertFromSockAddr(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Address::convertFromSockAddr(const struct sockaddr_in & source)
|
||||
{
|
||||
// extract IP bytes from ipv4add4
|
||||
const unsigned char * ip;
|
||||
char name[17] = {"\0"};
|
||||
|
||||
ip = reinterpret_cast<const unsigned char *>(&source.sin_addr);
|
||||
snprintf(name, 17, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); //lint !e534
|
||||
hostAddress = name;
|
||||
*addr4 = source;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get a human readable host address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(struct sockaddr_in & a)
|
||||
{
|
||||
Address b(a);
|
||||
printf("address = %%s\\n", b.getHostAddress().c_str());
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return A human readable host address string
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const std::string & Address::getHostAddress() const
|
||||
{
|
||||
return hostAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the port associated with this address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(struct sockaddr_in & a)
|
||||
{
|
||||
Address b(a);
|
||||
printf("port = %%i\\n", b.getHostPort());
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return A human readable port in host-byte order associated with
|
||||
this address.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned short Address::getHostPort() const
|
||||
{
|
||||
return ntohs(addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the BSD sockaddr describing this address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(SOCKET s, unsigned char * d, int l, const Address & a)
|
||||
{
|
||||
int t = sizeof(struct sockaddr_in);
|
||||
sendto(s, s, l, 0, reinterpret_cast<const struct sockaddr *>(&(a.getSockAddr4())), t);
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return a BSD sockaddr that describes this IPv4 address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const struct sockaddr_in & Address::getSockAddr4() const
|
||||
{
|
||||
return *addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief equality operator
|
||||
|
||||
The equality operator compares the ip address, ip port,
|
||||
and address family to establish equality.
|
||||
|
||||
Example:
|
||||
\code
|
||||
Address a("127.0.0.1", 55443);
|
||||
Address b;
|
||||
|
||||
b = a;
|
||||
assert(b == a);
|
||||
\endcode
|
||||
|
||||
@return True of the right hand side is equal to this address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator == (const Address & rhs) const
|
||||
{
|
||||
return (addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_family == rhs.addr4->sin_family &&
|
||||
addr4->sin_port == rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief less-than comparison operator
|
||||
|
||||
The < comparison operator compares the IP number and port. If
|
||||
the IP numbers are identical, but the left hand side port is
|
||||
less than the right hand side port, the operator will return
|
||||
true.
|
||||
|
||||
@return true if the left hand side's IP number is less than
|
||||
the right hand side IP number. If the numbers are equal, it
|
||||
will return true if the left hand side IP port is less
|
||||
than the right hand side port. Otherwise it returns false.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator < (const Address & rhs) const
|
||||
{
|
||||
return(addr4->sin_addr.s_addr < rhs.addr4->sin_addr.s_addr ||
|
||||
addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_port < rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief inequality operator
|
||||
|
||||
Leverages the equality operator, so whenever == returns true,
|
||||
this returns false, and visa versa.
|
||||
|
||||
@return true if the right hand side is not equal to the left
|
||||
hand side. False if they are equal.
|
||||
|
||||
@see Adress::operator==
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator != (const Address & rhs) const
|
||||
{
|
||||
return(! (rhs == *this));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief greater-than comparison operator
|
||||
|
||||
The > comparison operator compares the IP number and port. If
|
||||
the IP numbers are identical, but the right hand side port is
|
||||
lesser than the left hand side port, the operator will return
|
||||
true.
|
||||
|
||||
@return true if the left hand side's IP number is greater than
|
||||
the right hand side IP number. If the numbers are equal, it
|
||||
will return true if the left hand side IP port is greater
|
||||
than the right hand side port. Otherwise it returns false.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator > (const Address & rhs) const
|
||||
{
|
||||
return(addr4->sin_addr.s_addr > rhs.addr4->sin_addr.s_addr ||
|
||||
addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_port > rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief a hash_map support routine
|
||||
|
||||
The STL hash_map (present in most STL implementations) requires
|
||||
a size_t return from a hash function to identify which bucket
|
||||
a particular value should reside in. On 32 bit or better platforms
|
||||
the sockaddr_in.sin_addr.s_addr member is small enough to
|
||||
qualify as a hash-result, provides reasonably unique values
|
||||
and is reproducable given an address input.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@return the ip number member of a sockaddr_in struct
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
size_t Address::hashFunction() const
|
||||
{
|
||||
return addr4->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief STL map support routine
|
||||
|
||||
STL maps (including hash_maps) require unique keys, and therefore
|
||||
need to compare a key for equality with an existing target.
|
||||
|
||||
The functor uses Address::operator = for the comparison.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@return true if the left hand side and right hand side are equal
|
||||
using Address::operator =
|
||||
@see Address::operator=
|
||||
|
||||
*/
|
||||
bool Address::EqualFunction::operator () (const Address & lhs, const Address & rhs) const
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief STL hash_map support routine
|
||||
|
||||
The HashFunction::operator() invokes Address::hashFunction to
|
||||
determine an appropriate hash for the address.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@see Address::hashFunction
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
size_t Address::HashFunction::operator () (const Address & a) const
|
||||
{
|
||||
return a.hashFunction();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// NetworkGetHostName.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include "Address.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct HN
|
||||
{
|
||||
HN();
|
||||
std::string hostName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
HN::HN()
|
||||
{
|
||||
char name[512] = {"\0"};
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
Address a(name, 0);
|
||||
//hostName = name;
|
||||
hostName = a.getHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & NetworkHandler::getHostName()
|
||||
{
|
||||
static HN hn;
|
||||
return hn.hostName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & NetworkHandler::getHumanReadableHostName()
|
||||
{
|
||||
char name[512] = {"\0"};
|
||||
static std::string nameString;
|
||||
if(nameString.empty())
|
||||
{
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
name[sizeof(name) - 1] = 0;
|
||||
//hostName = name;
|
||||
nameString = name;
|
||||
}
|
||||
}
|
||||
return nameString;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct HL
|
||||
{
|
||||
HL();
|
||||
std::vector<std::pair<std::string, std::string> > addrList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
HL::HL() :
|
||||
addrList()
|
||||
{
|
||||
struct ifconf ifc;
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
// create a socket to perform SIOCGIFCONF on
|
||||
if(sock > -1)
|
||||
{
|
||||
// determine buffer size to receive array of if_req's, initialize it
|
||||
// when length is appropriate
|
||||
int reqSize = 100 * sizeof(struct ifreq);
|
||||
int lastReqSize = reqSize;
|
||||
for(;;)
|
||||
{
|
||||
char * buf = new char[reqSize];
|
||||
ifc.ifc_len = reqSize;
|
||||
ifc.ifc_buf = buf;
|
||||
memset(ifc.ifc_buf, 0, reqSize);
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
if (errno != EINVAL || lastReqSize != 0)
|
||||
{
|
||||
WARNING(true, ("Error getting interface list: %s", strerror(errno)));
|
||||
delete buf;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ifc.ifc_len == lastReqSize)
|
||||
break; // we have the reqs
|
||||
lastReqSize = ifc.ifc_len;
|
||||
}
|
||||
|
||||
// need more buffer space for request
|
||||
reqSize += sizeof(struct ifreq);
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
int reqCount = reqSize / sizeof(struct ifreq);
|
||||
int i;
|
||||
ifreq * reqs = (struct ifreq *)ifc.ifc_buf;
|
||||
for(i = 0; i < reqCount; ++i)
|
||||
{
|
||||
struct sockaddr_in * sa = (struct sockaddr_in *)&reqs[i].ifr_addr;
|
||||
if(sa->sin_family == AF_INET)
|
||||
{
|
||||
char addrbuf[17] = {"\0"};
|
||||
unsigned char * a = (unsigned char *)&sa->sin_addr;
|
||||
snprintf(addrbuf, sizeof(addrbuf), "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
|
||||
addrList.push_back(std::make_pair(std::string(reqs[i].ifr_name), std::string(addrbuf)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > & NetworkHandler::getInterfaceAddresses()
|
||||
{
|
||||
static HL hl;
|
||||
return hl.addrList;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -0,0 +1,236 @@
|
||||
//---------------------------------------------------------------------
|
||||
#pragma warning(disable : 4127)
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include <cassert>
|
||||
#include "Sock.h"
|
||||
#include <netdb.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
const int INVALID_SOCKET = 0xFFFFFFFF;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Sock::Sock() :
|
||||
handle(INVALID_SOCKET),
|
||||
lastError(Sock::SOCK_NO_ERROR),
|
||||
bindAddress()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
Sock::~Sock()
|
||||
{
|
||||
// ensure we don't block, and that pending
|
||||
// data is sent with a graceful shutdown
|
||||
int err;
|
||||
err = close(handle);
|
||||
assert(err == 0);
|
||||
handle = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Bind the socket to the specified local address
|
||||
*/
|
||||
bool Sock::bind(const Address & newBindAddress)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
int enable = 1;
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||
|
||||
bindAddress = newBindAddress;
|
||||
assert(handle != INVALID_SOCKET);
|
||||
socklen_t namelen = sizeof(struct sockaddr_in);
|
||||
int err = ::bind(handle, reinterpret_cast<const struct sockaddr *>(&(bindAddress.getSockAddr4())), namelen);
|
||||
if(err == 0)
|
||||
{
|
||||
result = true;
|
||||
struct sockaddr_in a;
|
||||
int r;
|
||||
r = getsockname(handle, reinterpret_cast<struct sockaddr *>(&a), &namelen);
|
||||
assert(r == 0);
|
||||
bindAddress = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
assert(err == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Sock::bind()
|
||||
{
|
||||
bool result = false;
|
||||
struct sockaddr_in a;
|
||||
socklen_t namelen = sizeof(struct sockaddr_in);
|
||||
memset(&a, 0, sizeof(struct sockaddr_in));
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = 0;
|
||||
a.sin_addr.s_addr = INADDR_ANY;
|
||||
assert(handle != INVALID_SOCKET);
|
||||
int err = ::bind(handle, reinterpret_cast<struct sockaddr *>(&a), namelen);
|
||||
if(err == 0)
|
||||
{
|
||||
result = true;
|
||||
int r;
|
||||
r = getsockname(handle, reinterpret_cast<struct sockaddr *>(&a), &namelen);
|
||||
assert(r == 0);
|
||||
bindAddress = a;
|
||||
}
|
||||
assert(err == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Sock::canRecv() const
|
||||
{
|
||||
pollfd r;
|
||||
r.fd = handle;
|
||||
r.events = POLLIN | POLLPRI | POLLERR;
|
||||
|
||||
int err = poll(&r, 1, 0);
|
||||
|
||||
if(err < 0)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINTR: // the system has interrupted the call, it's too busy to send right now
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (err > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
bool Sock::canSend() const
|
||||
{
|
||||
pollfd w;
|
||||
w.fd = handle;
|
||||
w.events = POLLOUT | POLLERR;
|
||||
int err = poll(&w, 1, 0);
|
||||
|
||||
if(err < 0)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINTR: // the system has interrupted the call, it's too busy to send right now
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (err > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned int Sock::getInputBytesPending() const
|
||||
{
|
||||
unsigned long int bytes = 0;
|
||||
int err;
|
||||
err = ioctl(handle, FIONREAD, &bytes); //lint !e1924 (I don't know WHAT Microsoft is doing here!)
|
||||
assert(err == 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const std::string Sock::getLastError() const
|
||||
{
|
||||
std::string errString;
|
||||
|
||||
switch(errno)
|
||||
{
|
||||
case EBADF:
|
||||
errString = "The argument s is not a valid descriptor.";
|
||||
break;
|
||||
case ENOTSOCK:
|
||||
errString = "The argument s is a file, not a socket.";
|
||||
break;
|
||||
case ENOPROTOOPT:
|
||||
errString = "The option is unknown at the level indicated.";
|
||||
break;
|
||||
case EFAULT:
|
||||
errString = "The address pointed to by optval is not in a valid part of the process address space. For getsockopt, this error may also be returned if optlen is not in a valid part of the process address space.";
|
||||
break;
|
||||
case ENOTTY:
|
||||
errString = "The scoket handle is not associated with a character special device.";
|
||||
break;
|
||||
case EINVAL:
|
||||
errString = "argument is not valid.";
|
||||
break;
|
||||
case EAGAIN:
|
||||
errString = "EAGAIN";
|
||||
break;
|
||||
case EDEADLK:
|
||||
errString = "EDEADLK";
|
||||
break;
|
||||
case ECONNRESET:
|
||||
errString = "The connection was reset by the peer.";
|
||||
lastError = CONNECTION_RESET;
|
||||
break;
|
||||
default:
|
||||
errString = strerror(errno);
|
||||
break;
|
||||
}
|
||||
|
||||
return errString;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Sock::getPeerName(struct sockaddr_in & target, int s)
|
||||
{
|
||||
socklen_t namelen = sizeof(struct sockaddr_in);
|
||||
int err;
|
||||
err = getpeername(s, reinterpret_cast<sockaddr *>(&(target)), &namelen);
|
||||
assert(err != -1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** @brief determine the maximum message size that may be sent on this socket
|
||||
*/
|
||||
const unsigned int Sock::getMaxMessageSendSize() const
|
||||
{
|
||||
int maxMsgSize = 1500;
|
||||
/** @todo get msg size via IP interface on Linux
|
||||
int optlen = sizeof(int);
|
||||
int result = getsockopt(handle, SOL_SOCKET, SO_MAX_MSG_SIZE, reinterpret_cast<char *>(&maxMsgSize), &optlen);
|
||||
if(result != 0)
|
||||
{
|
||||
perror("Sock::getMaxMessageSendSize() : getsockopt()");
|
||||
}
|
||||
*/
|
||||
return static_cast<unsigned int>(maxMsgSize);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Sock::setNonBlocking() const
|
||||
{
|
||||
assert(handle != INVALID_SOCKET);
|
||||
unsigned long int nb = 1;
|
||||
int err;
|
||||
err = ioctl(handle, FIONBIO, &nb); //lint !e569 // loss of precision in the FIONBIO macro, beyond my control
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Sock.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Sock_H
|
||||
#define INCLUDED_Sock_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/Address.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const unsigned int SOCK_ERROR = 0xFFFFFFFF;
|
||||
|
||||
/**
|
||||
@brief a BSD socket abstraction
|
||||
|
||||
Sock abstracts BSD sockets for platform independant operation. It
|
||||
also provides common socket operations to simplify socket management.
|
||||
|
||||
@see BroadcastSock
|
||||
@see TcpSock
|
||||
@see UdpSock
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class Sock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@brief failure states for a socket
|
||||
*/
|
||||
enum ErrorCodes
|
||||
{
|
||||
SOCK_NO_ERROR,
|
||||
CONNECTION_FAILED,
|
||||
CONNECTION_CLOSED,
|
||||
CONNECTION_RESET
|
||||
};
|
||||
|
||||
Sock();
|
||||
virtual ~Sock() = 0;
|
||||
bool bind(const Address & bindAddress);
|
||||
bool bind();
|
||||
bool canSend() const;
|
||||
bool canRecv() const;
|
||||
const Address & getBindAddress() const;
|
||||
const int getHandle() const;
|
||||
const unsigned int getInputBytesPending() const;
|
||||
const std::string getLastError() const;
|
||||
const enum ErrorCodes getLastErrorCode() const;
|
||||
const unsigned int getMaxMessageSendSize() const;
|
||||
static void getPeerName(struct sockaddr_in & target, int s);
|
||||
|
||||
private:
|
||||
// disabled
|
||||
Sock(const Sock & source);
|
||||
Sock & operator= (const Sock & source);
|
||||
|
||||
protected:
|
||||
void setNonBlocking() const;
|
||||
protected:
|
||||
int handle;
|
||||
|
||||
/**
|
||||
@brief support for setting/getting last error from derived
|
||||
sock classes
|
||||
*/
|
||||
mutable enum ErrorCodes lastError;
|
||||
private:
|
||||
Address bindAddress;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the local address of the socket
|
||||
|
||||
Until a socket is bound, the bind address may be reported as
|
||||
0.0.0.0:0
|
||||
|
||||
@return a const Address reference describing the local address
|
||||
of the socket.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const Address & Sock::getBindAddress() const
|
||||
{
|
||||
return bindAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the platform specific socket handle
|
||||
|
||||
the handle returned is not portable and should only be used locally
|
||||
for Sock specific operations.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const int Sock::getHandle() const
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the last error code on the socket
|
||||
|
||||
@return the last error code on the socket
|
||||
|
||||
@see Sock::ErrorCodes
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const enum Sock::ErrorCodes Sock::getLastErrorCode() const
|
||||
{
|
||||
return lastError;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#endif // _Sock_H
|
||||
|
||||
@@ -0,0 +1,610 @@
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "TcpClient.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
#include "Archive/Archive.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include "sharedLog/NetLogConnection.h"
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include <map>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned long KEEPALIVE_MS = 1000;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace TcpClientNamespace
|
||||
{
|
||||
std::set<TcpClient *> s_pendingConnectionSends;
|
||||
std::set<TcpClient *> s_tcpClients;
|
||||
bool s_installed = false;
|
||||
}
|
||||
|
||||
using namespace TcpClientNamespace;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient (int sockHandle, TcpServer * server) :
|
||||
m_socket(sockHandle),
|
||||
m_tcpServer(server),
|
||||
m_pendingSend(),
|
||||
m_connection(0),
|
||||
m_recvBuffer(0),
|
||||
m_recvBufferLength(0),
|
||||
m_remoteAddress(),
|
||||
m_refCount(0),
|
||||
m_connected (true),
|
||||
m_lastSendTime(0),
|
||||
m_bindPort(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
s_tcpClients.insert(this);
|
||||
setSockOptions();
|
||||
|
||||
struct sockaddr_in target;
|
||||
socklen_t namelen = sizeof(struct sockaddr_in);
|
||||
if (getpeername(sockHandle, reinterpret_cast<sockaddr *>(&target), &namelen) == 0)
|
||||
m_remoteAddress = target;
|
||||
struct sockaddr_in bindAddr;
|
||||
|
||||
if(getsockname(sockHandle, reinterpret_cast<struct sockaddr *>(&bindAddr), &namelen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient (const std::string & a, const unsigned short port) :
|
||||
m_socket(-1),
|
||||
m_tcpServer(0),
|
||||
m_connection(0),
|
||||
m_recvBuffer(0),
|
||||
m_recvBufferLength(0),
|
||||
m_remoteAddress(a, port),
|
||||
m_refCount(0),
|
||||
m_connected (false),
|
||||
m_lastSendTime(0),
|
||||
m_bindPort(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
FATAL(! s_installed, ("TcpClient is not installed!"));
|
||||
|
||||
s_tcpClients.insert(this);
|
||||
setupSocket();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpClient::~TcpClient()
|
||||
{
|
||||
FATAL(m_refCount > 0, ("Attempting to destroy a TcpClient while references still exist!"));
|
||||
std::set<TcpClient *>::iterator f = s_tcpClients.find(this);
|
||||
if(f != s_tcpClients.end())
|
||||
s_tcpClients.erase(f);
|
||||
f = s_pendingConnectionSends.find(this);
|
||||
if(f != s_pendingConnectionSends.end())
|
||||
s_pendingConnectionSends.erase(f);
|
||||
|
||||
delete[] m_recvBuffer;
|
||||
if(m_socket != -1)
|
||||
close (m_socket);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::addRef()
|
||||
{
|
||||
m_refCount++;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
std::string const &TcpClient::getRemoteAddress() const
|
||||
{
|
||||
return m_remoteAddress.getHostAddress();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getRemotePort() const
|
||||
{
|
||||
return m_remoteAddress.getHostPort();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setSockOptions()
|
||||
{
|
||||
int optval = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||
ioctl(m_socket, FIONBIO, &optval);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
void TcpClient::commit()
|
||||
{
|
||||
int sent = 0;
|
||||
const unsigned char * ptr = m_pendingSend.getBuffer();
|
||||
const unsigned char * const end = ptr + m_pendingSend.getSize();
|
||||
static Archive::ByteStream s_localScratchBuffer;
|
||||
s_localScratchBuffer.clear();
|
||||
int retries = 0;
|
||||
static const int maxRetries = ConfigSharedNetwork::getMaxTCPRetries();
|
||||
bool sentSomething = false;
|
||||
|
||||
do
|
||||
{
|
||||
// attempt to push pending data to socket
|
||||
sent = ::send (m_socket, ptr, end - ptr, MSG_NOSIGNAL);
|
||||
if(sent == -1)
|
||||
{
|
||||
// failed
|
||||
switch(errno)
|
||||
{
|
||||
// because it would block on a non-blocking socket
|
||||
case EAGAIN:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
case EINTR:
|
||||
{
|
||||
retries++;
|
||||
// requeue
|
||||
break;
|
||||
}
|
||||
// an unhandled error (connection reset, for example)
|
||||
default:
|
||||
{
|
||||
m_pendingSend.clear();
|
||||
perror("send: ");
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::commit send returned -1, errno=%d", errno);
|
||||
onConnectionClosed();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(sent > 0)
|
||||
{
|
||||
sentSomething=true;
|
||||
ptr += sent;
|
||||
if(sent < end - ptr)
|
||||
{
|
||||
// data was passed to the socket, but not all
|
||||
// of it could be committed, keep trying!
|
||||
retries = 0;
|
||||
Os::sleep(1);
|
||||
}
|
||||
}
|
||||
else if(sent == 0)
|
||||
{
|
||||
// tried to send and got nothing through (should have returned an error, but be thorough)
|
||||
retries ++;
|
||||
Os::sleep(1);
|
||||
}
|
||||
|
||||
} while(ptr < end && retries < maxRetries);
|
||||
|
||||
if(ptr == end)
|
||||
{
|
||||
// all data was committed, clear pending buffer
|
||||
m_pendingSend.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// bailed out before all data was committed, save unsent data for
|
||||
// next pass on commit()
|
||||
if (sentSomething)
|
||||
{
|
||||
s_localScratchBuffer.put(ptr, end - ptr);
|
||||
m_pendingSend.clear();
|
||||
m_pendingSend.put(s_localScratchBuffer.getBuffer(), s_localScratchBuffer.getSize());
|
||||
}
|
||||
s_pendingConnectionSends.insert(this);
|
||||
}
|
||||
|
||||
// clean up local accounting
|
||||
s_localScratchBuffer.clear();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flush()
|
||||
{
|
||||
if (m_connected && m_pendingSend.getSize() > 0)
|
||||
{
|
||||
// flush pending buffer
|
||||
commit();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flushPendingWrites()
|
||||
{
|
||||
std::set<TcpClient *> sends = s_pendingConnectionSends;
|
||||
s_pendingConnectionSends.clear();
|
||||
|
||||
for (std::set<TcpClient *>::const_iterator i = sends.begin(); i != sends.end(); ++i)
|
||||
{
|
||||
TcpClient * const c = *i;
|
||||
|
||||
if (c->m_connected)
|
||||
{
|
||||
c->flush();
|
||||
|
||||
if ( c->m_connection
|
||||
&& c->m_pendingSend.getSize()
|
||||
&& ConfigSharedNetwork::getLogSendingTooMuchData()
|
||||
&& !dynamic_cast<NetLogConnection const *>(c->m_connection))
|
||||
{
|
||||
WARNING(true, ("(%s) Failed to commit %d bytes this frame to %s:%d. This process is sending more data than the remote can receive!", c->m_connection->getConnectionDescription().c_str(), c->m_pendingSend.getSize(), c->getRemoteAddress().c_str(), c->getRemotePort()));
|
||||
LOG("Network", ("(%s) Failed to commit %d bytes this frame to %s:%d. This process is sending more data than the remote can receive!", c->m_connection->getConnectionDescription().c_str(), c->m_pendingSend.getSize(), c->getRemoteAddress().c_str(), c->getRemotePort()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
int TcpClient::getSocket() const
|
||||
{
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::install()
|
||||
{
|
||||
FATAL(s_installed, ("TcpClient is already installed!"));
|
||||
s_installed = true;
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionClosed()
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::onConnectionClosed called");
|
||||
m_connected = false;
|
||||
shutdown(m_socket, SHUT_RDWR);
|
||||
if(m_tcpServer)
|
||||
{
|
||||
m_tcpServer->removeClient(this);
|
||||
}
|
||||
close(m_socket);
|
||||
m_socket = -1;
|
||||
if(m_connection)
|
||||
{
|
||||
NetworkHandler::onTerminate(m_connection);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionOpened()
|
||||
{
|
||||
// Get the local port this socket was bound to. If
|
||||
// a client socket repeatedly attempts to connect to a local
|
||||
// service that should be listening on a port that the operating
|
||||
// system may assign AND the service isn't actually running and
|
||||
// using the port, the client socket may connect to itself.
|
||||
// For example, A client connecting to 127.0.0.1:50005, the operating
|
||||
// system may assign the client socket port 50005 and the connection
|
||||
// succeeds, but it is in fact a connection to itself, meaning the
|
||||
// client isn't actually talking to any valid service.
|
||||
struct sockaddr_in bindAddr;
|
||||
socklen_t addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
|
||||
// this *might* be a valid connection to a remote address, but
|
||||
// to easily catch all cases of loopback connections, attempt a
|
||||
// reconnect if the remote port is identical to the local port
|
||||
if(m_remoteAddress.getHostPort() == m_bindPort && ! m_tcpServer)
|
||||
{
|
||||
shutdown(m_socket, SHUT_RDWR);
|
||||
DEBUG_FATAL(m_tcpServer, ("Detected a loopback client connection on a TCP SERVER!!!"));
|
||||
close(m_socket);
|
||||
m_socket = -1;
|
||||
|
||||
// reconnect the socket
|
||||
// address and port info is initialized in the constructor
|
||||
setupSocket();
|
||||
LOG("Network", ("Detected a loopback, closing socket and reconnecting"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_connected = true;
|
||||
if(m_connection)
|
||||
{
|
||||
m_connection->onConnectionOpened();
|
||||
}
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onReceive (const unsigned char * const recvBuf, const int bytes)
|
||||
{
|
||||
if(m_connection)
|
||||
{
|
||||
m_connection->receive(recvBuf, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::queryConnect ()
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = m_socket;
|
||||
pfd.events = POLLOUT;
|
||||
pfd.revents = 0;
|
||||
int pollResult = poll(&pfd, 1, 0);
|
||||
if(pollResult > 0)
|
||||
{
|
||||
if (pfd.revents & POLLERR)
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::queryConnect POLLERR");
|
||||
onConnectionClosed();
|
||||
}
|
||||
else if (pfd.revents & POLLHUP)
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::queryConnect POLLHUP");
|
||||
onConnectionClosed();
|
||||
}
|
||||
else
|
||||
{
|
||||
onConnectionOpened();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::release()
|
||||
{
|
||||
m_refCount--;
|
||||
if(m_refCount == 0)
|
||||
{
|
||||
if (m_connected)
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::release called");
|
||||
onConnectionClosed();
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::remove()
|
||||
{
|
||||
FATAL(!s_installed, ("TcpClient already removed!"));
|
||||
std::set<TcpClient *>::iterator i;
|
||||
for(i = s_tcpClients.begin(); i != s_tcpClients.end(); ++i)
|
||||
{
|
||||
TcpClient * c = (*i);
|
||||
c->release();
|
||||
}
|
||||
s_installed = false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::send(const unsigned char * const buffer, const int bufferLen)
|
||||
{
|
||||
if (bufferLen)
|
||||
{
|
||||
m_lastSendTime = Clock::getFrameStartTimeMs();
|
||||
s_pendingConnectionSends.insert(this);
|
||||
if( !m_rawTCP )
|
||||
Archive::put(m_pendingSend, bufferLen);
|
||||
m_pendingSend.put(buffer, bufferLen);
|
||||
|
||||
static int const tcpMinimumFrame = ConfigSharedNetwork::getTcpMinimumFrame();
|
||||
if (static_cast<int>(m_pendingSend.getSize()) >= tcpMinimumFrame)
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setConnection(Connection * c)
|
||||
{
|
||||
m_connection = c;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::checkKeepalive()
|
||||
{
|
||||
if (m_connected)
|
||||
{
|
||||
unsigned long const timeNow = Clock::getFrameStartTimeMs();
|
||||
if (timeNow-m_lastSendTime > KEEPALIVE_MS)
|
||||
{
|
||||
m_lastSendTime = timeNow;
|
||||
s_pendingConnectionSends.insert(this);
|
||||
Archive::put(m_pendingSend, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::update()
|
||||
{
|
||||
addRef();
|
||||
if(!m_connected)
|
||||
{
|
||||
queryConnect();
|
||||
}
|
||||
|
||||
if(m_connected)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = m_socket;
|
||||
pfd.events = POLLIN|POLLHUP;
|
||||
pfd.revents = 0;
|
||||
int pollResult = poll (&pfd, 1, 0);
|
||||
// POLLERR is mutually exclusive with POLLIN and POLLHUP.
|
||||
// POLLIN and POLLHUP are not consistent cross-platform. Additionally,
|
||||
// a POLLHUP doesn't mean that there's not data available. The best,
|
||||
// cross-platform way to check for disconnection is to see if either
|
||||
// POLLHUP or POLLIN are set, and then read from the socket.
|
||||
// In cases where there's data, we'll just end up checking it next
|
||||
// frame anyway. In cases where there's no data, it means we've
|
||||
// disconnected so we can handle cleanup.
|
||||
if (pollResult)
|
||||
{
|
||||
if (m_recvBuffer == NULL)
|
||||
{
|
||||
m_recvBufferLength = 1500;
|
||||
m_recvBuffer = new unsigned char [m_recvBufferLength];
|
||||
}
|
||||
int bytesReceived = recv(m_socket, m_recvBuffer, m_recvBufferLength, 0);
|
||||
if (bytesReceived > 0)
|
||||
{
|
||||
onReceive(m_recvBuffer, bytesReceived);
|
||||
}
|
||||
else if (bytesReceived == -1)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
break;
|
||||
default:
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::update recv returned -1, errno=%d", errno);
|
||||
onConnectionClosed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (bytesReceived == 0)
|
||||
{
|
||||
// peer closed connection
|
||||
|
||||
|
||||
|
||||
if (m_connection)
|
||||
{
|
||||
// Log this, as it's a pretty deep change.
|
||||
LOG("Network", ("(%s) Read zero bytes on a successful poll (POLLIN|POLLHUP). Closing socket since we think it is closed.", m_connection->getConnectionDescription().c_str()));
|
||||
m_connection->setDisconnectReason("TcpClient::update recv returned 0");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Network", ("(null connection object) Read zero bytes on a successful poll (POLLIN|POLLHUP). Closing socket since we think it is closed."));
|
||||
}
|
||||
onConnectionClosed();
|
||||
}
|
||||
|
||||
if (bytesReceived == m_recvBufferLength)
|
||||
{
|
||||
// grow the buffer
|
||||
delete [] m_recvBuffer;
|
||||
m_recvBufferLength = m_recvBufferLength * 2;
|
||||
m_recvBuffer = new unsigned char [m_recvBufferLength];
|
||||
}
|
||||
}
|
||||
}
|
||||
release();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setupSocket()
|
||||
{
|
||||
FATAL(! s_installed, ("TcpClient is not installed!"));
|
||||
|
||||
protoent * p = getprotobyname ("tcp");
|
||||
const int entry = p->p_proto;
|
||||
m_socket = socket (AF_INET, SOCK_STREAM, entry);
|
||||
if (m_socket != -1)
|
||||
{
|
||||
setSockOptions();
|
||||
|
||||
int nameLen = sizeof (struct sockaddr_in);
|
||||
int result;
|
||||
result = connect (m_socket, reinterpret_cast<const struct sockaddr *> (&m_remoteAddress.getSockAddr4 () ), nameLen);
|
||||
if(result == -1)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINPROGRESS:
|
||||
case EALREADY:
|
||||
break;
|
||||
default:
|
||||
perror("connect ");
|
||||
if (m_connection)
|
||||
m_connection->setDisconnectReason("TcpClient::TcpClient connect returned -1, errno=%d", errno);
|
||||
onConnectionClosed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in bindAddr;
|
||||
socklen_t addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
void TcpClient::setRawTCP( bool bNewValue )
|
||||
{
|
||||
m_rawTCP = bNewValue;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::clearTcpServer()
|
||||
{
|
||||
m_tcpServer = 0;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// TcpClient.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpClient_H
|
||||
#define _INCLUDED_TcpClient_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "Archive/ByteStream.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include <string>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Connection;
|
||||
class TcpServer;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpClient
|
||||
{
|
||||
public:
|
||||
TcpClient(int sock, TcpServer *);
|
||||
TcpClient(const std::string & address, const unsigned short port);
|
||||
|
||||
void addRef();
|
||||
static void install();
|
||||
void release();
|
||||
static void remove();
|
||||
void send(const unsigned char * const buffer, const int length);
|
||||
|
||||
unsigned short getBindPort() const;
|
||||
std::string const &getRemoteAddress() const;
|
||||
unsigned short getRemotePort() const;
|
||||
void setPendingSendAllocatedSizeLimit(unsigned int limit);
|
||||
|
||||
// only used by clients
|
||||
void update();
|
||||
static void flushPendingWrites();
|
||||
|
||||
protected:
|
||||
friend class TcpServer;
|
||||
friend class Connection;
|
||||
|
||||
void setSockOptions();
|
||||
void commit();
|
||||
int getSocket() const;
|
||||
void onConnectionClosed();
|
||||
void onConnectionOpened();
|
||||
void onReceive(const unsigned char * const recvBuf, const int bytes);
|
||||
void queryConnect();
|
||||
void queueReceive();
|
||||
void setConnection(Connection *);
|
||||
void checkKeepalive();
|
||||
void clearTcpServer();
|
||||
void setRawTCP( bool bNewValue );
|
||||
|
||||
private:
|
||||
TcpClient & operator = (const TcpClient & rhs);
|
||||
TcpClient(const TcpClient & source);
|
||||
~TcpClient();
|
||||
void flush ();
|
||||
void setupSocket();
|
||||
int m_socket;
|
||||
TcpServer * m_tcpServer;
|
||||
Archive::ByteStream m_pendingSend;
|
||||
Connection * m_connection;
|
||||
unsigned char * m_recvBuffer;
|
||||
int m_recvBufferLength;
|
||||
Address m_remoteAddress;
|
||||
int m_refCount;
|
||||
bool m_connected;
|
||||
unsigned long m_lastSendTime;
|
||||
unsigned short m_bindPort;
|
||||
bool m_rawTCP;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline void TcpClient::setPendingSendAllocatedSizeLimit(const unsigned int limit)
|
||||
{
|
||||
m_pendingSend.setAllocatedSizeLimit(limit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpClient_H
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// TcpServer.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "TcpClient.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <vector>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpServer::TcpServer(Service * service, const std::string & a, const unsigned short port) :
|
||||
m_bindAddress(a, port),
|
||||
m_handle(-1),
|
||||
m_service(service),
|
||||
m_connections(),
|
||||
m_connectionSockets(),
|
||||
m_inputBuffer(0),
|
||||
m_inputBufferSize(0)
|
||||
{
|
||||
protoent * p = getprotobyname("tcp");
|
||||
if(p)
|
||||
{
|
||||
int entry = p->p_proto;
|
||||
m_handle = socket(AF_INET, SOCK_STREAM, entry);
|
||||
FATAL(m_handle == -1, ("Failed to create a server socket %s:%d", a.c_str(), port));
|
||||
int optval = 1;
|
||||
if(m_handle != -1)
|
||||
{
|
||||
int optResult = setsockopt(m_handle, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
FATAL(optResult == -1, ("Failed to set socket option SO_REUSEADDR"));
|
||||
unsigned long nb = 1;
|
||||
int ctlResult = ioctl(m_handle, FIONBIO, &nb);
|
||||
FATAL(ctlResult == -1, ("Failed to set socket non-blocking"));
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
int bindResult = bind(m_handle, (struct sockaddr *)(&m_bindAddress.getSockAddr4()), addrlen);
|
||||
FATAL(bindResult != 0, ("Failed to bind to port %d", port));
|
||||
if(bindResult == 0)
|
||||
{
|
||||
int result = listen(m_handle, 256);
|
||||
if(result == -1)
|
||||
perror("listen ");
|
||||
FATAL(result == -1, ("Failed to start listening on port %d", port));
|
||||
struct sockaddr_in b;
|
||||
getsockname(m_handle, (struct sockaddr *)(&b), &addrlen);
|
||||
m_bindAddress = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
TcpServer::~TcpServer()
|
||||
{
|
||||
close(m_handle);
|
||||
for (std::map<int, TcpClient *>::const_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
||||
(*i).second->clearTcpServer();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const std::string & TcpServer::getBindAddress() const
|
||||
{
|
||||
return m_bindAddress.getHostAddress();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned short TcpServer::getBindPort() const
|
||||
{
|
||||
return m_bindAddress.getHostPort();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpServer::onConnectionClosed(TcpClient * c)
|
||||
{
|
||||
if(c)
|
||||
{
|
||||
std::set<TcpClient *>::iterator f = m_pendingDestroys.find(c);
|
||||
if(f == m_pendingDestroys.end())
|
||||
{
|
||||
m_pendingDestroys.insert(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
void TcpServer::removeClient(TcpClient * c)
|
||||
{
|
||||
std::map<int, TcpClient *>::iterator f = m_connections.find(c->getSocket());
|
||||
if(f != m_connections.end())
|
||||
{
|
||||
// c->release();
|
||||
m_connections.erase(f);
|
||||
}
|
||||
|
||||
std::vector<pollfd>::iterator s;
|
||||
for(s = m_connectionSockets.begin(); s != m_connectionSockets.end(); ++s)
|
||||
{
|
||||
if((*s).fd == c->getSocket())
|
||||
{
|
||||
m_connectionSockets.erase(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpServer::update()
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = m_handle;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
|
||||
int result = poll(&pfd, 1, 0);
|
||||
if(result > 0)
|
||||
{
|
||||
// connection established
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(struct sockaddr_in);
|
||||
int newSock = accept(m_handle, (struct sockaddr *)(&addr), &len);
|
||||
if(newSock != -1)
|
||||
{
|
||||
TcpClient * ptc = new TcpClient(newSock, this);
|
||||
ptc->addRef();
|
||||
m_connections.insert(std::make_pair(newSock, ptc));
|
||||
struct pollfd readFd;
|
||||
readFd.fd = ptc->getSocket();
|
||||
readFd.events = POLLIN|POLLERR|POLLHUP;
|
||||
readFd.revents = 0;
|
||||
m_connectionSockets.push_back(readFd);
|
||||
ptc->onConnectionOpened();
|
||||
if(m_service)
|
||||
m_service->onConnectionOpened(ptc);
|
||||
ptc->release();
|
||||
}
|
||||
}
|
||||
|
||||
struct pollfd * clients = &m_connectionSockets[0];
|
||||
|
||||
int readResult = poll (clients, m_connectionSockets.size (), 0);
|
||||
if (readResult > 0)
|
||||
{
|
||||
std::vector<struct pollfd>::iterator i;
|
||||
std::vector<struct pollfd> cs = m_connectionSockets;
|
||||
for (i = cs.begin (); i != cs.end (); ++i)
|
||||
{
|
||||
if ((*i).revents & POLLERR)
|
||||
{
|
||||
std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd );
|
||||
if (f != m_connections.end ())
|
||||
{
|
||||
TcpClient * c = (*f).second;
|
||||
if (c->m_connection)
|
||||
c->m_connection->setDisconnectReason("TcpServer::update POLLERR");
|
||||
c->onConnectionClosed();
|
||||
}
|
||||
}
|
||||
// POLLERR is mutually exclusive with POLLIN and POLLHUP.
|
||||
// POLLIN and POLLHUP are not consistent cross-platform. Additionally,
|
||||
// a POLLHUP doesn't mean that there's not data available. The best,
|
||||
// cross-platform way to check for disconnection is to see if either
|
||||
// POLLHUP or POLLIN are set, and then read from the socket.
|
||||
// In cases where there's data, we'll just end up checking it next
|
||||
// frame anyway. In cases where there's no data, it means we've
|
||||
// disconnected so we can handle cleanup.
|
||||
else if( (*i).revents & (POLLIN|POLLHUP) )
|
||||
{
|
||||
|
||||
if (m_inputBuffer == 0)
|
||||
{
|
||||
m_inputBuffer = new unsigned char[1500];
|
||||
m_inputBufferSize = 1500;
|
||||
}
|
||||
int bytesReceived = recv ( (*i).fd, m_inputBuffer, m_inputBufferSize, 0);
|
||||
std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd );
|
||||
if (f != m_connections.end ())
|
||||
{
|
||||
TcpClient * c = (*f).second;
|
||||
std::set<TcpClient *>::iterator pd = m_pendingDestroys.find(c);
|
||||
if(pd == m_pendingDestroys.end())
|
||||
{
|
||||
c->addRef();
|
||||
if(bytesReceived > 0)
|
||||
{
|
||||
c->onReceive(m_inputBuffer, bytesReceived);
|
||||
}
|
||||
else if (bytesReceived == -1)
|
||||
{
|
||||
if (c->m_connection)
|
||||
c->m_connection->setDisconnectReason("TcpServer::update recv returned %d, errno=%d", bytesReceived, errno);
|
||||
c->onConnectionClosed();
|
||||
}
|
||||
else if (bytesReceived == 0)
|
||||
{
|
||||
// 0 bytes received on a read is the guaranteed signal for a
|
||||
// closed connection.
|
||||
if (c->m_connection)
|
||||
c->m_connection->setDisconnectReason("TcpServer::update recv returned no bytes, singaling a closed socket (bytes=%d, errno=%d", bytesReceived, errno);
|
||||
c->onConnectionClosed();
|
||||
}
|
||||
c->release();
|
||||
}
|
||||
}
|
||||
if (bytesReceived == m_inputBufferSize)
|
||||
{
|
||||
delete [] m_inputBuffer;
|
||||
m_inputBufferSize = m_inputBufferSize * 2;
|
||||
m_inputBuffer = new unsigned char [m_inputBufferSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
std::set<TcpClient *>::iterator pdIter;
|
||||
for(pdIter = m_pendingDestroys.begin(); pdIter != m_pendingDestroys.end(); ++pdIter)
|
||||
{
|
||||
removeClient((*pdIter));
|
||||
}
|
||||
m_pendingDestroys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// TcpServer.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpServer_H
|
||||
#define _INCLUDED_TcpServer_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "Address.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Service;
|
||||
class TcpClient;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpServer
|
||||
{
|
||||
public:
|
||||
TcpServer(Service * service, const std::string & bindAddress, const unsigned short bindPort);
|
||||
~TcpServer();
|
||||
|
||||
const std::string & getBindAddress () const;
|
||||
const unsigned short getBindPort () const;
|
||||
void onConnectionClosed (TcpClient *);
|
||||
void removeClient (TcpClient *);
|
||||
void update ();
|
||||
|
||||
private:
|
||||
TcpServer & operator = (const TcpServer & rhs);
|
||||
TcpServer(const TcpServer & source);
|
||||
|
||||
private:
|
||||
Address m_bindAddress;
|
||||
int m_handle;
|
||||
Service * m_service;
|
||||
std::map<int, TcpClient *> m_connections;
|
||||
std::vector<struct pollfd> m_connectionSockets;
|
||||
unsigned char * m_inputBuffer;
|
||||
int m_inputBufferSize;
|
||||
std::set<TcpClient *> m_pendingDestroys;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpServer_H
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "FirstSharedNetwork.h"
|
||||
#include <cassert>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include "sharedNetwork/UdpSock.h"
|
||||
|
||||
const int INVALID_SOCKET = 0xFFFFFFFF;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
UdpSock::UdpSock() :
|
||||
Sock()
|
||||
{
|
||||
handle = socket(AF_INET, SOCK_DGRAM, 17);
|
||||
assert(handle != INVALID_SOCKET);
|
||||
setNonBlocking();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
UdpSock::~UdpSock()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned int UdpSock::recvFrom(Address & outAddr, void * targetBuffer, const unsigned int bufferSize) const
|
||||
{
|
||||
socklen_t fromLen = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in addr;
|
||||
unsigned int result = ::recvfrom(handle, static_cast<char *>(targetBuffer), static_cast<int>(bufferSize), 0, reinterpret_cast<struct sockaddr *>(&addr), &fromLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
outAddr = addr;
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
const unsigned int UdpSock::sendTo(const Address & targetAddress, const void * sourceBuffer, const unsigned int length) const
|
||||
{
|
||||
unsigned int bytesSent = 0;
|
||||
if(canSend())
|
||||
{
|
||||
socklen_t toLen = sizeof(struct sockaddr_in);
|
||||
bytesSent = ::sendto(handle, sourceBuffer, static_cast<const int>(length), 0, reinterpret_cast<const struct sockaddr *>(&(targetAddress.getSockAddr4())), toLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
}
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void UdpSock::enableBroadcast()
|
||||
{
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(int);
|
||||
setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &optval, optlen);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// Address.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_Address_H
|
||||
#define INCLUDED_Address_H
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@brief An IPv4 network address
|
||||
|
||||
Address provides an interface for working
|
||||
with IPv4 addresses. It contains a resolved host name string and a
|
||||
BSD sockaddr. It also handles name to address resolution.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
public:
|
||||
Address();
|
||||
Address(const std::string & dottedDecimalIPv4Address, unsigned short hostPort);
|
||||
Address(const Address & source);
|
||||
Address(const struct sockaddr_in & ipv4sockaddr);
|
||||
~Address();
|
||||
Address & operator=(const Address & rhs);
|
||||
Address & operator=(const struct sockaddr_in & rhs);
|
||||
const bool operator<(const Address & rhs) const;
|
||||
const bool operator==(const Address & rhs) const;
|
||||
const bool operator!=(const Address & rhs) const;
|
||||
const bool operator>(const Address & rhs) const;
|
||||
const std::string & getHostAddress() const;
|
||||
const unsigned short getHostPort() const;
|
||||
size_t hashFunction() const;
|
||||
const struct sockaddr_in & getSockAddr4() const;
|
||||
|
||||
/**
|
||||
@brief Determine equality between to address for the STL hash_map
|
||||
@author Justin Randall
|
||||
*/
|
||||
struct EqualFunction
|
||||
{
|
||||
bool operator() (const Address & lhs, const Address & rhs) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@brief STL hash_map suport function -- returns the s_addr member of
|
||||
the BSD sockaddr struct
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
struct HashFunction
|
||||
{
|
||||
size_t operator() (const Address & a) const;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
void convertFromSockAddr(const struct sockaddr_in & source);
|
||||
private:
|
||||
struct sockaddr_in * addr4;
|
||||
std::string hostAddress;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\include TestAddress.h
|
||||
\example TestAddress.cpp
|
||||
*/
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#endif // _NetworkAddress_H
|
||||
@@ -0,0 +1,74 @@
|
||||
// BroadcastSock.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/BroadcastSock.h"
|
||||
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/UdpSock.h"
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a default broadcast sock
|
||||
|
||||
This constructor invokes the UdpSock default constructor, then
|
||||
sets the SO_BROADCAST option on the resulting UdpSock object.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
BroadcastSock::BroadcastSock() :
|
||||
udp(new UdpSock)
|
||||
{
|
||||
udp->enableBroadcast();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const bool BroadcastSock::bind(const unsigned short port)
|
||||
{
|
||||
return udp->bind(Address("", port));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const bool BroadcastSock::canRecv() const
|
||||
{
|
||||
return udp->canRecv();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned int BroadcastSock::recvFrom(Address & a, void * targetBuffer, const unsigned int targetBufferSize) const
|
||||
{
|
||||
unsigned int result = 0;
|
||||
if(udp)
|
||||
{
|
||||
result = udp->recvFrom(a, targetBuffer, targetBufferSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned int BroadcastSock::sendTo(const std::string & a, const unsigned short p, const void * b, const unsigned int l) const
|
||||
{
|
||||
return udp->sendTo(Address(a, p), b, l);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the BroadcastSock. doesn't do anything special.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
BroadcastSock::~BroadcastSock()
|
||||
{
|
||||
delete udp;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// BroadcastSock.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_BroadcastSock_H
|
||||
#define INCLUDED_BroadcastSock_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
|
||||
class Address;
|
||||
class UdpSock;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Extends UdpSock to receive broadcast messages.
|
||||
|
||||
A BroadcastSock will receive messages sent to
|
||||
the broadcast address, which is usually 255.255.255.255.
|
||||
|
||||
BroadcastSock objects cannot listen for traffic on
|
||||
the loopback interface.
|
||||
|
||||
Example:
|
||||
\code
|
||||
BroadcastSock b;
|
||||
UdpSock c;
|
||||
b.bind("", 45555);
|
||||
c.bind();
|
||||
|
||||
std::string s("Hi!");
|
||||
c.sendTo(Address("255.255.255.255", 45555), s.c_str(), s.length());
|
||||
unsigned char r[10] = {"\\0"};
|
||||
b.recv(r, 10); // r should contain Hi!
|
||||
\endcode
|
||||
|
||||
@see UdpSock
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class BroadcastSock
|
||||
{
|
||||
public:
|
||||
BroadcastSock();
|
||||
virtual ~BroadcastSock();
|
||||
const bool bind(const unsigned short port);
|
||||
const unsigned int sendTo(const std::string & address, const unsigned short port, const void * sourceBuffer, const unsigned int sourceBufferLength) const;
|
||||
const bool canRecv() const;
|
||||
const unsigned int recvFrom(Address & outAddress, void * targetBuffer, const unsigned int targetBufferSize) const;
|
||||
|
||||
private:
|
||||
BroadcastSock(const BroadcastSock & source);
|
||||
BroadcastSock & operator = (const BroadcastSock & rhs);
|
||||
|
||||
private:
|
||||
UdpSock * udp;
|
||||
};
|
||||
|
||||
/**
|
||||
\include TestBroadcastSock.h
|
||||
\example TestBroadcastSock.cpp
|
||||
*/
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#endif // _BroadcastSock_H
|
||||
@@ -0,0 +1,594 @@
|
||||
// ConfigSharedNetwork.cpp
|
||||
// Copyright 2000-2003, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace ConfigSharedNetworkNamespace
|
||||
{
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void remove();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
bool s_installed;
|
||||
|
||||
int crcBytes;
|
||||
int hashTableSize;
|
||||
int incomingBufferSize;
|
||||
int outgoingBufferSize;
|
||||
int clockSyncDelay;
|
||||
int maxConnections;
|
||||
int maxRawPacketSize;
|
||||
int maxInstandingPackets;
|
||||
int maxOutstandingBytes;
|
||||
int maxOutstandingPackets;
|
||||
bool processIcmpErrors;
|
||||
bool processOnSend;
|
||||
int fragmentSize;
|
||||
int pooledPacketMax;
|
||||
int pooledPacketSize;
|
||||
int packetHistoryMax;
|
||||
bool logAllNetworkTraffic;
|
||||
int oldestUnacknowledgedTimeout;
|
||||
int overflowLimit;
|
||||
int reportStatisticsInterval;
|
||||
int packetSizeWarnThreshold;
|
||||
int packetCountWarnThreshold;
|
||||
int byteCountWarnThreshold;
|
||||
bool reportMessages;
|
||||
int congestionWindowMinimum;
|
||||
int stallReportDelay;
|
||||
bool enableFlushAndConfirmAllData;
|
||||
bool fatalOnConnectionClosed;
|
||||
int logBackloggedPacketThreshold;
|
||||
bool useNetworkThread;
|
||||
int networkThreadSleepTimeMs;
|
||||
int keepAliveDelay;
|
||||
int pooledPacketInitial;
|
||||
int maxDataHoldTime;
|
||||
int resendDelayAdjust;
|
||||
int resendDelayPercent;
|
||||
int networkThreadPriority;
|
||||
int noDataTimeout;
|
||||
int reliableOverflowBytes;
|
||||
int icmpErrorRetryPeriod;
|
||||
int maxDataHoldSize;
|
||||
bool allowPortRemapping;
|
||||
bool useTcp;
|
||||
int tcpMinimumFrame;
|
||||
bool reportUdpDisconnects;
|
||||
bool reportTcpDisconnects;
|
||||
bool logConnectionConstructionDestruction;
|
||||
bool logConnectionDeferredMessagesWarning;
|
||||
bool logConnectionOpenedClosed;
|
||||
int logConnectionDeferredMessagesWarningInterval;
|
||||
|
||||
typedef unsigned short ReservedPortInt;
|
||||
typedef std::set<ReservedPortInt> ReservedPortSet;
|
||||
ReservedPortSet reservedPorts;
|
||||
|
||||
bool networkHandlerDispatchThrottle;
|
||||
int networkHandlerDispatchThrottleTimeMilliseconds;
|
||||
int networkHandlerDispatchQueueSize;
|
||||
int maxTCPRetries;
|
||||
|
||||
bool logSendingTooMuchData;
|
||||
}
|
||||
|
||||
using namespace ConfigSharedNetworkNamespace;
|
||||
|
||||
#define KEY_INT(a,b) (a = ConfigFile::getKeyInt("SharedNetwork", #a, b))
|
||||
#define KEY_BOOL(a,b) (a = ConfigFile::getKeyBool("SharedNetwork", #a, b))
|
||||
#define KEY_REAL(a,b) (a = ConfigFile::getKeyReal("SharedNetwork", #a, b))
|
||||
#define KEY_STRING(a,b) (a = ConfigFile::getKeyString("SharedNetwork", #a, b))
|
||||
|
||||
// ======================================================================
|
||||
// namespace ConfigSharedNetworkNamespace
|
||||
// ======================================================================
|
||||
|
||||
void ConfigSharedNetworkNamespace::remove()
|
||||
{
|
||||
DEBUG_FATAL(!s_installed, ("ConfigSharedNetwork not installed."));
|
||||
s_installed = false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// class ConfigSharedNetwork
|
||||
// ======================================================================
|
||||
|
||||
int ConfigSharedNetwork::getLogBackloggedPacketThreshold()
|
||||
{
|
||||
return logBackloggedPacketThreshold;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getResendDelayAdjust()
|
||||
{
|
||||
return resendDelayAdjust;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getResendDelayPercent()
|
||||
{
|
||||
return resendDelayPercent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxDataHoldTime()
|
||||
{
|
||||
return maxDataHoldTime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getFatalOnConnectionClosed()
|
||||
{
|
||||
return fatalOnConnectionClosed;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getKeepAliveDelay()
|
||||
{
|
||||
return keepAliveDelay;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getStallReportDelay()
|
||||
{
|
||||
return stallReportDelay;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getCongestionWindowMinimum()
|
||||
{
|
||||
return congestionWindowMinimum;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getEnableFlushAndConfirmAllData()
|
||||
{
|
||||
return enableFlushAndConfirmAllData;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getPooledPacketInitial()
|
||||
{
|
||||
return pooledPacketInitial;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getCrcBytes()
|
||||
{
|
||||
return crcBytes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getHashTableSize()
|
||||
{
|
||||
return hashTableSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getIncomingBufferSize()
|
||||
{
|
||||
return incomingBufferSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getOutgoingBufferSize()
|
||||
{
|
||||
return outgoingBufferSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getClockSyncDelay()
|
||||
{
|
||||
//-- We must have this value properly initialized.
|
||||
DEBUG_FATAL(!s_installed, ("ConfigSharedNetwork not installed."));
|
||||
return clockSyncDelay;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxConnections()
|
||||
{
|
||||
return maxConnections;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxRawPacketSize()
|
||||
{
|
||||
return maxRawPacketSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxInstandingPackets()
|
||||
{
|
||||
return maxInstandingPackets;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxOutstandingBytes()
|
||||
{
|
||||
return maxOutstandingBytes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxOutstandingPackets()
|
||||
{
|
||||
return maxOutstandingPackets;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getProcessOnSend()
|
||||
{
|
||||
return processOnSend;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getProcessIcmpErrors()
|
||||
{
|
||||
return processIcmpErrors;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getFragmentSize()
|
||||
{
|
||||
return fragmentSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getOverflowLimit()
|
||||
{
|
||||
return overflowLimit;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getPooledPacketMax()
|
||||
{
|
||||
return pooledPacketMax;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getPooledPacketSize()
|
||||
{
|
||||
return pooledPacketSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getPacketHistoryMax()
|
||||
{
|
||||
return packetHistoryMax;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getLogAllNetworkTraffic()
|
||||
{
|
||||
return logAllNetworkTraffic;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getOldestUnacknowledgedTimeout()
|
||||
{
|
||||
return oldestUnacknowledgedTimeout;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getReportStatisticsInterval()
|
||||
{
|
||||
return reportStatisticsInterval;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getPacketSizeWarnThreshold()
|
||||
{
|
||||
return packetSizeWarnThreshold;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getPacketCountWarnThreshold()
|
||||
{
|
||||
return packetCountWarnThreshold;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getReportMessages()
|
||||
{
|
||||
return reportMessages;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getByteCountWarnThreshold()
|
||||
{
|
||||
return byteCountWarnThreshold;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getUseNetworkThread()
|
||||
{
|
||||
if (useNetworkThread && useTcp)
|
||||
{
|
||||
WARNING(true, ("useNetworkThread is unsupported when useTcp is enabled. useNetworkThread has been disabled."));
|
||||
useNetworkThread = false;
|
||||
}
|
||||
return useNetworkThread;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getNetworkThreadSleepTimeMs()
|
||||
{
|
||||
return networkThreadSleepTimeMs;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getNetworkThreadPriority()
|
||||
{
|
||||
return networkThreadPriority;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getNoDataTimeout()
|
||||
{
|
||||
return noDataTimeout;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getReliableOverflowBytes()
|
||||
{
|
||||
return reliableOverflowBytes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getIcmpErrorRetryPeriod()
|
||||
{
|
||||
return icmpErrorRetryPeriod;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxDataHoldSize()
|
||||
{
|
||||
return maxDataHoldSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getAllowPortRemapping()
|
||||
{
|
||||
return allowPortRemapping;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getUseTcp()
|
||||
{
|
||||
return useTcp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getTcpMinimumFrame()
|
||||
{
|
||||
return tcpMinimumFrame;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getReportUdpDisconnects()
|
||||
{
|
||||
return reportUdpDisconnects;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getReportTcpDisconnects()
|
||||
{
|
||||
return reportTcpDisconnects;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getLogConnectionConstructionDestruction()
|
||||
{
|
||||
return logConnectionConstructionDestruction;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getLogConnectionOpenedClosed()
|
||||
{
|
||||
return logConnectionOpenedClosed;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getLogConnectionDeferredMessagesWarning()
|
||||
{
|
||||
return logConnectionDeferredMessagesWarning;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getLogConnectionDeferredMessagesWarningInterval()
|
||||
{
|
||||
return logConnectionDeferredMessagesWarningInterval;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getMaxTCPRetries()
|
||||
{
|
||||
return maxTCPRetries;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getIsPortReserved(unsigned short p)
|
||||
{
|
||||
ReservedPortSet::const_iterator f = reservedPorts.find(p);
|
||||
return (f != reservedPorts.end());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getNetworkHandlerDispatchThrottle()
|
||||
{
|
||||
return networkHandlerDispatchThrottle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getNetworkHandlerDispatchThrottleTimeMilliseconds()
|
||||
{
|
||||
return networkHandlerDispatchThrottleTimeMilliseconds;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int ConfigSharedNetwork::getNetworkHandlerDispatchQueueSize()
|
||||
{
|
||||
return networkHandlerDispatchQueueSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool ConfigSharedNetwork::getLogSendingTooMuchData()
|
||||
{
|
||||
return logSendingTooMuchData;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void ConfigSharedNetwork::install(int newClockSyncDelay)
|
||||
{
|
||||
DEBUG_FATAL(s_installed, ("ConfigSharedNetwork already installed."));
|
||||
|
||||
KEY_BOOL (logAllNetworkTraffic, false);
|
||||
KEY_INT (crcBytes, 2);
|
||||
KEY_INT (hashTableSize, 100);
|
||||
KEY_INT (incomingBufferSize, 4 * 1024 * 1024);
|
||||
KEY_INT (outgoingBufferSize, 4 * 1024 * 1024);
|
||||
KEY_INT (maxConnections, 1000);
|
||||
KEY_INT (maxRawPacketSize, 496);
|
||||
KEY_INT (maxInstandingPackets, 400);
|
||||
KEY_INT (maxOutstandingBytes, 200 * 1024);
|
||||
KEY_INT (maxOutstandingPackets, 400);
|
||||
KEY_BOOL (processOnSend, false);
|
||||
KEY_BOOL (processIcmpErrors, true);
|
||||
KEY_INT (fragmentSize, 496);
|
||||
KEY_INT (pooledPacketMax, 1024);
|
||||
KEY_INT (pooledPacketSize, -1);
|
||||
KEY_INT (packetHistoryMax, 100);
|
||||
KEY_INT (oldestUnacknowledgedTimeout, 90000);
|
||||
KEY_INT (overflowLimit, 0);
|
||||
KEY_INT (reportStatisticsInterval, 60000);
|
||||
KEY_INT (packetSizeWarnThreshold, 0);
|
||||
KEY_INT (packetCountWarnThreshold, 0);
|
||||
KEY_INT (byteCountWarnThreshold, 0);
|
||||
KEY_BOOL (reportMessages, false);
|
||||
KEY_INT (congestionWindowMinimum, 0);
|
||||
KEY_INT (stallReportDelay, 30000);
|
||||
KEY_BOOL (enableFlushAndConfirmAllData, true);
|
||||
KEY_BOOL (fatalOnConnectionClosed, false);
|
||||
KEY_INT (logBackloggedPacketThreshold, 65000);
|
||||
KEY_BOOL (useNetworkThread, false);
|
||||
KEY_INT (networkThreadSleepTimeMs, 20);
|
||||
KEY_INT (keepAliveDelay, 15000);
|
||||
KEY_INT (pooledPacketInitial, 1024);
|
||||
KEY_INT (maxDataHoldTime, 50);
|
||||
KEY_INT (resendDelayAdjust, 500);
|
||||
KEY_INT (resendDelayPercent, 125);
|
||||
KEY_INT (networkThreadPriority, 3);
|
||||
KEY_INT (noDataTimeout, 46000);
|
||||
KEY_INT (reliableOverflowBytes, 2 * 1024 * 1024);
|
||||
KEY_INT (icmpErrorRetryPeriod, 2000);
|
||||
KEY_INT (maxDataHoldSize, -1);
|
||||
KEY_BOOL (allowPortRemapping, true);
|
||||
KEY_BOOL (useTcp, true);
|
||||
KEY_INT (tcpMinimumFrame, 1000);
|
||||
KEY_BOOL (reportUdpDisconnects, false);
|
||||
KEY_BOOL (reportTcpDisconnects, true);
|
||||
KEY_BOOL (logConnectionConstructionDestruction, false);
|
||||
KEY_BOOL (logConnectionOpenedClosed, false);
|
||||
KEY_BOOL (logConnectionDeferredMessagesWarning, false);
|
||||
KEY_INT (logConnectionDeferredMessagesWarningInterval, 1000);
|
||||
KEY_INT (maxTCPRetries,1);
|
||||
KEY_BOOL (logSendingTooMuchData, true);
|
||||
{
|
||||
int i = 0;
|
||||
int p;
|
||||
do
|
||||
{
|
||||
p = ConfigFile::getKeyInt("SharedNetwork", "reservedPort", i, 0);
|
||||
if(p)
|
||||
{
|
||||
reservedPorts.insert(static_cast<ConfigSharedNetworkNamespace::ReservedPortInt>(p));
|
||||
++i;
|
||||
}
|
||||
} while(p > 0);
|
||||
}
|
||||
|
||||
KEY_BOOL (networkHandlerDispatchThrottle, false);
|
||||
KEY_INT (networkHandlerDispatchThrottleTimeMilliseconds, 100);
|
||||
KEY_INT (networkHandlerDispatchQueueSize, 1024);
|
||||
|
||||
//-- Do not let a config file override this setting.
|
||||
// It is critical that it be set properly in all client
|
||||
// and server apps.
|
||||
//KEY_INT (clockSyncDelay, 0);
|
||||
clockSyncDelay = newClockSyncDelay;
|
||||
|
||||
s_installed = true;
|
||||
ExitChain::add(remove, "ConfigSharedNetwork");
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,75 @@
|
||||
// ConfigSharedNetwork.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_ConfigSharedNetwork_H
|
||||
#define _INCLUDED_ConfigSharedNetwork_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class ConfigSharedNetwork
|
||||
{
|
||||
public:
|
||||
static void install (int clockSyncDelay);
|
||||
|
||||
static int getCrcBytes();
|
||||
static int getHashTableSize();
|
||||
static int getIncomingBufferSize();
|
||||
static int getOutgoingBufferSize();
|
||||
static int getClockSyncDelay();
|
||||
static int getMaxConnections();
|
||||
static int getMaxRawPacketSize();
|
||||
static int getMaxInstandingPackets();
|
||||
static int getMaxOutstandingBytes();
|
||||
static int getMaxOutstandingPackets();
|
||||
static int getPacketHistoryMax();
|
||||
static bool getProcessIcmpErrors();
|
||||
static bool getProcessOnSend();
|
||||
static int getFragmentSize();
|
||||
static int getPooledPacketMax();
|
||||
static int getPooledPacketSize();
|
||||
static int getOldestUnacknowledgedTimeout();
|
||||
static int getOverflowLimit();
|
||||
static int getReportStatisticsInterval();
|
||||
static int getPacketSizeWarnThreshold();
|
||||
static int getPacketCountWarnThreshold();
|
||||
static int getByteCountWarnThreshold();
|
||||
static bool getReportMessages();
|
||||
static int getCongestionWindowMinimum();
|
||||
static int getStallReportDelay();
|
||||
static bool getEnableFlushAndConfirmAllData();
|
||||
static bool getFatalOnConnectionClosed();
|
||||
static int getLogBackloggedPacketThreshold();
|
||||
static bool getLogAllNetworkTraffic();
|
||||
static bool getUseNetworkThread();
|
||||
static int getNetworkThreadSleepTimeMs();
|
||||
static int getKeepAliveDelay();
|
||||
static int getPooledPacketInitial();
|
||||
static int getMaxDataHoldTime();
|
||||
static int getResendDelayAdjust();
|
||||
static int getResendDelayPercent();
|
||||
static int getNetworkThreadPriority();
|
||||
static int getNoDataTimeout();
|
||||
static int getReliableOverflowBytes();
|
||||
static int getIcmpErrorRetryPeriod();
|
||||
static int getMaxDataHoldSize();
|
||||
static bool getAllowPortRemapping();
|
||||
static bool getUseTcp();
|
||||
static int getTcpMinimumFrame();
|
||||
static bool getReportUdpDisconnects();
|
||||
static bool getReportTcpDisconnects();
|
||||
static bool getLogConnectionConstructionDestruction();
|
||||
static bool getLogConnectionOpenedClosed();
|
||||
static bool getLogConnectionDeferredMessagesWarning();
|
||||
static int getLogConnectionDeferredMessagesWarningInterval();
|
||||
static bool getIsPortReserved(unsigned short p);
|
||||
static bool getNetworkHandlerDispatchThrottle();
|
||||
static int getNetworkHandlerDispatchThrottleTimeMilliseconds();
|
||||
static int getNetworkHandlerDispatchQueueSize();
|
||||
static int getMaxTCPRetries();
|
||||
static bool getLogSendingTooMuchData();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_ConfigSharedNetwork_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,144 @@
|
||||
// Connection.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_Connection_H
|
||||
#define INCLUDED_Connection_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
|
||||
#include "sharedFoundation/Watcher.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Archive
|
||||
{
|
||||
class ByteStream;
|
||||
}
|
||||
|
||||
class ConnectionHandler;
|
||||
class DeferredSend;
|
||||
class NetworkSetupData;
|
||||
class TcpClient;
|
||||
class UdpConnectionMT;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Connection : public NetworkHandler
|
||||
{
|
||||
public:
|
||||
Connection (const std::string & remoteAddress, const unsigned short remotePort, const NetworkSetupData & setup);
|
||||
explicit Connection (UdpConnectionMT * newConnection, TcpClient * t = 0);
|
||||
|
||||
virtual ~Connection ();
|
||||
void disconnect ();
|
||||
void describeConnection (const std::string &);
|
||||
const std::string & getConnectionDescription () const;
|
||||
const std::string & getRemoteAddress () const;
|
||||
const unsigned short getRemotePort () const;
|
||||
const UdpConnectionMT * getUdpConnection () const;
|
||||
UdpConnectionMT * getUdpConnection ();
|
||||
WatchedByList &getWatchedByList () const;
|
||||
uint16 getServerSyncStampShort () const;
|
||||
uint32 getServerSyncStampLong () const;
|
||||
Service * getService ();
|
||||
int getPendingBytes () const;
|
||||
int getOldestUnacknowledgedAge() const;
|
||||
int getCongestionWindowSize () const;
|
||||
int getAckAveragePing () const;
|
||||
int getLastSend () const;
|
||||
int getLastReceive () const;
|
||||
TcpClient * getTcpClient ();
|
||||
void setTcpClientPendingSendAllocatedSizeLimit(unsigned int limit);
|
||||
|
||||
virtual void onConnectionClosed () = 0;
|
||||
virtual void onConnectionOpened () = 0;
|
||||
virtual void onConnectionOverflowing (const unsigned int bytesPending);
|
||||
virtual void onConnectionStalled (const unsigned long stallTimeMs);
|
||||
virtual void reportReceive (const Archive::ByteStream & bs);
|
||||
virtual void reportSend (const Archive::ByteStream & bs);
|
||||
virtual void onReceive (const Archive::ByteStream & bs) = 0;
|
||||
void receive (const Archive::ByteStream & bs);
|
||||
virtual void send (const Archive::ByteStream & data, const bool reliable);
|
||||
void sendSharedPacket (const LogicalPacket * packet, const bool reliable);
|
||||
void setNoDataTimeout (const int timeout);
|
||||
void setOverflowLimit (const int newLimit);
|
||||
void setDisconnecting ();
|
||||
void setDisconnectReason (char const *fmt, ...);
|
||||
std::string const & getDisconnectReason () const;
|
||||
|
||||
static void install ();
|
||||
static void remove ();
|
||||
|
||||
protected:
|
||||
friend class Service;
|
||||
friend class NetworkHandler;
|
||||
friend class TcpClient;
|
||||
virtual void onConnectionClosed (Connection *);
|
||||
void onConnectionOpened (UdpConnectionMT *);
|
||||
int flushAndConfirmAllData ();
|
||||
void setService (Service * s);
|
||||
void receive (const unsigned char * const buffer, int length);
|
||||
static void update ();
|
||||
|
||||
virtual bool isNetLogConnection () const;
|
||||
void setRawTCP ( bool bNewValue );
|
||||
|
||||
private:
|
||||
Connection & operator = (const Connection & rhs);
|
||||
Connection(const Connection & source);
|
||||
|
||||
void checkOverflow (unsigned int bytesPending);
|
||||
void flush ();
|
||||
void reportSend (const int sendSize);
|
||||
void reportDeferredMessages() const;
|
||||
|
||||
protected:
|
||||
UdpConnectionMT * udpConnection;
|
||||
std::vector<std::pair<std::string, int> > m_pendingPackets;
|
||||
uint64 m_currentFrame;
|
||||
bool m_rawTCP;
|
||||
|
||||
private:
|
||||
std::string m_remoteAddress;
|
||||
unsigned short m_remotePort;
|
||||
std::vector<DeferredSend *> m_deferredMessages;
|
||||
int m_deferredDataSize;
|
||||
mutable WatchedByList m_watchedByList;
|
||||
int m_overflowLimit;
|
||||
int m_bytesReceived;
|
||||
int m_bytesSent;
|
||||
int m_sendPeakBytesPerSecond;
|
||||
int m_sendAverageBytesPerSecond;
|
||||
unsigned long m_connectionStartTime;
|
||||
int m_recvPeakBytesPerSecond;
|
||||
int m_recvAverageBytesPerSecond;
|
||||
unsigned long m_lastRecvTime;
|
||||
unsigned long m_lastSendTime;
|
||||
unsigned long m_lastRecvReportTime;
|
||||
unsigned long m_lastSendReportTime;
|
||||
unsigned long m_recvBytesReportInterval;
|
||||
unsigned long m_sendBytesReportInterval;
|
||||
Service * m_service;
|
||||
std::string m_description;
|
||||
ConnectionHandler * m_connectionHandler;
|
||||
TcpClient * m_tcpClient;
|
||||
Archive::ByteStream * m_tcpHeader;
|
||||
Archive::ByteStream * m_tcpInput;
|
||||
bool m_disconnecting;
|
||||
std::string m_disconnectReason;
|
||||
};
|
||||
|
||||
inline WatchedByList &Connection::getWatchedByList() const
|
||||
{
|
||||
return m_watchedByList;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_Connection_H
|
||||
@@ -0,0 +1,70 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConnectionHandler.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedCompression/ZlibCompressor.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
#include "sharedNetwork/ConnectionHandler.h"
|
||||
#include "sharedNetwork/UdpConnectionMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
ConnectionHandler::ConnectionHandler(Connection *owner) :
|
||||
UdpConnectionHandlerMT(),
|
||||
m_owner(owner)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ConnectionHandler::~ConnectionHandler()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ConnectionHandler::setOwner(Connection *owner)
|
||||
{
|
||||
m_owner = owner;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ConnectionHandler::OnRoutePacket(UdpConnectionMT *con, const uchar *data, int dataLen)
|
||||
{
|
||||
NetworkHandler::onReceive(m_owner, con, data, dataLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ConnectionHandler::OnConnectComplete(UdpConnectionMT *con)
|
||||
{
|
||||
NetworkHandler::onConnect(m_owner, con);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ConnectionHandler::OnTerminated(UdpConnectionMT *con)
|
||||
{
|
||||
NetworkHandler::onTerminate(m_owner, con);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void ConnectionHandler::OnPacketCorrupt(UdpConnectionMT *con, const uchar *data, int dataLen, UdpCorruptionReason reason)
|
||||
{
|
||||
UNREF(con);
|
||||
UNREF(data);
|
||||
UNREF(dataLen);
|
||||
UNREF(reason);
|
||||
con->Disconnect();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ConnectionHandler.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _ConnectionHandler_H_
|
||||
#define _ConnectionHandler_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/UdpHandlerMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Connection;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class ConnectionHandler: public UdpConnectionHandlerMT
|
||||
{
|
||||
public:
|
||||
ConnectionHandler(Connection *owner);
|
||||
|
||||
virtual void OnRoutePacket(UdpConnectionMT *con, unsigned char const *data, int dataLen);
|
||||
virtual void OnConnectComplete(UdpConnectionMT *con);
|
||||
virtual void OnTerminated(UdpConnectionMT *con);
|
||||
virtual void OnPacketCorrupt(UdpConnectionMT *con, const uchar *data, int dataLen, UdpCorruptionReason reason);
|
||||
void setOwner(Connection *owner);
|
||||
|
||||
private:
|
||||
ConnectionHandler(ConnectionHandler const &);
|
||||
ConnectionHandler &operator=(ConnectionHandler const &);
|
||||
|
||||
virtual ~ConnectionHandler();
|
||||
|
||||
private:
|
||||
Connection *m_owner;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _ConnectionHandler_H_
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// FirstSharedNetwork.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_FirstSharedNetwork_H
|
||||
#define INCLUDED_FirstSharedNetwork_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//#pragma warning ( disable : 4514 ) // unreferenced inline function has been removed (STL)
|
||||
//#pragma warning ( disable : 4702 ) // unreachable code (STL)
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedDebug/FirstSharedDebug.h"
|
||||
#include "sharedMemoryManager/FirstSharedMemoryManager.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // INCLUDED_FirstSharedNetwork_H
|
||||
@@ -0,0 +1,224 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ManagerHandler.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedCompression/ZlibCompressor.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
#include "sharedNetwork/ManagerHandler.h"
|
||||
#include "sharedNetwork/UdpConnectionMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace ManagerHandlerNamespace
|
||||
{
|
||||
int gs_recvTotalCompressedBytes = 0;
|
||||
int gs_recvTotalUncompressedBytes = 0;
|
||||
int gs_sendTotalCompressedBytes = 0;
|
||||
int gs_sendTotalUncompressedBytes = 0;
|
||||
}
|
||||
|
||||
using namespace ManagerHandlerNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
ManagerHandler::ManagerHandler(NetworkHandler *owner) :
|
||||
UdpManagerHandlerMT(),
|
||||
m_owner(owner),
|
||||
m_compressor(new ZlibCompressor()),
|
||||
m_recvCompressedBytes(0),
|
||||
m_recvUncompressedBytes(0),
|
||||
m_sendCompressedBytes(0),
|
||||
m_sendUncompressedBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerHandler::~ManagerHandler()
|
||||
{
|
||||
delete m_compressor;
|
||||
m_compressor = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ManagerHandler::setOwner(NetworkHandler *owner)
|
||||
{
|
||||
m_owner = owner;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ManagerHandler::OnConnectRequest(UdpConnectionMT * con)
|
||||
{
|
||||
NetworkHandler::onConnect(m_owner, con);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getRecvCompressedByteCount() const
|
||||
{
|
||||
return m_recvCompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getRecvTotalCompressedByteCount()
|
||||
{
|
||||
return gs_recvTotalCompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getRecvTotalUncompressedByteCount()
|
||||
{
|
||||
return gs_recvTotalUncompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getRecvUncompressedByteCount() const
|
||||
{
|
||||
return m_recvUncompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getSendCompressedByteCount() const
|
||||
{
|
||||
return m_sendCompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getSendTotalCompressedByteCount()
|
||||
{
|
||||
return gs_sendTotalCompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getSendTotalUncompressedByteCount()
|
||||
{
|
||||
return gs_sendTotalUncompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::getSendUncompressedByteCount() const
|
||||
{
|
||||
return m_sendUncompressedBytes;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float ManagerHandler::getCompressionRatio() const
|
||||
{
|
||||
float result = 0.0;
|
||||
if(m_sendCompressedBytes + m_recvCompressedBytes > 0)
|
||||
result = static_cast<float>(static_cast<float>(m_sendUncompressedBytes + m_recvUncompressedBytes) / static_cast<float>(m_sendCompressedBytes + m_recvCompressedBytes));
|
||||
else
|
||||
result = 1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float ManagerHandler::getTotalCompressionRatio()
|
||||
{
|
||||
float result = 0.0;
|
||||
if(gs_sendTotalCompressedBytes + gs_recvTotalCompressedBytes > 0)
|
||||
result = static_cast<float>(static_cast<float>(gs_sendTotalUncompressedBytes + gs_recvTotalUncompressedBytes) / static_cast<float>(gs_sendTotalCompressedBytes + gs_recvTotalCompressedBytes));
|
||||
else
|
||||
result = 1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::OnUserSuppliedEncrypt(UdpConnectionMT *, uchar *destData, const uchar *sourceData, int sourceLen)
|
||||
{
|
||||
m_sendUncompressedBytes += sourceLen;
|
||||
gs_sendTotalUncompressedBytes += sourceLen;
|
||||
|
||||
int result = 0;
|
||||
FATAL(!m_compressor, ("No compressor is available"));
|
||||
result = m_compressor->compress(sourceData, sourceLen, destData, sourceLen);
|
||||
if(result < 0 || result > sourceLen)
|
||||
{
|
||||
memcpy(destData, sourceData, sourceLen);
|
||||
destData[sourceLen] = 0;
|
||||
result = sourceLen + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
destData[result] = 1;
|
||||
result++;
|
||||
}
|
||||
|
||||
if(result > 0)
|
||||
{
|
||||
m_sendCompressedBytes += result;
|
||||
gs_sendTotalCompressedBytes += result;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sendCompressedBytes += sourceLen;
|
||||
gs_sendTotalCompressedBytes += sourceLen;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ManagerHandler::OnUserSuppliedDecrypt(UdpConnectionMT *, uchar *destData, const uchar *sourceData, int sourceLen)
|
||||
{
|
||||
m_recvCompressedBytes += sourceLen;
|
||||
gs_recvTotalCompressedBytes += sourceLen;
|
||||
|
||||
int result = -1;
|
||||
FATAL(!m_compressor, ("No compressor is available"));
|
||||
if(sourceData[sourceLen - 1] == 1)
|
||||
{
|
||||
static const int bufferSize = ConfigSharedNetwork::getMaxRawPacketSize();
|
||||
result = m_compressor->expand(sourceData, sourceLen - 1, destData, bufferSize);
|
||||
if (result < 0)
|
||||
{
|
||||
WARNING_STRICT_FATAL(result < 0, ("Failed to decompress a compressed buffer"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(result > 0)
|
||||
{
|
||||
m_recvUncompressedBytes += result;
|
||||
gs_recvTotalUncompressedBytes += result;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_recvUncompressedBytes += sourceLen;
|
||||
gs_recvTotalUncompressedBytes += sourceLen;
|
||||
}
|
||||
}
|
||||
else if(sourceData[sourceLen - 1] == 0)
|
||||
{
|
||||
memcpy(destData, sourceData, sourceLen - 1);
|
||||
result = sourceLen - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WARNING_STRICT_FATAL(true, ("invalid compression bit in buffer"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// ManagerHandler.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _ManagerHandler_H_
|
||||
#define _ManagerHandler_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionMT;
|
||||
class ZlibCompressor;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/UdpHandlerMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class ManagerHandler: public UdpManagerHandlerMT
|
||||
{
|
||||
public:
|
||||
ManagerHandler(NetworkHandler *owner);
|
||||
|
||||
static int getRecvTotalCompressedByteCount ();
|
||||
static int getRecvTotalUncompressedByteCount ();
|
||||
static int getSendTotalCompressedByteCount ();
|
||||
static int getSendTotalUncompressedByteCount ();
|
||||
static float getTotalCompressionRatio ();
|
||||
|
||||
void setOwner (NetworkHandler *owner);
|
||||
int getRecvCompressedByteCount () const;
|
||||
int getRecvUncompressedByteCount () const;
|
||||
int getSendCompressedByteCount () const;
|
||||
int getSendUncompressedByteCount () const;
|
||||
float getCompressionRatio () const;
|
||||
|
||||
virtual void OnConnectRequest(UdpConnectionMT *con);
|
||||
virtual int OnUserSuppliedEncrypt(UdpConnectionMT *con, uchar *destData, const uchar *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedDecrypt(UdpConnectionMT *con, uchar *destData, const uchar *sourceData, int sourceLen);
|
||||
|
||||
private:
|
||||
ManagerHandler(ManagerHandler const &);
|
||||
ManagerHandler &operator=(ManagerHandler const &);
|
||||
|
||||
virtual ~ManagerHandler();
|
||||
|
||||
private:
|
||||
NetworkHandler * m_owner;
|
||||
ZlibCompressor * m_compressor;
|
||||
int m_recvCompressedBytes;
|
||||
int m_recvUncompressedBytes;
|
||||
int m_sendCompressedBytes;
|
||||
int m_sendUncompressedBytes;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _ManagerHandler_H_
|
||||
|
||||
@@ -0,0 +1,679 @@
|
||||
// NetworkHandler.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
|
||||
#include "Archive/Archive.h"
|
||||
#include "sharedDebug/DebugFlags.h"
|
||||
#include "sharedDebug/PixCounter.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedFoundation/Watcher.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include "sharedLog/NetLogConnection.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/ManagerHandler.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "sharedNetwork/UdpLibraryMT.h"
|
||||
#include "sharedSynchronization/Guard.h"
|
||||
|
||||
#include "TcpClient.h"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace NetworkHandlerNamespace
|
||||
{
|
||||
bool ms_logThrottle = false;
|
||||
|
||||
#if PRODUCTION == 0
|
||||
PixCounter::ResetInteger s_bytesSentThisFrameForPix;
|
||||
PixCounter::ResetInteger s_bytesReceivedThisFrameForPix;
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace NetworkHandlerNamespace;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct IncomingData
|
||||
{
|
||||
Watcher<Connection> connection;
|
||||
Archive::ByteStream byteStream;
|
||||
};
|
||||
|
||||
struct Services
|
||||
{
|
||||
Services();
|
||||
~Services();
|
||||
std::set<UdpManagerMT *> udpServices;
|
||||
std::vector<UdpManagerMT *> deferredDestroyUdpManagers;
|
||||
std::deque<IncomingData> inputQueue;
|
||||
std::vector<Service *> services;
|
||||
};
|
||||
|
||||
static Services services;
|
||||
int s_bytesSentThisFrame = 0;
|
||||
int s_bytesReceivedThisFrame = 0;
|
||||
int s_packetsSentThisFrame = 0;
|
||||
int s_packetsReceivedThisFrame = 0;
|
||||
std::map<std::string, std::pair<int, int> > s_messageCount;
|
||||
bool s_updating = false;
|
||||
bool s_logBackloggedPackets = true;
|
||||
bool s_removing = false;
|
||||
static std::vector<Connection *> deferredDisconnects;
|
||||
uint64 s_currentFrame = 0;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
Services::Services()
|
||||
{
|
||||
UdpLibraryMT::getMutex();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
Services::~Services()
|
||||
{
|
||||
std::set<UdpManagerMT *>::const_iterator i;
|
||||
for(i = udpServices.begin(); i != udpServices.end(); ++i)
|
||||
{
|
||||
(*i)->Release();
|
||||
}
|
||||
udpServices.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
NetworkHandler::NetworkHandler() :
|
||||
m_bindPort(0),
|
||||
m_bindAddress(""),
|
||||
m_udpManager(0),
|
||||
m_managerHandler(0)
|
||||
{
|
||||
m_managerHandler = new ManagerHandler(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
NetworkHandler::~NetworkHandler()
|
||||
{
|
||||
if (m_udpManager)
|
||||
m_udpManager->ClearHandler();
|
||||
|
||||
m_managerHandler->setOwner(0);
|
||||
m_managerHandler->Release();
|
||||
m_managerHandler = 0;
|
||||
|
||||
if (m_udpManager)
|
||||
{
|
||||
if (s_updating)
|
||||
services.deferredDestroyUdpManagers.push_back(m_udpManager);
|
||||
else
|
||||
{
|
||||
std::set<UdpManagerMT *>::iterator f = services.udpServices.find(m_udpManager);
|
||||
if (f != services.udpServices.end())
|
||||
services.udpServices.erase(f);
|
||||
m_udpManager->Release();
|
||||
m_udpManager = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::dispatch()
|
||||
{
|
||||
LogManager::update();
|
||||
|
||||
UdpLibraryMT::mainThreadUpdate();
|
||||
|
||||
if (!services.inputQueue.empty())
|
||||
{
|
||||
size_t const startQueueSize = services.inputQueue.size();
|
||||
unsigned long const startTime = Clock::timeMs();
|
||||
bool const throttle = ConfigSharedNetwork::getNetworkHandlerDispatchThrottle();
|
||||
unsigned int const processTimeMilliseconds = static_cast<unsigned int>(ConfigSharedNetwork::getNetworkHandlerDispatchThrottleTimeMilliseconds());
|
||||
unsigned int const queueSize = static_cast<unsigned int>(ConfigSharedNetwork::getNetworkHandlerDispatchQueueSize());
|
||||
|
||||
while (!services.inputQueue.empty() && (services.inputQueue.size() > queueSize || (!throttle || (throttle && ((Clock::timeMs() - startTime) < processTimeMilliseconds)))))
|
||||
{
|
||||
std::deque<IncomingData>::iterator i = services.inputQueue.begin();
|
||||
|
||||
Connection * c = (*i).connection;
|
||||
if (c)
|
||||
{
|
||||
try
|
||||
{
|
||||
reportBytesReceived((*i).byteStream.getSize());
|
||||
int sendSize = (*i).byteStream.getSize();
|
||||
static const int packetSizeWarnThreshold = ConfigSharedNetwork::getPacketSizeWarnThreshold();
|
||||
if(packetSizeWarnThreshold > 0)
|
||||
{
|
||||
WARNING(sendSize > packetSizeWarnThreshold, ("large packet received (%d bytes) exceeds warning threshold %d defined as SharedNetwork/packetSizeWarnThreshold", sendSize, packetSizeWarnThreshold));
|
||||
}
|
||||
|
||||
c->receive((*i).byteStream);
|
||||
}
|
||||
catch(const Archive::ReadException & readException)
|
||||
{
|
||||
WARNING(true, ("Unhandled Archive read error (%s) on connection. Continuing to throw from NetwokrHandler::Dispatch", readException.what()));
|
||||
throw(readException);
|
||||
}
|
||||
}
|
||||
|
||||
services.inputQueue.pop_front();
|
||||
}
|
||||
|
||||
REPORT_LOG(ms_logThrottle && throttle && !services.inputQueue.empty(), ("NetworkHandler::dispatch: services.inputQueue has %d/%d messages remaining\n", services.inputQueue.size(), startQueueSize));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::flushAndConfirmAll()
|
||||
{
|
||||
static bool enabled = ConfigSharedNetwork::getEnableFlushAndConfirmAllData();
|
||||
|
||||
if(enabled)
|
||||
{
|
||||
std::vector<Service *>::iterator i;
|
||||
for(i = services.services.begin(); i != services.services.end(); ++i)
|
||||
{
|
||||
(*i)->flushAndConfirmAllData();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & NetworkHandler::getBindAddress() const
|
||||
{
|
||||
return m_bindAddress;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned short NetworkHandler::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::newManager(UdpManagerMT * u)
|
||||
{
|
||||
services.udpServices.insert(u);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::newService(Service * s)
|
||||
{
|
||||
services.services.push_back(s);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::removeService(Service * s)
|
||||
{
|
||||
std::vector<Service *>::iterator f = std::find(services.services.begin(), services.services.end(), s);
|
||||
if(f != services.services.end())
|
||||
services.services.erase(f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::onConnect(void * callback, UdpConnectionMT * connection)
|
||||
{
|
||||
if(callback)
|
||||
{
|
||||
NetworkHandler * h = reinterpret_cast<NetworkHandler *>(callback);
|
||||
if(connection)
|
||||
{
|
||||
h->onConnectionOpened(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::onReceive(Connection * c, const unsigned char * d, int s)
|
||||
{
|
||||
if(c)
|
||||
{
|
||||
services.inputQueue.push_back();
|
||||
services.inputQueue.back().connection = c;
|
||||
services.inputQueue.back().byteStream.put(d, s);
|
||||
|
||||
static const bool logAllNetworkTraffic = ConfigSharedNetwork::getLogAllNetworkTraffic();
|
||||
|
||||
if(logAllNetworkTraffic)
|
||||
{
|
||||
if(! dynamic_cast<const NetLogConnection *>(c))
|
||||
{
|
||||
std::string logChan = "Network:Recv:" + c->getRemoteAddress() + ":";
|
||||
char portBuf[7] = {"\0"};
|
||||
snprintf(portBuf, sizeof(portBuf), "%d", c->getRemotePort());
|
||||
logChan += portBuf;
|
||||
std::string output;
|
||||
const unsigned char * uc = d;
|
||||
while(uc < d + s)
|
||||
{
|
||||
if(isalpha(*uc))
|
||||
{
|
||||
char s = *uc;
|
||||
output += s;
|
||||
}
|
||||
else
|
||||
{
|
||||
char numBuf[128] = {"\0"};
|
||||
snprintf(numBuf, sizeof(numBuf), "[%d]", *uc);
|
||||
output += numBuf;
|
||||
}
|
||||
++uc;
|
||||
}
|
||||
LOG(logChan, ("%s", output.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::onReceive(void *, UdpConnectionMT * u, const unsigned char * d, int s)
|
||||
{
|
||||
Connection * c = reinterpret_cast<Connection *>(u->GetPassThroughData());
|
||||
onReceive(c, d, s);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::onTerminate(Connection * c)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
c->setDisconnectReason("NetworkHandler::onTerminate called");
|
||||
c->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::onTerminate(void * m, UdpConnectionMT * u)
|
||||
{
|
||||
if(m)
|
||||
{
|
||||
// NetworkHandler * s = reinterpret_cast<NetworkHandler *>(m);
|
||||
if(u)
|
||||
{
|
||||
u->AddRef();
|
||||
Connection * c = reinterpret_cast<Connection *>(u->GetPassThroughData());
|
||||
onTerminate(c);
|
||||
u->SetPassThroughData(0);
|
||||
u->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::setBindAddress(const std::string & address)
|
||||
{
|
||||
m_bindAddress = address;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::setBindPort(const unsigned short p)
|
||||
{
|
||||
m_bindPort = p;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::install()
|
||||
{
|
||||
Connection::install();
|
||||
UdpLibraryMT::install();
|
||||
|
||||
DebugFlags::registerFlag(ms_logThrottle, "SharedNetwork", "networkHandlerDispatchLogThrottle");
|
||||
DebugFlags::registerFlag(s_logBackloggedPackets, "SharedNetwork", "logBackloggedPackets");
|
||||
|
||||
#if PRODUCTION == 0
|
||||
s_bytesSentThisFrameForPix.bindToCounter("NetworkBytesSent");
|
||||
s_bytesReceivedThisFrameForPix.bindToCounter("NetworkBytesReceived");
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::remove()
|
||||
{
|
||||
s_removing = true;
|
||||
while (!services.services.empty())
|
||||
{
|
||||
// Service destructor calls removeService, which should the service at
|
||||
// begin() from the list
|
||||
delete *services.services.begin();
|
||||
}
|
||||
|
||||
UdpLibraryMT::remove();
|
||||
Connection::remove();
|
||||
|
||||
DebugFlags::unregisterFlag(ms_logThrottle);
|
||||
DebugFlags::unregisterFlag(s_logBackloggedPackets);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::update()
|
||||
{
|
||||
if (!UdpLibraryMT::getUseNetworkThread())
|
||||
{
|
||||
std::set<UdpManagerMT *>::const_iterator i;
|
||||
std::set<UdpManagerMT *>::const_iterator begin = services.udpServices.begin();
|
||||
std::set<UdpManagerMT *>::const_iterator end = services.udpServices.end();
|
||||
|
||||
s_updating = true;
|
||||
for(i = begin; i != end; ++i)
|
||||
(*i)->GiveTime();
|
||||
std::vector<Service *>::const_iterator is;
|
||||
for(is = services.services.begin(); is != services.services.end(); ++is)
|
||||
{
|
||||
(*is)->updateTcp();
|
||||
}
|
||||
|
||||
Connection::update();
|
||||
TcpClient::flushPendingWrites();
|
||||
|
||||
s_updating = false;
|
||||
|
||||
std::vector<UdpManagerMT *>::const_iterator im;
|
||||
for(im = services.deferredDestroyUdpManagers.begin(); im != services.deferredDestroyUdpManagers.end(); ++im)
|
||||
{
|
||||
UdpManagerMT * u = (*im);
|
||||
std::set<UdpManagerMT *>::iterator f = services.udpServices.find(u);
|
||||
if(f != services.udpServices.end())
|
||||
services.udpServices.erase(f);
|
||||
if(u)
|
||||
u->Release();
|
||||
}
|
||||
services.deferredDestroyUdpManagers.clear();
|
||||
}
|
||||
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
while (!deferredDisconnects.empty())
|
||||
{
|
||||
Connection *c = *deferredDisconnects.begin();
|
||||
deferredDisconnects.erase(deferredDisconnects.begin());
|
||||
c->onConnectionClosed();
|
||||
delete c;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const int NetworkHandler::getBytesReceivedThisFrame()
|
||||
{
|
||||
return s_bytesReceivedThisFrame;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const int NetworkHandler::getBytesSentThisFrame()
|
||||
{
|
||||
return s_bytesSentThisFrame;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::reportBytesReceived(const int bytes)
|
||||
{
|
||||
s_bytesReceivedThisFrame+=bytes;
|
||||
s_packetsReceivedThisFrame++;
|
||||
#if PRODUCTION == 0
|
||||
s_bytesReceivedThisFrameForPix += bytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::reportBytesSent(const int bytes)
|
||||
{
|
||||
s_bytesSentThisFrame+=bytes;
|
||||
s_packetsSentThisFrame++;
|
||||
#if PRODUCTION == 0
|
||||
s_bytesSentThisFrameForPix += bytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const int NetworkHandler::getPacketsReceivedThisFrame()
|
||||
{
|
||||
return s_packetsReceivedThisFrame;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const int NetworkHandler::getPacketsSentThisFrame()
|
||||
{
|
||||
return s_packetsSentThisFrame;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::reportMessage(const std::string & messageName, const int size)
|
||||
{
|
||||
static const bool reportMessages = ConfigSharedNetwork::getReportMessages();
|
||||
if(reportMessages)
|
||||
{
|
||||
std::map<std::string, std::pair<int, int> >::iterator f = s_messageCount.find(messageName);
|
||||
if(f != s_messageCount.end())
|
||||
{
|
||||
(*f).second.first++;
|
||||
(*f).second.second+=size;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::pair<int, int> newEntry = std::make_pair(1, size);
|
||||
s_messageCount[messageName] = newEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::clearBytesThisFrame()
|
||||
{
|
||||
s_currentFrame++;
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
|
||||
bool logMessageCounts = false;
|
||||
static const int backlogThreshold = ConfigSharedNetwork::getLogBackloggedPacketThreshold();
|
||||
if(s_logBackloggedPackets && backlogThreshold > 0)
|
||||
{
|
||||
std::vector<Service *>::iterator i;
|
||||
for(i = services.services.begin(); i != services.services.end(); ++i)
|
||||
{
|
||||
(*i)->logBackloggedPackets();
|
||||
}
|
||||
}
|
||||
|
||||
static const int packetCountWarnThreshold = ConfigSharedNetwork::getPacketCountWarnThreshold();
|
||||
if(packetCountWarnThreshold > 0)
|
||||
{
|
||||
if(s_packetsSentThisFrame > packetCountWarnThreshold)
|
||||
{
|
||||
LOG("Network:ExcessivePackets:Send", ("packet send count (%d packets) for this frame exceeds warning threshold %d defined as SharedNetwork/packetCountWarnThreshold", NetworkHandler::getPacketsSentThisFrame(), packetCountWarnThreshold));
|
||||
logMessageCounts = true;
|
||||
}
|
||||
if(s_packetsReceivedThisFrame > packetCountWarnThreshold)
|
||||
{
|
||||
LOG("Network:ExcessivePackets:Recv", ("packet receive count (%d packets) for this frame exceeds warning threshold %d defined as SharedNetwork/packetCountWarnThreshold", s_packetsReceivedThisFrame, packetCountWarnThreshold));
|
||||
logMessageCounts = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const int byteCountWarnThreshold = ConfigSharedNetwork::getByteCountWarnThreshold();
|
||||
if(byteCountWarnThreshold > 0)
|
||||
{
|
||||
if(s_bytesSentThisFrame > byteCountWarnThreshold)
|
||||
{
|
||||
LOG("Network:ExcessiveBytes:Send", ("byte send count (%d bytes) for this frame exceeds warning threshold %d defined as SharedNetwork/byteCountWarnThreshold", s_bytesSentThisFrame, byteCountWarnThreshold));
|
||||
logMessageCounts = true;
|
||||
}
|
||||
if(s_bytesReceivedThisFrame > byteCountWarnThreshold)
|
||||
{
|
||||
LOG("Network:ExcessiveBytes:Recv", ("byte receive count (%d bytes) for this frame exceeds warning threshold %d defined as SharedNetwork/byteCountWarnThreshold", s_bytesReceivedThisFrame, byteCountWarnThreshold));
|
||||
logMessageCounts = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(logMessageCounts)
|
||||
{
|
||||
static const bool reportMessages = ConfigSharedNetwork::getReportMessages();
|
||||
if(reportMessages)
|
||||
{
|
||||
std::map<std::string, std::pair<int, int> >::iterator i;
|
||||
static std::pair<int, int> zeros = std::make_pair(0, 0);
|
||||
static char msgBuf[256];
|
||||
for(i = s_messageCount.begin(); i != s_messageCount.end(); ++i)
|
||||
{
|
||||
snprintf(msgBuf, sizeof(msgBuf), "[%s] - %d messages, %d total bytes", (*i).first.c_str(), (*i).second.first, (*i).second.second);
|
||||
LOG("Network:MessageCount", ("%s", msgBuf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_messageCount.clear();
|
||||
s_bytesReceivedThisFrame = 0;
|
||||
s_bytesSentThisFrame = 0;
|
||||
s_packetsReceivedThisFrame = 0;
|
||||
s_packetsSentThisFrame = 0;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
LogicalPacket const *NetworkHandler::createPacket(unsigned char const *data, int size)
|
||||
{
|
||||
if (m_udpManager)
|
||||
return m_udpManager->CreatePacket(data, size);
|
||||
return UdpMiscMT::CreateQuickLogicalPacket(data, size);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::releasePacket(LogicalPacket const *p)
|
||||
{
|
||||
p->Release();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool NetworkHandler::removing()
|
||||
{
|
||||
return s_removing;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool NetworkHandler::isPortReserved(unsigned short p)
|
||||
{
|
||||
return(ConfigSharedNetwork::getIsPortReserved(p));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void NetworkHandler::disconnectConnection(Connection * c)
|
||||
{
|
||||
if(! s_removing)
|
||||
{
|
||||
std::vector<Connection *>::iterator f = std::find(deferredDisconnects.begin(), deferredDisconnects.end(), c);
|
||||
if(f == deferredDisconnects.end())
|
||||
{
|
||||
deferredDisconnects.push_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
uint64 NetworkHandler::getCurrentFrame()
|
||||
{
|
||||
return s_currentFrame;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int NetworkHandler::getRecvTotalCompressedByteCount()
|
||||
{
|
||||
return ManagerHandler::getRecvTotalCompressedByteCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int NetworkHandler::getRecvTotalUncompressedByteCount()
|
||||
{
|
||||
return ManagerHandler::getRecvTotalUncompressedByteCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int NetworkHandler::getSendTotalCompressedByteCount()
|
||||
{
|
||||
return ManagerHandler::getSendTotalCompressedByteCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int NetworkHandler::getSendTotalUncompressedByteCount()
|
||||
{
|
||||
return ManagerHandler::getSendTotalUncompressedByteCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
float NetworkHandler::getTotalCompressionRatio()
|
||||
{
|
||||
return ManagerHandler::getTotalCompressionRatio();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool NetworkHandler::isAddressLocal(const std::string & address)
|
||||
{
|
||||
Address addr(address, 0);
|
||||
|
||||
bool result = false;
|
||||
const std::vector<std::pair<std::string, std::string> > & localAddresses = NetworkHandler::getInterfaceAddresses();
|
||||
std::vector<std::pair<std::string, std::string> >::const_iterator i;
|
||||
for(i = localAddresses.begin(); i != localAddresses.end(); ++i)
|
||||
{
|
||||
if(i->second == addr.getHostAddress())
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// NetworkHandler.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_NetworkHandler_H
|
||||
#define INCLUDED_NetworkHandler_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Connection;
|
||||
class LogicalPacket;
|
||||
class ManagerHandler;
|
||||
class Service;
|
||||
class UdpConnectionMT;
|
||||
class UdpManagerMT;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class NetworkHandler
|
||||
{
|
||||
public:
|
||||
NetworkHandler();
|
||||
virtual ~NetworkHandler() = 0;
|
||||
|
||||
static void install ();
|
||||
static void remove ();
|
||||
static void dispatch ();
|
||||
static void flushAndConfirmAll ();
|
||||
static const int getBytesReceivedThisFrame();
|
||||
static const int getBytesSentThisFrame();
|
||||
static const int getPacketsReceivedThisFrame();
|
||||
static const int getPacketsSentThisFrame();
|
||||
|
||||
static int getRecvTotalCompressedByteCount ();
|
||||
static int getRecvTotalUncompressedByteCount ();
|
||||
static int getSendTotalCompressedByteCount ();
|
||||
static int getSendTotalUncompressedByteCount ();
|
||||
static float getTotalCompressionRatio ();
|
||||
|
||||
static const std::string & getHostName ();
|
||||
static const std::string & getHumanReadableHostName();
|
||||
static const std::vector<std::pair<std::string, std::string> > & getInterfaceAddresses ();
|
||||
static bool isAddressLocal (const std::string & address);
|
||||
static void update ();
|
||||
static void clearBytesThisFrame ();
|
||||
static void reportMessage (const std::string & message, const int size);
|
||||
|
||||
virtual void onConnectionOpened (UdpConnectionMT *) = 0;
|
||||
const std::string & getBindAddress () const;
|
||||
const unsigned short getBindPort () const;
|
||||
virtual void onConnectionClosed (Connection *) = 0;
|
||||
void setBindAddress (const std::string & address);
|
||||
void setBindPort (const unsigned short port);
|
||||
static bool removing ();
|
||||
LogicalPacket const * createPacket (unsigned char const *data, int size);
|
||||
void releasePacket (LogicalPacket const *p);
|
||||
static bool isPortReserved (unsigned short port);
|
||||
static void onTerminate (Connection * c);
|
||||
|
||||
protected:
|
||||
friend class ConnectionHandler;
|
||||
friend class ManagerHandler;
|
||||
|
||||
static void reportBytesSent(const int bytes);
|
||||
static void reportBytesReceived(const int bytes);
|
||||
static void onConnect(void * callback, UdpConnectionMT * connection);
|
||||
static void onReceive(Connection *, const unsigned char *, int);
|
||||
static void onReceive(void *, UdpConnectionMT * u, const unsigned char * d, int s);
|
||||
static void onTerminate(void * m, UdpConnectionMT * u);
|
||||
static uint64 getCurrentFrame();
|
||||
|
||||
void newManager(UdpManagerMT *);
|
||||
void newService(Service *);
|
||||
void removeService(Service *);
|
||||
virtual int flushAndConfirmAllData () = 0;
|
||||
static void disconnectConnection(Connection *);
|
||||
|
||||
private:
|
||||
NetworkHandler & operator = (const NetworkHandler & rhs);
|
||||
NetworkHandler(const NetworkHandler & source);
|
||||
|
||||
private:
|
||||
unsigned short m_bindPort;
|
||||
std::string m_bindAddress;
|
||||
|
||||
protected:
|
||||
UdpManagerMT * m_udpManager;
|
||||
ManagerHandler * m_managerHandler;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_NetworkHandler_H
|
||||
@@ -0,0 +1,58 @@
|
||||
// NetworkSetupData.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedNetwork/NetworkSetupData.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
NetworkSetupData::NetworkSetupData() :
|
||||
crcBytes(ConfigSharedNetwork::getCrcBytes()),
|
||||
hashTableSize(ConfigSharedNetwork::getHashTableSize()),
|
||||
incomingBufferSize(ConfigSharedNetwork::getIncomingBufferSize()),
|
||||
outgoingBufferSize(ConfigSharedNetwork::getOutgoingBufferSize()),
|
||||
clockSyncDelay(ConfigSharedNetwork::getClockSyncDelay()),
|
||||
keepAliveDelay(ConfigSharedNetwork::getKeepAliveDelay()),
|
||||
maxConnections(ConfigSharedNetwork::getMaxConnections()),
|
||||
maxRawPacketSize(ConfigSharedNetwork::getMaxRawPacketSize()),
|
||||
maxInstandingPackets(ConfigSharedNetwork::getMaxInstandingPackets()),
|
||||
maxOutstandingBytes(ConfigSharedNetwork::getMaxOutstandingBytes()),
|
||||
maxOutstandingPackets(ConfigSharedNetwork::getMaxOutstandingPackets()),
|
||||
processIcmpErrors(ConfigSharedNetwork::getProcessIcmpErrors()),
|
||||
processOnSend(ConfigSharedNetwork::getProcessOnSend()),
|
||||
fragmentSize(ConfigSharedNetwork::getFragmentSize()),
|
||||
pooledPacketMax(ConfigSharedNetwork::getPooledPacketMax()),
|
||||
pooledPacketSize(ConfigSharedNetwork::getPooledPacketSize()),
|
||||
pooledPacketInitial(ConfigSharedNetwork::getPooledPacketInitial()),
|
||||
packetHistoryMax(ConfigSharedNetwork::getPacketHistoryMax()),
|
||||
logAllNetworkTraffic(ConfigSharedNetwork::getLogAllNetworkTraffic()),
|
||||
oldestUnacknowledgedTimeout(ConfigSharedNetwork::getOldestUnacknowledgedTimeout()),
|
||||
overflowLimit(ConfigSharedNetwork::getOverflowLimit()),
|
||||
congestionWindowMinimum(ConfigSharedNetwork::getCongestionWindowMinimum()),
|
||||
maxDataHoldTime(ConfigSharedNetwork::getMaxDataHoldTime()),
|
||||
resendDelayAdjust(ConfigSharedNetwork::getResendDelayAdjust()),
|
||||
resendDelayPercent(ConfigSharedNetwork::getResendDelayPercent()),
|
||||
noDataTimeout(ConfigSharedNetwork::getNoDataTimeout()),
|
||||
reliableOverflowBytes(ConfigSharedNetwork::getReliableOverflowBytes()),
|
||||
icmpErrorRetryPeriod(ConfigSharedNetwork::getIcmpErrorRetryPeriod()),
|
||||
maxDataHoldSize(ConfigSharedNetwork::getMaxDataHoldSize()),
|
||||
port(0),
|
||||
bindInterface(std::string("")),
|
||||
compress(false),
|
||||
allowPortRemapping(ConfigSharedNetwork::getAllowPortRemapping()),
|
||||
useTcp(ConfigSharedNetwork::getUseTcp())
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
NetworkSetupData::~NetworkSetupData()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// NetworkSetupData.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_NetworkSetupData_H
|
||||
#define _INCLUDED_NetworkSetupData_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class NetworkSetupData
|
||||
{
|
||||
public:
|
||||
NetworkSetupData();
|
||||
virtual ~NetworkSetupData();
|
||||
|
||||
public:
|
||||
int crcBytes;
|
||||
int hashTableSize;
|
||||
int incomingBufferSize;
|
||||
int outgoingBufferSize;
|
||||
int clockSyncDelay;
|
||||
int keepAliveDelay;
|
||||
int maxConnections;
|
||||
int maxRawPacketSize;
|
||||
int maxInstandingPackets;
|
||||
int maxOutstandingBytes;
|
||||
int maxOutstandingPackets;
|
||||
bool processIcmpErrors;
|
||||
bool processOnSend;
|
||||
int fragmentSize;
|
||||
int pooledPacketMax;
|
||||
int pooledPacketSize;
|
||||
int pooledPacketInitial;
|
||||
int packetHistoryMax;
|
||||
bool logAllNetworkTraffic;
|
||||
int oldestUnacknowledgedTimeout;
|
||||
int overflowLimit;
|
||||
int congestionWindowMinimum;
|
||||
int maxDataHoldTime;
|
||||
int resendDelayAdjust;
|
||||
int resendDelayPercent;
|
||||
int noDataTimeout;
|
||||
int reliableOverflowBytes;
|
||||
int icmpErrorRetryPeriod;
|
||||
int maxDataHoldSize;
|
||||
unsigned short port;
|
||||
std::string bindInterface;
|
||||
bool compress;
|
||||
bool allowPortRemapping;
|
||||
bool useTcp;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_NetworkSetupData_H
|
||||
@@ -0,0 +1,332 @@
|
||||
// Service.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "ConfigSharedNetwork.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include "sharedMessageDispatch/Transceiver.h"
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/ManagerHandler.h"
|
||||
#include "sharedNetwork/NetworkSetupData.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "sharedNetwork/UdpLibraryMT.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
ConnectionAllocatorBase::~ConnectionAllocatorBase()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//Service::Service(const ConnectionAllocatorBase & c, const unsigned short port, const int m, const int keepAliveDelay, const std::string & interfaceAddress, const bool compress) :
|
||||
Service::Service(const ConnectionAllocatorBase & c, const NetworkSetupData & setup) :
|
||||
connectionAllocator(c.clone()),
|
||||
m_callback(new MessageDispatch::Callback),
|
||||
m_tcpServer(0)
|
||||
{
|
||||
std::string realAddress;
|
||||
if(setup.bindInterface.length() > 0)
|
||||
{
|
||||
// is the address an interface? If so, change it to an IP address
|
||||
const std::vector<std::pair<std::string, std::string> > & ifaces = NetworkHandler::getInterfaceAddresses();
|
||||
std::vector<std::pair<std::string, std::string> >::const_iterator i;
|
||||
for(i = ifaces.begin(); i != ifaces.end(); ++i)
|
||||
{
|
||||
if((*i).first == setup.bindInterface)
|
||||
{
|
||||
realAddress = (*i).second;
|
||||
break;
|
||||
}
|
||||
if((*i).second == setup.bindInterface)
|
||||
{
|
||||
realAddress = (*i).second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(realAddress.length() == 0)
|
||||
{
|
||||
// the requested bind interfae does not exactly match one of the
|
||||
// interfaces on this host. See if there is a partial match
|
||||
// with the supplied address and an interface address
|
||||
for(i = ifaces.begin(); i != ifaces.end(); ++i)
|
||||
{
|
||||
if(setup.bindInterface.length() < (*i).second.length())
|
||||
{
|
||||
if((*i).second.substr(0, setup.bindInterface.length()) == setup.bindInterface)
|
||||
{
|
||||
realAddress = (*i).second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(! setup.useTcp)
|
||||
{
|
||||
UdpManagerMT::Params p;
|
||||
p.handler = m_managerHandler ? m_managerHandler->getManagerHandler() : 0;
|
||||
p.crcBytes = setup.crcBytes;
|
||||
p.hashTableSize = setup.hashTableSize;
|
||||
p.incomingBufferSize = setup.incomingBufferSize;
|
||||
p.outgoingBufferSize = setup.outgoingBufferSize;
|
||||
p.clockSyncDelay = 0;// Servers don't sync their clocks to clients
|
||||
p.keepAliveDelay = setup.keepAliveDelay;
|
||||
p.maxConnections = setup.maxConnections;
|
||||
p.maxRawPacketSize = setup.maxRawPacketSize;
|
||||
p.maxDataHoldTime = setup.maxDataHoldTime;
|
||||
p.packetHistoryMax = setup.packetHistoryMax;
|
||||
p.port = setup.port;
|
||||
p.pooledPacketMax = setup.pooledPacketMax;
|
||||
p.pooledPacketSize = setup.pooledPacketSize;
|
||||
p.pooledPacketInitial = setup.pooledPacketInitial;
|
||||
p.oldestUnacknowledgedTimeout = setup.oldestUnacknowledgedTimeout;
|
||||
p.processIcmpErrors = setup.processIcmpErrors;
|
||||
p.noDataTimeout = setup.noDataTimeout;
|
||||
p.reliableOverflowBytes = setup.reliableOverflowBytes;
|
||||
p.icmpErrorRetryPeriod = setup.icmpErrorRetryPeriod;
|
||||
p.maxDataHoldSize = setup.maxDataHoldSize;
|
||||
p.allowPortRemapping = setup.allowPortRemapping;
|
||||
|
||||
|
||||
if(realAddress.length() > 0)
|
||||
{
|
||||
strncpy(p.bindIpAddress, realAddress.c_str(), sizeof(p.bindIpAddress));
|
||||
}
|
||||
|
||||
p.reliable[0].maxInstandingPackets = setup.maxInstandingPackets;
|
||||
p.reliable[0].maxOutstandingBytes = setup.maxOutstandingBytes;
|
||||
p.reliable[0].maxOutstandingPackets = setup.maxOutstandingPackets;
|
||||
p.reliable[0].processOnSend = setup.processOnSend;
|
||||
p.reliable[0].congestionWindowMinimum = setup.congestionWindowMinimum;
|
||||
p.reliable[0].resendDelayAdjust = setup.resendDelayAdjust;
|
||||
p.reliable[0].resendDelayPercent = setup.resendDelayPercent;
|
||||
|
||||
for (int j = 1; j < UdpManager::cReliableChannelCount; j++)
|
||||
p.reliable[j] = p.reliable[0];
|
||||
|
||||
p.userSuppliedEncryptExpansionBytes = 1;
|
||||
|
||||
if(setup.compress)
|
||||
{
|
||||
p.encryptMethod[0] = UdpManager::cEncryptMethodUserSupplied;
|
||||
p.encryptMethod[1] = UdpManager::cEncryptMethodXor;
|
||||
}
|
||||
|
||||
if(setup.port == 0)
|
||||
{
|
||||
m_udpManager = 0;
|
||||
UdpManagerMT * m = 0;
|
||||
do
|
||||
{
|
||||
if(! m)
|
||||
{
|
||||
m = new UdpManagerMT(&p);
|
||||
}
|
||||
|
||||
m_udpManager = m;
|
||||
setBindPort(static_cast<unsigned short>(m_udpManager->GetLocalPort()));
|
||||
if(isPortReserved(getBindPort()))
|
||||
{
|
||||
m = new UdpManagerMT(&p);
|
||||
m_udpManager->Release();
|
||||
m_udpManager = 0;
|
||||
}
|
||||
} while(! m_udpManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_udpManager = new UdpManagerMT(&p);
|
||||
setBindPort(static_cast<unsigned short>(m_udpManager->GetLocalPort()));
|
||||
}
|
||||
|
||||
newManager(m_udpManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tcpServer = new TcpServer(this, realAddress, setup.port);
|
||||
setBindPort(m_tcpServer->getBindPort());
|
||||
}
|
||||
|
||||
if(realAddress.length() > 0)
|
||||
{
|
||||
setBindAddress(realAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
setBindAddress(NetworkHandler::getHostName());
|
||||
}
|
||||
|
||||
m_maxConnections = setup.maxConnections;
|
||||
newService(this);
|
||||
|
||||
m_callback->connect(*this, &Service::onConnectionClosed);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
Service::~Service()
|
||||
{
|
||||
removeService(this);
|
||||
|
||||
for (std::set<Connection *>::const_iterator i = connections.begin(); i != connections.end(); ++i)
|
||||
{
|
||||
Connection *c = *i;
|
||||
c->setDisconnectReason("Service destroyed");
|
||||
c->setService(0);
|
||||
c->disconnect();
|
||||
}
|
||||
|
||||
delete connectionAllocator;
|
||||
delete m_callback;
|
||||
|
||||
connections.clear();
|
||||
connectionAllocator = NULL;
|
||||
m_callback = NULL;
|
||||
delete m_tcpServer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::onConnectionClosed(Connection * c)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
std::set<Connection *>::iterator f = connections.find(c);
|
||||
if (f != connections.end())
|
||||
{
|
||||
if (m_tcpServer)
|
||||
m_tcpServer->onConnectionClosed(c->getTcpClient());
|
||||
connections.erase(f);
|
||||
}
|
||||
c->setService(0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::onConnectionOpened(Connection * c)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
c->setService(this);
|
||||
c->onConnectionOpened();
|
||||
connections.insert(c);
|
||||
WARNING((connections.size() >= static_cast<size_t>(m_maxConnections)), ("Service has reached it's maximum connection count %d", m_maxConnections));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::onConnectionOpened(UdpConnectionMT * u)
|
||||
{
|
||||
DEBUG_REPORT_LOG(true, ("connection opened for service on port %d\n", getBindPort()));
|
||||
Connection * c = connectionAllocator->allocateConnection(u);
|
||||
onConnectionOpened(c);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::onConnectionOpened(TcpClient * c)
|
||||
{
|
||||
Connection * conn = connectionAllocator->allocateConnection(0, c);
|
||||
onConnectionOpened(conn);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::removeConnection(Connection * c)
|
||||
{
|
||||
std::set<Connection *>::iterator f = connections.find(c);
|
||||
if (f != connections.end())
|
||||
connections.erase(f);
|
||||
c->setService(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
int Service::flushAndConfirmAllData()
|
||||
{
|
||||
std::set<Connection *>::const_iterator i;
|
||||
|
||||
if(m_udpManager)
|
||||
{
|
||||
int totalBytesPending = 0;
|
||||
unsigned long startTime = Clock::timeMs();
|
||||
bool needReport = false;
|
||||
unsigned long stallReportDelay = ConfigSharedNetwork::getStallReportDelay();
|
||||
do
|
||||
{
|
||||
if(stallReportDelay > 0)
|
||||
{
|
||||
if(Clock::timeMs() - stallReportDelay > startTime)
|
||||
{
|
||||
needReport = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_udpManager->GiveTime();
|
||||
totalBytesPending = 0;
|
||||
for(i = connections.begin(); i != connections.end(); ++i)
|
||||
{
|
||||
if(needReport)
|
||||
{
|
||||
if((*i)->udpConnection->TotalPendingBytes() > 0)
|
||||
{
|
||||
(*i)->onConnectionStalled(Clock::timeMs() - startTime);
|
||||
}
|
||||
}
|
||||
totalBytesPending += (*i)->udpConnection->TotalPendingBytes();
|
||||
}
|
||||
|
||||
if(needReport)
|
||||
{
|
||||
stallReportDelay += ConfigSharedNetwork::getStallReportDelay();
|
||||
needReport = false;
|
||||
}
|
||||
} while(totalBytesPending > 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::logBackloggedPackets()
|
||||
{
|
||||
static const int threshold = ConfigSharedNetwork::getLogBackloggedPacketThreshold();
|
||||
std::set<Connection *>::iterator i;
|
||||
for(i = connections.begin(); i != connections.end(); ++i)
|
||||
{
|
||||
int pendingBytes = (*i)->getPendingBytes();
|
||||
if(pendingBytes > threshold)
|
||||
{
|
||||
LOG("Network", ("Backlog:%s:%s [%d] bytes still pending, congestion window size=%d. ack average ping=%d, oldest unacknowledged=%d, lastSend=%d, lastReceive=%d", (*i)->getRemoteAddress().c_str(), (*i)->getConnectionDescription().c_str(), pendingBytes, (*i)->getCongestionWindowSize(), (*i)->getAckAveragePing(), (*i)->getOldestUnacknowledgedAge(), (*i)->getLastSend(), (*i)->getLastReceive()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void Service::updateTcp()
|
||||
{
|
||||
if(m_tcpServer)
|
||||
{
|
||||
m_tcpServer->update();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Service::broadcast(Archive::ByteStream const &bs, bool reliable)
|
||||
{
|
||||
for (std::set<Connection *>::const_iterator i = connections.begin(); i != connections.end(); ++i)
|
||||
(*i)->send(bs, reliable);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Service.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_Service_H
|
||||
#define INCLUDED_Service_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
class Connection;
|
||||
class UdpConnectionMT;
|
||||
class NetworkSetupData;
|
||||
class TcpServer;
|
||||
class TcpClient;
|
||||
|
||||
namespace Archive
|
||||
{
|
||||
class ByteStream;
|
||||
}
|
||||
|
||||
namespace MessageDispatch
|
||||
{
|
||||
class Callback;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct ConnectionAllocatorBase
|
||||
{
|
||||
virtual ~ConnectionAllocatorBase() = 0;
|
||||
virtual ConnectionAllocatorBase * clone() const = 0;
|
||||
virtual Connection * allocateConnection(UdpConnectionMT *, TcpClient * t = 0) const = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<typename ConnectionType>
|
||||
struct ConnectionAllocator : public ConnectionAllocatorBase
|
||||
{
|
||||
ConnectionAllocatorBase * clone() const
|
||||
{
|
||||
return new ConnectionAllocator<ConnectionType>;
|
||||
}
|
||||
|
||||
Connection * allocateConnection(UdpConnectionMT * u, TcpClient * t = 0) const
|
||||
{
|
||||
return new ConnectionType(u, t);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Service : public NetworkHandler
|
||||
{
|
||||
public:
|
||||
//Service(const ConnectionAllocatorBase & connectionAllocator, const unsigned short listenPort, const int maxConnections, const int keepAliveDelay = 1000, const std::string & interfaceAddress = std::string(""), const bool compress=false);
|
||||
Service(const ConnectionAllocatorBase & connectionAllocator, const NetworkSetupData & setupData);
|
||||
virtual ~Service();
|
||||
|
||||
void onConnectionOpened(TcpClient * t);
|
||||
void onConnectionOpened(Connection * c);
|
||||
virtual void onConnectionOpened(UdpConnectionMT * udpConnection);
|
||||
virtual void onConnectionClosed(Connection * connection);
|
||||
void logBackloggedPackets();
|
||||
|
||||
template<typename ConnectionType>
|
||||
void setConnectionAllocator(const ConnectionType * const)
|
||||
{
|
||||
connectionAllocator = new ConnectionAllocator<ConnectionType>();
|
||||
}
|
||||
|
||||
int flushAndConfirmAllData();
|
||||
void removeConnection(Connection * c);
|
||||
void updateTcp();
|
||||
void broadcast(Archive::ByteStream const &bs, bool reliable);
|
||||
|
||||
private:
|
||||
Service & operator = (const Service & rhs);
|
||||
Service(const Service & source);
|
||||
|
||||
const ConnectionAllocatorBase * connectionAllocator;
|
||||
std::set<Connection *> connections;
|
||||
int m_maxConnections;
|
||||
MessageDispatch::Callback * m_callback;
|
||||
TcpServer * m_tcpServer;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_Service_H
|
||||
@@ -0,0 +1,73 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SetupSharedNetwork.cpp
|
||||
// Copyright 2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/SetupSharedNetwork.h"
|
||||
|
||||
#include "sharedDebug/InstallTimer.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace SetupSharedNetworkNamespace
|
||||
{
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void remove();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
bool s_installed;
|
||||
}
|
||||
|
||||
using namespace SetupSharedNetworkNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void SetupSharedNetworkNamespace::remove()
|
||||
{
|
||||
DEBUG_FATAL(!s_installed, ("SetupSharedNetworkNamespace not installed."));
|
||||
s_installed = false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void SetupSharedNetwork::getDefaultClientSetupData(SetupData &data)
|
||||
{
|
||||
//-- It is extremely important to have this value setup correctly for the client and server.
|
||||
// The client should not be able to muck with this since it influences things like
|
||||
// movement validation.
|
||||
data.m_clockSyncDelay = 45000;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SetupSharedNetwork::getDefaultServerSetupData(SetupData &data)
|
||||
{
|
||||
//-- It is extremely important to have this value setup correctly for the client and server.
|
||||
// The client should not be able to muck with this since it influences things like
|
||||
// movement validation.
|
||||
data.m_clockSyncDelay = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void SetupSharedNetwork::install(SetupData &setupData)
|
||||
{
|
||||
InstallTimer const installTimer("SetupSharedNetwork::install");
|
||||
|
||||
DEBUG_FATAL(s_installed, ("SetupSharedNetwork already installed."));
|
||||
|
||||
ConfigSharedNetwork::install(setupData.m_clockSyncDelay);
|
||||
|
||||
s_installed = true;
|
||||
ExitChain::add(remove, "SetupSharedNetwork");
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,34 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// SetupSharedNetwork.h
|
||||
// Copyright 2003 Sony Online Entertainment, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_SetupSharedNetwork_H
|
||||
#define INCLUDED_SetupSharedNetwork_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class SetupSharedNetwork
|
||||
{
|
||||
public:
|
||||
|
||||
struct SetupData
|
||||
{
|
||||
int m_clockSyncDelay;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static void getDefaultClientSetupData(SetupData &data);
|
||||
static void getDefaultServerSetupData(SetupData &data);
|
||||
|
||||
static void install(SetupData &setupData);
|
||||
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,328 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Events.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "Events.h"
|
||||
#include "UdpHandlerMT.h"
|
||||
#include "sharedSynchronization/Guard.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static unsigned char *s_outgoingEventData;
|
||||
static int s_outgoingEventSize;
|
||||
static int s_outgoingEventMax;
|
||||
static unsigned char *s_incomingEventData;
|
||||
static int s_incomingEventSize;
|
||||
static int s_incomingEventMax;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
inline int padEventLength(int length)
|
||||
{
|
||||
return (length+15)&(~15);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static void growIncoming(int amount)
|
||||
{
|
||||
int newSize = s_incomingEventSize + amount;
|
||||
if (newSize > s_incomingEventMax)
|
||||
{
|
||||
int newMax = s_incomingEventMax*2;
|
||||
while (newSize > newMax)
|
||||
newMax *= 2;
|
||||
unsigned char *newData = new unsigned char[newMax];
|
||||
memcpy(newData, s_incomingEventData, s_incomingEventSize);
|
||||
delete [] s_incomingEventData;
|
||||
s_incomingEventData = newData;
|
||||
s_incomingEventMax = newMax;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void growOutgoing(int amount)
|
||||
{
|
||||
int newSize = s_outgoingEventSize + amount;
|
||||
if (newSize > s_outgoingEventMax)
|
||||
{
|
||||
int newMax = s_outgoingEventMax*2;
|
||||
while (newSize > newMax)
|
||||
newMax *= 2;
|
||||
unsigned char *newData = new unsigned char[newMax];
|
||||
memcpy(newData, s_outgoingEventData, s_outgoingEventSize);
|
||||
delete [] s_outgoingEventData;
|
||||
s_outgoingEventData = newData;
|
||||
s_outgoingEventMax = newMax;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void Events::install()
|
||||
{
|
||||
s_incomingEventMax = 1024*1024;
|
||||
s_incomingEventData = new unsigned char[s_incomingEventMax];
|
||||
s_outgoingEventMax = 1024*1024;
|
||||
s_outgoingEventData = new unsigned char[s_outgoingEventMax];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::remove()
|
||||
{
|
||||
delete [] s_incomingEventData;
|
||||
s_incomingEventData = 0;
|
||||
delete [] s_outgoingEventData;
|
||||
s_outgoingEventData = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::processIncoming()
|
||||
{
|
||||
int pos = 0;
|
||||
while (pos < s_incomingEventSize)
|
||||
{
|
||||
EventBase *event = reinterpret_cast<EventBase*>(s_incomingEventData+pos);
|
||||
switch (event->getType())
|
||||
{
|
||||
case ET_Receive:
|
||||
reinterpret_cast<EventReceive *>(event)->process(s_incomingEventData+pos+sizeof(EventReceive));
|
||||
break;
|
||||
case ET_ConnectComplete:
|
||||
reinterpret_cast<EventConnectComplete *>(event)->process();
|
||||
break;
|
||||
case ET_ConnectRequest:
|
||||
reinterpret_cast<EventConnectRequest *>(event)->process();
|
||||
break;
|
||||
case ET_Terminated:
|
||||
reinterpret_cast<EventTerminated *>(event)->process();
|
||||
break;
|
||||
default:
|
||||
FATAL(true, ("Unknown incoming event type"));
|
||||
break;
|
||||
}
|
||||
pos += event->getLength();
|
||||
}
|
||||
s_incomingEventSize = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::processOutgoing()
|
||||
{
|
||||
int pos = 0;
|
||||
while (pos < s_outgoingEventSize)
|
||||
{
|
||||
EventBase *event = reinterpret_cast<EventBase*>(s_outgoingEventData+pos);
|
||||
switch (event->getType())
|
||||
{
|
||||
case ET_SendRaw:
|
||||
reinterpret_cast<EventSendRaw *>(event)->process(s_outgoingEventData+pos+sizeof(EventSendRaw));
|
||||
break;
|
||||
case ET_SendLogicalPacket:
|
||||
reinterpret_cast<EventSendLogicalPacket *>(event)->process();
|
||||
break;
|
||||
default:
|
||||
FATAL(true, ("Unknown incoming event type"));
|
||||
break;
|
||||
}
|
||||
pos += event->getLength();
|
||||
}
|
||||
s_outgoingEventSize = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::pushIncomingEventReceive(UdpConnectionMT *udpConnectionMT, unsigned char const *data, int dataLen)
|
||||
{
|
||||
int length = padEventLength(sizeof(EventReceive)+dataLen);
|
||||
growIncoming(length);
|
||||
new(s_incomingEventData+s_incomingEventSize) EventReceive(udpConnectionMT, dataLen);
|
||||
memcpy(s_incomingEventData+s_incomingEventSize+sizeof(EventReceive), data, dataLen);
|
||||
s_incomingEventSize += length;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::pushIncomingEventConnectComplete(UdpConnectionMT *udpConnectionMT)
|
||||
{
|
||||
int length = padEventLength(sizeof(EventConnectComplete));
|
||||
growIncoming(length);
|
||||
new(s_incomingEventData+s_incomingEventSize) EventConnectComplete(udpConnectionMT);
|
||||
s_incomingEventSize += length;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::pushIncomingEventConnectRequest(UdpManagerHandlerMT *udpManagerHandlerMT, UdpConnection *udpConnection)
|
||||
{
|
||||
int length = padEventLength(sizeof(EventConnectRequest));
|
||||
growIncoming(length);
|
||||
new(s_incomingEventData+s_incomingEventSize) EventConnectRequest(udpManagerHandlerMT, udpConnection);
|
||||
s_incomingEventSize += length;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::pushIncomingEventTerminated(UdpConnectionMT *udpConnectionMT)
|
||||
{
|
||||
int length = padEventLength(sizeof(EventTerminated));
|
||||
growIncoming(length);
|
||||
new(s_incomingEventData+s_incomingEventSize) EventTerminated(udpConnectionMT);
|
||||
s_incomingEventSize += length;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::pushOutgoingEventSendRaw(UdpConnection *udpConnection, UdpChannel udpChannel, unsigned char const *data, int dataLen)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
int length = padEventLength(sizeof(EventSendRaw)+dataLen);
|
||||
growOutgoing(length);
|
||||
new(s_outgoingEventData+s_outgoingEventSize) EventSendRaw(udpConnection, udpChannel, dataLen);
|
||||
memcpy(s_outgoingEventData+s_outgoingEventSize+sizeof(EventSendRaw), data, dataLen);
|
||||
s_outgoingEventSize += length;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Events::pushOutgoingEventSendLogicalPacket(UdpConnection *udpConnection, UdpChannel udpChannel, LogicalPacket const *logicalPacket)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
int length = padEventLength(sizeof(EventSendLogicalPacket));
|
||||
growOutgoing(length);
|
||||
new(s_outgoingEventData+s_outgoingEventSize) EventSendLogicalPacket(udpConnection, udpChannel, logicalPacket);
|
||||
s_outgoingEventSize += length;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventBase::EventBase(EventType eventType, int length) :
|
||||
m_eventType(eventType),
|
||||
m_length(padEventLength(length))
|
||||
{
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventReceive::EventReceive(UdpConnectionMT *udpConnectionMT, int dataLen) :
|
||||
EventBase(ET_Receive, sizeof(EventReceive)+dataLen),
|
||||
m_udpConnectionMT(udpConnectionMT),
|
||||
m_dataLen(dataLen)
|
||||
{
|
||||
udpConnectionMT->AddRef();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void EventReceive::process(unsigned char const *data)
|
||||
{
|
||||
m_udpConnectionMT->processReceive(data, m_dataLen);
|
||||
m_udpConnectionMT->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventConnectComplete::EventConnectComplete(UdpConnectionMT *udpConnectionMT) :
|
||||
EventBase(ET_ConnectComplete, sizeof(EventConnectComplete)),
|
||||
m_udpConnectionMT(udpConnectionMT)
|
||||
{
|
||||
udpConnectionMT->AddRef();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void EventConnectComplete::process()
|
||||
{
|
||||
m_udpConnectionMT->processConnectComplete();
|
||||
m_udpConnectionMT->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventConnectRequest::EventConnectRequest(UdpManagerHandlerMT *udpManagerHandlerMT, UdpConnection *udpConnection) :
|
||||
EventBase(ET_ConnectRequest, sizeof(EventConnectRequest)),
|
||||
m_udpManagerHandlerMT(udpManagerHandlerMT),
|
||||
m_udpConnectionMT(0)
|
||||
{
|
||||
udpManagerHandlerMT->AddRef();
|
||||
udpConnection->AddRef();
|
||||
m_udpConnectionMT = new UdpConnectionMT(udpConnection);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void EventConnectRequest::process()
|
||||
{
|
||||
m_udpManagerHandlerMT->OnConnectRequest(m_udpConnectionMT);
|
||||
m_udpConnectionMT->Release();
|
||||
m_udpManagerHandlerMT->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventTerminated::EventTerminated(UdpConnectionMT *udpConnectionMT) :
|
||||
EventBase(ET_Terminated, sizeof(EventTerminated)),
|
||||
m_udpConnectionMT(udpConnectionMT)
|
||||
{
|
||||
udpConnectionMT->AddRef();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void EventTerminated::process()
|
||||
{
|
||||
m_udpConnectionMT->processTerminated();
|
||||
m_udpConnectionMT->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventSendRaw::EventSendRaw(UdpConnection *udpConnection, UdpChannel udpChannel, int dataLen) :
|
||||
EventBase(ET_SendRaw, sizeof(EventSendRaw)+dataLen),
|
||||
m_udpConnection(udpConnection),
|
||||
m_udpChannel(udpChannel),
|
||||
m_dataLen(dataLen)
|
||||
{
|
||||
udpConnection->AddRef();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void EventSendRaw::process(unsigned char const *data)
|
||||
{
|
||||
m_udpConnection->Send(m_udpChannel, data, m_dataLen);
|
||||
m_udpConnection->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
EventSendLogicalPacket::EventSendLogicalPacket(UdpConnection *udpConnection, UdpChannel udpChannel, LogicalPacket const *logicalPacket) :
|
||||
EventBase(ET_SendLogicalPacket, sizeof(EventSendLogicalPacket)),
|
||||
m_udpConnection(udpConnection),
|
||||
m_udpChannel(udpChannel),
|
||||
m_logicalPacket(logicalPacket)
|
||||
{
|
||||
udpConnection->AddRef();
|
||||
logicalPacket->AddRef();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void EventSendLogicalPacket::process()
|
||||
{
|
||||
m_udpConnection->Send(m_udpChannel, m_logicalPacket);
|
||||
m_logicalPacket->Release();
|
||||
m_udpConnection->Release();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Events.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _Events_H_
|
||||
#define _Events_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "UdpLibraryMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
enum EventType
|
||||
{
|
||||
// incoming event types
|
||||
ET_ConnectComplete,
|
||||
ET_ConnectRequest,
|
||||
ET_Receive,
|
||||
ET_Terminated,
|
||||
// outgoing event types
|
||||
ET_SendLogicalPacket,
|
||||
ET_SendRaw
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class Events
|
||||
{
|
||||
public:
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
static void processIncoming();
|
||||
static void processOutgoing();
|
||||
|
||||
static void pushIncomingEventReceive(UdpConnectionMT *udpConnectionMT, unsigned char const *data, int dataLen);
|
||||
static void pushIncomingEventConnectComplete(UdpConnectionMT *udpConnectionMT);
|
||||
static void pushIncomingEventConnectRequest(UdpManagerHandlerMT *udpManagerHandlerMT, UdpConnection *udpConnection);
|
||||
static void pushIncomingEventTerminated(UdpConnectionMT *udpConnectionMT);
|
||||
static void pushOutgoingEventSendRaw(UdpConnection *udpConnection, UdpChannel udpChannel, unsigned char const *data, int dataLen);
|
||||
static void pushOutgoingEventSendLogicalPacket(UdpConnection *udpConnection, UdpChannel udpChannel, LogicalPacket const *logicalPacket);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventBase
|
||||
{
|
||||
public:
|
||||
EventBase(EventType eventType, int length);
|
||||
|
||||
EventType getType() const;
|
||||
int getLength() const;
|
||||
|
||||
private:
|
||||
EventType m_eventType;
|
||||
int m_length;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline EventType EventBase::getType() const
|
||||
{
|
||||
return m_eventType;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline int EventBase::getLength() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventReceive: public EventBase
|
||||
{
|
||||
public:
|
||||
EventReceive(UdpConnectionMT *udpConnectionMT, int dataLen);
|
||||
void process(unsigned char const *data);
|
||||
|
||||
private:
|
||||
UdpConnectionMT *m_udpConnectionMT;
|
||||
int m_dataLen;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventConnectComplete: public EventBase
|
||||
{
|
||||
public:
|
||||
EventConnectComplete(UdpConnectionMT *udpConnectionMT);
|
||||
void process();
|
||||
|
||||
private:
|
||||
UdpConnectionMT *m_udpConnectionMT;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventConnectRequest: public EventBase
|
||||
{
|
||||
public:
|
||||
EventConnectRequest(UdpManagerHandlerMT *udpManagerHandlerMT, UdpConnection *udpConnection);
|
||||
void process();
|
||||
|
||||
private:
|
||||
UdpManagerHandlerMT *m_udpManagerHandlerMT;
|
||||
UdpConnectionMT *m_udpConnectionMT;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventTerminated: public EventBase
|
||||
{
|
||||
public:
|
||||
EventTerminated(UdpConnectionMT *udpConnectionMT);
|
||||
void process();
|
||||
|
||||
private:
|
||||
UdpConnectionMT *m_udpConnectionMT;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventSendRaw: public EventBase
|
||||
{
|
||||
public:
|
||||
EventSendRaw(UdpConnection *udpConnection, UdpChannel udpChannel, int dataLen);
|
||||
void process(unsigned char const *data);
|
||||
|
||||
private:
|
||||
UdpConnection *m_udpConnection;
|
||||
UdpChannel m_udpChannel;
|
||||
int m_dataLen;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventSendLogicalPacket: public EventBase
|
||||
{
|
||||
public:
|
||||
EventSendLogicalPacket(UdpConnection *udpConnection, UdpChannel udpChannel, LogicalPacket const *logicalPacket);
|
||||
void process();
|
||||
|
||||
private:
|
||||
UdpConnection *m_udpConnection;
|
||||
UdpChannel m_udpChannel;
|
||||
LogicalPacket const *m_logicalPacket;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _Events_H_
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpConnectionHandlerMT.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "UdpConnectionHandlerMT.h"
|
||||
#include "UdpConnectionMT.h"
|
||||
#include "UdpLibraryMT.h"
|
||||
#include "Events.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
UdpConnectionHandlerMT::UdpConnectionHandlerMT() :
|
||||
m_refCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpConnectionHandlerMT::~UdpConnectionHandlerMT()
|
||||
{
|
||||
DEBUG_FATAL (m_refCount != 0, ("UdpConnectionHandlerMT dtor called with nonzero refcount"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerMT::AddRef()
|
||||
{
|
||||
++m_refCount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerMT::Release()
|
||||
{
|
||||
if (--m_refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerMT::OnConnectComplete(UdpConnectionMT *)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerMT::OnTerminated(UdpConnectionMT *)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerMT::OnPacketCorrupt(UdpConnectionMT *con, const uchar *data, int dataLen, UdpCorruptionReason reason)
|
||||
{
|
||||
UNREF(con);
|
||||
UNREF(data);
|
||||
UNREF(dataLen);
|
||||
UNREF(reason);
|
||||
con->Disconnect();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpConnectionHandlerMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpConnectionHandlerMT_H_
|
||||
#define _UdpConnectionHandlerMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "UdpLibrary.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionMT;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionHandlerMT
|
||||
{
|
||||
public:
|
||||
UdpConnectionHandlerMT();
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
virtual void OnRoutePacket(UdpConnectionMT *con, unsigned char const *data, int dataLen) = 0;
|
||||
virtual void OnConnectComplete(UdpConnectionMT *con);
|
||||
virtual void OnTerminated(UdpConnectionMT *con);
|
||||
virtual void OnPacketCorrupt(UdpConnectionMT *con, const uchar *data, int dataLen, UdpCorruptionReason reason);
|
||||
|
||||
private:
|
||||
UdpConnectionHandlerMT(UdpConnectionHandlerMT const &);
|
||||
UdpConnectionHandlerMT &operator=(UdpConnectionHandlerMT const &);
|
||||
|
||||
protected:
|
||||
virtual ~UdpConnectionHandlerMT();
|
||||
|
||||
private:
|
||||
int m_refCount;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpConnectionHandlerMT_H_
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpConnectionMT.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "UdpLibraryMT.h"
|
||||
#include "UdpConnectionHandlerMT.h"
|
||||
#include "Events.h"
|
||||
#include "sharedSynchronization/Guard.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionHandlerInternal: public UdpConnectionHandler
|
||||
{
|
||||
public:
|
||||
UdpConnectionHandlerInternal();
|
||||
|
||||
void setOwner(UdpConnectionHandlerMT *owner);
|
||||
void processReceive(UdpConnectionMT *conMT, unsigned char const *data, int dataLen);
|
||||
void processTerminated(UdpConnectionMT *conMT);
|
||||
void processConnectComplete(UdpConnectionMT *conMT);
|
||||
|
||||
virtual void OnRoutePacket(UdpConnection *con, unsigned char const *data, int dataLen);
|
||||
virtual void OnConnectComplete(UdpConnection *con);
|
||||
virtual void OnTerminated(UdpConnection *con);
|
||||
virtual void OnPacketCorrupt(UdpConnection *con, const uchar *data, int dataLen, UdpCorruptionReason reason);
|
||||
|
||||
private:
|
||||
UdpConnectionHandlerInternal(UdpConnectionHandlerInternal const &);
|
||||
UdpConnectionHandlerInternal &operator=(UdpConnectionHandlerInternal const &);
|
||||
|
||||
private:
|
||||
UdpConnectionHandlerMT *m_owner;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpConnectionHandlerInternal::UdpConnectionHandlerInternal() :
|
||||
m_owner(0)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::setOwner(UdpConnectionHandlerMT *owner)
|
||||
{
|
||||
m_owner = owner;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::processReceive(UdpConnectionMT *conMT, unsigned char const *data, int dataLen)
|
||||
{
|
||||
if (m_owner)
|
||||
m_owner->OnRoutePacket(conMT, data, dataLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::processTerminated(UdpConnectionMT *conMT)
|
||||
{
|
||||
if (m_owner)
|
||||
m_owner->OnTerminated(conMT);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::processConnectComplete(UdpConnectionMT *conMT)
|
||||
{
|
||||
if (m_owner)
|
||||
m_owner->OnConnectComplete(conMT);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::OnRoutePacket(UdpConnection *con, unsigned char const *data, int dataLen)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
NOT_NULL(conMT);
|
||||
if (UdpLibraryMT::getUseNetworkThread())
|
||||
Events::pushIncomingEventReceive(conMT, data, dataLen);
|
||||
else if (m_owner)
|
||||
m_owner->OnRoutePacket(conMT, data, dataLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::OnConnectComplete(UdpConnection *con)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
NOT_NULL(conMT);
|
||||
if (UdpLibraryMT::getUseNetworkThread())
|
||||
Events::pushIncomingEventConnectComplete(conMT);
|
||||
else if (m_owner)
|
||||
m_owner->OnConnectComplete(conMT);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::OnTerminated(UdpConnection *con)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
NOT_NULL(conMT);
|
||||
if (UdpLibraryMT::getUseNetworkThread())
|
||||
Events::pushIncomingEventTerminated(conMT);
|
||||
else if (m_owner)
|
||||
m_owner->OnTerminated(conMT);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionHandlerInternal::OnPacketCorrupt(UdpConnection *con, const uchar *data, int dataLen, UdpCorruptionReason reason)
|
||||
{
|
||||
UdpConnectionMT * conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
m_owner->OnPacketCorrupt(conMT, data, dataLen, reason);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
// Note: this is only called in situations where the UdpLibraryMT mutex is locked already, and we are taking over a reference already gotten from newing the connection
|
||||
UdpConnectionMT::UdpConnectionMT(UdpConnection *udpConnection) :
|
||||
m_refCount(1),
|
||||
m_udpConnection(udpConnection),
|
||||
m_passThroughData(0),
|
||||
m_connectionHandlerInternal(new UdpConnectionHandlerInternal)
|
||||
{
|
||||
udpConnection->SetPassThroughData(this);
|
||||
udpConnection->SetHandler(m_connectionHandlerInternal);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpConnectionMT::~UdpConnectionMT()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
m_udpConnection->SetHandler(0);
|
||||
m_udpConnection->SetPassThroughData(0);
|
||||
m_udpConnection->Release();
|
||||
m_udpConnection = 0;
|
||||
delete m_connectionHandlerInternal;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::AddRef()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
++m_refCount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::Release()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
if (--m_refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::processReceive(unsigned char const *data, int dataLen)
|
||||
{
|
||||
m_connectionHandlerInternal->processReceive(this, data, dataLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::processTerminated()
|
||||
{
|
||||
m_connectionHandlerInternal->processTerminated(this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::processConnectComplete()
|
||||
{
|
||||
m_connectionHandlerInternal->processConnectComplete(this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool UdpConnectionMT::Send(UdpChannel channel, unsigned char const *data, int dataLen)
|
||||
{
|
||||
if (UdpLibraryMT::getUseNetworkThread())
|
||||
{
|
||||
Events::pushOutgoingEventSendRaw(m_udpConnection, channel, data, dataLen);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return m_udpConnection->Send(channel, data, dataLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool UdpConnectionMT::Send(UdpChannel channel, LogicalPacket const *packet)
|
||||
{
|
||||
if (UdpLibraryMT::getUseNetworkThread())
|
||||
{
|
||||
Events::pushOutgoingEventSendLogicalPacket(m_udpConnection, channel, packet);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return m_udpConnection->Send(channel, packet);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::Disconnect(int flushTimeout)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
m_udpConnection->Disconnect(flushTimeout);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void *UdpConnectionMT::GetPassThroughData() const
|
||||
{
|
||||
return m_passThroughData;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpConnection::DisconnectReason UdpConnectionMT::GetDisconnectReason() const
|
||||
{
|
||||
return m_udpConnection->GetDisconnectReason();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpConnection::Status UdpConnectionMT::GetStatus() const
|
||||
{
|
||||
// TODO: change this after status is cached
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->GetStatus();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpConnectionMT::TotalPendingBytes() const
|
||||
{
|
||||
// TODO: change this after cached
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->TotalPendingBytes();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
unsigned short UdpConnectionMT::ServerSyncStampShort() const
|
||||
{
|
||||
// TODO: is there a cleaner way to deal with this?
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->ServerSyncStampShort();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
unsigned long UdpConnectionMT::ServerSyncStampLong() const
|
||||
{
|
||||
// TODO: is there a cleaner way to deal with this?
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->ServerSyncStampLong();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpIpAddress UdpConnectionMT::GetDestinationIp() const
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->GetDestinationIp();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpConnectionMT::GetDestinationPort() const
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->GetDestinationPort();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::GetChannelStatus(UdpChannel channel, UdpConnection::ChannelStatus *channelStatus) const
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
m_udpConnection->GetChannelStatus(channel, channelStatus);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpConnectionMT::LastReceive() const
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->LastReceive();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpConnectionMT::LastSend() const
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpConnection->LastSend();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::SetHandler(UdpConnectionHandlerMT *handler)
|
||||
{
|
||||
m_connectionHandlerInternal->setOwner(handler);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::SetPassThroughData(void *passThroughData)
|
||||
{
|
||||
m_passThroughData = passThroughData;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpConnectionMT::SetNoDataTimeout(int noDataTimeout)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
m_udpConnection->SetNoDataTimeout(noDataTimeout);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpConnectionMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpConnectionMT_H_
|
||||
#define _UdpConnectionMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "UdpLibrary.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionHandlerMT;
|
||||
class UdpConnectionHandlerInternal;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionMT
|
||||
{
|
||||
public:
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
void processReceive(unsigned char const *data, int dataLen);
|
||||
void processTerminated();
|
||||
void processConnectComplete();
|
||||
|
||||
bool Send(UdpChannel channel, unsigned char const *data, int dataLen);
|
||||
bool Send(UdpChannel channel, LogicalPacket const *packet);
|
||||
void Disconnect(int flushTimeout = 0);
|
||||
|
||||
UdpConnection::DisconnectReason GetDisconnectReason() const;
|
||||
void *GetPassThroughData() const;
|
||||
UdpConnection::Status GetStatus() const;
|
||||
int TotalPendingBytes() const;
|
||||
unsigned short ServerSyncStampShort() const;
|
||||
unsigned long ServerSyncStampLong() const;
|
||||
UdpIpAddress GetDestinationIp() const;
|
||||
int GetDestinationPort() const;
|
||||
void GetChannelStatus(UdpChannel channel, UdpConnection::ChannelStatus *channelStatus) const;
|
||||
int LastReceive() const;
|
||||
int LastSend() const;
|
||||
|
||||
void SetHandler(UdpConnectionHandlerMT *handler);
|
||||
void SetPassThroughData(void *passThroughData);
|
||||
void SetNoDataTimeout(int noDataTimeout);
|
||||
|
||||
private:
|
||||
UdpConnectionMT(UdpConnectionMT const &);
|
||||
UdpConnectionMT &operator=(UdpConnectionMT const &);
|
||||
|
||||
private:
|
||||
friend class UdpManagerMT;
|
||||
friend class UdpManagerHandlerMT;
|
||||
friend class EventConnectRequest;
|
||||
UdpConnectionMT(UdpConnection *udpConnection);
|
||||
~UdpConnectionMT();
|
||||
|
||||
private:
|
||||
int m_refCount;
|
||||
UdpConnection *m_udpConnection;
|
||||
void *m_passThroughData;
|
||||
UdpConnectionHandlerInternal *m_connectionHandlerInternal;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpConnectionMT_H_
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpHandlerMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpHandlerMT_H_
|
||||
#define _UdpHandlerMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "UdpLibrary.h"
|
||||
#include "UdpConnectionHandlerMT.h"
|
||||
#include "UdpManagerHandlerMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpHandlerMT_H_
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpLibraryMT.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "UdpLibraryMT.h"
|
||||
#include "Events.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/Os.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedSynchronization/Guard.h"
|
||||
#include "sharedThread/RunThread.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
bool UdpLibraryMT::ms_useNetworkThread;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static std::set<UdpManager *> s_udpManagers;
|
||||
static std::vector<UdpManager *> s_udpManagerPendingRemoves;
|
||||
static bool s_updating;
|
||||
static volatile bool s_threadRunning;
|
||||
static volatile bool s_threadShutdown;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static void networkThreadFunc()
|
||||
{
|
||||
Thread::getCurrentThread()->setPriority(static_cast<Thread::ePriority>(ConfigSharedNetwork::getNetworkThreadPriority()));
|
||||
while (!s_threadShutdown)
|
||||
{
|
||||
Os::sleep(ConfigSharedNetwork::getNetworkThreadSleepTimeMs());
|
||||
UdpLibraryMT::networkThreadUpdate();
|
||||
}
|
||||
s_threadRunning = false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void startNetworkThread()
|
||||
{
|
||||
s_threadShutdown = false;
|
||||
if (!s_threadRunning)
|
||||
{
|
||||
s_threadRunning = true;
|
||||
runThread(networkThreadFunc);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void stopNetworkThread()
|
||||
{
|
||||
s_threadShutdown = true;
|
||||
while (s_threadRunning)
|
||||
Os::sleep(1);
|
||||
s_threadShutdown = false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void UdpLibraryMT::install()
|
||||
{
|
||||
Events::install();
|
||||
ms_useNetworkThread = ConfigSharedNetwork::getUseNetworkThread();
|
||||
if (ms_useNetworkThread)
|
||||
startNetworkThread();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpLibraryMT::remove()
|
||||
{
|
||||
if (s_threadRunning)
|
||||
stopNetworkThread();
|
||||
|
||||
{
|
||||
Guard lock(getMutex());
|
||||
Events::remove();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
RecursiveMutex &UdpLibraryMT::getMutex()
|
||||
{
|
||||
static RecursiveMutex mutex;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpLibraryMT::registerUdpManager(UdpManager *udpManager)
|
||||
{
|
||||
s_udpManagers.insert(udpManager);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpLibraryMT::unregisterUdpManager(UdpManager *udpManager)
|
||||
{
|
||||
if (s_updating)
|
||||
{
|
||||
udpManager->AddRef();
|
||||
s_udpManagerPendingRemoves.push_back(udpManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::set<UdpManager*>::iterator i = s_udpManagers.find(udpManager);
|
||||
if (i != s_udpManagers.end())
|
||||
s_udpManagers.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpLibraryMT::mainThreadUpdate()
|
||||
{
|
||||
// update from main thread - process incoming events
|
||||
|
||||
Guard lock(getMutex());
|
||||
|
||||
Events::processIncoming();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpLibraryMT::networkThreadUpdate()
|
||||
{
|
||||
// update from network thread - process outgoing events, then give time to the UdpManagers
|
||||
#ifdef _DEBUG
|
||||
unsigned long const lockStart = Clock::timeMs();
|
||||
#endif
|
||||
|
||||
Guard lock(getMutex());
|
||||
|
||||
#ifdef _DEBUG
|
||||
unsigned long const lockStop = Clock::timeMs();
|
||||
#endif
|
||||
|
||||
Events::processOutgoing();
|
||||
|
||||
s_updating = true;
|
||||
|
||||
{
|
||||
for (std::set<UdpManager *>::iterator i = s_udpManagers.begin(); i != s_udpManagers.end(); ++i)
|
||||
(*i)->GiveTime();
|
||||
}
|
||||
|
||||
s_updating = false;
|
||||
|
||||
{
|
||||
for (std::vector<UdpManager *>::iterator i = s_udpManagerPendingRemoves.begin(); i != s_udpManagerPendingRemoves.end(); ++i)
|
||||
{
|
||||
unregisterUdpManager(*i);
|
||||
(*i)->Release();
|
||||
}
|
||||
s_udpManagerPendingRemoves.clear();
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
unsigned long const updateStop = Clock::timeMs();
|
||||
|
||||
if (updateStop - lockStart > 500)
|
||||
{
|
||||
static const Os::OsPID_t id = Os::getProcessId();
|
||||
fprintf(stderr, "Network:PID %d:ThreadUpdate:guard lock time=%lu, processing time = %lu\n", id, lockStop - lockStart, updateStop - lockStop);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpLibraryMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpLibraryMT_H_
|
||||
#define _UdpLibraryMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "UdpLibrary.h"
|
||||
|
||||
#include "UdpConnectionMT.h"
|
||||
#include "UdpManagerMT.h"
|
||||
#include "UdpMiscMT.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class EventBase;
|
||||
class RecursiveMutex;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpLibraryMT
|
||||
{
|
||||
public:
|
||||
static void install();
|
||||
static void remove();
|
||||
|
||||
static RecursiveMutex &getMutex();
|
||||
static bool getUseNetworkThread();
|
||||
static void registerUdpManager(UdpManager *udpManager);
|
||||
static void unregisterUdpManager(UdpManager *udpManager);
|
||||
static void pushOutgoingEvent(EventBase *event);
|
||||
static void pushIncomingEvent(EventBase *event);
|
||||
|
||||
static void mainThreadUpdate();
|
||||
static void networkThreadUpdate();
|
||||
|
||||
private:
|
||||
UdpLibraryMT();
|
||||
UdpLibraryMT(UdpLibraryMT const &);
|
||||
UdpLibraryMT& operator=(UdpLibraryMT const &);
|
||||
|
||||
static bool ms_useNetworkThread;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline bool UdpLibraryMT::getUseNetworkThread()
|
||||
{
|
||||
return ms_useNetworkThread;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpLibraryMT_H_
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpManagerHandlerMT.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "UdpHandlerMT.h"
|
||||
#include "UdpLibraryMT.h"
|
||||
#include "UdpConnectionMT.h"
|
||||
#include "Events.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpManagerHandlerInternal: public UdpManagerHandler
|
||||
{
|
||||
public:
|
||||
UdpManagerHandlerInternal(UdpManagerHandlerMT *owner);
|
||||
|
||||
virtual void OnConnectRequest(UdpConnection *con);
|
||||
virtual int OnUserSuppliedEncrypt(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedDecrypt(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedEncrypt2(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedDecrypt2(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
|
||||
virtual ~UdpManagerHandlerInternal ();
|
||||
|
||||
private:
|
||||
UdpManagerHandlerMT *m_owner;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
UdpManagerHandlerInternal::~UdpManagerHandlerInternal ()
|
||||
{
|
||||
m_owner = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
UdpManagerHandlerInternal::UdpManagerHandlerInternal(UdpManagerHandlerMT *owner) :
|
||||
m_owner(owner)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerHandlerInternal::OnConnectRequest(UdpConnection *con)
|
||||
{
|
||||
m_owner->queueConnectRequest(con);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerInternal::OnUserSuppliedEncrypt(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
return m_owner->OnUserSuppliedEncrypt(conMT, destData, sourceData, sourceLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerInternal::OnUserSuppliedDecrypt(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
return m_owner->OnUserSuppliedDecrypt(conMT, destData, sourceData, sourceLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerInternal::OnUserSuppliedEncrypt2(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
return m_owner->OnUserSuppliedEncrypt2(conMT, destData, sourceData, sourceLen);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerInternal::OnUserSuppliedDecrypt2(UdpConnection *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
UdpConnectionMT *conMT = reinterpret_cast<UdpConnectionMT *>(con->GetPassThroughData());
|
||||
return m_owner->OnUserSuppliedDecrypt2(conMT, destData, sourceData, sourceLen);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
UdpManagerHandlerMT::UdpManagerHandlerMT() :
|
||||
m_refCount(1),
|
||||
m_managerHandler(0)
|
||||
{
|
||||
m_managerHandler = new UdpManagerHandlerInternal(this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpManagerHandlerMT::~UdpManagerHandlerMT()
|
||||
{
|
||||
delete m_managerHandler;
|
||||
m_managerHandler = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerHandlerMT::AddRef()
|
||||
{
|
||||
++m_refCount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerHandlerMT::Release()
|
||||
{
|
||||
if (--m_refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerMT::OnUserSuppliedEncrypt(UdpConnectionMT *, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
memcpy(destData, sourceData, sourceLen);
|
||||
return sourceLen;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
int UdpManagerHandlerMT::OnUserSuppliedDecrypt(UdpConnectionMT *, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
memcpy(destData, sourceData, sourceLen);
|
||||
return sourceLen;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerMT::OnUserSuppliedEncrypt2(UdpConnectionMT *, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
memcpy(destData, sourceData, sourceLen);
|
||||
return sourceLen;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerHandlerMT::OnUserSuppliedDecrypt2(UdpConnectionMT *, unsigned char *destData, unsigned char const *sourceData, int sourceLen)
|
||||
{
|
||||
memcpy(destData, sourceData, sourceLen);
|
||||
return sourceLen;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpManagerHandler *UdpManagerHandlerMT::getManagerHandler()
|
||||
{
|
||||
return m_managerHandler;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerHandlerMT::queueConnectRequest(UdpConnection *con)
|
||||
{
|
||||
|
||||
if (UdpLibraryMT::getUseNetworkThread())
|
||||
Events::pushIncomingEventConnectRequest(this, con);
|
||||
else
|
||||
{
|
||||
con->AddRef();
|
||||
UdpConnectionMT *udpConnectionMT = new UdpConnectionMT(con);
|
||||
OnConnectRequest(udpConnectionMT);
|
||||
udpConnectionMT->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpManagerHandlerMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpManagerHandlerMT_H_
|
||||
#define _UdpManagerHandlerMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionMT;
|
||||
class UdpManagerHandlerInternal;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpManagerHandlerMT
|
||||
{
|
||||
public:
|
||||
UdpManagerHandlerMT();
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
virtual void OnConnectRequest(UdpConnectionMT *con) = 0;
|
||||
virtual int OnUserSuppliedEncrypt(UdpConnectionMT *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedDecrypt(UdpConnectionMT *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedEncrypt2(UdpConnectionMT *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
virtual int OnUserSuppliedDecrypt2(UdpConnectionMT *con, unsigned char *destData, unsigned char const *sourceData, int sourceLen);
|
||||
|
||||
UdpManagerHandler *getManagerHandler();
|
||||
void update();
|
||||
|
||||
private:
|
||||
UdpManagerHandlerMT(UdpManagerHandlerMT const &);
|
||||
UdpManagerHandlerMT &operator=(UdpManagerHandlerMT const &);
|
||||
|
||||
protected:
|
||||
virtual ~UdpManagerHandlerMT();
|
||||
|
||||
friend class UdpManagerHandlerInternal;
|
||||
void queueConnectRequest(UdpConnection *con);
|
||||
|
||||
private:
|
||||
int m_refCount;
|
||||
UdpManagerHandlerInternal *m_managerHandler;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpManagerHandlerMT_H_
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpManagerMT.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "UdpManagerMT.h"
|
||||
#include "UdpLibraryMT.h"
|
||||
#include "sharedSynchronization/Guard.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
UdpManagerMT::UdpManagerMT(UdpManager::Params *params) :
|
||||
m_refCount(1),
|
||||
m_udpManager(0)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
m_udpManager = new UdpManager(params);
|
||||
UdpLibraryMT::registerUdpManager(m_udpManager);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpManagerMT::~UdpManagerMT()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
UdpLibraryMT::unregisterUdpManager(m_udpManager);
|
||||
m_udpManager->SetHandler(0);
|
||||
m_udpManager->Release();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerMT::AddRef()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
++m_refCount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
void UdpManagerMT::Release()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
if (--m_refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerMT::GiveTime()
|
||||
{
|
||||
if (!UdpLibraryMT::getUseNetworkThread())
|
||||
m_udpManager->GiveTime();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
UdpConnectionMT *UdpManagerMT::EstablishConnection(char const *serverAddress, int serverPort, int timeout)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
UdpConnection *connection = m_udpManager->EstablishConnection(serverAddress, serverPort, timeout);
|
||||
if (connection)
|
||||
return new UdpConnectionMT(connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
LogicalPacket const *UdpManagerMT::CreatePacket(void const *data, int dataLen, void const *data2, int dataLen2)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpManager->CreatePacket(data, dataLen, data2, dataLen2);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int UdpManagerMT::GetLocalPort()
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return m_udpManager->GetLocalPort();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpManagerMT::ClearHandler()
|
||||
{
|
||||
m_udpManager->SetHandler(0);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpManagerMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpManagerMT_H_
|
||||
#define _UdpManagerMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "UdpLibrary.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpConnectionMT;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpManagerMT
|
||||
{
|
||||
public:
|
||||
typedef UdpManager::Params Params;
|
||||
|
||||
public:
|
||||
UdpManagerMT(UdpManager::Params *params);
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
void GiveTime();
|
||||
|
||||
UdpConnectionMT *EstablishConnection(char const *serverAddress, int serverPort, int timeout = 0);
|
||||
LogicalPacket const *CreatePacket(void const *data, int dataLen, void const *data2 = 0, int dataLen2 = 0);
|
||||
void ClearHandler();
|
||||
int GetLocalPort();
|
||||
|
||||
private:
|
||||
UdpManagerMT(UdpManagerMT const &);
|
||||
UdpManagerMT& operator=(UdpManagerMT const &);
|
||||
|
||||
~UdpManagerMT();
|
||||
|
||||
private:
|
||||
int m_refCount;
|
||||
UdpManager *m_udpManager;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpManagerMT_H_
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpMiscMT.cpp
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "UdpMiscMT.h"
|
||||
#include "UdpLibraryMT.h"
|
||||
#include "sharedSynchronization/Guard.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
LogicalPacket const *UdpMiscMT::CreateQuickLogicalPacket(void const *data, int dataLen, void const *data2, int dataLen2)
|
||||
{
|
||||
Guard lock(UdpLibraryMT::getMutex());
|
||||
return UdpMisc::CreateQuickLogicalPacket(data, dataLen, data2, dataLen2);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// UdpMiscMT.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef _UdpMiscMT_H_
|
||||
#define _UdpMiscMT_H_
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class LogicalPacket;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
class UdpMiscMT
|
||||
{
|
||||
public:
|
||||
static LogicalPacket const *CreateQuickLogicalPacket(void const *data, int dataLen, void const *data2 = 0, int dataLen2 = 0);
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _UdpMiscMT_H_
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// UdpSock.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#ifndef INCLUDED_UdpSock_H
|
||||
#define INCLUDED_UdpSock_H
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/Sock.h"
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief a datagram socket
|
||||
|
||||
The UdpSock class describes an abstraction for datagram sockets.
|
||||
UdpSock sends and receives unreliably with no flow control.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class UdpSock : public Sock
|
||||
{
|
||||
public:
|
||||
UdpSock();
|
||||
virtual ~UdpSock();
|
||||
|
||||
virtual const unsigned int recvFrom (Address & outTargetAddress, void * targetBuffer, const unsigned int bufferSize) const;
|
||||
virtual const unsigned int sendTo (const Address & targetAddress, const void * sourceBuffer, const unsigned int length) const;
|
||||
void enableBroadcast ();
|
||||
|
||||
private:
|
||||
UdpSock(const UdpSock & source);
|
||||
UdpSock & operator = (const UdpSock & source);
|
||||
};
|
||||
|
||||
/**
|
||||
\include TestUdpSock.h
|
||||
\example TestUdpSock.cpp
|
||||
*/
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#endif // _UdpSock_H
|
||||
@@ -0,0 +1,404 @@
|
||||
// Address.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <winsock.h>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Construct an empty address (INADDR_ANY)
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::Address() :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress("0.0.0.0")
|
||||
{
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_family = AF_INET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct an address from a human readable dotted-decimal
|
||||
host address and port
|
||||
|
||||
Care should be taken when using this constructor. It could potentially
|
||||
invoke gethostbyname() and block while the resolver returns a
|
||||
valid ip address.
|
||||
|
||||
@author Justin Randall
|
||||
|
||||
@todo Add a static resolver cache to Address to reduce potential
|
||||
calls to gethostbyname()
|
||||
*/
|
||||
Address::Address(const std::string & newHostAddress, const unsigned short newHostPort) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(newHostAddress)
|
||||
{
|
||||
HOSTENT * h;
|
||||
unsigned long u;
|
||||
|
||||
memset(addr4, 0, sizeof(struct sockaddr_in));
|
||||
addr4->sin_port = htons(newHostPort);
|
||||
addr4->sin_family = AF_INET;
|
||||
// was an address supplied?
|
||||
if(hostAddress.size() > 0)
|
||||
{
|
||||
// Is the first byte a number? (IP names begin with an alpha)
|
||||
if(!isdigit(hostAddress[0]))
|
||||
{
|
||||
// The first byte is a letter, resolve it
|
||||
if( (h = gethostbyname(hostAddress.c_str())) != 0)
|
||||
{
|
||||
memcpy(&addr4->sin_addr, h->h_addr_list[0], sizeof(addr4->sin_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// boom! grab the entry from the h_addr member instead!
|
||||
if( (h = gethostbyname(hostAddress.c_str())) != 0)
|
||||
{
|
||||
memcpy(&addr4->sin_addr, h->h_addr, sizeof(addr4->sin_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// no resolution, INADDR_ANY
|
||||
// could be that the network needs a kick in the ass
|
||||
memset(&addr4->sin_addr, 0, sizeof(addr4->sin_addr));
|
||||
}
|
||||
}
|
||||
|
||||
// extract IP bytes from ipv4add4
|
||||
const unsigned char * ip;
|
||||
char name[17] = {"\0"};
|
||||
|
||||
ip = reinterpret_cast<const unsigned char *>(&addr4->sin_addr);
|
||||
_snprintf(name, 17, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); //lint !e534
|
||||
hostAddress = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A dotted decimal ip number string was supplied. Convert for sin_addr
|
||||
u = inet_addr(hostAddress.c_str());
|
||||
memcpy(&addr4->sin_addr, &u, sizeof(addr4->sin_addr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing was supplied, assign INADDR_ANY
|
||||
addr4->sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
convertFromSockAddr(*addr4);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Address copy constructor
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::Address(const Address & source) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress(source.hostAddress)
|
||||
{
|
||||
*addr4 = *source.addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Constructs an address from a BSD sockaddr structure
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::Address(const struct sockaddr_in & ipv4addr) :
|
||||
addr4(new struct sockaddr_in),
|
||||
hostAddress()
|
||||
{
|
||||
convertFromSockAddr(ipv4addr);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Destroy an address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address::~Address()
|
||||
{
|
||||
delete addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Aassign an address to anothe address
|
||||
*/
|
||||
Address & Address::operator = (const Address & rhs)
|
||||
{
|
||||
if(this != &rhs)
|
||||
{
|
||||
hostAddress = rhs.hostAddress;
|
||||
*addr4 = *rhs.addr4;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Assign an address to a BSD sockaddr_in structure
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Address & Address::operator = (const struct sockaddr_in & rhs)
|
||||
{
|
||||
convertFromSockAddr(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Address::convertFromSockAddr(const struct sockaddr_in & source)
|
||||
{
|
||||
// extract IP bytes from ipv4add4
|
||||
const unsigned char * ip;
|
||||
char name[17] = {"\0"};
|
||||
|
||||
ip = reinterpret_cast<const unsigned char *>(&source.sin_addr);
|
||||
_snprintf(name, 17, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); //lint !e534
|
||||
hostAddress = name;
|
||||
if(addr4 != &source)
|
||||
*addr4 = source;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get a human readable host address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(struct sockaddr_in & a)
|
||||
{
|
||||
Address b(a);
|
||||
printf("address = %%s\\n", b.getHostAddress().c_str());
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return A human readable host address string
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const std::string & Address::getHostAddress() const
|
||||
{
|
||||
return hostAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the port associated with this address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(struct sockaddr_in & a)
|
||||
{
|
||||
Address b(a);
|
||||
printf("port = %%i\\n", b.getHostPort());
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return A human readable port in host-byte order associated with
|
||||
this address.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned short Address::getHostPort() const
|
||||
{
|
||||
return ntohs(addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the BSD sockaddr describing this address
|
||||
|
||||
Example:
|
||||
\code
|
||||
void foo(SOCKET s, unsigned char * d, int l, const Address & a)
|
||||
{
|
||||
int t = sizeof(struct sockaddr_in);
|
||||
sendto(s, s, l, 0, reinterpret_cast<const struct sockaddr *>(&(a.getSockAddr4())), t);
|
||||
}
|
||||
\endcode
|
||||
|
||||
@return a BSD sockaddr that describes this IPv4 address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const struct sockaddr_in & Address::getSockAddr4() const
|
||||
{
|
||||
return *addr4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief equality operator
|
||||
|
||||
The equality operator compares the ip address, ip port,
|
||||
and address family to establish equality.
|
||||
|
||||
Example:
|
||||
\code
|
||||
Address a("127.0.0.1", 55443);
|
||||
Address b;
|
||||
|
||||
b = a;
|
||||
\endcode
|
||||
|
||||
@return True of the right hand side is equal to this address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator == (const Address & rhs) const
|
||||
{
|
||||
return (addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_family == rhs.addr4->sin_family &&
|
||||
addr4->sin_port == rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief less-than comparison operator
|
||||
|
||||
The < comparison operator compares the IP number and port. If
|
||||
the IP numbers are identical, but the left hand side port is
|
||||
less than the right hand side port, the operator will return
|
||||
true.
|
||||
|
||||
@return true if the left hand side's IP number is less than
|
||||
the right hand side IP number. If the numbers are equal, it
|
||||
will return true if the left hand side IP port is less
|
||||
than the right hand side port. Otherwise it returns false.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator < (const Address & rhs) const
|
||||
{
|
||||
return(addr4->sin_addr.s_addr < rhs.addr4->sin_addr.s_addr ||
|
||||
addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_port < rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief inequality operator
|
||||
|
||||
Leverages the equality operator, so whenever == returns true,
|
||||
this returns false, and visa versa.
|
||||
|
||||
@return true if the right hand side is not equal to the left
|
||||
hand side. False if they are equal.
|
||||
|
||||
@see Adress::operator==
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator != (const Address & rhs) const
|
||||
{
|
||||
return(! (rhs == *this));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief greater-than comparison operator
|
||||
|
||||
The > comparison operator compares the IP number and port. If
|
||||
the IP numbers are identical, but the right hand side port is
|
||||
lesser than the left hand side port, the operator will return
|
||||
true.
|
||||
|
||||
@return true if the left hand side's IP number is greater than
|
||||
the right hand side IP number. If the numbers are equal, it
|
||||
will return true if the left hand side IP port is greater
|
||||
than the right hand side port. Otherwise it returns false.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const bool Address::operator > (const Address & rhs) const
|
||||
{
|
||||
return(addr4->sin_addr.s_addr > rhs.addr4->sin_addr.s_addr ||
|
||||
addr4->sin_addr.s_addr == rhs.addr4->sin_addr.s_addr &&
|
||||
addr4->sin_port > rhs.addr4->sin_port);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief a hash_map support routine
|
||||
|
||||
The STL hash_map (present in most STL implementations) requires
|
||||
a size_t return from a hash function to identify which bucket
|
||||
a particular value should reside in. On 32 bit or better platforms
|
||||
the sockaddr_in.sin_addr.s_addr member is small enough to
|
||||
qualify as a hash-result, provides reasonably unique values
|
||||
and is reproducable given an address input.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@return the ip number member of a sockaddr_in struct
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
size_t Address::hashFunction() const
|
||||
{
|
||||
return addr4->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief STL map support routine
|
||||
|
||||
STL maps (including hash_maps) require unique keys, and therefore
|
||||
need to compare a key for equality with an existing target.
|
||||
|
||||
The functor uses Address::operator = for the comparison.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@return true if the left hand side and right hand side are equal
|
||||
using Address::operator =
|
||||
@see Address::operator=
|
||||
|
||||
*/
|
||||
bool Address::EqualFunction::operator () (const Address & lhs, const Address & rhs) const
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief STL hash_map support routine
|
||||
|
||||
The HashFunction::operator() invokes Address::hashFunction to
|
||||
determine an appropriate hash for the address.
|
||||
|
||||
Example:
|
||||
\code
|
||||
typedef std::hash_map<Address, Connection *, Address::HashFunction, Address::EqualFunction> AddressMap;
|
||||
\endcode
|
||||
|
||||
@see Address::hashFunction
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
size_t Address::HashFunction::operator () (const Address & a) const
|
||||
{
|
||||
return a.hashFunction();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
@@ -0,0 +1,9 @@
|
||||
// FirstSharedNetwork.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// NetworkGetHostName.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/NetworkHandler.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct HN
|
||||
{
|
||||
HN();
|
||||
std::string hostName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
HN::HN()
|
||||
{
|
||||
char name[512] = {"\0"};
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
Address a(name, 0);
|
||||
hostName = a.getHostAddress();//name;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & NetworkHandler::getHostName()
|
||||
{
|
||||
static HN hn;
|
||||
return hn.hostName;
|
||||
}
|
||||
|
||||
const std::string & NetworkHandler::getHumanReadableHostName()
|
||||
{
|
||||
char name[512] = {"\0"};
|
||||
static std::string nameString;
|
||||
if(nameString.empty())
|
||||
{
|
||||
if(gethostname(name, sizeof(name)) == 0)
|
||||
{
|
||||
name[sizeof(name) - 1] = 0;
|
||||
//hostName = name;
|
||||
nameString = name;
|
||||
}
|
||||
}
|
||||
return nameString;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > & NetworkHandler::getInterfaceAddresses()
|
||||
{
|
||||
static std::vector<std::pair<std::string, std::string> > s;
|
||||
return s;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@@ -0,0 +1,85 @@
|
||||
// OverlappedTcp.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "OverlappedTcp.h"
|
||||
#include <vector>
|
||||
#include "TcpClient.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedTcp::~OverlappedTcp()
|
||||
{
|
||||
delete[] m_acceptData;
|
||||
delete[] m_recvBuf.buf;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
struct OverlappedFreeList
|
||||
{
|
||||
~OverlappedFreeList();
|
||||
std::vector<OverlappedTcp *> allOverlapped;
|
||||
std::vector<OverlappedTcp *> freeOverlapped;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedFreeList::~OverlappedFreeList()
|
||||
{
|
||||
std::vector<OverlappedTcp *>::const_iterator i;
|
||||
for(i = allOverlapped.begin(); i != allOverlapped.end(); ++i)
|
||||
{
|
||||
OverlappedTcp * t = (*i);
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedFreeList overlappedFreeList;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedTcp * getFreeOverlapped()
|
||||
{
|
||||
OverlappedTcp * result = NULL;
|
||||
|
||||
if(! overlappedFreeList.freeOverlapped.empty())
|
||||
{
|
||||
result = overlappedFreeList.freeOverlapped.back();
|
||||
overlappedFreeList.freeOverlapped.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new OverlappedTcp;
|
||||
result->m_bytes = 0;
|
||||
memset(&result->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||
result->m_recvBuf.buf = new char[1024];
|
||||
result->m_recvBuf.len = 1024;
|
||||
result->m_tcpClient = 0;
|
||||
result->m_tcpServer = 0;
|
||||
result->m_acceptData = 0;
|
||||
overlappedFreeList.allOverlapped.push_back(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void releaseOverlapped(OverlappedTcp * o)
|
||||
{
|
||||
o->m_bytes = 0;
|
||||
o->m_tcpClient = 0;
|
||||
o->m_tcpServer = 0;
|
||||
o->m_acceptData = 0;
|
||||
memset(&o->m_overlapped, 0, sizeof(OVERLAPPED));
|
||||
overlappedFreeList.freeOverlapped.push_back(o);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// OverlappedTcp.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_OverlappedTcp_H
|
||||
#define _INCLUDED_OverlappedTcp_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpClient;
|
||||
class TcpServer;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
struct OverlappedTcp
|
||||
{
|
||||
~OverlappedTcp();
|
||||
OVERLAPPED m_overlapped;
|
||||
|
||||
enum OPERATIONS
|
||||
{
|
||||
INVALID,
|
||||
ACCEPT,
|
||||
SEND,
|
||||
RECV
|
||||
};
|
||||
|
||||
unsigned char * m_acceptData; // getting peer name during accept
|
||||
DWORD m_bytes;
|
||||
enum OPERATIONS m_operation;
|
||||
const TcpServer * m_tcpServer;
|
||||
TcpClient * m_tcpClient; // accepted sock when operation is accept
|
||||
WSABUF m_recvBuf;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
OverlappedTcp * getFreeOverlapped();
|
||||
void releaseOverlapped(OverlappedTcp *);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_OverlappedTcp_H
|
||||
@@ -0,0 +1,366 @@
|
||||
// Sock.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/Sock.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
struct WinsockStartupObject
|
||||
{
|
||||
WinsockStartupObject();
|
||||
~WinsockStartupObject();
|
||||
};
|
||||
|
||||
WinsockStartupObject::WinsockStartupObject()
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested;
|
||||
|
||||
wVersionRequested = MAKEWORD(2,0);
|
||||
int err;
|
||||
err = WSAStartup(wVersionRequested, &wsaData);
|
||||
}
|
||||
|
||||
WinsockStartupObject::~WinsockStartupObject()
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
WinsockStartupObject wso;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a Sock
|
||||
|
||||
This constructor sets handle to INVALID_SOCKET, lastError to
|
||||
Sock::SOCK_NO_ERROR and the bindAddress to the default Address.
|
||||
|
||||
@see Address
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Sock::Sock() :
|
||||
handle(INVALID_SOCKET),
|
||||
lastError(Sock::SOCK_NO_ERROR),
|
||||
bindAddress()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the Sock object
|
||||
|
||||
checks for a valid socket close. It is an error to close a socket
|
||||
that will fail a close operation.
|
||||
|
||||
Also resets handle to INVALID_SOCKET
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
Sock::~Sock()
|
||||
{
|
||||
// ensure we don't block, and that pending
|
||||
// data is sent with a graceful shutdown
|
||||
int err;
|
||||
err = closesocket(handle);
|
||||
if(err == SOCKET_ERROR)
|
||||
{
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
handle = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief Bind the socket to the specified local address
|
||||
*/
|
||||
bool Sock::bind(const Address & newBindAddress)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
int enable = 1;
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||
|
||||
bindAddress = newBindAddress;
|
||||
int namelen = sizeof(struct sockaddr_in);
|
||||
int err = ::bind(handle, reinterpret_cast<const struct sockaddr *>(&(bindAddress.getSockAddr4())), namelen);
|
||||
if(err == 0)
|
||||
{
|
||||
result = true;
|
||||
struct sockaddr_in a;
|
||||
int r;
|
||||
r = getsockname(handle, reinterpret_cast<struct sockaddr *>(&a), &namelen);
|
||||
bindAddress = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
OutputDebugString(getLastError().c_str());
|
||||
OutputDebugString("\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief bind the socket to the first available local address
|
||||
as provided by the operating system.
|
||||
|
||||
This bind call is useful for client sockets, or server sockets that
|
||||
can report their new address to a locator service.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
bool Sock::bind()
|
||||
{
|
||||
bool result = false;
|
||||
struct sockaddr_in a;
|
||||
int namelen = sizeof(struct sockaddr_in);
|
||||
memset(&a, 0, sizeof(struct sockaddr_in));
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = 0;
|
||||
a.sin_addr.s_addr = INADDR_ANY;
|
||||
int err = ::bind(handle, reinterpret_cast<struct sockaddr *>(&a), namelen);
|
||||
if(err == 0)
|
||||
{
|
||||
result = true;
|
||||
int r;
|
||||
r = getsockname(handle, reinterpret_cast<struct sockaddr *>(&a), &namelen);
|
||||
bindAddress = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine if a socket is ready to receive
|
||||
|
||||
On Win32, select is invoked. On Linux, the poll() system call is
|
||||
used to deterine readability of a socket.
|
||||
|
||||
@return true if the socket can read data without blocking.
|
||||
|
||||
@author Justin Randall
|
||||
|
||||
@todo Win32 should be using WSAEventSelect and WSAEnumNetworkEvents
|
||||
if they outperform select.
|
||||
*/
|
||||
bool Sock::canRecv() const
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set r;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&r);
|
||||
#pragma warning (disable : 4127)
|
||||
FD_SET(handle, &r); //lint !e717 // I have no idea why MS makes this a do { .. } while(0); macro?! Pointless.
|
||||
return (select(1, &r, 0, 0, &tv) > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine writeability of the socket
|
||||
|
||||
Win32 systems use select, Linux use poll.
|
||||
|
||||
@return true if the socket can send data without blocking.
|
||||
@author Justin Randall
|
||||
|
||||
@todo Win32 should be using WSAEventSelect and WSAEnumNetworkEvents
|
||||
if they outperform select.
|
||||
*/
|
||||
bool Sock::canSend() const
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set w;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&w);
|
||||
FD_SET(handle, &w); //lint !e717 // I have no idea why MS makes this a do { .. } while(0); macro?! Pointless.
|
||||
|
||||
return (select(1, 0, &w, 0, &tv) > 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine the number of bytes pending on the socket
|
||||
|
||||
Uses ioctl (ioctlsocket on win32) to determine the number
|
||||
of bytes pending.
|
||||
|
||||
@return the number of unread bytes pending on the socket
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned int Sock::getInputBytesPending() const
|
||||
{
|
||||
unsigned long int bytes = 0;
|
||||
int err;
|
||||
err = ioctlsocket(handle, FIONREAD, &bytes); //lint !e1924 (I don't know WHAT Microsoft is doing here!)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine the error state of the socket
|
||||
|
||||
This routine also sets the lastError member of the Sock object, which
|
||||
is used to determine common errors (connection failure, connection
|
||||
closed, connection reset, etc..)
|
||||
|
||||
@return an STL string that describes the error state of the socket,
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const std::string Sock::getLastError() const
|
||||
{
|
||||
std::string errString;
|
||||
int iErr = WSAGetLastError();
|
||||
|
||||
switch(iErr)
|
||||
{
|
||||
case WSAENOPROTOOPT:
|
||||
errString = "Bad protocol option. An unknown, invalid or unsupported option or level was specified in a getsockopt or setsockopt call.";
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
errString = "The network subsystem has failed.";
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
errString = "The buf parameter is not completely contained in a valid part of the user address space.";
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
errString = "The socket is not connected.";
|
||||
lastError = Sock::CONNECTION_FAILED;
|
||||
break;
|
||||
case WSAEINTR:
|
||||
errString = "The (blocking) call was canceled through WSACancelBlockingCall.";
|
||||
break;
|
||||
case WSAEINPROGRESS:
|
||||
errString = "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.";
|
||||
break;
|
||||
case WSAENETRESET:
|
||||
errString = "The connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress.";
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
errString = "The descriptor is not a socket.";
|
||||
break;
|
||||
case WSAEOPNOTSUPP:
|
||||
errString = "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.";
|
||||
break;
|
||||
case WSAESHUTDOWN:
|
||||
errString = "The socket has been shut down; it is not possible to recv on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.";
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
errString = "The socket is marked as nonblocking and the receive operation would block.";
|
||||
break;
|
||||
case WSAEMSGSIZE:
|
||||
errString = "The message was too large to fit into the specified buffer and was truncated.";
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
errString = "The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled or (for byte stream sockets only) len was zero or negative.";
|
||||
break;
|
||||
case WSAECONNABORTED:
|
||||
errString = "The virtual circuit was terminated due to a time-out or other failure. The application should close the socket as it is no longer usable.";
|
||||
lastError = Sock::CONNECTION_RESET;
|
||||
break;
|
||||
case WSAETIMEDOUT:
|
||||
errString = "The connection has been dropped because of a network failure or because the peer system failed to respond.";
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
errString = "The virtual circuit was reset by the remote side executing a \"hard\" or \"abortive\" close. The application should close the socket as it is no longer usable. On a UDP datagram socket this error would indicate that a previous send operation resulted in an ICMP \"Port Unreachable\" message.";
|
||||
lastError = Sock::CONNECTION_RESET;
|
||||
break;
|
||||
case WSAECONNREFUSED:
|
||||
errString = "No connection could be made because the target machine actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host - i.e. one with no server application running. ";
|
||||
lastError = Sock::CONNECTION_FAILED;
|
||||
break;
|
||||
default:
|
||||
errString = "An unknown socket error has occurred.";
|
||||
break;
|
||||
}
|
||||
|
||||
return errString;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** @brief determine the maximum message size that may be sent on this socket
|
||||
*/
|
||||
const unsigned int Sock::getMaxMessageSendSize() const
|
||||
{
|
||||
/*
|
||||
int maxMsgSize = 400;
|
||||
int optlen = sizeof(int);
|
||||
int result = getsockopt(handle, SOL_SOCKET, SO_MAX_MSG_SIZE, reinterpret_cast<char *>(&maxMsgSize), &optlen);
|
||||
if(result != 0)
|
||||
{
|
||||
int errCode = WSAGetLastError();
|
||||
switch(errCode)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
OutputDebugString("A successful WSAStartup call must occur before using this function. ");
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
OutputDebugString("The network subsystem has failed. ");
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
OutputDebugString("One of the optval or the optlen parameters is not a valid part of the user address space, or the optlen parameter is too small. ");
|
||||
case WSAEINPROGRESS:
|
||||
OutputDebugString("A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. ");
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
OutputDebugString("The level parameter is unknown or invalid. ");
|
||||
break;
|
||||
case WSAENOPROTOOPT:
|
||||
OutputDebugString("The option is unknown or unsupported by the indicated protocol family. ");
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
OutputDebugString("The descriptor is not a socket. ");
|
||||
break;
|
||||
default:
|
||||
OutputDebugString("An unknown error occurred while processing getsockopt");
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return 400;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get a BSD sockaddr struct describing the remote address
|
||||
of a socket
|
||||
|
||||
@param target a BSD sockaddr struct that will receive the peer
|
||||
address
|
||||
@param s the socket to query for the peername
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Sock::getPeerName(struct sockaddr_in & target, SOCKET s)
|
||||
{
|
||||
int namelen = sizeof(struct sockaddr_in);
|
||||
int err;
|
||||
err = getpeername(s, reinterpret_cast<sockaddr *>(&(target)), &namelen);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/** @brief a support routine to place the socket in non-blocking mode
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
void Sock::setNonBlocking() const
|
||||
{
|
||||
unsigned long int nb = 1;
|
||||
int err;
|
||||
err = ioctlsocket(handle, FIONBIO, &nb); //lint !e569 // loss of precision in the FIONBIO macro, beyond my control
|
||||
if(err == SOCKET_ERROR)
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
@@ -0,0 +1,129 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Sock.h
|
||||
//
|
||||
// Copyright 2003 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Sock_H
|
||||
#define INCLUDED_Sock_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedNetwork/Address.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const unsigned int SOCK_ERROR = 0xFFFFFFFF;
|
||||
typedef unsigned int SOCKET;
|
||||
|
||||
/**
|
||||
@brief a BSD socket abstraction
|
||||
|
||||
Sock abstracts BSD sockets for platform independant operation. It
|
||||
also provides common socket operations to simplify socket management.
|
||||
|
||||
@see BroadcastSock
|
||||
@see TcpSock
|
||||
@see UdpSock
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
class Sock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@brief failure states for a socket
|
||||
*/
|
||||
enum ErrorCodes
|
||||
{
|
||||
SOCK_NO_ERROR,
|
||||
CONNECTION_FAILED,
|
||||
CONNECTION_CLOSED,
|
||||
CONNECTION_RESET
|
||||
};
|
||||
|
||||
Sock();
|
||||
virtual ~Sock() = 0;
|
||||
bool bind(const Address & bindAddress);
|
||||
bool bind();
|
||||
bool canSend() const;
|
||||
bool canRecv() const;
|
||||
const Address & getBindAddress() const;
|
||||
const SOCKET getHandle() const;
|
||||
const unsigned int getInputBytesPending() const;
|
||||
const std::string getLastError() const;
|
||||
const enum ErrorCodes getLastErrorCode() const;
|
||||
const unsigned int getMaxMessageSendSize() const;
|
||||
static void getPeerName(struct sockaddr_in & target, SOCKET s);
|
||||
|
||||
private:
|
||||
// disabled
|
||||
Sock(const Sock & source);
|
||||
Sock & operator= (const Sock & source);
|
||||
|
||||
protected:
|
||||
void setNonBlocking() const;
|
||||
protected:
|
||||
int handle;
|
||||
|
||||
/**
|
||||
@brief support for setting/getting last error from derived
|
||||
sock classes
|
||||
*/
|
||||
mutable enum ErrorCodes lastError;
|
||||
private:
|
||||
Address bindAddress;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the local address of the socket
|
||||
|
||||
Until a socket is bound, the bind address may be reported as
|
||||
0.0.0.0:0
|
||||
|
||||
@return a const Address reference describing the local address
|
||||
of the socket.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const Address & Sock::getBindAddress() const
|
||||
{
|
||||
return bindAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief return the platform specific socket handle
|
||||
|
||||
the handle returned is not portable and should only be used locally
|
||||
for Sock specific operations.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const SOCKET Sock::getHandle() const
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief get the last error code on the socket
|
||||
|
||||
@return the last error code on the socket
|
||||
|
||||
@see Sock::ErrorCodes
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
inline const enum Sock::ErrorCodes Sock::getLastErrorCode() const
|
||||
{
|
||||
return lastError;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#endif // _Sock_H
|
||||
|
||||
@@ -0,0 +1,631 @@
|
||||
// TcpClient.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "Archive/Archive.h"
|
||||
#include "Archive/ByteStream.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/ConfigSharedNetwork.h"
|
||||
#include "sharedNetwork/Connection.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "OverlappedTcp.h"
|
||||
#include "TcpClient.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned long KEEPALIVE_MS = 1000;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace TcpClientNamespace
|
||||
{
|
||||
std::set<TcpClient *> s_pendingConnectionSends;
|
||||
std::set<TcpClient *> s_pendingConnectionRemoves;
|
||||
std::set<TcpClient *> s_tcpClients;
|
||||
QOS s_sqos;
|
||||
QOS s_gqos;
|
||||
}
|
||||
|
||||
using namespace TcpClientNamespace;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient(HANDLE parentIOCP) :
|
||||
m_connectEvent(INVALID_HANDLE_VALUE),
|
||||
m_socket(),
|
||||
m_tcpServer(0),
|
||||
m_localIOCP(INVALID_HANDLE_VALUE),
|
||||
m_pendingSend(),
|
||||
m_connection(0),
|
||||
m_refCount(0),
|
||||
m_connected(false),
|
||||
m_ownHandle(false),
|
||||
m_lastSendTime(0),
|
||||
m_bindPort(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
static PROTOENT * p = getprotobyname ("tcp");
|
||||
if (p)
|
||||
{
|
||||
static int entry = p->p_proto;
|
||||
m_socket = WSASocket (AF_INET, SOCK_STREAM, entry, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
char optval = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||
unsigned long opt = 1;
|
||||
ioctlsocket(m_socket, FIONBIO, &opt);
|
||||
|
||||
struct sockaddr_in bindAddr;
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
|
||||
m_localIOCP = CreateIoCompletionPort (reinterpret_cast<HANDLE> (m_socket), parentIOCP, 0, 0);
|
||||
queueReceive();
|
||||
}
|
||||
s_tcpClients.insert(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient::TcpClient(const std::string & remoteAddress, const unsigned short remotePort) :
|
||||
m_connectEvent(INVALID_HANDLE_VALUE),
|
||||
m_socket(),
|
||||
m_localIOCP(INVALID_HANDLE_VALUE),
|
||||
m_connection(0),
|
||||
m_refCount(0),
|
||||
m_connected(false),
|
||||
m_ownHandle(true),
|
||||
m_lastSendTime(0),
|
||||
m_rawTCP( false )
|
||||
{
|
||||
static PROTOENT * p = getprotobyname ("tcp");
|
||||
if (p)
|
||||
{
|
||||
static int entry = p->p_proto;
|
||||
m_socket = WSASocket (AF_INET, SOCK_STREAM, entry, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
if (m_socket != INVALID_SOCKET)
|
||||
{
|
||||
int nameLen = sizeof (struct sockaddr_in);
|
||||
static WSABUF emptyBuf;
|
||||
emptyBuf.buf = 0;
|
||||
emptyBuf.len = 0;
|
||||
|
||||
Address a(remoteAddress, remotePort);
|
||||
char optval = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||
unsigned long opt = 1;
|
||||
ioctlsocket(m_socket, FIONBIO, &opt);
|
||||
|
||||
int result;
|
||||
result = WSAConnect (m_socket, reinterpret_cast<const struct sockaddr *> (&a.getSockAddr4 () ), nameLen, 0, &emptyBuf, &s_sqos, &s_gqos);
|
||||
m_connectEvent = WSACreateEvent ();
|
||||
WSAEventSelect (m_socket, m_connectEvent, FD_CONNECT);
|
||||
m_localIOCP = CreateIoCompletionPort (reinterpret_cast<HANDLE> (m_socket), 0, 0, 0);
|
||||
struct sockaddr_in bindAddr;
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
if(getsockname(m_socket, reinterpret_cast<struct sockaddr *>(&bindAddr), &addrLen) == 0)
|
||||
{
|
||||
m_bindPort = ntohs(bindAddr.sin_port);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
s_tcpClients.insert(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient::~TcpClient()
|
||||
{
|
||||
s_pendingConnectionRemoves.insert(this);
|
||||
std::set<TcpClient *>::iterator f = s_tcpClients.find(this);
|
||||
if(f != s_tcpClients.end())
|
||||
s_tcpClients.erase(f);
|
||||
|
||||
closesocket (m_socket);
|
||||
if(m_ownHandle)
|
||||
CloseHandle(m_localIOCP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::addRef()
|
||||
{
|
||||
m_refCount++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
std::string const &TcpClient::getRemoteAddress() const
|
||||
{
|
||||
// TODO: implement this
|
||||
static std::string dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
unsigned short TcpClient::getRemotePort() const
|
||||
{
|
||||
// TODO: implement this
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::commit(const unsigned char * const buffer, const int bufferLen)
|
||||
{
|
||||
WSABUF wsaBuf;
|
||||
|
||||
// yuck, docs say this is actually going to be const for the send,
|
||||
// but WSABUF::buf is not const!
|
||||
wsaBuf.buf = (char *)buffer;
|
||||
wsaBuf.len = bufferLen;
|
||||
|
||||
OverlappedTcp * op = getFreeOverlapped ();
|
||||
if (op)
|
||||
{
|
||||
op->m_operation = OverlappedTcp::SEND;
|
||||
op->m_tcpClient = const_cast<TcpClient *>(this);
|
||||
int sent;
|
||||
sent = WSASend (m_socket, &wsaBuf, 1, &op->m_bytes, 0, &op->m_overlapped, NULL);
|
||||
if(sent == SOCKET_ERROR)
|
||||
{
|
||||
int errCode = WSAGetLastError();
|
||||
char * err;
|
||||
if(errCode != WSA_IO_PENDING)
|
||||
{
|
||||
switch(errCode)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
err = "A successful WSAStartup must occur before using this function.";
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
err = "The network subsystem has failed.";
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
err = "The socket is not connected.";
|
||||
break;
|
||||
case WSAEINTR:
|
||||
err = "The (blocking) call was canceled through WSACancelBlockingCall. \n";
|
||||
break;
|
||||
case WSAEINPROGRESS:
|
||||
err = "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n";
|
||||
break;
|
||||
case WSAENETRESET:
|
||||
err = "The connection has been broken due to \"keep-alive\" activity detecting a failure while the operation was in progress.";
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
err = "The descriptor is not a socket.";
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
err = "The lpBuffers parameter is not completely contained in a valid part of the user address space.";
|
||||
break;
|
||||
case WSAEOPNOTSUPP:
|
||||
err = "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.";
|
||||
break;
|
||||
case WSAESHUTDOWN:
|
||||
err = "The socket has been shut down; it is not possible to call WSARecv on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH. \n";
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
err = "Overlapped sockets: There are too many outstanding overlapped I/O requests. Nonoverlapped sockets: The socket is marked as nonblocking and the receive operation cannot be completed immediately. \n";
|
||||
break;
|
||||
case WSAEMSGSIZE:
|
||||
err = "The message was too large to fit into the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded.";
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
err = "The socket has not been bound (for example, with bind).";
|
||||
break;
|
||||
case WSAECONNABORTED:
|
||||
err = "The virtual circuit was terminated due to a time-out or other failure. \n";
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
err = "The virtual circuit was reset by the remote side. \n";
|
||||
break;
|
||||
case WSAEDISCON:
|
||||
err = "Socket s is message oriented and the virtual circuit was gracefully closed by the remote side. \n";
|
||||
break;
|
||||
case WSA_IO_PENDING:
|
||||
err = "An overlapped operation was successfully initiated and completion will be indicated at a later time. \n";
|
||||
break;
|
||||
case WSA_OPERATION_ABORTED:
|
||||
err = "The overlapped operation has been canceled due to the closure of the socket. \n";
|
||||
break;
|
||||
default:
|
||||
err = "An unknown error occured while processing WSARecv().";
|
||||
break;
|
||||
}
|
||||
onConnectionClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flush()
|
||||
{
|
||||
if(m_connected && m_pendingSend.getSize() > 0)
|
||||
{
|
||||
// put it on the wire
|
||||
commit(m_pendingSend.getBuffer(), m_pendingSend.getSize());
|
||||
m_pendingSend.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::flushPendingWrites()
|
||||
{
|
||||
std::set<TcpClient *>::iterator f;
|
||||
std::set<TcpClient *>::iterator i;
|
||||
for(i = s_pendingConnectionSends.begin(); i != s_pendingConnectionSends.end(); ++i)
|
||||
{
|
||||
if(s_pendingConnectionRemoves.empty())
|
||||
{
|
||||
(*i)->flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
f = s_pendingConnectionRemoves.find((*i));
|
||||
if(f == s_pendingConnectionRemoves.end())
|
||||
(*i)->flush();
|
||||
}
|
||||
}
|
||||
s_pendingConnectionSends.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
SOCKET TcpClient::getSocket() const
|
||||
{
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::install()
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD(2,2);
|
||||
WSADATA wsaData;
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
s_sqos.ProviderSpecific.buf = 0;
|
||||
s_sqos.ProviderSpecific.len = 0;
|
||||
|
||||
s_sqos.ReceivingFlowspec.DelayVariation = 0;
|
||||
s_sqos.ReceivingFlowspec.Latency = 0;
|
||||
s_sqos.ReceivingFlowspec.MaxSduSize = 0;
|
||||
s_sqos.ReceivingFlowspec.MinimumPolicedSize = 0;
|
||||
s_sqos.ReceivingFlowspec.PeakBandwidth = 0;
|
||||
s_sqos.ReceivingFlowspec.ServiceType = 0;
|
||||
s_sqos.ReceivingFlowspec.TokenBucketSize = 0;
|
||||
s_sqos.ReceivingFlowspec.TokenRate = 0;
|
||||
|
||||
s_sqos.SendingFlowspec.DelayVariation = 0;
|
||||
s_sqos.SendingFlowspec.Latency = 0;
|
||||
s_sqos.SendingFlowspec.MaxSduSize = 0;
|
||||
s_sqos.SendingFlowspec.MinimumPolicedSize = 0;
|
||||
s_sqos.SendingFlowspec.PeakBandwidth = 0;
|
||||
s_sqos.SendingFlowspec.ServiceType = 0;
|
||||
s_sqos.SendingFlowspec.TokenBucketSize = 0;
|
||||
s_sqos.SendingFlowspec.TokenRate = 0;
|
||||
|
||||
s_gqos.ProviderSpecific.buf = 0;
|
||||
s_gqos.ProviderSpecific.len = 0;
|
||||
|
||||
s_gqos.ReceivingFlowspec.DelayVariation = 0;
|
||||
s_gqos.ReceivingFlowspec.Latency = 0;
|
||||
s_gqos.ReceivingFlowspec.MaxSduSize = 0;
|
||||
s_gqos.ReceivingFlowspec.MinimumPolicedSize = 0;
|
||||
s_gqos.ReceivingFlowspec.PeakBandwidth = 0;
|
||||
s_gqos.ReceivingFlowspec.ServiceType = 0;
|
||||
s_gqos.ReceivingFlowspec.TokenBucketSize = 0;
|
||||
s_gqos.ReceivingFlowspec.TokenRate = 0;
|
||||
|
||||
s_gqos.SendingFlowspec.DelayVariation = 0;
|
||||
s_gqos.SendingFlowspec.Latency = 0;
|
||||
s_gqos.SendingFlowspec.MaxSduSize = 0;
|
||||
s_gqos.SendingFlowspec.MinimumPolicedSize = 0;
|
||||
s_gqos.SendingFlowspec.PeakBandwidth = 0;
|
||||
s_gqos.SendingFlowspec.ServiceType = 0;
|
||||
s_gqos.SendingFlowspec.TokenBucketSize = 0;
|
||||
s_gqos.SendingFlowspec.TokenRate = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionClosed()
|
||||
{
|
||||
m_connected = false;
|
||||
if(m_connection)
|
||||
{
|
||||
NetworkHandler::onTerminate(m_connection);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onConnectionOpened()
|
||||
{
|
||||
m_connected = true;
|
||||
queueReceive();
|
||||
flush();
|
||||
if(m_connection)
|
||||
m_connection->onConnectionOpened();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::onReceive(const unsigned char * const buffer, const int length)
|
||||
{
|
||||
queueReceive();
|
||||
if(m_connection)
|
||||
{
|
||||
m_connection->receive(buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::queryConnect()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
WSANETWORKEVENTS w;
|
||||
if (WSAEnumNetworkEvents (m_socket, m_connectEvent, &w) != SOCKET_ERROR)
|
||||
{
|
||||
if (w.lNetworkEvents == FD_CONNECT)
|
||||
{
|
||||
if (w.iErrorCode[FD_CONNECT_BIT] == 0)
|
||||
{
|
||||
CloseHandle (m_connectEvent);
|
||||
result = true;
|
||||
onConnectionOpened();
|
||||
}
|
||||
else
|
||||
{
|
||||
onConnectionClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::queueReceive()
|
||||
{
|
||||
OverlappedTcp * op = getFreeOverlapped();
|
||||
op->m_operation = OverlappedTcp::RECV;
|
||||
op->m_tcpClient = const_cast<TcpClient *>(this);
|
||||
DWORD flags = 0;
|
||||
int result;
|
||||
result = WSARecv(m_socket, &op->m_recvBuf, 1, &op->m_bytes, &flags, &op->m_overlapped, NULL);
|
||||
|
||||
if(result == SOCKET_ERROR)
|
||||
{
|
||||
int errCode = WSAGetLastError();
|
||||
char * err;
|
||||
if(errCode != WSA_IO_PENDING)
|
||||
{
|
||||
switch(errCode)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
err = "A successful WSAStartup must occur before using this function.";
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
err = "The network subsystem has failed.";
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
err = "The socket is not connected.";
|
||||
break;
|
||||
case WSAEINTR:
|
||||
err = "The (blocking) call was canceled through WSACancelBlockingCall. \n";
|
||||
break;
|
||||
case WSAEINPROGRESS:
|
||||
err = "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. \n";
|
||||
break;
|
||||
case WSAENETRESET:
|
||||
err = "The connection has been broken due to \"keep-alive\" activity detecting a failure while the operation was in progress.";
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
err = "The descriptor is not a socket.";
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
err = "The lpBuffers parameter is not completely contained in a valid part of the user address space.";
|
||||
break;
|
||||
case WSAEOPNOTSUPP:
|
||||
err = "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.";
|
||||
break;
|
||||
case WSAESHUTDOWN:
|
||||
err = "The socket has been shut down; it is not possible to call WSARecv on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH. \n";
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
err = "Overlapped sockets: There are too many outstanding overlapped I/O requests. Nonoverlapped sockets: The socket is marked as nonblocking and the receive operation cannot be completed immediately. \n";
|
||||
break;
|
||||
case WSAEMSGSIZE:
|
||||
err = "The message was too large to fit into the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded.";
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
err = "The socket has not been bound (for example, with bind).";
|
||||
break;
|
||||
case WSAECONNABORTED:
|
||||
err = "The virtual circuit was terminated due to a time-out or other failure. \n";
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
err = "The virtual circuit was reset by the remote side. \n";
|
||||
break;
|
||||
case WSAEDISCON:
|
||||
err = "Socket s is message oriented and the virtual circuit was gracefully closed by the remote side. \n";
|
||||
break;
|
||||
case WSA_IO_PENDING:
|
||||
err = "An overlapped operation was successfully initiated and completion will be indicated at a later time. \n";
|
||||
break;
|
||||
case WSA_OPERATION_ABORTED:
|
||||
err = "The overlapped operation has been canceled due to the closure of the socket. \n";
|
||||
break;
|
||||
default:
|
||||
err = "An unknown error occured while processing WSARecv().";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::send(const unsigned char * const buffer, const int length)
|
||||
{
|
||||
if (length)
|
||||
{
|
||||
m_lastSendTime = Clock::getFrameStartTimeMs();
|
||||
s_pendingConnectionSends.insert(this);
|
||||
if( !m_rawTCP )
|
||||
Archive::put(m_pendingSend, length);
|
||||
m_pendingSend.put(buffer, length);
|
||||
|
||||
static int const tcpMinimumFrame = ConfigSharedNetwork::getTcpMinimumFrame();
|
||||
if (static_cast<int>(m_pendingSend.getSize()) >= tcpMinimumFrame)
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setConnection(Connection * c)
|
||||
{
|
||||
m_connection = c;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void TcpClient::update()
|
||||
{
|
||||
OVERLAPPED * overlapped = 0;
|
||||
OverlappedTcp * op = 0;
|
||||
unsigned long int bytesTransferred = 0;
|
||||
unsigned long int completionKey = 0;
|
||||
bool success = false;
|
||||
|
||||
if (m_connected)
|
||||
{
|
||||
unsigned long timeNow = Clock::getFrameStartTimeMs();
|
||||
if (timeNow-m_lastSendTime > KEEPALIVE_MS)
|
||||
{
|
||||
m_lastSendTime = timeNow;
|
||||
s_pendingConnectionSends.insert(this);
|
||||
Archive::put(m_pendingSend, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(! m_connected)
|
||||
queryConnect();
|
||||
|
||||
//PlatformTcpClient::queryConnects();
|
||||
do
|
||||
{
|
||||
success = false;
|
||||
int ok = GetQueuedCompletionStatus(
|
||||
m_localIOCP, // completion port of interest
|
||||
&bytesTransferred, // number of bytes sent or received
|
||||
&completionKey,
|
||||
&overlapped,
|
||||
0 // timeout immediately if there are no completions
|
||||
);
|
||||
if(ok)
|
||||
{
|
||||
op = reinterpret_cast<OverlappedTcp *>(overlapped);
|
||||
if(op)
|
||||
{
|
||||
switch(op->m_operation)
|
||||
{
|
||||
case OverlappedTcp::RECV:
|
||||
{
|
||||
if(op->m_tcpClient != 0)
|
||||
{
|
||||
if(bytesTransferred > 0)
|
||||
{
|
||||
op->m_tcpClient->onReceive((const unsigned char * const)op->m_recvBuf.buf, bytesTransferred);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case OverlappedTcp::SEND:
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
releaseOverlapped(op);
|
||||
}
|
||||
}
|
||||
} while(success);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::setRawTCP( bool bNewValue )
|
||||
{
|
||||
m_rawTCP = bNewValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::release()
|
||||
{
|
||||
m_refCount--;
|
||||
if(m_refCount < 1)
|
||||
{
|
||||
if(m_connected)
|
||||
onConnectionClosed();
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::remove()
|
||||
{
|
||||
std::set<TcpClient *>::iterator i;
|
||||
for(i = s_tcpClients.begin(); i != s_tcpClients.end(); ++i)
|
||||
{
|
||||
TcpClient * c = (*i);
|
||||
delete c;
|
||||
}
|
||||
s_tcpClients.clear();
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpClient::checkKeepalive()
|
||||
{
|
||||
unsigned long const timeNow = Clock::getFrameStartTimeMs();
|
||||
if (timeNow-m_lastSendTime > KEEPALIVE_MS)
|
||||
{
|
||||
m_lastSendTime = timeNow;
|
||||
s_pendingConnectionSends.insert(this);
|
||||
Archive::put(m_pendingSend, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// TcpClient.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpClient_H
|
||||
#define _INCLUDED_TcpClient_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <winsock2.h>
|
||||
#include "Archive/ByteStream.h"
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Connection;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpClient
|
||||
{
|
||||
public:
|
||||
explicit TcpClient(HANDLE parentIOCP);
|
||||
TcpClient(const std::string & address, const unsigned short port);
|
||||
~TcpClient();
|
||||
|
||||
static void install();
|
||||
static void remove();
|
||||
void send(const unsigned char * const buffer, const int length);
|
||||
unsigned short getBindPort() const;
|
||||
std::string const &getRemoteAddress() const;
|
||||
unsigned short getRemotePort() const;
|
||||
void setPendingSendAllocatedSizeLimit(unsigned int limit);
|
||||
|
||||
// only used by clients
|
||||
void update();
|
||||
static void flushPendingWrites();
|
||||
|
||||
protected:
|
||||
friend TcpServer;
|
||||
friend Connection;
|
||||
|
||||
void addRef();
|
||||
void commit(const unsigned char * const buffer, const int bufferLen);
|
||||
SOCKET getSocket() const;
|
||||
void onConnectionClosed();
|
||||
void onConnectionOpened();
|
||||
void onReceive(const unsigned char * const recvBuf, const int bytes);
|
||||
void queryConnect();
|
||||
void queueReceive();
|
||||
void release();
|
||||
void setConnection(Connection *);
|
||||
|
||||
void checkKeepalive();
|
||||
void setRawTCP( bool bNewValue );
|
||||
|
||||
|
||||
private:
|
||||
TcpClient & operator = (const TcpClient & rhs);
|
||||
TcpClient(const TcpClient & source);
|
||||
void flush ();
|
||||
|
||||
WSAEVENT m_connectEvent;
|
||||
SOCKET m_socket;
|
||||
TcpServer * m_tcpServer;
|
||||
HANDLE m_localIOCP;
|
||||
Archive::ByteStream m_pendingSend;
|
||||
Connection * m_connection;
|
||||
int m_refCount;
|
||||
bool m_connected;
|
||||
bool m_ownHandle;
|
||||
unsigned long m_lastSendTime;
|
||||
unsigned short m_bindPort;
|
||||
|
||||
bool m_rawTCP;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline void TcpClient::setPendingSendAllocatedSizeLimit(const unsigned int limit)
|
||||
{
|
||||
m_pendingSend.setAllocatedSizeLimit(limit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpClient_H
|
||||
@@ -0,0 +1,194 @@
|
||||
// TcpServer.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include <winsock2.h>
|
||||
#include <mswsock.h>
|
||||
#include "sharedNetwork/Address.h"
|
||||
#include "sharedNetwork/Service.h"
|
||||
#include "OverlappedTcp.h"
|
||||
#include "TcpClient.h"
|
||||
#include "TcpServer.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpServer::TcpServer(Service * service, const std::string & bindAddress, const unsigned short bindPort) :
|
||||
m_handle(),
|
||||
m_localIOCP(),
|
||||
m_pendingConnections(),
|
||||
m_bindAddress(bindAddress),
|
||||
m_bindPort(bindPort),
|
||||
m_service(service)
|
||||
{
|
||||
static PROTOENT * p = getprotobyname("tcp");
|
||||
if(p)
|
||||
{
|
||||
static int entry = p->p_proto;
|
||||
m_handle = WSASocket(AF_INET, SOCK_STREAM, entry, NULL, 0, WSA_FLAG_OVERLAPPED);
|
||||
if(m_handle != INVALID_SOCKET)
|
||||
{
|
||||
m_localIOCP = CreateIoCompletionPort(reinterpret_cast<HANDLE>(m_handle), 0, 0, 0);
|
||||
Address a(bindAddress, bindPort);
|
||||
|
||||
int result = bind(m_handle, reinterpret_cast<const sockaddr *>(&a.getSockAddr4()), sizeof(struct sockaddr_in));
|
||||
if(result == 0)
|
||||
{
|
||||
struct sockaddr_in b;
|
||||
int addrlen = sizeof(struct sockaddr_in);
|
||||
getsockname(m_handle, (struct sockaddr *)(&b), &addrlen);
|
||||
m_bindPort = ntohs(b.sin_port);
|
||||
result = listen(m_handle, 256);
|
||||
queueAccept();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpServer::~TcpServer()
|
||||
{
|
||||
closesocket(m_handle);
|
||||
CloseHandle(m_localIOCP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
TcpClient * TcpServer::accept()
|
||||
{
|
||||
TcpClient * result = 0;
|
||||
if(! m_pendingConnections.empty())
|
||||
{
|
||||
result = m_pendingConnections.back();
|
||||
m_pendingConnections.pop_back();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const unsigned short TcpServer::getBindPort() const
|
||||
{
|
||||
return m_bindPort;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpServer::onConnectionClosed(TcpClient *)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpServer::queueAccept()
|
||||
{
|
||||
OverlappedTcp * op = getFreeOverlapped();
|
||||
|
||||
// this will contain struct sockaddr data with additional
|
||||
// book keeping when Windows returns an overlapped
|
||||
// accept operation (nevermind that +16 or * 2, I don't have the MS
|
||||
// kb article handy, but it's a gross workaround for the documented
|
||||
// API and what acceptData really expects to have).
|
||||
op->m_acceptData = new unsigned char[(sizeof( struct sockaddr_in ) + 16 ) * 2];
|
||||
op->m_operation = OverlappedTcp::ACCEPT;
|
||||
op->m_tcpServer = this;
|
||||
op->m_tcpClient = new TcpClient(m_localIOCP);
|
||||
AcceptEx(
|
||||
m_handle,
|
||||
op->m_tcpClient->getSocket(),
|
||||
op->m_acceptData,
|
||||
0,
|
||||
sizeof(struct sockaddr_in) + 16,
|
||||
sizeof(struct sockaddr_in) + 16,
|
||||
&op->m_bytes,
|
||||
&op->m_overlapped);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void TcpServer::update()
|
||||
{
|
||||
OVERLAPPED * overlapped = 0;
|
||||
OverlappedTcp * op = 0;
|
||||
unsigned long int bytesTransferred = 0;
|
||||
unsigned long int completionKey = 0;
|
||||
bool success = false;
|
||||
|
||||
do
|
||||
{
|
||||
success = false;
|
||||
int ok = GetQueuedCompletionStatus(
|
||||
m_localIOCP, // completion port of interest
|
||||
&bytesTransferred, // number of bytes sent or received
|
||||
&completionKey,
|
||||
&overlapped,
|
||||
0 // timeout immediately if there are no completions
|
||||
);
|
||||
if(ok)
|
||||
{
|
||||
op = reinterpret_cast<OverlappedTcp *>(overlapped);
|
||||
if(op)
|
||||
{
|
||||
switch(op->m_operation)
|
||||
{
|
||||
case OverlappedTcp::ACCEPT:
|
||||
{
|
||||
if(op->m_tcpServer == this)
|
||||
{
|
||||
if(op->m_acceptData != 0)
|
||||
{
|
||||
// Extremely lame hack to keep things safe from Winsock stacktrashing
|
||||
//struct sockaddr_in local;
|
||||
//struct sockaddr_in remote;
|
||||
//memcpy(&local, reinterpret_cast<struct sockaddr_in *>(op->m_acceptData + 10), sizeof(struct sockaddr_in));
|
||||
//memcpy(&remote, reinterpret_cast<struct sockaddr_in *>(op->m_acceptData + 38), sizeof(struct sockaddr_in));
|
||||
delete[] op->m_acceptData;
|
||||
TcpClient * newClient = op->m_tcpClient;
|
||||
newClient->addRef();
|
||||
newClient->onConnectionOpened();
|
||||
m_pendingConnections.push_back(newClient);
|
||||
success = true;
|
||||
queueAccept();
|
||||
if(m_service)
|
||||
{
|
||||
m_service->onConnectionOpened(newClient);
|
||||
}
|
||||
newClient->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OverlappedTcp::RECV:
|
||||
{
|
||||
if(op->m_tcpClient != 0)
|
||||
{
|
||||
op->m_tcpClient->onReceive((const unsigned char * const)op->m_recvBuf.buf, bytesTransferred);
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
case OverlappedTcp::SEND:
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
releaseOverlapped(op);
|
||||
}
|
||||
}
|
||||
} while(success);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const std::string & TcpServer::getBindAddress() const
|
||||
{
|
||||
return m_bindAddress;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// TcpServer.h
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_TcpServer_H
|
||||
#define _INCLUDED_TcpServer_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class Service;
|
||||
class TcpClient;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class TcpServer
|
||||
{
|
||||
public:
|
||||
TcpServer(Service * service, const std::string & bindAddress, const unsigned short bindPort);
|
||||
~TcpServer();
|
||||
|
||||
TcpClient * accept ();
|
||||
const std::string & getBindAddress () const;
|
||||
const unsigned short getBindPort () const;
|
||||
void onConnectionClosed (TcpClient *);
|
||||
void update ();
|
||||
|
||||
private:
|
||||
TcpServer & operator = (const TcpServer & rhs);
|
||||
TcpServer(const TcpServer & source);
|
||||
|
||||
void queueAccept ();
|
||||
|
||||
private:
|
||||
SOCKET m_handle;
|
||||
HANDLE m_localIOCP;
|
||||
std::vector<TcpClient *> m_pendingConnections;
|
||||
std::string m_bindAddress;
|
||||
unsigned short m_bindPort;
|
||||
Service * m_service;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#endif // _INCLUDED_TcpServer_H
|
||||
@@ -0,0 +1,108 @@
|
||||
// UdpSock.cpp
|
||||
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#include "sharedNetwork/FirstSharedNetwork.h"
|
||||
#include "sharedNetwork/UdpSock.h"
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a UdpSock object
|
||||
|
||||
Allocates the socket descriptor, sets it to non-blocking mode.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
UdpSock::UdpSock() :
|
||||
Sock()
|
||||
{
|
||||
handle = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
setNonBlocking();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the UdpSock object
|
||||
|
||||
Doesn't do anything special.
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
UdpSock::~UdpSock()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief receive a datagram
|
||||
|
||||
Receives a datagram and populates the outAddr parameter with the
|
||||
source address of the message.
|
||||
|
||||
Calling Sock::getInputBytesPending can provide a hint before
|
||||
allocating the user supplied target buffer.
|
||||
|
||||
@param outAddr target Address reference that receives
|
||||
the message source IP address
|
||||
@param targetBuffer a user supplied buffer to receive the data.
|
||||
@param targetBufferSize the size of the user supplied buffer
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned int UdpSock::recvFrom(Address & outAddr, void * targetBuffer, const unsigned int bufferSize) const
|
||||
{
|
||||
int fromLen = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in addr;
|
||||
unsigned int result = ::recvfrom(handle, static_cast<char *>(targetBuffer), static_cast<int>(bufferSize), 0, reinterpret_cast<struct sockaddr *>(&addr), &fromLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
outAddr = addr;
|
||||
if(result == SOCK_ERROR)
|
||||
{
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
@brief send a datagram to a remote system
|
||||
|
||||
sendTo sends a datagram to a remote system.
|
||||
|
||||
@param targetAddress System to receive the datagram
|
||||
@param sourceBuffer A user supplied buffer containint the data
|
||||
to be sent
|
||||
@param length The amount of data in the source buffer to
|
||||
send
|
||||
|
||||
@return The number of bytes sent on success
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
const unsigned int UdpSock::sendTo(const Address & targetAddress, const void * sourceBuffer, const unsigned int length) const
|
||||
{
|
||||
unsigned int bytesSent = 0;
|
||||
if(canSend())
|
||||
{
|
||||
int toLen = sizeof(struct sockaddr_in);
|
||||
bytesSent = ::sendto(handle, static_cast<const char *>(sourceBuffer), static_cast<int>(length), 0, reinterpret_cast<const struct sockaddr *>(&(targetAddress.getSockAddr4())), toLen); //lint !e732 // MS wants an int, should be unsigned IMO
|
||||
if(bytesSent != length)
|
||||
{
|
||||
OutputDebugString(getLastError().c_str());
|
||||
}
|
||||
}
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void UdpSock::enableBroadcast()
|
||||
{
|
||||
char optval = 1;
|
||||
int err;
|
||||
err = setsockopt(getHandle(), SOL_SOCKET, SO_BROADCAST, &optval, sizeof(char));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user