Init
This commit is contained in:
191
DependentExtensions/cat/net/DNSClient.hpp
Normal file
191
DependentExtensions/cat/net/DNSClient.hpp
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// TODO: React to timeouts from DNS server by switching to a backup
|
||||
// TODO: Use TTL from DNS record instead of fixed constant
|
||||
// TODO: If the DNS resolution load is high, it would make sense to put
|
||||
// multiple requests in the same DNS packet
|
||||
// TODO: Retransmissions could also be grouped into the same DNS packets
|
||||
// TODO: The locks held in DNSClient are fairly coarse and could be broken up
|
||||
|
||||
#ifndef CAT_DNS_CLIENT_HPP
|
||||
#define CAT_DNS_CLIENT_HPP
|
||||
|
||||
#include <cat/net/ThreadPoolSockets.hpp>
|
||||
#include <cat/threads/Thread.hpp>
|
||||
#include <cat/threads/WaitableFlag.hpp>
|
||||
#include <cat/crypt/rand/Fortuna.hpp>
|
||||
#include <cat/port/FastDelegate.h>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
static const int HOSTNAME_MAXLEN = 63; // Max characters in a hostname request
|
||||
static const int DNSREQ_TIMEOUT = 3000; // DNS request timeout interval
|
||||
static const int DNSREQ_REPOST_TIME = 300; // Number of milliseconds between retries
|
||||
static const int DNSREQ_MAX_SIMUL = 2048; // Maximum number of simultaneous DNS requests
|
||||
static const int DNSCACHE_MAX_REQS = 8; // Maximum number of requests to cache
|
||||
static const int DNSCACHE_MAX_RESP = 8; // Maximum number of responses to cache
|
||||
static const int DNSCACHE_TIMEOUT = 60000; // Time until a cached response is dropped
|
||||
|
||||
// Prototype: bool MyResultCallback(const char *, const NetAddr*, int);
|
||||
typedef fastdelegate::FastDelegate3<const char *, const NetAddr*, int, bool> DNSResultCallback;
|
||||
|
||||
|
||||
//// DNSRequest
|
||||
|
||||
struct DNSCallback
|
||||
{
|
||||
DNSCallback *next;
|
||||
|
||||
DNSResultCallback cb;
|
||||
ThreadRefObject *ref;
|
||||
};
|
||||
|
||||
struct DNSRequest
|
||||
{
|
||||
DNSRequest *last, *next;
|
||||
|
||||
u32 first_post_time; // Timestamp for first post, for timeout
|
||||
u32 last_post_time; // Timestamp for last post, for retries and cache
|
||||
|
||||
// Our copy of the hostname string
|
||||
char hostname[HOSTNAME_MAXLEN+1];
|
||||
u16 id; // Random request ID
|
||||
DNSCallback callback_head;
|
||||
|
||||
// For caching purposes
|
||||
NetAddr responses[DNSCACHE_MAX_RESP];
|
||||
int num_responses;
|
||||
};
|
||||
|
||||
|
||||
//// DNSClient
|
||||
|
||||
class DNSClient : Thread, public UDPEndpoint, public Singleton<DNSClient>
|
||||
{
|
||||
static const int TICK_RATE = 200; // milliseconds
|
||||
static const int DNS_THREAD_KILL_TIMEOUT = 10000; // 10 seconds
|
||||
|
||||
CAT_SINGLETON(DNSClient)
|
||||
: UDPEndpoint(REFOBJ_PRIO_0+5)
|
||||
{
|
||||
_server_addr.Invalidate();
|
||||
_dns_unavailable = true;
|
||||
|
||||
_cache_head = _cache_tail = 0;
|
||||
_cache_size = 0;
|
||||
|
||||
_request_head = _request_tail = 0;
|
||||
_request_queue_size = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~DNSClient();
|
||||
|
||||
/*
|
||||
In your startup code, call Initialize() and check the return value.
|
||||
In your shutdown code, call Shutdown(). This will delete the DNSClient object.
|
||||
*/
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
/*
|
||||
If hostname is numeric or in the cache, the callback function will be invoked
|
||||
immediately from the requesting thread, rather than from another thread.
|
||||
|
||||
First attempts numerical resolve of hostname, then queries the DNS server.
|
||||
|
||||
Hostname string length limited to HOSTNAME_MAXLEN characters.
|
||||
Caches the most recent DNSCACHE_MAX_REQS requests.
|
||||
Returns up to DNSCACHE_MAX_RESP addresses per resolve request.
|
||||
Performs DNS lookup on a cached request after DNSCACHE_TIMEOUT.
|
||||
Gives up on DNS lookup after DNSREQ_TIMEOUT.
|
||||
|
||||
If holdRef is valid, the reference will be held until the callback completes.
|
||||
|
||||
If no results were found, array_length == 0.
|
||||
If the callback returns false, the result will not be entered into the cache.
|
||||
|
||||
The resolved addresses may need to be promoted to IPv6.
|
||||
|
||||
If Resolve() returns false, no callback will be generated.
|
||||
*/
|
||||
bool Resolve(const char *hostname, DNSResultCallback, ThreadRefObject *holdRef = 0);
|
||||
|
||||
private:
|
||||
NetAddr _server_addr;
|
||||
volatile bool _dns_unavailable;
|
||||
FortunaOutput *_csprng;
|
||||
|
||||
private:
|
||||
Mutex _request_lock;
|
||||
DNSRequest *_request_head;
|
||||
DNSRequest *_request_tail;
|
||||
int _request_queue_size;
|
||||
|
||||
bool GetUnusedID(u16 &id); // not thread-safe, caller must lock
|
||||
bool IsValidHostname(const char *hostname);
|
||||
DNSRequest *PullRequest(u16 id); // not thread-safe, caller must lock
|
||||
|
||||
private:
|
||||
Mutex _cache_lock;
|
||||
DNSRequest *_cache_head;
|
||||
DNSRequest *_cache_tail;
|
||||
int _cache_size;
|
||||
|
||||
// These functions do not lock, caller must lock:
|
||||
void CacheAdd(DNSRequest *req); // Assumes not already in cache
|
||||
DNSRequest *CacheGet(const char *hostname); // Case-insensitive
|
||||
void CacheKill(DNSRequest *req); // Assumes already in cache
|
||||
|
||||
private:
|
||||
bool GetServerAddr();
|
||||
bool BindToRandomPort(bool ignoreUnreachable);
|
||||
bool PostDNSPacket(DNSRequest *req, u32 now);
|
||||
bool PerformLookup(DNSRequest *req); // not thread-safe, caller must lock
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
|
||||
virtual void OnClose();
|
||||
virtual void OnUnreachable(const NetAddr &src);
|
||||
|
||||
protected:
|
||||
void ProcessDNSResponse(DNSRequest *req, int qdcount, int ancount, u8 *data, u32 bytes);
|
||||
void NotifyRequesters(DNSRequest *req);
|
||||
|
||||
private:
|
||||
WaitableFlag _kill_flag;
|
||||
|
||||
bool ThreadFunction(void *param);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_DNS_CLIENT_HPP
|
||||
188
DependentExtensions/cat/net/Sockets.hpp
Normal file
188
DependentExtensions/cat/net/Sockets.hpp
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_SOCKETS_HPP
|
||||
#define CAT_SOCKETS_HPP
|
||||
|
||||
#include <cat/Platform.hpp>
|
||||
#include <string>
|
||||
|
||||
#if defined(CAT_OS_WINDOWS)
|
||||
# include <WS2tcpip.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define CAT_IP4_LOOPBACK "127.0.0.1"
|
||||
#define CAT_IP6_LOOPBACK "::1"
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
//// Data Types
|
||||
|
||||
#if defined(CAT_OS_WINDOWS)
|
||||
typedef SOCKET Socket;
|
||||
CAT_INLINE bool CloseSocket(Socket s) { return !closesocket(s); }
|
||||
#else
|
||||
typedef int Socket;
|
||||
static const Socket INVALID_SOCKET = -1;
|
||||
static const int SOCKET_ERROR = -1;
|
||||
CAT_INLINE bool CloseSocket(Socket s) { return !close(s); }
|
||||
#endif
|
||||
|
||||
typedef u16 Port;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
// Wrapper for IPv4 and IPv6 addresses
|
||||
class NetAddr
|
||||
{
|
||||
union
|
||||
{
|
||||
u8 v6_bytes[16];
|
||||
u16 v6_words[8];
|
||||
u64 v6[2];
|
||||
struct {
|
||||
u32 v4;
|
||||
u32 v4_padding[3];
|
||||
};
|
||||
} _ip; // Network order
|
||||
|
||||
union
|
||||
{
|
||||
u32 _valid;
|
||||
struct {
|
||||
Port _port; // Host order
|
||||
u16 _family; // Host order
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
static const int IP4_BYTES = 4;
|
||||
static const int IP6_BYTES = 16;
|
||||
|
||||
typedef sockaddr_in6 SockAddr;
|
||||
|
||||
public:
|
||||
CAT_INLINE NetAddr() {}
|
||||
NetAddr(const char *ip_str, Port port = 0);
|
||||
NetAddr(const sockaddr_in6 &addr);
|
||||
NetAddr(const sockaddr_in &addr);
|
||||
NetAddr(const sockaddr *addr);
|
||||
NetAddr(int a, int b, int c, int d, Port port = 0);
|
||||
|
||||
public:
|
||||
NetAddr(const NetAddr &addr);
|
||||
NetAddr &operator=(const NetAddr &addr);
|
||||
|
||||
public:
|
||||
bool Wrap(const sockaddr_in6 &addr);
|
||||
bool Wrap(const sockaddr_in &addr);
|
||||
bool Wrap(const sockaddr *addr);
|
||||
|
||||
public:
|
||||
// Promote an IPv4 address to an IPv6 address if needed
|
||||
bool PromoteTo6();
|
||||
|
||||
// Demote an IPv6 address to an IPv4 address if possible,
|
||||
// otherwise marks address as invalid and returns false
|
||||
bool DemoteTo4();
|
||||
|
||||
CAT_INLINE bool Convert(bool To6) { if (To6) return PromoteTo6(); else return DemoteTo4(); }
|
||||
|
||||
public:
|
||||
CAT_INLINE bool Valid() const { return _valid != 0; }
|
||||
CAT_INLINE bool Is6() const { return _family == AF_INET6; }
|
||||
|
||||
CAT_INLINE const u32 GetIP4() const { return _ip.v4; }
|
||||
CAT_INLINE const u64 *GetIP6() const { return _ip.v6; }
|
||||
|
||||
CAT_INLINE Port GetPort() const { return _port; }
|
||||
CAT_INLINE void SetPort(Port port) { _port = port; }
|
||||
|
||||
// Mark the address as invalid
|
||||
CAT_INLINE void Invalidate() { _valid = 0; }
|
||||
|
||||
public:
|
||||
bool EqualsIPOnly(const NetAddr &addr) const;
|
||||
bool operator==(const NetAddr &addr) const;
|
||||
bool operator!=(const NetAddr &addr) const;
|
||||
|
||||
public:
|
||||
// To validate external input; don't want clients connecting
|
||||
// to their local network instead of the actual game server.
|
||||
bool IsInternetRoutable();
|
||||
|
||||
// Returns true if the address is routable on local network or Internet.
|
||||
// Returns false if the address is IPv4 multicast, loopback, or weird.
|
||||
bool IsRoutable();
|
||||
|
||||
public:
|
||||
bool SetFromString(const char *ip_str, Port port = 0);
|
||||
std::string IPToString() const;
|
||||
|
||||
bool SetFromRawIP(const u8 *ip_binary, int bytes);
|
||||
bool SetFromDotDecimals(int a, int b, int c, int d, Port port = 0);
|
||||
|
||||
public:
|
||||
bool Unwrap(SockAddr &addr, int &addr_len, bool PromoteToIP6 = false) const;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
//// Helper Functions
|
||||
|
||||
// Run startup and cleanup functions needed under some OS
|
||||
bool StartupSockets(); // returns false on error
|
||||
void CleanupSockets();
|
||||
|
||||
// inout_OnlyIPv4: Indicates that only IPv4 is requested by caller
|
||||
// Sets OnlyIPv4 if IPv6 will be unsupported
|
||||
// Returns true on success
|
||||
bool CreateSocket(int type, int protocol, bool SupportIPv4, Socket &out_s, bool &inout_OnlyIPv4);
|
||||
|
||||
// Returns true on success
|
||||
bool NetBind(Socket s, Port port, bool OnlyIPv4);
|
||||
|
||||
// Returns 0 on failure
|
||||
Port GetBoundPort(Socket s);
|
||||
|
||||
|
||||
//// Error Codes
|
||||
|
||||
// Returns a string describing the last error from Winsock2 API
|
||||
std::string SocketGetLastErrorString();
|
||||
std::string SocketGetErrorString(int code);
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_SOCKETS_HPP
|
||||
116
DependentExtensions/cat/net/SphynxClient.hpp
Normal file
116
DependentExtensions/cat/net/SphynxClient.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_SPHYNX_CLIENT_HPP
|
||||
#define CAT_SPHYNX_CLIENT_HPP
|
||||
|
||||
#include <cat/net/SphynxTransport.hpp>
|
||||
#include <cat/crypt/tunnel/KeyAgreementInitiator.hpp>
|
||||
#include <cat/threads/Thread.hpp>
|
||||
#include <cat/threads/WaitableFlag.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
namespace sphynx {
|
||||
|
||||
|
||||
//// sphynx::Client
|
||||
|
||||
class Client : Thread, public UDPEndpoint, public Transport
|
||||
{
|
||||
static const int HANDSHAKE_TICK_RATE = 100; // milliseconds
|
||||
static const int INITIAL_HELLO_POST_INTERVAL = 200; // milliseconds
|
||||
static const int CONNECT_TIMEOUT = 6000; // milliseconds
|
||||
static const u32 MTU_PROBE_INTERVAL = 8000; // 8 seconds
|
||||
static const int CLIENT_THREAD_KILL_TIMEOUT = 10000; // 10 seconds
|
||||
|
||||
static const int SESSION_KEY_BYTES = 32;
|
||||
char _session_key[SESSION_KEY_BYTES];
|
||||
|
||||
KeyAgreementInitiator _key_agreement_initiator;
|
||||
u8 _server_public_key[PUBLIC_KEY_BYTES];
|
||||
u8 _cached_challenge[CHALLENGE_BYTES];
|
||||
|
||||
WaitableFlag _kill_flag;
|
||||
|
||||
protected:
|
||||
u32 _last_send_mstsc;
|
||||
NetAddr _server_addr;
|
||||
bool _connected;
|
||||
AuthenticatedEncryption _auth_enc;
|
||||
|
||||
// Last time a packet was received from the server -- for disconnect timeouts
|
||||
u32 _last_recv_tsc;
|
||||
|
||||
public:
|
||||
Client();
|
||||
virtual ~Client();
|
||||
|
||||
bool SetServerKey(ThreadPoolLocalStorage *tls, const void *server_key, int key_bytes, const char *session_key);
|
||||
|
||||
bool Connect(const char *hostname, Port port);
|
||||
bool Connect(const NetAddr &addr);
|
||||
|
||||
void Disconnect();
|
||||
|
||||
protected:
|
||||
bool IsConnected() { return _connected; }
|
||||
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnConnectFail() = 0;
|
||||
virtual void OnConnect(ThreadPoolLocalStorage *tls) = 0;
|
||||
virtual void OnTimestampDeltaUpdate(u32 rtt, s32 delta) {}
|
||||
virtual void OnMessage(ThreadPoolLocalStorage *tls, BufferStream msg, u32 bytes) = 0;
|
||||
virtual void OnDisconnect() = 0;
|
||||
virtual void OnTick(ThreadPoolLocalStorage *tls, u32 now) = 0;
|
||||
|
||||
private:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
|
||||
virtual void OnWrite(u32 bytes);
|
||||
|
||||
private:
|
||||
bool PostHello();
|
||||
void OnUnreachable(const NetAddr &src);
|
||||
|
||||
// Return false to remove resolve from cache
|
||||
bool OnResolve(const char *hostname, const NetAddr *array, int array_length);
|
||||
|
||||
virtual bool PostPacket(u8 *buffer, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes);
|
||||
|
||||
private:
|
||||
bool ThreadFunction(void *param);
|
||||
};
|
||||
|
||||
|
||||
} // namespace sphynx
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_SPHYNX_CLIENT_HPP
|
||||
706
DependentExtensions/cat/net/SphynxCollexion.hpp
Normal file
706
DependentExtensions/cat/net/SphynxCollexion.hpp
Normal file
@ -0,0 +1,706 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_SPHYNX_COLLEXION_HPP
|
||||
#define CAT_SPHYNX_COLLEXION_HPP
|
||||
|
||||
#include <cat/threads/Mutex.hpp>
|
||||
#include <cat/threads/RegionAllocator.hpp>
|
||||
#include <cat/net/SphynxTransport.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
namespace sphynx {
|
||||
|
||||
|
||||
/*
|
||||
The purpose of sphynx::Collexion and sphynx::CollexionIterator is to
|
||||
store lists of Connexion object references and iterate through them.
|
||||
|
||||
Since the number of clients may be in the thousands, I feel it is
|
||||
important to scale effectively. So in the Collexion data structure,
|
||||
insertion and removal are O(1) operations. Also locks should be held
|
||||
for the smallest amount of time possible, so I have taken care to make
|
||||
locks short and reduce the amount of locking. For example, the iterator
|
||||
caches large blocks of data instead of locking for each iteration.
|
||||
|
||||
The design is optimized for cache usage, re-using common code to benefit
|
||||
from code cache and allocating and accessing table entries on cache line
|
||||
boundaries to double memory performance over a naive approach.
|
||||
*/
|
||||
|
||||
|
||||
//// sphynx::Collexion
|
||||
|
||||
template<class T>
|
||||
class CollexionIterator;
|
||||
|
||||
template<class T>
|
||||
struct CollexionElement
|
||||
{
|
||||
// Number of active enumerators using this element
|
||||
// If references are held it cannot be deleted
|
||||
// so the KILL flag is set on the 'next' member and
|
||||
// the final enumerator to reduce the reference count
|
||||
// to zero is responsible for removal.
|
||||
u32 refcnt;
|
||||
|
||||
// Bitfield:
|
||||
// 1 bit: COLLISION FLAG
|
||||
// 1 bit: KILL FLAG
|
||||
// 30 bits: Table index to next element in list + 1
|
||||
u32 next;
|
||||
|
||||
// Data at this table element
|
||||
T *conn;
|
||||
};
|
||||
|
||||
struct CollexionElement2
|
||||
{
|
||||
// Previous table element in list + 1
|
||||
u32 last;
|
||||
|
||||
// Hash of data pointer from main entry (so it doesn't need to be recalculated during growth)
|
||||
u32 hash;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class Collexion
|
||||
{
|
||||
static const u32 COLLIDE_MASK = 0x80000000;
|
||||
static const u32 KILL_MASK = 0x40000000;
|
||||
static const u32 NEXT_MASK = 0x3fffffff;
|
||||
static const u32 MIN_ALLOCATED = 32;
|
||||
|
||||
private:
|
||||
// Number of used table elements
|
||||
u32 _used;
|
||||
|
||||
// Number of allocated table elements
|
||||
u32 _allocated;
|
||||
|
||||
// First table index in list of active elements
|
||||
u32 _first;
|
||||
|
||||
// Primary table
|
||||
CollexionElement<T> *_table;
|
||||
|
||||
// Secondary table, split off so that primary table elements will
|
||||
// fit on a cache line. Contains data that is only accessed rarely.
|
||||
CollexionElement2 *_table2;
|
||||
|
||||
// Table lock
|
||||
Mutex _lock;
|
||||
|
||||
protected:
|
||||
// Attempt to double size of hash table (does not hold lock)
|
||||
bool DoubleTable();
|
||||
|
||||
// Hash a pointer to a 32-bit table key
|
||||
static CAT_INLINE u32 HashPtr(T *ptr)
|
||||
{
|
||||
u64 key = 0xBADdecafDEADbeef;
|
||||
|
||||
#if defined(CAT_WORD_64)
|
||||
key ^= *(u64*)&ptr;
|
||||
#else
|
||||
key ^= *(u32*)&ptr;
|
||||
#endif
|
||||
|
||||
key = (~key) + (key << 18);
|
||||
key = key ^ (key >> 31);
|
||||
key = key * 21;
|
||||
key = key ^ (key >> 11);
|
||||
key = key + (key << 6);
|
||||
key = key ^ (key >> 22);
|
||||
return (u32)key;
|
||||
}
|
||||
|
||||
// Common functions shared by interface for good code cache usage:
|
||||
|
||||
// Unlink a table key
|
||||
void Unlink(u32 key);
|
||||
|
||||
// Fill an iterator with the next set of data
|
||||
// Returns false if no data remains to fill
|
||||
void Fill(CollexionIterator<T> &iter, u32 first);
|
||||
|
||||
// Find a hash table key based on data
|
||||
u32 Find(T *conn);
|
||||
|
||||
public:
|
||||
// Ctor zeros everything
|
||||
Collexion()
|
||||
{
|
||||
_first = 0;
|
||||
_used = 0;
|
||||
_allocated = 0;
|
||||
_table = 0;
|
||||
_table2 = 0;
|
||||
}
|
||||
|
||||
// Dtor releases dangling memory
|
||||
~Collexion();
|
||||
|
||||
// Returns true if table is empty
|
||||
CAT_INLINE bool IsEmpty() { return _used == 0; }
|
||||
|
||||
// Insert Connexion object, return false if already present or out of memory
|
||||
bool Insert(T *conn);
|
||||
|
||||
// Remove Connexion object from list if it exists
|
||||
bool Remove(T *conn);
|
||||
|
||||
// Begin iterating through list
|
||||
void Begin(CollexionIterator<T> &iter);
|
||||
|
||||
// Iterate
|
||||
void Next(CollexionIterator<T> &iter, bool refill = true);
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::CollexionIterator
|
||||
|
||||
template<class T>
|
||||
class CollexionIterator
|
||||
{
|
||||
friend class Collexion<T>;
|
||||
|
||||
static const u32 MAX_CACHE = 256;
|
||||
|
||||
// Parent Collexion object
|
||||
Collexion<T> *_parent;
|
||||
|
||||
// First and last hash table indices in parent
|
||||
u32 _first, _last;
|
||||
|
||||
// Stores the size of the parent when snapshot was taken,
|
||||
// will invalidate _first and _last if table changed size
|
||||
u32 _prev_allocated;
|
||||
|
||||
// Connexion object cache, to avoid locking and unlocking a lot
|
||||
T *_cache[MAX_CACHE];
|
||||
|
||||
// Offset into cache and total elements in cache
|
||||
// Will grab another cache once offset reaches total
|
||||
u32 _offset, _total;
|
||||
|
||||
public:
|
||||
// Smart pointer -style accessors
|
||||
CAT_INLINE T *Get() throw() { return _cache[_offset]; }
|
||||
CAT_INLINE T *operator->() throw() { return _cache[_offset]; }
|
||||
CAT_INLINE T &operator*() throw() { return *_cache[_offset]; }
|
||||
CAT_INLINE operator T*() { return _cache[_offset]; }
|
||||
|
||||
public:
|
||||
// Ctor: Grabs first cache of Connexions
|
||||
CollexionIterator(Collexion<T> &begin);
|
||||
|
||||
// Dtor: Calls Release()
|
||||
~CollexionIterator();
|
||||
|
||||
// Iterate to next Connexion object in list
|
||||
CollexionIterator &operator++();
|
||||
|
||||
// Releases reference to any outstanding Connexions
|
||||
void Release();
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::Collexion
|
||||
|
||||
template<class T>
|
||||
bool Collexion<T>::DoubleTable()
|
||||
{
|
||||
u32 new_allocated = _allocated << 1;
|
||||
if (new_allocated < MIN_ALLOCATED) new_allocated = MIN_ALLOCATED;
|
||||
|
||||
// Allocate secondary table
|
||||
u32 new_bytes2 = sizeof(CollexionElement2) * new_allocated;
|
||||
CollexionElement2 *new_table2 = reinterpret_cast<CollexionElement2*>(
|
||||
RegionAllocator::ii->Acquire(new_bytes2) );
|
||||
|
||||
if (!new_table2) return false;
|
||||
|
||||
// Allocate primary table
|
||||
u32 new_bytes = sizeof(CollexionElement<T>) * new_allocated;
|
||||
CollexionElement<T> *new_table = reinterpret_cast<CollexionElement<T> *>(
|
||||
RegionAllocator::ii->Acquire(new_bytes) );
|
||||
|
||||
if (!new_table)
|
||||
{
|
||||
RegionAllocator::ii->Release(new_table2);
|
||||
return false;
|
||||
}
|
||||
|
||||
CAT_CLR(new_table, new_bytes);
|
||||
|
||||
u32 new_first = 0;
|
||||
|
||||
if (_table && _table2)
|
||||
{
|
||||
// For each entry in the old table,
|
||||
u32 ii = _first, mask = _allocated - 1;
|
||||
|
||||
while (ii)
|
||||
{
|
||||
--ii;
|
||||
CollexionElement<T> *oe = &_table[ii];
|
||||
u32 hash = _table2[ii].hash;
|
||||
u32 key = hash & mask;
|
||||
|
||||
// While collisions occur,
|
||||
while (new_table[key].conn)
|
||||
{
|
||||
// Mark collision
|
||||
new_table[key].next |= COLLIDE_MASK;
|
||||
|
||||
// Walk collision list
|
||||
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
|
||||
}
|
||||
|
||||
// Fill new table element
|
||||
new_table[key].conn = oe->conn;
|
||||
new_table2[key].hash = hash;
|
||||
// new_table[key].refcnt is already zero
|
||||
|
||||
// Link new element to new list
|
||||
if (new_first)
|
||||
{
|
||||
new_table[key].next |= new_first;
|
||||
new_table2[new_first - 1].last = key;
|
||||
}
|
||||
// new_table[key].next is already zero so no need to zero it here
|
||||
new_first = key + 1;
|
||||
|
||||
// Get next old table entry
|
||||
ii = oe->next & NEXT_MASK;
|
||||
}
|
||||
|
||||
// Zero head->last
|
||||
new_table2[new_first - 1].last = 0;
|
||||
}
|
||||
|
||||
// Resulting linked list starting with _first-1 will extend until e->next == 0
|
||||
|
||||
if (_table2) RegionAllocator::ii->Release(_table2);
|
||||
if (_table) RegionAllocator::ii->Release(_table);
|
||||
|
||||
_table = new_table;
|
||||
_table2 = new_table2;
|
||||
_allocated = new_allocated;
|
||||
_first = new_first;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Collexion<T>::~Collexion()
|
||||
{
|
||||
if (_table2)
|
||||
{
|
||||
RegionAllocator::ii->Release(_table2);
|
||||
}
|
||||
|
||||
// If table doesn't exist, return
|
||||
if (!_table) return;
|
||||
|
||||
// For each allocated table entry,
|
||||
for (u32 ii = 0; ii < _allocated; ++ii)
|
||||
{
|
||||
// Get Connexion object
|
||||
T *conn = _table[ii].conn;
|
||||
|
||||
// If object is valid, release it
|
||||
if (conn) conn->ReleaseRef();
|
||||
}
|
||||
|
||||
// Release table memory
|
||||
RegionAllocator::ii->Release(_table);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool Collexion<T>::Insert(T *conn)
|
||||
{
|
||||
u32 hash = HashPtr(conn);
|
||||
conn->AddRef();
|
||||
|
||||
AutoMutex lock(_lock);
|
||||
|
||||
// If more than half of the table will be used,
|
||||
if (_used >= (_allocated >> 1))
|
||||
{
|
||||
// Double the size of the table (O(1) allocation pattern)
|
||||
// Growing pains are softened by careful design
|
||||
if (!DoubleTable())
|
||||
{
|
||||
// On growth failure, return false
|
||||
lock.Release();
|
||||
|
||||
conn->ReleaseRef();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Mask off high bits to make table key from hash
|
||||
u32 mask = _allocated - 1;
|
||||
u32 key = hash & mask;
|
||||
|
||||
// While empty table entry not found,
|
||||
while (_table[key].conn)
|
||||
{
|
||||
// If Connexion object is already in the table,
|
||||
if (_table[key].conn == conn)
|
||||
{
|
||||
// Return false on duplicate
|
||||
lock.Release();
|
||||
|
||||
conn->ReleaseRef();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark as a collision
|
||||
_table[key].next |= COLLIDE_MASK;
|
||||
|
||||
// Walk collision list
|
||||
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
|
||||
}
|
||||
|
||||
// Fill new element
|
||||
_table[key].conn = conn;
|
||||
_table[key].refcnt = 0;
|
||||
_table2[key].hash = hash;
|
||||
_table2[key].last = 0;
|
||||
|
||||
// Link new element to front of list
|
||||
if (_first) _table2[_first - 1].last = key + 1;
|
||||
_table[key].next = (_table[key].next & COLLIDE_MASK) | _first;
|
||||
_first = key + 1;
|
||||
|
||||
++_used;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Collexion<T>::Unlink(u32 key)
|
||||
{
|
||||
// Clear reference
|
||||
_table[key].conn = 0;
|
||||
|
||||
// Unlink from active list
|
||||
u32 next = _table[key].next & NEXT_MASK;
|
||||
u32 last = _table2[key].last;
|
||||
|
||||
if (last) _table[last-1].next = (_table[last-1].next & ~NEXT_MASK) | next;
|
||||
else _first = next;
|
||||
if (next) _table2[next-1].last = last;
|
||||
|
||||
// If this key was a leaf on a collision wind,
|
||||
if (!(_table[key].next & COLLIDE_MASK))
|
||||
{
|
||||
u32 mask = _allocated - 1;
|
||||
|
||||
do
|
||||
{
|
||||
// Go backwards through the collision list one step
|
||||
key = ((key + COLLISION_INCRINVERSE) * COLLISION_MULTINVERSE) & mask;
|
||||
|
||||
// Stop where collision list stops
|
||||
if (!(_table[key].next & COLLIDE_MASK))
|
||||
break;
|
||||
|
||||
// Turn off collision key for previous entry
|
||||
_table[key].next &= ~COLLIDE_MASK;
|
||||
|
||||
} while (!_table[key].conn);
|
||||
}
|
||||
|
||||
// Update number of used elements
|
||||
--_used;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool Collexion<T>::Remove(T *conn)
|
||||
{
|
||||
u32 hash = HashPtr(conn);
|
||||
|
||||
AutoMutex lock(_lock);
|
||||
|
||||
// If table doesn't exist,
|
||||
if (!_allocated) return false;
|
||||
|
||||
// Mask off high bits to make table key from hash
|
||||
u32 mask = _allocated - 1;
|
||||
u32 key = hash & mask;
|
||||
|
||||
// While target table entry not found,
|
||||
for (;;)
|
||||
{
|
||||
// If target was found,
|
||||
if (_table[key].conn == conn)
|
||||
{
|
||||
if (_table[key].refcnt)
|
||||
{
|
||||
// Mark it killed so iterator can clean it up when it's finished
|
||||
_table[key].next |= KILL_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Unlink(key);
|
||||
|
||||
lock.Release();
|
||||
|
||||
conn->ReleaseRef();
|
||||
}
|
||||
|
||||
// Return success
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(_table[key].next & COLLIDE_MASK))
|
||||
{
|
||||
break; // End of collision list
|
||||
}
|
||||
|
||||
// Walk collision list
|
||||
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
|
||||
}
|
||||
|
||||
// Return failure: not found
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Collexion<T>::Fill(CollexionIterator<T> &iter, u32 first)
|
||||
{
|
||||
u32 key = first;
|
||||
|
||||
// Find first list element that does not want to die
|
||||
while (key && (_table[key-1].next & KILL_MASK))
|
||||
{
|
||||
// Go to next
|
||||
key = _table[key-1].next & NEXT_MASK;
|
||||
}
|
||||
|
||||
iter._offset = 0;
|
||||
|
||||
// If no elements in table,
|
||||
if (!key)
|
||||
{
|
||||
// Return empty set
|
||||
iter._cache[0] = 0;
|
||||
iter._total = 0;
|
||||
iter._first = 0;
|
||||
iter._last = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remember size of hash table in case it grows before iterator is done
|
||||
iter._prev_allocated = _allocated;
|
||||
|
||||
// Remember first key for next iteration
|
||||
iter._first = key;
|
||||
|
||||
// For each of the first MAX_CACHE elements in the table, copy the data pointer to cache
|
||||
u32 ii = 0, final = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// If element does not want to die,
|
||||
if (!(_table[key-1].next & KILL_MASK))
|
||||
{
|
||||
// Copy data pointer
|
||||
iter._cache[ii] = _table[key-1].conn;
|
||||
|
||||
// Increment reference count for element
|
||||
_table[key-1].refcnt++;
|
||||
|
||||
// Remember key as the next iteration starting point
|
||||
final = key;
|
||||
|
||||
// Check if copy is complete
|
||||
if (++ii >= CollexionIterator<T>::MAX_CACHE) break;
|
||||
}
|
||||
|
||||
// Go to next key
|
||||
key = _table[key-1].next & NEXT_MASK;
|
||||
|
||||
} while (key);
|
||||
|
||||
// Record number of elements written
|
||||
iter._total = ii;
|
||||
|
||||
// Remember next key for next iteration
|
||||
iter._last = final;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Collexion<T>::Begin(CollexionIterator<T> &iter)
|
||||
{
|
||||
iter._parent = this;
|
||||
|
||||
AutoMutex lock(_lock);
|
||||
|
||||
Fill(iter, _first);
|
||||
}
|
||||
|
||||
// Find a hash table key based on data
|
||||
template<class T>
|
||||
u32 Collexion<T>::Find(T *conn)
|
||||
{
|
||||
u32 mask = _allocated - 1;
|
||||
u32 key = HashPtr(conn) & mask;
|
||||
|
||||
// Find the object in the collision list starting at the expected location
|
||||
while (_table[key].conn != conn)
|
||||
{
|
||||
// If at the end of the collision list,
|
||||
if (!(_table[key].next & COLLIDE_MASK))
|
||||
break; // Should never happen
|
||||
|
||||
// Walk collision list
|
||||
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Collexion<T>::Next(CollexionIterator<T> &iter, bool refill)
|
||||
{
|
||||
T *release_list[CollexionIterator<T>::MAX_CACHE];
|
||||
u32 release_ii = 0;
|
||||
|
||||
u32 key = iter._first;
|
||||
u32 last = iter._last;
|
||||
|
||||
// If iteration is done,
|
||||
if (!key) return;
|
||||
|
||||
AutoMutex lock(_lock);
|
||||
|
||||
// If hash table changed size (rare),
|
||||
if (iter._prev_allocated != _allocated)
|
||||
{
|
||||
// iter._first and iter._last are invalid
|
||||
// ...but we can find them again based on the cached pointers!
|
||||
key = Find(iter._cache[0]) + 1;
|
||||
last = Find(iter._cache[iter._total - 1]) + 1;
|
||||
}
|
||||
|
||||
last = _table[last-1].next & NEXT_MASK;
|
||||
|
||||
// Release any table elements that want to die now
|
||||
do
|
||||
{
|
||||
u32 flags = _table[key-1].next;
|
||||
|
||||
// If reference count is now zero for this element,
|
||||
if (0 == --_table[key-1].refcnt)
|
||||
{
|
||||
// If element wants to die,
|
||||
if (flags & KILL_MASK)
|
||||
{
|
||||
// Prepare to release data after lock is released
|
||||
release_list[release_ii++] = _table[key-1].conn;
|
||||
|
||||
Unlink(key-1);
|
||||
}
|
||||
}
|
||||
|
||||
key = flags & NEXT_MASK;
|
||||
|
||||
} while (key != last);
|
||||
|
||||
// Fill iterator starting with next key
|
||||
if (refill) Fill(iter, key);
|
||||
|
||||
lock.Release();
|
||||
|
||||
if (!refill)
|
||||
{
|
||||
// Return empty set
|
||||
iter._cache[0] = 0;
|
||||
iter._total = 0;
|
||||
iter._offset = 0;
|
||||
iter._first = 0;
|
||||
iter._last = 0;
|
||||
}
|
||||
|
||||
// Release data awaiting destruction
|
||||
for (u32 ii = 0; ii < release_ii; ++ii)
|
||||
{
|
||||
release_list[ii]->ReleaseRef();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// sphynx::CollexionIterator
|
||||
|
||||
template<class T>
|
||||
CollexionIterator<T>::CollexionIterator(Collexion<T> &begin)
|
||||
{
|
||||
begin.Begin(*this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CollexionIterator<T>::~CollexionIterator()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CollexionIterator<T> &CollexionIterator<T>::operator++()
|
||||
{
|
||||
if (++_offset >= _total)
|
||||
{
|
||||
_parent->Next(*this, true);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void CollexionIterator<T>::Release()
|
||||
{
|
||||
if (_parent)
|
||||
{
|
||||
_parent->Next(*this, false);
|
||||
_parent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace sphynx
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_SPHYNX_COLLEXION_HPP
|
||||
300
DependentExtensions/cat/net/SphynxServer.hpp
Normal file
300
DependentExtensions/cat/net/SphynxServer.hpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_SPHYNX_SERVER_HPP
|
||||
#define CAT_SPHYNX_SERVER_HPP
|
||||
|
||||
#include <cat/net/SphynxTransport.hpp>
|
||||
#include <cat/threads/RWLock.hpp>
|
||||
#include <cat/threads/Thread.hpp>
|
||||
#include <cat/threads/WaitableFlag.hpp>
|
||||
#include <cat/net/SphynxCollexion.hpp>
|
||||
#include <cat/crypt/cookie/CookieJar.hpp>
|
||||
#include <cat/crypt/tunnel/KeyAgreementResponder.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
namespace sphynx {
|
||||
|
||||
|
||||
/*
|
||||
Designed for server hardware with many processors.
|
||||
|
||||
In order to handle many users, the Sphynx server opens up a single UDP port
|
||||
to accept new connections, and several other UDP data ports for data.
|
||||
|
||||
For retransmissions and detecting link loss due to timeout, the server runs
|
||||
several additional threads that wake up periodically to perform timed tasks.
|
||||
|
||||
Server uses thread pool to receive packets on connect and worker ports,
|
||||
meaning that packets are processed by any free CPU as soon as they arrive.
|
||||
|
||||
Sphynx Server
|
||||
UDP Hello Port [1]
|
||||
+ In case this thread spins constantly, only use one CPU for new
|
||||
connections since in-game experience is more important than login
|
||||
+ Assigns users to a data port after handshake completes
|
||||
|
||||
UDP Data Ports [4 * (CPU Count)]
|
||||
+ Spread users evenly across several ports since
|
||||
only one packet can be processed from a single port at a time
|
||||
+ Any free CPU will process incoming packets as fast as possible
|
||||
|
||||
ServerTimer threads [(CPU Count) / 2]
|
||||
+ In case these threads spin constantly, they only consume
|
||||
half of the CPU resources available
|
||||
+ Wake up every X milliseconds according to Transport::TICK_RATE
|
||||
+ Detect link loss due to silence timeout
|
||||
+ Update transport layer
|
||||
+ Retransmit lost messages
|
||||
+ Re-evaluate bandwidth and transmit queued messages
|
||||
*/
|
||||
|
||||
|
||||
//// sphynx::Connexion
|
||||
|
||||
// Derive from sphynx::Connexion and sphynx::Server to define server behavior
|
||||
class Connexion : public Transport, public ThreadRefObject
|
||||
{
|
||||
friend class Server;
|
||||
friend class Map;
|
||||
friend class ServerWorker;
|
||||
friend class ServerTimer;
|
||||
|
||||
public:
|
||||
Connexion();
|
||||
virtual ~Connexion() {}
|
||||
|
||||
private:
|
||||
volatile u32 _destroyed;
|
||||
|
||||
u32 _key; // Map hash table index, unique for each active connection
|
||||
Connexion *_next_delete;
|
||||
ServerWorker *_server_worker;
|
||||
|
||||
u8 _first_challenge[64]; // First challenge seen from this client address
|
||||
u8 _cached_answer[128]; // Cached answer to this first challenge, to avoid eating server CPU time
|
||||
|
||||
private:
|
||||
// Return false to destroy this object
|
||||
bool Tick(ThreadPoolLocalStorage *tls, u32 now);
|
||||
|
||||
void OnRawData(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes);
|
||||
|
||||
virtual bool PostPacket(u8 *buffer, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes);
|
||||
|
||||
public:
|
||||
CAT_INLINE bool IsValid() { return _destroyed == 0; }
|
||||
CAT_INLINE u32 GetKey() { return _key; }
|
||||
|
||||
void Destroy();
|
||||
|
||||
protected:
|
||||
NetAddr _client_addr;
|
||||
|
||||
// Last time a packet was received from this user -- for disconnect timeouts
|
||||
u32 _last_recv_tsc;
|
||||
|
||||
bool _seen_encrypted;
|
||||
AuthenticatedEncryption _auth_enc;
|
||||
|
||||
protected:
|
||||
virtual void OnConnect(ThreadPoolLocalStorage *tls) = 0;
|
||||
virtual void OnDestroy() = 0;
|
||||
virtual void OnTick(ThreadPoolLocalStorage *tls, u32 now) = 0;
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::Map
|
||||
|
||||
class Map
|
||||
{
|
||||
protected:
|
||||
CAT_INLINE u32 hash_addr(const NetAddr &addr, u32 salt);
|
||||
|
||||
public:
|
||||
struct Slot
|
||||
{
|
||||
Connexion *connection;
|
||||
bool collision;
|
||||
Slot *next;
|
||||
};
|
||||
|
||||
protected:
|
||||
u32 _hash_salt;
|
||||
CAT_ALIGNED(16) Slot _table[HASH_TABLE_SIZE];
|
||||
RWLock _table_lock;
|
||||
|
||||
public:
|
||||
Map();
|
||||
virtual ~Map();
|
||||
|
||||
// Lookup client by address
|
||||
Connexion *Lookup(const NetAddr &addr);
|
||||
|
||||
// Lookup client by key
|
||||
Connexion *Lookup(u32 key);
|
||||
|
||||
// May return false if network address in Connexion is already in the map.
|
||||
// This averts a potential race condition but should never happen during
|
||||
// normal operation, so the Connexion allocation by caller won't be wasted.
|
||||
bool Insert(Connexion *conn);
|
||||
|
||||
// Destroy a list described by the 'next' member of Slot
|
||||
void DestroyList(Map::Slot *kill_list);
|
||||
|
||||
void Tick(ThreadPoolLocalStorage *tls);
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::ServerWorker
|
||||
|
||||
class ServerWorker : public UDPEndpoint
|
||||
{
|
||||
friend class Map;
|
||||
|
||||
protected:
|
||||
Map *_conn_map;
|
||||
ServerTimer *_server_timer;
|
||||
|
||||
protected:
|
||||
volatile u32 _session_count;
|
||||
|
||||
public:
|
||||
ServerWorker(Map *conn_map, ServerTimer *server_timer);
|
||||
virtual ~ServerWorker();
|
||||
|
||||
void IncrementPopulation();
|
||||
void DecrementPopulation();
|
||||
u32 GetPopulation() { return _session_count; }
|
||||
|
||||
protected:
|
||||
void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
|
||||
void OnWrite(u32 bytes) {}
|
||||
void OnClose();
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::ServerTimer
|
||||
|
||||
class ServerTimer : Thread
|
||||
{
|
||||
protected:
|
||||
Map *_conn_map;
|
||||
|
||||
protected:
|
||||
ServerWorker **_workers;
|
||||
int _worker_count;
|
||||
|
||||
protected:
|
||||
Map::Slot *_insert_head;
|
||||
Mutex _insert_lock;
|
||||
|
||||
protected:
|
||||
Map::Slot *_active_head;
|
||||
|
||||
public:
|
||||
ServerTimer(Map *conn_map, ServerWorker **workers, int worker_count);
|
||||
virtual ~ServerTimer();
|
||||
|
||||
CAT_INLINE bool Valid() { return _worker_count > 0; }
|
||||
|
||||
public:
|
||||
void InsertSlot(Map::Slot *slot);
|
||||
|
||||
protected:
|
||||
CAT_INLINE void Tick(ThreadPoolLocalStorage *tls);
|
||||
bool ThreadFunction(void *param);
|
||||
|
||||
protected:
|
||||
static const int TIMER_THREAD_KILL_TIMEOUT = 10000;
|
||||
|
||||
WaitableFlag _kill_flag;
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::Server
|
||||
|
||||
class Server : public UDPEndpoint
|
||||
{
|
||||
public:
|
||||
Server();
|
||||
virtual ~Server();
|
||||
|
||||
bool StartServer(ThreadPoolLocalStorage *tls, Port port, u8 *public_key, int public_bytes, u8 *private_key, int private_bytes, const char *session_key);
|
||||
|
||||
u32 GetTotalPopulation();
|
||||
|
||||
static bool GenerateKeyPair(ThreadPoolLocalStorage *tls, const char *public_key_file,
|
||||
const char *private_key_file, u8 *public_key,
|
||||
int public_bytes, u8 *private_key, int private_bytes);
|
||||
|
||||
private:
|
||||
static const int SESSION_KEY_BYTES = 32;
|
||||
char _session_key[SESSION_KEY_BYTES];
|
||||
|
||||
Port _server_port;
|
||||
Map _conn_map;
|
||||
|
||||
CookieJar _cookie_jar;
|
||||
KeyAgreementResponder _key_agreement_responder;
|
||||
u8 _public_key[PUBLIC_KEY_BYTES];
|
||||
|
||||
static const int WORKER_LIMIT = 32; // Maximum number of workers
|
||||
ServerWorker **_workers;
|
||||
int _worker_count;
|
||||
|
||||
ServerTimer **_timers;
|
||||
int _timer_count;
|
||||
|
||||
private:
|
||||
ServerWorker *FindLeastPopulatedPort();
|
||||
|
||||
void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
|
||||
void OnWrite(u32 bytes);
|
||||
void OnClose();
|
||||
|
||||
protected:
|
||||
// Must return a new instance of your Connexion derivation
|
||||
virtual Connexion *NewConnexion() = 0;
|
||||
|
||||
// IP address filter: Return true to allow the connection to be made
|
||||
virtual bool AcceptNewConnexion(const NetAddr &src) = 0;
|
||||
|
||||
// Lookup client by key
|
||||
Connexion *Lookup(u32 key);
|
||||
};
|
||||
|
||||
|
||||
} // namespace sphynx
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_SPHYNX_SERVER_HPP
|
||||
455
DependentExtensions/cat/net/SphynxTransport.hpp
Normal file
455
DependentExtensions/cat/net/SphynxTransport.hpp
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_SPHYNX_TRANSPORT_HPP
|
||||
#define CAT_SPHYNX_TRANSPORT_HPP
|
||||
|
||||
#include <cat/net/ThreadPoolSockets.hpp>
|
||||
#include <cat/threads/Mutex.hpp>
|
||||
#include <cat/crypt/tunnel/AuthenticatedEncryption.hpp>
|
||||
#include <cat/parse/BufferStream.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
namespace sphynx {
|
||||
|
||||
|
||||
/*
|
||||
Based on what I have envisioned needing for my game, the following protocol is being
|
||||
used after spending weeks looking at alternatives and false-starts. It provides signaled
|
||||
disconnects, fragmentation, MTU discovery, time synchronization, three reliable ordered
|
||||
streams, one unordered reliable stream, and unreliable delivery.
|
||||
|
||||
The Transport object that implements a sender/receiver in the protocol requires 276 bytes
|
||||
of memory per server connection, plus 32 bytes per message fragment in flight, plus buffers
|
||||
for queued send/recv packets, and it keeps two mutexes for thread-safety. A lockless memory
|
||||
allocator is used to allocate all buffers except the fragmented message reassembly buffer.
|
||||
|
||||
Packet format on top of UDP header:
|
||||
|
||||
E { HDR(2 bytes)|ACK-ID(3 bytes)|DATA || ... || MAC(8 bytes) } || IV(3 bytes)
|
||||
|
||||
E: ChaCha-12 stream cipher.
|
||||
IV: Initialization vector used by security layer (Randomly initialized).
|
||||
MAC: Message authentication code used by security layer (HMAC-MD5).
|
||||
|
||||
HDR|ACK-ID|DATA: A message block inside the datagram. The HDR and ACK-ID
|
||||
fields employ compression to use as little as 1 byte together.
|
||||
|
||||
Each message follows the same format. A two-byte header followed by data:
|
||||
|
||||
--- Message Header (16 bits) ---
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
<-- LSB ----------------- MSB -->
|
||||
| BHI |I|R| SOP | BLO |
|
||||
---------------------------------
|
||||
|
||||
DATA_BYTES: BHI | BLO = Number of bytes in data part of message.
|
||||
If BHI = "111"b, the BLO byte is omitted and the receiver can
|
||||
assume that the rest of the packet contains just one message.
|
||||
I: 1=Followed by ACK-ID field. 0=ACK-ID is one higher than the last.
|
||||
R: 1=Reliable. 0=Unreliable.
|
||||
SOP: Super opcodes:
|
||||
0=Data (reliable or unreliable)
|
||||
1=Fragment (reliable)
|
||||
2=ACK (unreliable)
|
||||
3=MTU Probe (unreliable)
|
||||
4=MTU Set (unordered reliable)
|
||||
5=Time Ping (unreliable)
|
||||
6=Time Pong (unreliable)
|
||||
7=Disconnect (unreliable)
|
||||
|
||||
When the I bit is set, the data part is preceded by an ACK-ID,
|
||||
which is then applied to all following reliable messages.
|
||||
This additional size is NOT accounted for in the DATA_BYTES field.
|
||||
|
||||
When the FRAG opcode used for the first time in an ordered stream,
|
||||
the data part begins with a 16-bit Fragment Header.
|
||||
This additional size IS accounted for in the DATA_BYTES field.
|
||||
|
||||
Often times there is just one message in a datagram. To compress
|
||||
the header in this case, when BHI = 7 the receiver assumes that
|
||||
only one message is in the packet and uses the payload length to
|
||||
determine the length of the single message. BLO byte is omitted.
|
||||
|
||||
This *could* also be used on the final message in a cluster,
|
||||
but it cannot be done without a memcpy to cover up the extra
|
||||
header byte, which I don't consider worthwhile...
|
||||
|
||||
------------- ACK-ID Field (24 bits) ------------
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
|
||||
<-- LSB --------------------------------- MSB -->
|
||||
| S | IDA (5) |C| IDB (7) |C| IDC (8) |
|
||||
-------------------------------------------------
|
||||
|
||||
C: 1=Continues to next byte.
|
||||
S: 0=Unordered stream, 1-3: Ordered streams.
|
||||
ID: IDC | IDB | IDA (20 bits)
|
||||
|
||||
On retransmission, the ACK-ID field uses no compression
|
||||
since the receiver state cannot be determined.
|
||||
|
||||
--- Fragment Header (16 bits) ---
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
<-- LSB ----------------- MSB -->
|
||||
| TOTAL_BYTES(16) |
|
||||
---------------------------------
|
||||
|
||||
TOTAL_BYTES: Total bytes in data part of fragmented message,
|
||||
not including this header.
|
||||
*/
|
||||
|
||||
/*
|
||||
ACK message format:
|
||||
|
||||
Header: I=0, R=0, SOP=SOP_ACK
|
||||
Data: ROLLUP(3) || RANGE1 || RANGE2 || ... ROLLUP(3) || RANGE1 || RANGE2 || ...
|
||||
|
||||
ROLLUP = Next expected ACK-ID. Acknowledges every ID before this one.
|
||||
|
||||
RANGE1:
|
||||
START || END
|
||||
|
||||
START = First inclusive ACK-ID in a range to acknowledge.
|
||||
END = Final inclusive ACK-ID in a range to acknowledge.
|
||||
|
||||
Negative acknowledgment can be inferred from the holes in the RANGEs.
|
||||
|
||||
------------ ROLLUP Field (24 bits) -------------
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
|
||||
<-- LSB --------------------------------- MSB -->
|
||||
|1| S | IDA (5) | IDB (8) | IDC (8) |
|
||||
-------------------------------------------------
|
||||
|
||||
1: Indicates start of ROLLUP field.
|
||||
S: 0=Unordered stream, 1-3: Ordered streams.
|
||||
ID: IDC | IDB | IDA (21 bits)
|
||||
|
||||
ROLLUP is always 3 bytes since we cannot tell how far ahead the remote host is now.
|
||||
|
||||
--------- RANGE START Field (24 bits) -----------
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
|
||||
<-- LSB --------------------------------- MSB -->
|
||||
|0|E| IDA (5) |C| IDB (7) |C| IDC (8) |
|
||||
-------------------------------------------------
|
||||
|
||||
0: Indicates start of RANGE field.
|
||||
C: 1=Continues to next byte.
|
||||
E: 1=Has end field. 0=One ID in range.
|
||||
ID: IDC | IDB | IDA (20 bits) + last ack id in message
|
||||
|
||||
---------- RANGE END Field (24 bits) ------------
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
|
||||
<-- LSB --------------------------------- MSB -->
|
||||
| IDA (7) |C| IDB (7) |C| IDC (8) |
|
||||
-------------------------------------------------
|
||||
|
||||
C: 1=Continues to next byte.
|
||||
ID: IDC | IDB | IDA (22 bits) + START.ID
|
||||
*/
|
||||
|
||||
class Connexion;
|
||||
class Map;
|
||||
class Server;
|
||||
class ServerWorker;
|
||||
class ServerTimer;
|
||||
class Client;
|
||||
class Transport;
|
||||
|
||||
#if defined(CAT_WORD_32)
|
||||
#define CAT_PACK_TRANSPORT_STATE_STRUCTURES /* For 32-bit version, this allows fragments to fit in 32 bytes */
|
||||
#else // 64-bit version:
|
||||
//#define CAT_PACK_TRANSPORT_STATE_STRUCTURES /* No advantage for 64-bit version */
|
||||
#endif
|
||||
|
||||
//#define CAT_TRANSPORT_DEBUG_LOGGING /* Enables info messages on console */
|
||||
#define CAT_VERBOSE_VALIDATION /* Enables input error messages on console */
|
||||
|
||||
// Protocol constants
|
||||
static const u32 PROTOCOL_MAGIC = 0xC47D0001;
|
||||
static const int PUBLIC_KEY_BYTES = 64;
|
||||
static const int PRIVATE_KEY_BYTES = 32;
|
||||
static const int CHALLENGE_BYTES = PUBLIC_KEY_BYTES;
|
||||
static const int ANSWER_BYTES = PUBLIC_KEY_BYTES*2;
|
||||
static const int HASH_TABLE_SIZE = 32768; // Power-of-2
|
||||
static const int HASH_TABLE_MASK = HASH_TABLE_SIZE - 1;
|
||||
static const int MAX_POPULATION = HASH_TABLE_SIZE / 2;
|
||||
|
||||
// (multiplier-1) divisible by all prime factors of table size
|
||||
// (multiplier-1) is a multiple of 4 if table size is a multiple of 4
|
||||
// These constants are from Press, Teukolsky, Vetterling and Flannery's
|
||||
// "Numerical Recipes in FORTRAN: The Art of Scientific Computing"
|
||||
static const u32 COLLISION_MULTIPLIER = 71*5861 * 4 + 1;
|
||||
static const u32 COLLISION_INCREMENTER = 1013904223;
|
||||
|
||||
// If multiplier changes, this needs to be recalculated (multiplicative inverse of above)
|
||||
static const u32 COLLISION_MULTINVERSE = 4276115653;
|
||||
static const u32 COLLISION_INCRINVERSE = 0 - COLLISION_INCREMENTER;
|
||||
|
||||
|
||||
// Handshake types
|
||||
enum HandshakeType
|
||||
{
|
||||
C2S_HELLO,
|
||||
S2C_COOKIE,
|
||||
C2S_CHALLENGE,
|
||||
S2C_ANSWER,
|
||||
S2C_ERROR
|
||||
};
|
||||
|
||||
// Handshake errors
|
||||
enum HandshakeError
|
||||
{
|
||||
ERR_SERVER_FULL
|
||||
};
|
||||
|
||||
// Stream modes
|
||||
enum StreamMode
|
||||
{
|
||||
STREAM_UNORDERED = 0, // Reliable, unordered stream 0
|
||||
STREAM_1 = 1, // Reliable, ordered stream 1
|
||||
STREAM_2 = 2, // Reliable, ordered stream 2
|
||||
STREAM_3 = 3 // Reliable, ordered stream 3
|
||||
};
|
||||
|
||||
// Super Opcodes
|
||||
enum SuperOpcode
|
||||
{
|
||||
SOP_DATA, // 0=Data (reliable or unreliable)
|
||||
SOP_FRAG, // 1=Fragment (reliable)
|
||||
SOP_ACK, // 2=ACK (unreliable)
|
||||
SOP_MTU_PROBE, // 3=MTU Probe (unreliable)
|
||||
SOP_MTU_SET, // 4=MTU Set (unordered reliable)
|
||||
SOP_TIME_PING, // 5=Time Ping (unreliable)
|
||||
SOP_TIME_PONG, // 6=Time Pong (unreliable)
|
||||
SOP_DISCO, // 7=Disconnect (unreliable)
|
||||
};
|
||||
|
||||
|
||||
//// sphynx::Transport
|
||||
|
||||
#if defined(CAT_PACK_TRANSPORT_STATE_STRUCTURES)
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
#endif // CAT_PACK_TRANSPORT_STATE_STRUCTURES
|
||||
|
||||
// Receive state: Receive queue
|
||||
struct RecvQueue
|
||||
{
|
||||
static const u32 FRAG_FLAG = 0x80000000;
|
||||
static const u32 BYTE_MASK = 0x7fffffff;
|
||||
|
||||
RecvQueue *next; // Next in queue
|
||||
RecvQueue *prev; // Previous in queue
|
||||
u32 id; // Acknowledgment id
|
||||
u32 bytes; // High bit: Fragment?
|
||||
|
||||
// Message contents follow
|
||||
};
|
||||
|
||||
// Send state: Send queue
|
||||
struct SendQueue
|
||||
{
|
||||
SendQueue *next; // Next in queue
|
||||
SendQueue *prev; // Previous in queue
|
||||
u32 ts_firstsend; // Millisecond-resolution timestamp when it was first sent
|
||||
u32 ts_lastsend; // Millisecond-resolution timestamp when it was last sent
|
||||
union
|
||||
{
|
||||
u32 sent_bytes; // In send queue: Number of sent bytes while fragmenting a large message
|
||||
u32 id; // In sent list: Acknowledgment id
|
||||
};
|
||||
u16 bytes; // Data bytes
|
||||
u16 frag_count; // Number of fragments remaining to be delivered
|
||||
u16 sop; // Super opcode of message
|
||||
|
||||
// Message contents follow
|
||||
};
|
||||
|
||||
struct SendFrag : public SendQueue
|
||||
{
|
||||
SendQueue *full_data; // Object containing message data
|
||||
u16 offset; // Fragment data offset
|
||||
};
|
||||
|
||||
// Temporary send node structure, nestled in the encryption overhead of outgoing packets
|
||||
struct TempSendNode // Size <= 11 bytes = AuthenticatedEncryption::OVERHEAD_BYTES
|
||||
{
|
||||
static const u32 SINGLE_FLAG = 0x8000;
|
||||
static const u32 BYTE_MASK = 0x7fff;
|
||||
|
||||
TempSendNode *next;
|
||||
u16 negative_offset; // Number of bytes before this structure, and single flag
|
||||
};
|
||||
|
||||
#if defined(CAT_PACK_TRANSPORT_STATE_STRUCTURES)
|
||||
#pragma pack(pop)
|
||||
#endif // CAT_PACK_TRANSPORT_STATE_STRUCTURES
|
||||
|
||||
class Transport
|
||||
{
|
||||
protected:
|
||||
static const u8 BHI_MASK = 7;
|
||||
static const u8 BHI_SINGLE_MESSAGE = 7;
|
||||
static const u8 I_MASK = 1 << 3;
|
||||
static const u8 R_MASK = 1 << 4;
|
||||
static const u32 SOP_SHIFT = 5;
|
||||
|
||||
static const u32 NUM_STREAMS = 4; // Number of reliable streams
|
||||
static const u32 MIN_RTT = 50; // Minimum milliseconds for RTT
|
||||
|
||||
static const int TIMEOUT_DISCONNECT = 15000; // 15 seconds
|
||||
static const int SILENCE_LIMIT = 9333; // 9.333 seconds: Time silent before sending a keep-alive (0-length unordered reliable message)
|
||||
|
||||
static const int TICK_RATE = 20; // 20 milliseconds
|
||||
|
||||
static const u32 MINIMUM_MTU = 576; // Dialup
|
||||
static const u32 MEDIUM_MTU = 1400; // Highspeed with unexpected overhead, maybe VPN
|
||||
static const u32 MAXIMUM_MTU = 1500; // Highspeed
|
||||
|
||||
static const u32 IPV6_OPTIONS_BYTES = 40; // TODO: Not sure about this
|
||||
static const u32 IPV6_HEADER_BYTES = 40 + IPV6_OPTIONS_BYTES;
|
||||
|
||||
static const u32 IPV4_OPTIONS_BYTES = 40;
|
||||
static const u32 IPV4_HEADER_BYTES = 20 + IPV4_OPTIONS_BYTES;
|
||||
|
||||
static const u32 UDP_HEADER_BYTES = 8;
|
||||
|
||||
static const u32 FRAG_THRESHOLD = 32; // Fragment if FRAG_THRESHOLD bytes would be in each fragment
|
||||
|
||||
static const u32 MAX_MESSAGE_DATALEN = 65535-1; // Maximum number of bytes in the data part of a message (-1 for the opcode)
|
||||
|
||||
protected:
|
||||
// Maximum transfer unit (MTU) in UDP payload bytes, excluding the IP and UDP headers and encryption overhead
|
||||
u32 _max_payload_bytes;
|
||||
|
||||
public:
|
||||
void InitializePayloadBytes(bool ip6);
|
||||
|
||||
protected:
|
||||
// Receive state: Next expected ack id to receive
|
||||
u32 _next_recv_expected_id[NUM_STREAMS];
|
||||
|
||||
// Receive state: Synchronization objects
|
||||
volatile bool _got_reliable[NUM_STREAMS];
|
||||
Mutex _recv_lock; // Just needs to protect writes OnDatagram() from messing up reads on tick
|
||||
|
||||
// Receive state: Fragmentation
|
||||
u8 *_fragment_buffer[NUM_STREAMS]; // Buffer for accumulating fragment
|
||||
u32 _fragment_length[NUM_STREAMS]; // Number of bytes in fragment buffer
|
||||
u32 _fragment_offset[NUM_STREAMS]; // Current write offset in buffer
|
||||
|
||||
static const u32 FRAG_MIN = 0; // Min bytes for a fragmented message
|
||||
static const u32 FRAG_MAX = 65535; // Max bytes for a fragmented message
|
||||
|
||||
// Receive state: Receive queue head
|
||||
RecvQueue *_recv_queue_head[NUM_STREAMS], *_recv_queue_tail[NUM_STREAMS];
|
||||
|
||||
private:
|
||||
void RunQueue(ThreadPoolLocalStorage *tls, u32 ack_id, u32 stream);
|
||||
void QueueRecv(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes, u32 ack_id, u32 stream, u32 super_opcode);
|
||||
|
||||
protected:
|
||||
// Send state: Synchronization objects
|
||||
Mutex _send_lock;
|
||||
|
||||
// Send state: Next ack id to use
|
||||
u32 _next_send_id[NUM_STREAMS];
|
||||
|
||||
// Send state: Estimated round-trip time
|
||||
u32 _rtt; // milliseconds
|
||||
|
||||
// Send state: Last rollup ack id from remote receiver
|
||||
u32 _send_next_remote_expected[NUM_STREAMS];
|
||||
|
||||
// Send state: Combined writes
|
||||
u8 *_send_buffer;
|
||||
u32 _send_buffer_bytes;
|
||||
u32 _send_buffer_stream, _send_buffer_ack_id; // Used to compress ACK-ID by setting I=0 after the first reliable message
|
||||
u32 _send_buffer_msg_count; // Used to compress datagrams with a single message by omitting the header's BLO field
|
||||
|
||||
// Queue of messages that are waiting to be sent
|
||||
SendQueue *_send_queue_head[NUM_STREAMS], *_send_queue_tail[NUM_STREAMS];
|
||||
|
||||
// List of messages that are waiting to be acknowledged
|
||||
SendQueue *_sent_list_head[NUM_STREAMS], *_sent_list_tail[NUM_STREAMS];
|
||||
|
||||
bool _disconnected;
|
||||
|
||||
private:
|
||||
void TransmitQueued();
|
||||
void Retransmit(u32 stream, SendQueue *node, u32 now); // Does not hold the send lock!
|
||||
void WriteACK();
|
||||
void OnACK(u8 *data, u32 data_bytes);
|
||||
void OnMTUSet(u8 *data, u32 data_bytes);
|
||||
|
||||
public:
|
||||
Transport();
|
||||
virtual ~Transport();
|
||||
|
||||
public:
|
||||
// ata_bytes: Length of msg_data
|
||||
bool WriteUnreliable(u8 msg_opcode, const void *msg_data = 0, u32 data_bytes = 0);
|
||||
bool WriteReliable(StreamMode, u8 msg_opcode, const void *msg_data = 0, u32 data_bytes = 0, SuperOpcode super_opcode = SOP_DATA);
|
||||
void FlushWrite();
|
||||
|
||||
protected:
|
||||
// Notify transport layer of disconnect to halt message processing
|
||||
CAT_INLINE void TransportDisconnected() { _disconnected = true; }
|
||||
CAT_INLINE bool IsDisconnected() { return _disconnected; }
|
||||
|
||||
void TickTransport(ThreadPoolLocalStorage *tls, u32 now);
|
||||
void OnDatagram(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes);
|
||||
|
||||
private:
|
||||
void OnFragment(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes, u32 stream);
|
||||
void CombineNextWrite();
|
||||
|
||||
protected:
|
||||
// skip_bytes: Number of bytes to skip at the start of the buffer
|
||||
// buf_bytes and msg_bytes contain the skipped bytes
|
||||
virtual bool PostPacket(u8 *data, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes) = 0;
|
||||
virtual void OnTimestampDeltaUpdate(u32 rtt, s32 delta) {}
|
||||
virtual void OnMessage(ThreadPoolLocalStorage *tls, BufferStream msg, u32 bytes) = 0;
|
||||
virtual void OnDisconnect() = 0;
|
||||
|
||||
protected:
|
||||
bool PostMTUProbe(ThreadPoolLocalStorage *tls, u16 payload_bytes);
|
||||
bool PostTimePing();
|
||||
bool PostTimePong(u32 client_ts);
|
||||
bool PostDisconnect();
|
||||
};
|
||||
|
||||
|
||||
} // namespace sphynx
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_SPHYNX_TRANSPORT_HPP
|
||||
95
DependentExtensions/cat/net/ThreadPoolSockets.hpp
Normal file
95
DependentExtensions/cat/net/ThreadPoolSockets.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// TODO: Half-open connections can easily DoS the TCP server right now.
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
#include <cat/threads/ThreadPool.hpp>
|
||||
#include <cat/net/Sockets.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnexion;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
void ReportUnexpectedSocketError(int error);
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
|
||||
#if defined (CAT_OS_WINDOWS) // Windows-style IOCP
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
#include <cat/net/win/TCPServer.hpp>
|
||||
#include <cat/net/win/TCPConnexion.hpp>
|
||||
#include <cat/net/win/TCPClient.hpp>
|
||||
#include <cat/net/win/UDPEndpoint.hpp>
|
||||
|
||||
#elif defined(CAT_OS_LINUX) // Linux-style eventfd
|
||||
|
||||
#include <cat/net/linux/TCPServer.hpp>
|
||||
#include <cat/net/linux/TCPConnexion.hpp>
|
||||
#include <cat/net/linux/TCPClient.hpp>
|
||||
#include <cat/net/linux/UDPEndpoint.hpp>
|
||||
|
||||
#elif defined(CAT_OS_OSX) || defined(CAT_OS_BSD) // BSD-style kevent
|
||||
|
||||
#include <cat/net/bsd/TCPServer.hpp>
|
||||
#include <cat/net/bsd/TCPConnexion.hpp>
|
||||
#include <cat/net/bsd/TCPClient.hpp>
|
||||
#include <cat/net/bsd/UDPEndpoint.hpp>
|
||||
|
||||
#else // Fall-back
|
||||
|
||||
#include <cat/net/generic/TCPServer.hpp>
|
||||
#include <cat/net/generic/TCPConnexion.hpp>
|
||||
#include <cat/net/generic/TCPClient.hpp>
|
||||
#include <cat/net/generic/UDPEndpoint.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
348
DependentExtensions/cat/net/bsd/TCPClient.hpp
Normal file
348
DependentExtensions/cat/net/bsd/TCPClient.hpp
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// TODO: Half-open connections can easily DoS the TCP server right now.
|
||||
// TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent)
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
#include <cat/threads/ThreadPool.hpp>
|
||||
#include <cat/net/Sockets.hpp>
|
||||
|
||||
#if defined(CAT_MS_SOCKET_API)
|
||||
# include <MSWSock.h>
|
||||
# include <cat/port/WindowsInclude.hpp>
|
||||
#endif
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnection;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
|
||||
//// Buffer Management
|
||||
|
||||
// Generate a buffer to pass to Post()
|
||||
u8 *GetPostBuffer(u32 bytes);
|
||||
|
||||
void *ResizePostBuffer(void *buffer, u32 newBytes);
|
||||
|
||||
// Release a buffer provided by GetPostBuffer()
|
||||
// Note: Once the buffer is submitted to Post() this is unnecessary
|
||||
void ReleasePostBuffer(void *buffer);
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
242
DependentExtensions/cat/net/bsd/TCPConnection.hpp
Normal file
242
DependentExtensions/cat/net/bsd/TCPConnection.hpp
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
347
DependentExtensions/cat/net/bsd/TCPServer.hpp
Normal file
347
DependentExtensions/cat/net/bsd/TCPServer.hpp
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnection;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
|
||||
//// Buffer Management
|
||||
|
||||
// Generate a buffer to pass to Post()
|
||||
u8 *GetPostBuffer(u32 bytes);
|
||||
|
||||
void *ResizePostBuffer(void *buffer, u32 newBytes);
|
||||
|
||||
// Release a buffer provided by GetPostBuffer()
|
||||
// Note: Once the buffer is submitted to Post() this is unnecessary
|
||||
void ReleasePostBuffer(void *buffer);
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
319
DependentExtensions/cat/net/bsd/UDPEndpoint.hpp
Normal file
319
DependentExtensions/cat/net/bsd/UDPEndpoint.hpp
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
#define CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
348
DependentExtensions/cat/net/generic/TCPClient.hpp
Normal file
348
DependentExtensions/cat/net/generic/TCPClient.hpp
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// TODO: Half-open connections can easily DoS the TCP server right now.
|
||||
// TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent)
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
#include <cat/threads/ThreadPool.hpp>
|
||||
#include <cat/net/Sockets.hpp>
|
||||
|
||||
#if defined(CAT_MS_SOCKET_API)
|
||||
# include <MSWSock.h>
|
||||
# include <cat/port/WindowsInclude.hpp>
|
||||
#endif
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnection;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
|
||||
//// Buffer Management
|
||||
|
||||
// Generate a buffer to pass to Post()
|
||||
u8 *GetPostBuffer(u32 bytes);
|
||||
|
||||
void *ResizePostBuffer(void *buffer, u32 newBytes);
|
||||
|
||||
// Release a buffer provided by GetPostBuffer()
|
||||
// Note: Once the buffer is submitted to Post() this is unnecessary
|
||||
void ReleasePostBuffer(void *buffer);
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
242
DependentExtensions/cat/net/generic/TCPConnection.hpp
Normal file
242
DependentExtensions/cat/net/generic/TCPConnection.hpp
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
347
DependentExtensions/cat/net/generic/TCPServer.hpp
Normal file
347
DependentExtensions/cat/net/generic/TCPServer.hpp
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnection;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
|
||||
//// Buffer Management
|
||||
|
||||
// Generate a buffer to pass to Post()
|
||||
u8 *GetPostBuffer(u32 bytes);
|
||||
|
||||
void *ResizePostBuffer(void *buffer, u32 newBytes);
|
||||
|
||||
// Release a buffer provided by GetPostBuffer()
|
||||
// Note: Once the buffer is submitted to Post() this is unnecessary
|
||||
void ReleasePostBuffer(void *buffer);
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
319
DependentExtensions/cat/net/generic/UDPEndpoint.hpp
Normal file
319
DependentExtensions/cat/net/generic/UDPEndpoint.hpp
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
#define CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
348
DependentExtensions/cat/net/linux/TCPClient.hpp
Normal file
348
DependentExtensions/cat/net/linux/TCPClient.hpp
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// TODO: Half-open connections can easily DoS the TCP server right now.
|
||||
// TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent)
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
#include <cat/threads/ThreadPool.hpp>
|
||||
#include <cat/net/Sockets.hpp>
|
||||
|
||||
#if defined(CAT_MS_SOCKET_API)
|
||||
# include <MSWSock.h>
|
||||
# include <cat/port/WindowsInclude.hpp>
|
||||
#endif
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnection;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
|
||||
//// Buffer Management
|
||||
|
||||
// Generate a buffer to pass to Post()
|
||||
u8 *GetPostBuffer(u32 bytes);
|
||||
|
||||
void *ResizePostBuffer(void *buffer, u32 newBytes);
|
||||
|
||||
// Release a buffer provided by GetPostBuffer()
|
||||
// Note: Once the buffer is submitted to Post() this is unnecessary
|
||||
void ReleasePostBuffer(void *buffer);
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
242
DependentExtensions/cat/net/linux/TCPConnection.hpp
Normal file
242
DependentExtensions/cat/net/linux/TCPConnection.hpp
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
347
DependentExtensions/cat/net/linux/TCPServer.hpp
Normal file
347
DependentExtensions/cat/net/linux/TCPServer.hpp
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
|
||||
#define CAT_THREAD_POOL_SOCKETS_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Thread Pool Sockets library
|
||||
|
||||
Provides a framework for rapidly developing TCP/UDP server and client objects
|
||||
that make use of high performance APIs under various server and desktop
|
||||
operating systems.
|
||||
|
||||
All network events are processed by a thread pool managed by ThreadPool.
|
||||
*/
|
||||
|
||||
class TCPServer;
|
||||
class TCPConnection;
|
||||
class TCPClient;
|
||||
class UDPEndpoint;
|
||||
|
||||
|
||||
//// Buffer Management
|
||||
|
||||
// Generate a buffer to pass to Post()
|
||||
u8 *GetPostBuffer(u32 bytes);
|
||||
|
||||
void *ResizePostBuffer(void *buffer, u32 newBytes);
|
||||
|
||||
// Release a buffer provided by GetPostBuffer()
|
||||
// Note: Once the buffer is submitted to Post() this is unnecessary
|
||||
void ReleasePostBuffer(void *buffer);
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_SOCKETS_HPP
|
||||
319
DependentExtensions/cat/net/linux/UDPEndpoint.hpp
Normal file
319
DependentExtensions/cat/net/linux/UDPEndpoint.hpp
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
#define CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
#include <MSWSock.h>
|
||||
#include <cat/port/WindowsInclude.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
//// Overlapped Sockets
|
||||
|
||||
// AcceptEx() OVERLAPPED structure
|
||||
struct AcceptExOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address either!
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
|
||||
void Set(Socket s);
|
||||
};
|
||||
|
||||
// WSARecvFrom() OVERLAPPED structure
|
||||
struct RecvFromOverlapped
|
||||
{
|
||||
TypedOverlapped tov;
|
||||
|
||||
// Not necessarily and IPv6 address,
|
||||
// but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
|
||||
// data follows...
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnection() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnection;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPServer();
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
virtual TCPConnection *InstantiateServerConnection() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
private:
|
||||
bool QueueAcceptEx();
|
||||
bool QueueAccepts();
|
||||
|
||||
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection();
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true iff the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPClient();
|
||||
virtual ~TCPClient();
|
||||
|
||||
bool ValidClient();
|
||||
|
||||
bool Connect(const NetAddr &remoteServerAddress);
|
||||
void DisconnectServer();
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer() = 0;
|
||||
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToServer(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueConnectEx(const NetAddr &remoteServerAddress);
|
||||
void OnConnectExComplete(int error);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
void *_queueBuffer;
|
||||
u32 _queueBytes;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued();
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool PostToServer(void *buffer, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
UDPEndpoint();
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
bool Valid();
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(Port port = 0, bool ignoreUnreachable = true);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling Post() with addr.PromoteTo6()
|
||||
bool Post(const NetAddr &addr, void *data, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual void OnWrite(u32 bytes) = 0;
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
private:
|
||||
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
|
||||
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
|
||||
|
||||
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendToComplete(int error, u32 bytes);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_THREAD_POOL_UDP_ENDPOINT_HPP
|
||||
126
DependentExtensions/cat/net/win/TCPClient.hpp
Normal file
126
DependentExtensions/cat/net/win/TCPClient.hpp
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_TCP_CLIENT_HPP
|
||||
#define CAT_TCP_CLIENT_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
class TCPClient
|
||||
|
||||
Object that represents a TCPClient bound to a single port
|
||||
|
||||
ValidClient() : Returns true if the client socket is valid
|
||||
|
||||
Connect() : Connects to the given address
|
||||
DisconnectServer() : Disconnects from the server
|
||||
PostToServer() : Send a message to the server (will fail if not connected)
|
||||
|
||||
OnConnectToServer() : Called when connection is accepted
|
||||
OnReadFromServer() : Return false to disconnect the server in response to data
|
||||
OnWriteToServer() : Informs the derived class that data has been sent
|
||||
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
|
||||
*/
|
||||
class TCPClient : public ThreadRefObject
|
||||
{
|
||||
// Remembers if socket is IPv6 so that user-provided
|
||||
// addresses can be promoted if necessary.
|
||||
bool _ipv6;
|
||||
Socket _socket;
|
||||
volatile u32 _disconnecting; // Disconnect flag
|
||||
|
||||
public:
|
||||
TCPClient(int priorityLevel);
|
||||
virtual ~TCPClient();
|
||||
|
||||
CAT_INLINE bool Valid() { return _socket != SOCKET_ERROR; }
|
||||
|
||||
void Disconnect();
|
||||
bool Connect(bool onlySupportIPv4, const NetAddr &remoteServerAddress);
|
||||
|
||||
public:
|
||||
bool Post(u8 *data, u32 data_bytes, u32 skip_bytes = 0);
|
||||
|
||||
private:
|
||||
bool ConnectEx(const NetAddr &remoteServerAddress);
|
||||
bool Read(AsyncBuffer *buffer = 0);
|
||||
bool Disco(AsyncBuffer *buffer = 0);
|
||||
|
||||
private:
|
||||
bool OnConnectEx(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
bool OnRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
bool OnWrite(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
bool OnDisco(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnConnectToServer(ThreadPoolLocalStorage *tls) = 0;
|
||||
virtual bool OnReadFromServer(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual bool OnWriteToServer(ThreadPoolLocalStorage *tls, AsyncBuffer *buffer, u32 bytes) = 0; // true = delete AsyncBuffer object
|
||||
virtual void OnDisconnectFromServer() = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
class TCPClientQueued
|
||||
|
||||
Base class for a TCP client that needs to queue up data for sending before
|
||||
a connection has been established. e.g. Uplink for a proxy server.
|
||||
|
||||
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
|
||||
*/
|
||||
class TCPClientQueued : public TCPClient
|
||||
{
|
||||
private:
|
||||
volatile bool _queuing;
|
||||
|
||||
Mutex _queueLock;
|
||||
AsyncBuffer *_queueBuffer;
|
||||
|
||||
protected:
|
||||
void PostQueuedToServer();
|
||||
|
||||
public:
|
||||
TCPClientQueued(int priorityLevel);
|
||||
virtual ~TCPClientQueued();
|
||||
|
||||
bool Post(u8 *data, u32 data_bytes, u32 skip_bytes = 0);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_TCP_CLIENT_HPP
|
||||
102
DependentExtensions/cat/net/win/TCPConnection.hpp
Normal file
102
DependentExtensions/cat/net/win/TCPConnection.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_TCP_CONNECTION_HPP
|
||||
#define CAT_TCP_CONNECTION_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnection
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
DisconnectClient() : Disconnect the client
|
||||
PostToClient() : Send a message to the client
|
||||
ValidServerConnection() : Returns true iff the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnection : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
friend class ThreadPool;
|
||||
|
||||
public:
|
||||
TCPConnection(int priorityLevel);
|
||||
virtual ~TCPConnection();
|
||||
|
||||
bool ValidServerConnection();
|
||||
|
||||
void DisconnectClient();
|
||||
bool PostToClient(void *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual void OnWriteToClient(u32 bytes) = 0;
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
|
||||
private:
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
TypedOverlapped *_recvOv;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
private:
|
||||
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
bool QueueWSARecv();
|
||||
void OnWSARecvComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
|
||||
void OnWSASendComplete(int error, u32 bytes);
|
||||
|
||||
bool QueueDisconnectEx();
|
||||
void OnDisconnectExComplete(int error);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_TCP_CONNECTION_HPP
|
||||
98
DependentExtensions/cat/net/win/TCPConnexion.hpp
Normal file
98
DependentExtensions/cat/net/win/TCPConnexion.hpp
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_TCP_CONNEXION_HPP
|
||||
#define CAT_TCP_CONNEXION_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
class TCPConnexion
|
||||
|
||||
Object that represents a TCPServer's connection from a TCPClient
|
||||
|
||||
Object is instantiated just before accepting a connection
|
||||
|
||||
Disconnect() : Disconnect the client
|
||||
Post() : Send a message to the client
|
||||
Valid() : Returns true if the connection is valid
|
||||
|
||||
OnConnectFromClient() : Return false to deny this connection
|
||||
OnReadFromClient() : Return false to disconnect the client in response to a message
|
||||
OnWriteToClient() : Informs the derived class that data has been sent
|
||||
OnDisconectFromClient() : Informs the derived class that the client has disconnected
|
||||
*/
|
||||
class TCPConnexion : public ThreadRefObject
|
||||
{
|
||||
friend class TCPServer;
|
||||
|
||||
Socket _socket;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
volatile u32 _disconnecting;
|
||||
|
||||
bool Accept(ThreadPoolLocalStorage *tls, Socket listenSocket, Socket acceptSocket,
|
||||
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
|
||||
const NetAddr &remoteClientAddress);
|
||||
|
||||
public:
|
||||
TCPConnexion(int priorityLevel);
|
||||
virtual ~TCPConnexion();
|
||||
|
||||
CAT_INLINE bool Valid() { return _socket != SOCKET_ERROR; }
|
||||
|
||||
void Disconnect();
|
||||
bool Post(u8 *data, u32 data_bytes, u32 skip_bytes = 0);
|
||||
|
||||
private:
|
||||
bool Read(AsyncBuffer *buffer = 0);
|
||||
bool Disco(AsyncBuffer *buffer = 0);
|
||||
|
||||
private:
|
||||
bool OnRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
bool OnWrite(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
bool OnDisco(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual bool OnConnectFromClient(ThreadPoolLocalStorage *tls, const NetAddr &remoteClientAddress) = 0; // false = disconnect
|
||||
virtual bool OnReadFromClient(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes) = 0; // false = disconnect
|
||||
virtual bool OnWriteToClient(ThreadPoolLocalStorage *tls, AsyncBuffer *buffer, u32 bytes) = 0; // true = delete AsyncBuffer
|
||||
virtual void OnDisconnectFromClient() = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_TCP_CONNEXION_HPP
|
||||
97
DependentExtensions/cat/net/win/TCPServer.hpp
Normal file
97
DependentExtensions/cat/net/win/TCPServer.hpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_TCP_SERVER_HPP
|
||||
#define CAT_TCP_SERVER_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
class TCPServer
|
||||
|
||||
Object that represents a TCP server bound to a single port
|
||||
|
||||
Overload InstantiateServerConnexion() to subclass connections with the server
|
||||
*/
|
||||
class TCPServer : public ThreadRefObject
|
||||
{
|
||||
friend class TCPConnexion;
|
||||
|
||||
Socket _socket;
|
||||
LPFN_ACCEPTEX _lpfnAcceptEx;
|
||||
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
|
||||
LPFN_DISCONNECTEX _lpfnDisconnectEx;
|
||||
Port _port;
|
||||
|
||||
struct AcceptTag
|
||||
{
|
||||
Socket acceptSocket;
|
||||
|
||||
// Space pre-allocated to receive addresses
|
||||
// NOTE: This is not necessarily how the addresses are organized in memory
|
||||
struct
|
||||
{
|
||||
// Not necessarily an IPv6 address
|
||||
sockaddr_in6 addr[2];
|
||||
u8 padding[2*16];
|
||||
} addresses;
|
||||
};
|
||||
|
||||
bool PostAccept(AsyncBuffer *buffer = 0);
|
||||
bool QueueAccepts();
|
||||
|
||||
public:
|
||||
TCPServer(int priorityLevel);
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool ValidServer();
|
||||
Port GetPort();
|
||||
|
||||
bool Bind(bool onlySupportIPv4, Port port = 0);
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
// Return true to release overlapped object memory, or return false to keep it
|
||||
virtual bool OnAccept(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual TCPConnexion *InstantiateServerConnexion() = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_TCP_SERVER_HPP
|
||||
105
DependentExtensions/cat/net/win/UDPEndpoint.hpp
Normal file
105
DependentExtensions/cat/net/win/UDPEndpoint.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_UDP_ENDPOINT_HPP
|
||||
#define CAT_UDP_ENDPOINT_HPP
|
||||
|
||||
/*
|
||||
Windows version of thread pool sockets with IO Completion Ports
|
||||
|
||||
Included from <cat/net/ThreadPoolSockets.hpp>
|
||||
Do not include directly
|
||||
*/
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
class UDPEndpoint
|
||||
|
||||
Object that represents a UDP endpoint bound to a single port
|
||||
*/
|
||||
class UDPEndpoint : public ThreadRefObject
|
||||
{
|
||||
Socket _socket;
|
||||
Port _port;
|
||||
volatile u32 _closing;
|
||||
bool _ipv6;
|
||||
|
||||
struct RecvFromTag
|
||||
{
|
||||
// Not necessarily an IPv6 address, but we allocate enough space for one
|
||||
int addrLen;
|
||||
sockaddr_in6 addr;
|
||||
};
|
||||
|
||||
public:
|
||||
UDPEndpoint(int priorityLevel);
|
||||
virtual ~UDPEndpoint();
|
||||
|
||||
CAT_INLINE bool Valid() { return _socket != SOCKET_ERROR; }
|
||||
Port GetPort();
|
||||
|
||||
// Is6() result is only valid AFTER Bind()
|
||||
CAT_INLINE bool Is6() { return _ipv6; }
|
||||
CAT_INLINE bool IsClosed() { return _closing != 0; }
|
||||
|
||||
// For servers: Bind() with ignoreUnreachable = true ((default))
|
||||
// For clients: Bind() with ignoreUnreachable = false and call this
|
||||
// after the first packet from the server is received.
|
||||
bool IgnoreUnreachable();
|
||||
|
||||
// Disabled by default; useful for MTU discovery
|
||||
bool DontFragment(bool df = true);
|
||||
|
||||
void Close(); // Invalidates this object
|
||||
bool Bind(bool onlySupportIPv4, Port port = 0, bool ignoreUnreachable = true, int kernelReceiveBufferBytes = 0);
|
||||
bool QueueWSARecvFrom();
|
||||
|
||||
// If Is6() == true, the address must be promoted to IPv6
|
||||
// before calling PostWrite() with addr.PromoteTo6()
|
||||
// skip_bytes: Number of bytes to skip at the start of the post buffer
|
||||
bool Post(const NetAddr &addr, u8 *data, u32 data_bytes, u32 skip_bytes = 0);
|
||||
|
||||
private:
|
||||
bool Read(AsyncBuffer *buffer = 0);
|
||||
|
||||
bool OnReadComplete(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
bool OnWriteComplete(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
|
||||
|
||||
protected:
|
||||
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
|
||||
virtual bool OnWrite(ThreadPoolLocalStorage *tls, AsyncBuffer *buffer, u32 bytes) { return true; } // false = do not delete AsyncBase object
|
||||
virtual void OnClose() = 0;
|
||||
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_UDP_ENDPOINT_HPP
|
||||
Reference in New Issue
Block a user