src/network/core/packet.cpp
changeset 5584 1111b4d36e35
parent 5528 45a70016d39a
child 5587 167d9a91ef02
equal deleted inserted replaced
5583:136d8764c7e6 5584:1111b4d36e35
       
     1 /* $Id$ */
       
     2 
       
     3 #ifdef ENABLE_NETWORK
       
     4 
       
     5 #include "../../stdafx.h"
       
     6 #include "../../macros.h"
       
     7 #include "../../string.h"
       
     8 
       
     9 #include "packet.h"
       
    10 
       
    11 /**
       
    12  * @file packet.h Basic functions to create, fill and read packets.
       
    13  */
       
    14 
       
    15 
       
    16 /* Do not want to include functions.h and all required headers */
       
    17 extern void NORETURN CDECL error(const char *str, ...);
       
    18 
       
    19 
       
    20 /**
       
    21  * Create a packet for sending
       
    22  * @param type the of packet
       
    23  * @return the newly created packet
       
    24  */
       
    25 Packet *NetworkSend_Init(const PacketType type)
       
    26 {
       
    27 	Packet *packet = malloc(sizeof(Packet));
       
    28 	/* An error is inplace here, because it simply means we ran out of memory. */
       
    29 	if (packet == NULL) error("Failed to allocate Packet");
       
    30 
       
    31 	/* Skip the size so we can write that in before sending the packet */
       
    32 	packet->size = sizeof(packet->size);
       
    33 	packet->buffer[packet->size++] = type;
       
    34 	packet->pos = 0;
       
    35 
       
    36 	return packet;
       
    37 }
       
    38 
       
    39 /**
       
    40  * Writes the packet size from the raw packet from packet->size
       
    41  * @param packet the packet to write the size of
       
    42  */
       
    43 void NetworkSend_FillPacketSize(Packet *packet)
       
    44 {
       
    45 	packet->buffer[0] = GB(packet->size, 0, 8);
       
    46 	packet->buffer[1] = GB(packet->size, 8, 8);
       
    47 }
       
    48 
       
    49 /**
       
    50  * The next couple of functions make sure we can send
       
    51  *  uint8, uint16, uint32 and uint64 endian-safe
       
    52  *  over the network. The least significant bytes are
       
    53  *  sent first.
       
    54  *
       
    55  *  So 0x01234567 would be sent as 67 45 23 01.
       
    56  */
       
    57 
       
    58 void NetworkSend_uint8(Packet *packet, uint8 data)
       
    59 {
       
    60 	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
       
    61 	packet->buffer[packet->size++] = data;
       
    62 }
       
    63 
       
    64 void NetworkSend_uint16(Packet *packet, uint16 data)
       
    65 {
       
    66 	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
       
    67 	packet->buffer[packet->size++] = GB(data, 0, 8);
       
    68 	packet->buffer[packet->size++] = GB(data, 8, 8);
       
    69 }
       
    70 
       
    71 void NetworkSend_uint32(Packet *packet, uint32 data)
       
    72 {
       
    73 	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
       
    74 	packet->buffer[packet->size++] = GB(data,  0, 8);
       
    75 	packet->buffer[packet->size++] = GB(data,  8, 8);
       
    76 	packet->buffer[packet->size++] = GB(data, 16, 8);
       
    77 	packet->buffer[packet->size++] = GB(data, 24, 8);
       
    78 }
       
    79 
       
    80 void NetworkSend_uint64(Packet *packet, uint64 data)
       
    81 {
       
    82 	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
       
    83 	packet->buffer[packet->size++] = GB(data,  0, 8);
       
    84 	packet->buffer[packet->size++] = GB(data,  8, 8);
       
    85 	packet->buffer[packet->size++] = GB(data, 16, 8);
       
    86 	packet->buffer[packet->size++] = GB(data, 24, 8);
       
    87 	packet->buffer[packet->size++] = GB(data, 32, 8);
       
    88 	packet->buffer[packet->size++] = GB(data, 40, 8);
       
    89 	packet->buffer[packet->size++] = GB(data, 48, 8);
       
    90 	packet->buffer[packet->size++] = GB(data, 56, 8);
       
    91 }
       
    92 
       
    93 /**
       
    94  *  Sends a string over the network. It sends out
       
    95  *  the string + '\0'. No size-byte or something.
       
    96  */
       
    97 void NetworkSend_string(Packet *packet, const char* data)
       
    98 {
       
    99 	assert(data != NULL);
       
   100 	assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1);
       
   101 	while ((packet->buffer[packet->size++] = *data++) != '\0') {}
       
   102 }
       
   103 
       
   104 
       
   105 /**
       
   106  * Receiving commands
       
   107  * Again, the next couple of functions are endian-safe
       
   108  *  see the comment before NetworkSend_uint8 for more info.
       
   109  */
       
   110 
       
   111 
       
   112 extern uint CloseConnection(NetworkClientState *cs);
       
   113 
       
   114 /** Is it safe to read from the packet, i.e. didn't we run over the buffer ? */
       
   115 static inline bool CanReadFromPacket(NetworkClientState *cs, const Packet *packet, const uint bytes_to_read)
       
   116 {
       
   117 	/* Don't allow reading from a closed socket */
       
   118 	if (HasClientQuit(cs)) return false;
       
   119 
       
   120 	/* Check if variable is within packet-size */
       
   121 	if (packet->pos + bytes_to_read > packet->size) {
       
   122 		CloseConnection(cs);
       
   123 		return false;
       
   124 	}
       
   125 
       
   126 	return true;
       
   127 }
       
   128 
       
   129 /**
       
   130  * Reads the packet size from the raw packet and stores it in the packet->size
       
   131  * @param packet the packet to read the size of
       
   132  */
       
   133 void NetworkRecv_ReadPacketSize(Packet *packet)
       
   134 {
       
   135 	packet->size  = (uint16)packet->buffer[0];
       
   136 	packet->size += (uint16)packet->buffer[1] << 8;
       
   137 }
       
   138 
       
   139 uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet)
       
   140 {
       
   141 	uint8 n;
       
   142 
       
   143 	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
       
   144 
       
   145 	n = packet->buffer[packet->pos++];
       
   146 	return n;
       
   147 }
       
   148 
       
   149 uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet)
       
   150 {
       
   151 	uint16 n;
       
   152 
       
   153 	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
       
   154 
       
   155 	n  = (uint16)packet->buffer[packet->pos++];
       
   156 	n += (uint16)packet->buffer[packet->pos++] << 8;
       
   157 	return n;
       
   158 }
       
   159 
       
   160 uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet)
       
   161 {
       
   162 	uint32 n;
       
   163 
       
   164 	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
       
   165 
       
   166 	n  = (uint32)packet->buffer[packet->pos++];
       
   167 	n += (uint32)packet->buffer[packet->pos++] << 8;
       
   168 	n += (uint32)packet->buffer[packet->pos++] << 16;
       
   169 	n += (uint32)packet->buffer[packet->pos++] << 24;
       
   170 	return n;
       
   171 }
       
   172 
       
   173 uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet)
       
   174 {
       
   175 	uint64 n;
       
   176 
       
   177 	if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0;
       
   178 
       
   179 	n  = (uint64)packet->buffer[packet->pos++];
       
   180 	n += (uint64)packet->buffer[packet->pos++] << 8;
       
   181 	n += (uint64)packet->buffer[packet->pos++] << 16;
       
   182 	n += (uint64)packet->buffer[packet->pos++] << 24;
       
   183 	n += (uint64)packet->buffer[packet->pos++] << 32;
       
   184 	n += (uint64)packet->buffer[packet->pos++] << 40;
       
   185 	n += (uint64)packet->buffer[packet->pos++] << 48;
       
   186 	n += (uint64)packet->buffer[packet->pos++] << 56;
       
   187 	return n;
       
   188 }
       
   189 
       
   190 /** Reads a string till it finds a '\0' in the stream */
       
   191 void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size)
       
   192 {
       
   193 	PacketSize pos;
       
   194 	char *bufp = buffer;
       
   195 
       
   196 	/* Don't allow reading from a closed socket */
       
   197 	if (HasClientQuit(cs)) return;
       
   198 
       
   199 	pos = p->pos;
       
   200 	while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {}
       
   201 
       
   202 	if (size == 0 || pos == p->size) {
       
   203 		*buffer = '\0';
       
   204 		/* If size was sooner to zero then the string in the stream
       
   205 		 *  skip till the \0, so than packet can be read out correctly for the rest */
       
   206 		while (pos < p->size && p->buffer[pos] != '\0') pos++;
       
   207 		pos++;
       
   208 	}
       
   209 	p->pos = pos;
       
   210 
       
   211 	str_validate(bufp);
       
   212 }
       
   213 
       
   214 #endif /* ENABLE_NETWORK */