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