TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
G3D::LightweightConduit Class Reference

#include <NetworkDevice.h>

Classes

class  PacketSizeException
 

Public Member Functions

 ~LightweightConduit ()
 
int maxMessageSize () const
 
template<typename T >
void send (const NetAddress &a, uint32 type, const T &msg)
 
template<typename T >
void send (const Array< NetAddress > &a, uint32 type, const T &m)
 
bool receive (NetAddress &sender)
 
template<typename T >
bool receive (NetAddress &sender, T &message)
 
bool receive ()
 
virtual uint32 waitingMessageType ()
 
virtual bool messageWaiting ()
 
- Public Member Functions inherited from G3D::Conduit
virtual ~Conduit ()
 
uint64 bytesSent () const
 
uint64 messagesSent () const
 
uint64 bytesReceived () const
 
uint64 messagesReceived () const
 
bool ok () const
 
- Public Member Functions inherited from G3D::ReferenceCountedObject
virtual ~ReferenceCountedObject ()
 

Static Public Member Functions

static LightweightConduitRef create (uint16 receivePort, bool enableReceive, bool enableBroadcast)
 

Private Member Functions

 LightweightConduit (uint16 receivePort, bool enableReceive, bool enableBroadcast)
 
void sendBuffer (const NetAddress &a, BinaryOutput &b)
 
template<typename T >
void serializeMessage (uint32 type, const T &m, BinaryOutput &b) const
 

Private Attributes

bool alreadyReadMessage
 
NetAddress messageSender
 
uint32 messageType
 
Array< uint8messageBuffer
 
int MTU
 

Friends

class NetworkDevice
 

Additional Inherited Members

- Protected Member Functions inherited from G3D::Conduit
 Conduit ()
 
- Protected Attributes inherited from G3D::Conduit
uint64 mSent
 
uint64 mReceived
 
uint64 bSent
 
uint64 bReceived
 
SOCKET sock
 
BinaryOutput binaryOutput
 

Detailed Description

Provides fast but unreliable transfer of messages. On a LAN, LightweightConduit will probably never drop messages but you might get your messages out of order. On an internet connection it might drop messages altogether. Messages are never corrupted, however. LightweightConduit requires a little less setup and overhead than ReliableConduit. ReliableConduit guarantees message delivery and order but requires a persistent connection.

To set up a LightweightConduit (assuming you have already made subclasses of G3D::NetMessage based on your application's pcommunication protocol):

[Server Side]

  1. Call LightweightConduit::create(port, true, false), where port is the port on which you will receive messages.

  2. Poll LightweightConduit::messageWaiting from your main loop. When it is true (or, equivalently, when LightweightConduit::waitingMessageType is non-zero) there is an incoming message.

  3. To read the incoming message, call LightweightConduit::receive with the appropriate class type, which mist have a deserialize method. LightweightConduit::waitingMessageType tells you what class is needed (you make up your own message constants for your program; numbers under 1000 are reserved for G3D's internal use).

  4. When done, simply set the G3D::LightweightConduitRef to NULL or let it go out of scope and the conduit cleans itself up automatically.

[Client Side]

  1. Call G3D::LightweightConduit::create(). If you will broadcast to all servers on a LAN, set the third optional argument to true (the default is false for no broadcast). You can also set up the receive port as if it was a server to send and receive from a single LightweightConduit.

  2. To send, call G3D::LightweightConduit::send with the target address and a pointer to an instance of the message you want to send.

  3. When done, simply set the G3D::LightweightConduitRef to NULL or let it go out of scope and the conduit cleans itself up automatically.

Deprecated:

Constructor & Destructor Documentation

G3D::LightweightConduit::LightweightConduit ( uint16  receivePort,
bool  enableReceive,
bool  enableBroadcast 
)
private
1001  {
1003 
1004  Log::common()->print("Creating a UDP socket ");
1005  sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1006 
1007  if (sock == SOCKET_ERROR) {
1008  sock = 0;
1009  Log::common()->println("FAIL");
1011  return;
1012  }
1013  Log::common()->println("Ok");
1014 
1015  if (enableReceive) {
1016  debugAssert(port != 0);
1017  if (! nd->bind(sock, NetAddress(0, port))) {
1018  nd->closesocket(sock);
1019  sock = (SOCKET)SOCKET_ERROR;
1020  }
1021  }
1022 
1023  // Figuring out the MTU seems very complicated, so we just set it to 1000,
1024  // which is likely to be safe. See IP_MTU for more information.
1025  MTU = 1000;
1026 
1028 
1029  if (enableBroadcast) {
1030  int TR = true;
1031  if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
1032  (const char*)&TR, sizeof(TR)) != 0) {
1033  Log::common()->println("Call to setsockopt failed");
1035  nd->closesocket(sock);
1036  sock = 0;
1037  return;
1038  }
1039  }
1040 
1041  Log::common()->printf("Done creating UDP socket %d\n", sock);
1042 
1043  alreadyReadMessage = false;
1044 }
static void increaseBufferSize(SOCKET sock)
Definition: NetworkDevice.cpp:587
friend class NetworkDevice
Definition: NetworkDevice.h:409
static std::string socketErrorCode(int code)
Definition: networkHelpers.h:64
SOCKET sock
Definition: NetworkDevice.h:67
void print(const std::string &s)
Definition: Log.cpp:138
void __cdecl printf(const char *fmt,...) G3D_CHECK_PRINTF_METHOD_ARGS
Definition: Log.cpp:119
#define debugAssert(exp)
Definition: debugAssert.h:160
static Log * common()
Definition: Log.cpp:100
void println(const std::string &s)
Definition: Log.cpp:144
int MTU
Definition: NetworkDevice.h:438
#define SOCKET
Definition: netheaders.h:20
static NetworkDevice * instance()
Definition: NetworkDevice.cpp:109
bool alreadyReadMessage
Definition: NetworkDevice.h:415

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

G3D::LightweightConduit::~LightweightConduit ( )

Closes the socket.

1047  {
1048 }

Member Function Documentation

LightweightConduitRef G3D::LightweightConduit::create ( uint16  receivePort,
bool  enableReceive,
bool  enableBroadcast 
)
static
992  {
993 
994  return LightweightConduitRef(new LightweightConduit(receivePort, enableReceive, enableBroadcast));
995 }
LightweightConduit(uint16 receivePort, bool enableReceive, bool enableBroadcast)
Definition: NetworkDevice.cpp:999
shared_ptr< class LightweightConduit > LightweightConduitRef
Definition: NetworkDevice.h:355

+ Here is the call graph for this function:

int G3D::LightweightConduit::maxMessageSize ( ) const
inline

The maximum length of a message that can be sent (G3D places a small header at the front of each UDP packet; this is already taken into account by the value returned).

490  {
491  return MTU - 4;
492  }
int MTU
Definition: NetworkDevice.h:438

+ Here is the caller graph for this function:

bool G3D::LightweightConduit::messageWaiting ( )
virtual

If true, receive will return true.

Reimplemented from G3D::Conduit.

1087  {
1088  // We may have already pulled the message off the network stream
1090 }
virtual bool messageWaiting()
Definition: NetworkDevice.cpp:579
bool alreadyReadMessage
Definition: NetworkDevice.h:415

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::LightweightConduit::receive ( NetAddress sender)
1051  {
1052  // This both checks to ensure that a message was waiting and
1053  // actively consumes the message from the network stream if
1054  // it has not been read yet.
1055  uint32 t = waitingMessageType();
1056  if (t == 0) {
1057  return false;
1058  }
1059 
1060  sender = messageSender;
1061  alreadyReadMessage = false;
1062 
1063  if (messageBuffer.size() < 4) {
1064  // Something went wrong
1065  return false;
1066  }
1067 
1068  return true;
1069 }
virtual uint32 waitingMessageType()
Definition: NetworkDevice.cpp:1093
Array< uint8 > messageBuffer
Definition: NetworkDevice.h:430
NetAddress messageSender
Definition: NetworkDevice.h:420
uint32_t uint32
Definition: Define.h:150
int size() const
Definition: Array.h:430
bool alreadyReadMessage
Definition: NetworkDevice.h:415

+ Here is the call graph for this function:

template<typename T >
bool G3D::LightweightConduit::receive ( NetAddress sender,
T &  message 
)
inline
515  {
516  bool r = receive(sender);
517  if (r) {
518  BinaryInput b((messageBuffer.getCArray() + 4),
519  messageBuffer.size() - 4,
521  message.deserialize(b);
522  }
523 
524  return r;
525  }
T * getCArray()
Definition: Array.h:256
Array< uint8 > messageBuffer
Definition: NetworkDevice.h:430
bool receive()
Definition: NetworkDevice.h:527
static const bool NO_COPY
Definition: BinaryInput.h:147
int size() const
Definition: Array.h:430
Definition: System.h:50

+ Here is the call graph for this function:

bool G3D::LightweightConduit::receive ( )
inline
527  {
528  static NetAddress ignore;
529  return receive(ignore);
530  }
bool receive()
Definition: NetworkDevice.h:527

+ Here is the caller graph for this function:

template<typename T >
void G3D::LightweightConduit::send ( const NetAddress a,
uint32  type,
const T &  msg 
)
inline
495  {
497  serializeMessage(type, msg, binaryOutput);
499  }
void reset()
Definition: BinaryOutput.cpp:240
BinaryOutput binaryOutput
Definition: NetworkDevice.h:73
void serializeMessage(uint32 type, const T &m, BinaryOutput &b) const
Definition: NetworkDevice.h:442
void sendBuffer(const NetAddress &a, BinaryOutput &b)
Definition: NetworkDevice.cpp:1072

+ Here is the call graph for this function:

template<typename T >
void G3D::LightweightConduit::send ( const Array< NetAddress > &  a,
uint32  type,
const T &  m 
)
inline

Send the same message to multiple addresses (only serializes once). Useful when server needs to send to a known list of addresses (unlike direct UDP broadcast to all addresses on the subnet)

504  {
506  serializeMessage(type, m, binaryOutput);
507 
508  for (int i = 0; i < a.size(); ++i) {
509  sendBuffer(a[i], binaryOutput);
510  }
511  }
void reset()
Definition: BinaryOutput.cpp:240
BinaryOutput binaryOutput
Definition: NetworkDevice.h:73
void serializeMessage(uint32 type, const T &m, BinaryOutput &b) const
Definition: NetworkDevice.h:442
void sendBuffer(const NetAddress &a, BinaryOutput &b)
Definition: NetworkDevice.cpp:1072

+ Here is the call graph for this function:

void G3D::LightweightConduit::sendBuffer ( const NetAddress a,
BinaryOutput b 
)
private
1072  {
1074  if (sendto(sock, (const char*)b.getCArray(), (int)b.size(), 0,
1075  (struct sockaddr *) &(a.addr), sizeof(a.addr)) == SOCKET_ERROR) {
1076  Log::common()->printf("Error occured while sending packet "
1077  "to %s\n", inet_ntoa(a.addr.sin_addr));
1079  nd->closesocket(sock);
1080  } else {
1081  ++mSent;
1082  bSent += b.size();
1083  }
1084 }
friend class NetworkDevice
Definition: NetworkDevice.h:409
uint64 bSent
Definition: NetworkDevice.h:64
static std::string socketErrorCode(int code)
Definition: networkHelpers.h:64
uint64 mSent
Definition: NetworkDevice.h:62
SOCKET sock
Definition: NetworkDevice.h:67
void __cdecl printf(const char *fmt,...) G3D_CHECK_PRINTF_METHOD_ARGS
Definition: Log.cpp:119
static Log * common()
Definition: Log.cpp:100
void println(const std::string &s)
Definition: Log.cpp:144
static NetworkDevice * instance()
Definition: NetworkDevice.cpp:109

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

template<typename T >
void G3D::LightweightConduit::serializeMessage ( uint32  type,
const T &  m,
BinaryOutput b 
) const
inlineprivate
445  {
446 
447  debugAssert(type != 0);
448  b.writeUInt32(type);
449  m.serialize(b);
450  b.writeUInt32(1);
451 
452  debugAssertM(b.size() < MTU,
453  format("This LightweightConduit is limited to messages of "
454  "%d bytes (Ethernet hardware limit; this is the "
455  "'UDP MTU')", maxMessageSize()));
456 
457  if (b.size() >= MTU) {
458  throw LightweightConduit::PacketSizeException(
459  format("This LightweightConduit is limited to messages of "
460  "%d bytes (Ethernet hardware limit; this is the "
461  "'UDP MTU')", maxMessageSize()),
462  (int)b.size() - 4, // Don't count the type header
463  maxMessageSize());
464  }
465  }
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
#define debugAssert(exp)
Definition: debugAssert.h:160
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
int maxMessageSize() const
Definition: NetworkDevice.h:490
int MTU
Definition: NetworkDevice.h:438

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

uint32 G3D::LightweightConduit::waitingMessageType ( )
virtual

Returns the type of the waiting message (i.e. the type supplied with send). The return value is zero when there is no message waiting.

One way to use this is to have a Table mapping message types to pre-allocated subclasses so receiving looks like:

    // My base class for messages.
    class Message {
        virtual void serialize(BinaryOutput&) const;
        virtual void deserialize(BinaryInput&);
        virtual void process() = 0;
    };
    Message* m = table[conduit->waitingMessageType()];
    conduit->receive(m);
    m->process();

Another is to simply switch on the message type:

    switch (conduit->waitingMessageType()) {
    case 0:
       // No message
       break;
    case ENTITY_SPAWN_MSG:
       {
          EntitySpawnMsg m;
          condiut->receive(m);
          spawnEntity(m.id, m.position, m.modelID);
       }
       break;
       ...
    }
 

Implements G3D::Conduit.

1093  {
1095  if (! messageWaiting()) {
1096  return 0;
1097  }
1098 
1099  if (! alreadyReadMessage) {
1100  messageBuffer.resize(8192);
1101 
1102  SOCKADDR_IN remote_addr;
1103  int iRemoteAddrLen = sizeof(sockaddr);
1104 
1105  int ret = recvfrom(sock, (char*)messageBuffer.getCArray(),
1106  messageBuffer.size(), 0, (struct sockaddr *) &remote_addr,
1107  (socklen_t*)&iRemoteAddrLen);
1108 
1109  if (ret == SOCKET_ERROR) {
1110  Log::common()->println("Error: recvfrom failed in "
1111  "LightweightConduit::waitingMessageType().");
1113  nd->closesocket(sock);
1114  messageBuffer.resize(0);
1115  messageSender = NetAddress();
1116  messageType = 0;
1117  return 0;
1118  }
1119 
1120  messageSender = NetAddress(remote_addr);
1121 
1122  ++mReceived;
1123  bReceived += ret;
1124 
1126 
1127  // The type is the first four bytes. It is little endian.
1130  } else {
1131  // Swap the byte order
1132  for (int i = 0; i < 4; ++i) {
1133  ((char*)&messageType)[i] = messageBuffer[3 - i];
1134  }
1135  }
1136 
1137  alreadyReadMessage = true;
1138  }
1139 
1140  return messageType;
1141 }
friend class NetworkDevice
Definition: NetworkDevice.h:409
void resize(size_t n, bool shrinkIfNecessary=true)
Definition: Array.h:490
static std::string socketErrorCode(int code)
Definition: networkHelpers.h:64
T * getCArray()
Definition: Array.h:256
virtual bool messageWaiting()
Definition: NetworkDevice.cpp:1087
#define SOCKADDR_IN
Definition: netheaders.h:17
SOCKET sock
Definition: NetworkDevice.h:67
Array< uint8 > messageBuffer
Definition: NetworkDevice.h:430
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43
NetAddress messageSender
Definition: NetworkDevice.h:420
uint32_t uint32
Definition: Define.h:150
int size() const
Definition: Array.h:430
uint32 messageType
Definition: NetworkDevice.h:425
static G3DEndian machineEndian()
Definition: System.h:219
Definition: System.h:50
uint64 bReceived
Definition: NetworkDevice.h:65
static Log * common()
Definition: Log.cpp:100
void println(const std::string &s)
Definition: Log.cpp:144
uint64 mReceived
Definition: NetworkDevice.h:63
static NetworkDevice * instance()
Definition: NetworkDevice.cpp:109
bool alreadyReadMessage
Definition: NetworkDevice.h:415

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Friends And Related Function Documentation

friend class NetworkDevice
friend

Member Data Documentation

bool G3D::LightweightConduit::alreadyReadMessage
private

True when waitingForMessageType has read the message from the network into messageType/messageStream.

Array<uint8> G3D::LightweightConduit::messageBuffer
private

The message received (the type has already been read off).

NetAddress G3D::LightweightConduit::messageSender
private

Origin of the received message.

uint32 G3D::LightweightConduit::messageType
private

The type of the last message received.

int G3D::LightweightConduit::MTU
private

Maximum transmission unit (packet size in bytes) for this socket. May vary between sockets.


The documentation for this class was generated from the following files: