1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
#ifndef NLSERVERCLIENT_H
#define NLSERVERCLIENT_H
#include "ArNetPacket.h"
#include "ArServerCommands.h"
#include "ArNetPacketReceiverTcp.h"
#include "ArNetPacketSenderTcp.h"
class ArServerData;
class ArServerUserInfo;
#include "ArServerClientData.h"
#include "ArServerClientIdentifier.h"
/**
This class represents the server's connection to the client, and
contains the socket that the server uses to talk to the client and
the information for sending packets to the client.
**/
class ArServerClient
{
public:
/// The state of the connection
enum ServerState {
STATE_SENT_INTRO, ///< opened socket, sent our intro to the server
STATE_REJECTED, ///< Client was rejected by server
STATE_CONNECTED, ///< Client is connected to server
STATE_DISCONNECTED ///< Client has disconnected from server
};
/// Constructor
AREXPORT ArServerClient(
ArSocket *tcpSocket, unsigned int udpPort, long authKey,
long introKey, ArRetFunctor2<bool, ArNetPacket *,
struct sockaddr_in *> *sendUdpCallback,
std::map<unsigned int, ArServerData *> *dataMap,
const char *passwordKey, const char *serverKey,
const ArServerUserInfo *userInfo = NULL,
int rejecting = 0, const char *rejectingString = "",
bool debugLogging = false,
const char *serverClientName = "ArServerBase_unknown",
bool logPasswordFailureVerbosely = false,
bool allowSlowPackets = true, bool allowIdlePackets = true,
const char *enforceProtocolVersion = "",
ArServerCommands::Type enforceType = ArServerCommands::TYPE_UNSPECIFIED);
/// Destructor
AREXPORT virtual ~ArServerClient();
/// The callback for taking care of the TCP connection
AREXPORT bool tcpCallback(void);
/// The callback for taking care of slow packets
AREXPORT bool slowPacketCallback(void);
/// The callback for taking care of idle packets (logic on idle elsewhere)
AREXPORT bool idlePacketCallback(void);
/// Sets the backup timeout
AREXPORT void setBackupTimeout(double timeoutInMins);
/// Process the packet whever it came from
AREXPORT void processPacket(ArNetPacket *packet, bool tcp = true);
/// Send a packet over TCP.
/// The command ID of the outgoing packet will be set to the current command ID
/// (from the incoming packet).
AREXPORT virtual bool sendPacketTcp(ArNetPacket *packet);
/// Send a packet over UDP (unless client only wants TCP; then sends over TCP).
/// The command ID of the outgoing packet will be set to the current command ID
/// (from the incoming packet).
AREXPORT virtual bool sendPacketUdp(ArNetPacket *packet);
/// Sees if this client has access to a given group
AREXPORT bool hasGroupAccess(const char *group);
/** Broadcasts a packet over TCP if this client wants this data -- For internal
* use only!
* @internal
*/
AREXPORT void broadcastPacketTcp(ArNetPacket *packet);
/** Broadcasts a packet over UDP if this client wants this data (unless client only wants tcp then sends over tcp) -- For internal ArNetworking use only!
* @internal
*/
AREXPORT void broadcastPacketUdp(ArNetPacket *packet);
/// Logs the tracking information (packet and byte counts)
AREXPORT void logTracking(bool terse);
/// Clears the tracking information (resets counters)
AREXPORT void resetTracking(void);
/// Gets the IP string of the client
AREXPORT const char *getIPString(void) const;
/// Gets the identifier of this server client
AREXPORT ArServerClientIdentifier getIdentifier(void) const;
/// Sets the identifier of this server client
AREXPORT void setIdentifier(ArServerClientIdentifier identifier);
/// Sends a shutdown command to the socket
AREXPORT void shutdown(void);
/// Sets the sin (network address) for the UDP socket
AREXPORT void setUdpAddress(struct sockaddr_in *sin);
/// Gets the sin (network address) for the UDP socket
AREXPORT struct sockaddr_in *getUdpAddress(void);
/// Gets the authKey used for setting up UDP from this client to the server
AREXPORT long getAuthKey(void);
/// Processes the auth packets that came from udp
AREXPORT void processAuthPacket(ArNetPacket *packet, struct sockaddr_in *sin);
/// Handles the requests for packets
AREXPORT void handleRequests(void);
/// Internal function to get the tcp socket
AREXPORT ArSocket *getTcpSocket(void) { return &myTcpSocket; }
/// Forcibly disconnect a client (for client/server switching)
AREXPORT void forceDisconnect(bool quiet);
/// Gets how often a command is asked for
AREXPORT long getFrequency(ArTypes::UByte2 command);
/// Sets the TCP only flag
AREXPORT void useTcpOnly(void) { myTcpOnly = true; }
/// Gets the tcp only flag
AREXPORT bool isTcpOnly(void) { return myTcpOnly; }
/// Gets the state
AREXPORT ServerState getState(void) { return myState; }
/// Gets if we have any slow packets to process
AREXPORT bool hasSlowPackets(void) { return myHaveSlowPackets; }
/// Gets if we have any idle packets to process
AREXPORT bool hasIdlePackets(void) { return myHaveIdlePackets; }
/// Starts a new request transaction, incrementing the count.
/**
* This method is intended to be called solely by the ArServerBase.
* It MUST be followed by a call to endRequestTransaction().
*
* Request transactions are used under certain circumstances to
* indicate that a number of related request/reply packets must
* be completely processed before background idle processing can
* proceed. See ArServerBase for more information.
**/
AREXPORT void startRequestTransaction();
/// Ends the most recent request transaction, decrementing the count.
/**
* This method is intended to be called solely by the ArServerBase.
* @see startRequestTransaction().
**/
AREXPORT bool endRequestTransaction();
/// Returns the number of request transactions that are currently in progress.
/**
* This method is intended to be called solely by the ArServerBase.
* @see startRequestTransaction().
**/
AREXPORT int getRequestTransactionCount();
/// Returns the command ID for the specified name, or 0 if it is not found
AREXPORT unsigned int findCommandFromName(const char *commandName) const;
/// Get creation time
AREXPORT ArTime getCreationTime(void) { return myCreationTime; }
protected:
const char *findCommandName(unsigned int command) const;
// Some members so that we don't have to pass the number around
std::list<unsigned int> myCommandStack;
std::list<bool> myForceTcpStack;
std::list<unsigned int> mySlowIdleCommandStack;
std::list<bool> mySlowIdleForceTcpStack;
AREXPORT bool setupPacket(ArNetPacket *packet);
// Pushes a new number onto our little stack of numbers
void pushCommand(unsigned int num);
// Pops the command off the stack
void popCommand(void);
// Pushes a new number onto our little stack of numbers
void pushSlowIdleCommand(unsigned int num);
// Pops the command off the stack
void popSlowIdleCommand(void);
// Gets the command we're on
unsigned int getCommand();
// Gets the command we're on
bool getForceTcpFlag();
// Pushes a new forceTcp flag onto our little stack of flags
void pushForceTcpFlag(bool forceTcp);
// Pops the command off the stack
void popForceTcpFlag(void);
// Pushes a new forceTcp flag onto our little stack of flags
void pushSlowIdleForceTcpFlag(bool forceTcp);
// Pops the command off the stack
void popSlowIdleForceTcpFlag(void);
// this sends a list packet to our client
void sendListPacket(void);
// this could just be dealth with by seeing if myUserInfo is NULL,
// but that may be confusing
const ArServerUserInfo *myUserInfo;
std::set<std::string, ArStrCaseCmpOp> myGroups;
ArNetPacketSenderTcp myTcpSender;
std::map<unsigned int, ArServerData *> *myDataMap;
std::list<ArServerClientData *> myRequested;
void internalSwitchState(ServerState state);
ServerState myState;
ArTime myStateStart;
bool myUdpConfirmedFrom;
bool myUdpConfirmedTo;
ArSocket myTcpSocket;
ArNetPacketReceiverTcp myTcpReceiver;
ArFunctor2C<ArServerClient, ArNetPacket *, bool> myProcessPacketCB;
ArRetFunctor2<bool, ArNetPacket *, struct sockaddr_in *> *mySendUdpCB;
struct sockaddr_in mySin;
long myAuthKey;
long myIntroKey;
bool myTcpOnly;
bool mySentTcpOnly;
std::string myPasswordKey;
std::string myServerKey;
bool myDebugLogging;
ArLog::LogLevel myVerboseLogLevel;
std::string myLogPrefix;
ArServerClientIdentifier myIdentifier;
std::string myIPString;
double myBackupTimeout;
int myRejecting;
std::string myRejectingString;
std::string myEnforceProtocolVersion;
ArServerCommands::Type myEnforceType;
ArTime myTrackingStarted;
class Tracker
{
public:
Tracker() { reset(); }
virtual ~Tracker() {}
void reset(void)
{ myPacketsTcp = 0; myBytesTcp = 0; myPacketsUdp = 0; myBytesUdp = 0; }
long myPacketsTcp;
long myBytesTcp;
long myPacketsUdp;
long myBytesUdp;
};
AREXPORT void trackPacketSent(ArNetPacket *packet, bool tcp);
AREXPORT void trackPacketReceived(ArNetPacket *packet, ArTypes::UByte2);
std::map<ArTypes::UByte2, Tracker *> myTrackingSentMap;
std::map<ArTypes::UByte2, Tracker *> myTrackingReceivedMap;
bool myLogPasswordFailureVerbosely;
bool myAllowSlowPackets;
bool myAllowIdlePackets;
ArThread *mySlowIdleThread;
bool myHaveSlowPackets;
bool myHaveIdlePackets;
ArMutex mySlowPacketsMutex;
std::list<ArNetPacket *> mySlowPackets;
ArMutex myIdlePacketsMutex;
std::list<ArNetPacket *> myIdlePackets;
/// Number of "request transactions" that are currently in progress for this client.
int myRequestTransactionCount;
/// Mutex for multi-threaded access to the request transaction count.
ArMutex myRequestTransactionMutex;
ArTime myCreationTime;
};
#endif
|