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