rubidium@5720: /* $Id$ */ rubidium@5720: celestar@6447: /** celestar@6447: * @file packet.cpp Basic functions to create, fill and read packets. celestar@6447: */ celestar@6447: rubidium@5720: #ifdef ENABLE_NETWORK rubidium@5720: rubidium@5720: #include "../../stdafx.h" rubidium@9723: #include "../../string_func.h" rubidium@5720: rubidium@5720: #include "packet.h" rubidium@5720: rubidium@6149: /** rubidium@6149: * Create a packet that is used to read from a network socket rubidium@6149: * @param cs the socket handler associated with the socket we are reading from rubidium@6149: */ rubidium@6149: Packet::Packet(NetworkSocketHandler *cs) rubidium@6149: { rubidium@6149: assert(cs != NULL); rubidium@6149: rubidium@6149: this->cs = cs; rubidium@6149: this->next = NULL; rubidium@6149: this->pos = 0; // We start reading from here rubidium@6149: this->size = 0; rubidium@6149: } rubidium@6149: rubidium@6149: /** rubidium@6149: * Creates a packet to send rubidium@6149: * @param type of the packet to send rubidium@6149: */ rubidium@6149: Packet::Packet(PacketType type) rubidium@6149: { rubidium@6149: this->cs = NULL; rubidium@6149: this->next = NULL; rubidium@6149: rubidium@6149: /* Skip the size so we can write that in before sending the packet */ rubidium@6149: this->pos = 0; rubidium@6149: this->size = sizeof(PacketSize); rubidium@6149: this->buffer[this->size++] = type; rubidium@6149: } rubidium@5720: rubidium@5720: /** rubidium@5720: * Create a packet for sending rubidium@5720: * @param type the of packet rubidium@5720: * @return the newly created packet rubidium@5720: */ rubidium@6149: Packet *NetworkSend_Init(PacketType type) rubidium@5720: { rubidium@6149: Packet *packet = new Packet(type); rubidium@5720: /* An error is inplace here, because it simply means we ran out of memory. */ rubidium@5720: if (packet == NULL) error("Failed to allocate Packet"); rubidium@5720: rubidium@5720: return packet; rubidium@5720: } rubidium@5720: rubidium@5720: /** rubidium@5720: * Writes the packet size from the raw packet from packet->size rubidium@5720: */ rubidium@6573: void Packet::PrepareToSend() rubidium@5720: { rubidium@6149: assert(this->cs == NULL && this->next == NULL); rubidium@6149: rubidium@6149: this->buffer[0] = GB(this->size, 0, 8); rubidium@6149: this->buffer[1] = GB(this->size, 8, 8); rubidium@6149: rubidium@6149: this->pos = 0; // We start reading from here rubidium@5720: } rubidium@5720: rubidium@5720: /** rubidium@5720: * The next couple of functions make sure we can send rubidium@5720: * uint8, uint16, uint32 and uint64 endian-safe rubidium@5720: * over the network. The least significant bytes are rubidium@5720: * sent first. rubidium@5720: * rubidium@5720: * So 0x01234567 would be sent as 67 45 23 01. rubidium@6169: * rubidium@6169: * A bool is sent as a uint8 where zero means false rubidium@6169: * and non-zero means true. rubidium@5720: */ rubidium@5720: rubidium@6169: void Packet::Send_bool(bool data) rubidium@6169: { rubidium@6169: this->Send_uint8(data ? 1 : 0); rubidium@6169: } rubidium@6169: rubidium@6151: void Packet::Send_uint8(uint8 data) rubidium@5720: { rubidium@6151: assert(this->size < sizeof(this->buffer) - sizeof(data)); rubidium@6151: this->buffer[this->size++] = data; rubidium@5720: } rubidium@5720: rubidium@6151: void Packet::Send_uint16(uint16 data) rubidium@5720: { rubidium@6151: assert(this->size < sizeof(this->buffer) - sizeof(data)); rubidium@6151: this->buffer[this->size++] = GB(data, 0, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 8, 8); rubidium@5720: } rubidium@5720: rubidium@6151: void Packet::Send_uint32(uint32 data) rubidium@5720: { rubidium@6151: assert(this->size < sizeof(this->buffer) - sizeof(data)); rubidium@6151: this->buffer[this->size++] = GB(data, 0, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 8, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 16, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 24, 8); rubidium@6151: } rubidium@6151: rubidium@6151: void Packet::Send_uint64(uint64 data) rubidium@6151: { rubidium@6151: assert(this->size < sizeof(this->buffer) - sizeof(data)); rubidium@6151: this->buffer[this->size++] = GB(data, 0, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 8, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 16, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 24, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 32, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 40, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 48, 8); rubidium@6151: this->buffer[this->size++] = GB(data, 56, 8); rubidium@5720: } rubidium@5720: rubidium@5720: /** rubidium@5720: * Sends a string over the network. It sends out rubidium@5720: * the string + '\0'. No size-byte or something. rubidium@6115: * @param data the string to send rubidium@5720: */ rubidium@6151: void Packet::Send_string(const char* data) rubidium@5720: { rubidium@5720: assert(data != NULL); truelight@9718: /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */ truelight@9718: assert(this->size + strlen(data) + 1 <= sizeof(this->buffer)); rubidium@6151: while ((this->buffer[this->size++] = *data++) != '\0') {} rubidium@5720: } rubidium@5720: rubidium@5720: rubidium@5720: /** rubidium@5720: * Receiving commands rubidium@5720: * Again, the next couple of functions are endian-safe rubidium@6169: * see the comment before Send_bool for more info. rubidium@5720: */ rubidium@5720: rubidium@5720: rubidium@5720: /** Is it safe to read from the packet, i.e. didn't we run over the buffer ? */ rubidium@6151: bool Packet::CanReadFromPacket(uint bytes_to_read) rubidium@5720: { rubidium@5875: /* Don't allow reading from a quit client/client who send bad data */ rubidium@6151: if (this->cs->HasClientQuit()) return false; rubidium@5720: rubidium@5720: /* Check if variable is within packet-size */ rubidium@6151: if (this->pos + bytes_to_read > this->size) { rubidium@6151: this->cs->CloseConnection(); rubidium@5720: return false; rubidium@5720: } rubidium@5720: rubidium@5720: return true; rubidium@5720: } rubidium@5720: rubidium@5720: /** rubidium@5720: * Reads the packet size from the raw packet and stores it in the packet->size rubidium@5720: */ rubidium@6573: void Packet::ReadRawPacketSize() rubidium@5720: { rubidium@6149: assert(this->cs != NULL && this->next == NULL); rubidium@6149: this->size = (PacketSize)this->buffer[0]; rubidium@6149: this->size += (PacketSize)this->buffer[1] << 8; rubidium@6149: } rubidium@6149: rubidium@6149: /** rubidium@6149: * Prepares the packet so it can be read rubidium@6149: */ rubidium@6573: void Packet::PrepareToRead() rubidium@6149: { rubidium@6149: this->ReadRawPacketSize(); rubidium@6149: rubidium@6149: /* Put the position on the right place */ rubidium@6149: this->pos = sizeof(PacketSize); rubidium@5720: } rubidium@5720: rubidium@6573: bool Packet::Recv_bool() rubidium@6169: { rubidium@6169: return this->Recv_uint8() != 0; rubidium@6169: } rubidium@6169: rubidium@6573: uint8 Packet::Recv_uint8() rubidium@5720: { rubidium@5720: uint8 n; rubidium@5720: rubidium@6151: if (!this->CanReadFromPacket(sizeof(n))) return 0; rubidium@5720: rubidium@6151: n = this->buffer[this->pos++]; rubidium@5720: return n; rubidium@5720: } rubidium@5720: rubidium@6573: uint16 Packet::Recv_uint16() rubidium@5720: { rubidium@6151: uint16 n; rubidium@5720: rubidium@6151: if (!this->CanReadFromPacket(sizeof(n))) return 0; rubidium@5720: rubidium@6151: n = (uint16)this->buffer[this->pos++]; rubidium@6151: n += (uint16)this->buffer[this->pos++] << 8; rubidium@5720: return n; rubidium@5720: } rubidium@5720: rubidium@6573: uint32 Packet::Recv_uint32() rubidium@6151: { rubidium@6151: uint32 n; rubidium@6151: rubidium@6151: if (!this->CanReadFromPacket(sizeof(n))) return 0; rubidium@6151: rubidium@6151: n = (uint32)this->buffer[this->pos++]; rubidium@6151: n += (uint32)this->buffer[this->pos++] << 8; rubidium@6151: n += (uint32)this->buffer[this->pos++] << 16; rubidium@6151: n += (uint32)this->buffer[this->pos++] << 24; rubidium@6151: return n; rubidium@6151: } rubidium@6151: rubidium@6573: uint64 Packet::Recv_uint64() rubidium@5720: { rubidium@5720: uint64 n; rubidium@5720: rubidium@6151: if (!this->CanReadFromPacket(sizeof(n))) return 0; rubidium@5720: rubidium@6151: n = (uint64)this->buffer[this->pos++]; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 8; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 16; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 24; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 32; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 40; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 48; rubidium@6151: n += (uint64)this->buffer[this->pos++] << 56; rubidium@5720: return n; rubidium@5720: } rubidium@5720: rubidium@5720: /** Reads a string till it finds a '\0' in the stream */ rubidium@6151: void Packet::Recv_string(char *buffer, size_t size) rubidium@5720: { rubidium@5720: PacketSize pos; rubidium@5720: char *bufp = buffer; rubidium@5720: rubidium@5720: /* Don't allow reading from a closed socket */ rubidium@5875: if (cs->HasClientQuit()) return; rubidium@5720: rubidium@6151: pos = this->pos; rubidium@6151: while (--size > 0 && pos < this->size && (*buffer++ = this->buffer[pos++]) != '\0') {} rubidium@5720: rubidium@6151: if (size == 0 || pos == this->size) { rubidium@5720: *buffer = '\0'; rubidium@5720: /* If size was sooner to zero then the string in the stream rubidium@5720: * skip till the \0, so than packet can be read out correctly for the rest */ rubidium@6151: while (pos < this->size && this->buffer[pos] != '\0') pos++; rubidium@5720: pos++; rubidium@5720: } rubidium@6151: this->pos = pos; rubidium@5720: rubidium@5720: str_validate(bufp); rubidium@5720: } rubidium@5720: rubidium@5720: #endif /* ENABLE_NETWORK */