# HG changeset patch # User Teemu Piippo # Date 1469199595 -10800 # Node ID 970d58a01e8bd7b18e701dff42390c9f3234eedf # Parent 9f71f854474a04762014eda9493dc98dd94dc19d# Parent de7574d292ad616ccb013e70819cb1fec3387d55 Merged with default diff -r 9f71f854474a -r 970d58a01e8b sources/basics.h --- a/sources/basics.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/basics.h Fri Jul 22 17:59:55 2016 +0300 @@ -90,6 +90,11 @@ return (a < b) ? b : (a > c) ? c : a; } +inline const char *plural(int value) +{ + return value != 1 ? "s" : ""; +} + template char (&_ArraySizeHelper(T (&array)[N]))[N]; #define countof(array) (sizeof(_ArraySizeHelper( array ))) diff -r 9f71f854474a -r 970d58a01e8b sources/interface.cpp --- a/sources/interface.cpp Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/interface.cpp Fri Jul 22 17:59:55 2016 +0300 @@ -168,7 +168,7 @@ m_inputHistory << ""; m_outputLines.clear(); m_outputLines << ColoredLine(); - m_session.set_interface(this); + m_session.setInterface(this); resetTitle(); if (::has_colors()) @@ -230,7 +230,7 @@ // void Interface::safeDisconnect(std::function afterwards) { - if (m_session.is_active()) + if (m_session.isActive()) { m_disconnectCallback = afterwards; setInputState(INPUTSTATE_CONFIRM_DISCONNECTION); @@ -480,7 +480,7 @@ { String text; - switch (m_session.state()) + switch (m_session.getState()) { case RCON_DISCONNECTED: text = "Disconnected."; @@ -495,19 +495,19 @@ { String adminText; - if (m_session.num_admins() == 0) + if (m_session.getAdminCount() == 0) { adminText = "No other admins"; } else { - adminText.sprintf("%d other admin%s", m_session.num_admins(), - m_session.num_admins() != 1 ? "s" : ""); + adminText.sprintf("%d other admin%s", m_session.getAdminCount(), + m_session.getAdminCount() != 1 ? "s" : ""); } text.sprintf("%s | %s | %s", m_session.address().to_string(IPAddress::WITH_PORT).chars(), - m_session.level().chars(), + m_session.getLevel().chars(), adminText.chars()); } break; @@ -517,7 +517,7 @@ text += " | "; text += "Ctrl+N to connect, Ctrl+Q to "; - text +=(m_session.state() == RCON_DISCONNECTED) ? "quit" : "disconnect"; + text +=(m_session.getState() == RCON_DISCONNECTED) ? "quit" : "disconnect"; if (text != m_statusBarText) { @@ -775,7 +775,7 @@ and(space == -1 or space >= m_cursorPosition)) { String start = getCurrentInput().mid(0, m_cursorPosition); - m_session.request_tab_complete(start); + m_session.requestTabCompletion(start); } } break; @@ -809,7 +809,7 @@ if (m_inputState == INPUTSTATE_PASSWORD and not getCurrentInput().isEmpty()) { m_session.disconnect(); - m_session.set_password(getCurrentInput()); + m_session.setPassword(getCurrentInput()); m_session.connect(m_remoteAddress); setInputState(INPUTSTATE_NORMAL); } @@ -821,7 +821,7 @@ handleCommand(getCurrentInput()); flushInput(); } - else if (m_session.send_command(getCurrentInput())) + else if (m_session.sendCommand(getCurrentInput())) { flushInput(); } @@ -1007,7 +1007,7 @@ m_remoteAddress.port = 10666; m_session.disconnect(); - m_session.set_password(password); + m_session.setPassword(password); m_session.connect(m_remoteAddress); } @@ -1079,7 +1079,7 @@ if (address.port == 0) address.port = 10666; - m_session.set_password(args[1]); + m_session.setPassword(args[1]); m_session.disconnect(); m_session.connect(m_remoteAddress = address); } diff -r 9f71f854474a -r 970d58a01e8b sources/list.h --- a/sources/list.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/list.h Fri Jul 22 17:59:55 2016 +0300 @@ -58,12 +58,24 @@ Container (const C& other) : m_container (other) {} + Container(std::initializer_list initializerList) : + m_container(initializerList) {} + T& append (const T& value) { m_container.push_back (value); return m_container[m_container.size() - 1]; } + void append(const T* values, size_t numValues) + { + size_t i0 = size(); + resize(size() + numValues); + + for (size_t i : range(numValues)) + (*this)[i0 + i] = values[i]; + } + Iterator begin() { return m_container.begin(); @@ -256,22 +268,29 @@ std::sort (begin(), end()); } - Self splice (int a, int b) const + Self splice(int start, int end, int step = 1) const { - if (a < 0 or b >= size() or b < a) - return Self(); + start = clamp(start, 0, size() - 1); + end = clamp(end, 0, size() - 1); - Self result; + if (end <= start) + { + return Self(); + } + else + { + Self result; - for (int i = a; i < b; ++i) - result << operator[] (i); + for (int i : range(start, end, step)) + result << operator[] (i); - return result; + return result; + } } - Self splice (const Range& a) const + Self splice(Range& range) const { - return splice (a.min(), a.max()); + return splice(range.min(), range.max(), range.step()); } Self& operator<< (const T& value) @@ -358,6 +377,12 @@ Vector (T* data, size_t length) : Super (std::vector (data, data + length)) {} + Vector(std::initializer_list initializerList) : + Super(initializerList) {} + + Vector(const Super& other) : + Super(other) {} + T* data() { return Super::m_container.data(); @@ -374,4 +399,6 @@ } }; +typedef Vector ByteArray; + END_ZFC_NAMESPACE diff -r 9f71f854474a -r 970d58a01e8b sources/main.cpp --- a/sources/main.cpp Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/main.cpp Fri Jul 22 17:59:55 2016 +0300 @@ -84,7 +84,7 @@ FD_ZERO (&fdset); FD_SET (0, &fdset); - int fd = iface.getSession()->socket()->file_descriptor(); + int fd = iface.getSession()->getSocket()->file_descriptor(); highest = zfc::max (highest, fd); FD_SET (fd, &fdset); diff -r 9f71f854474a -r 970d58a01e8b sources/mystring.cpp --- a/sources/mystring.cpp Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/mystring.cpp Fri Jul 22 17:59:55 2016 +0300 @@ -561,6 +561,16 @@ } /*! + * \brief Constructs a string from a vector of bytes. The bytes do not have to be null-terminated. + * \param bytes Bytes to use for construction + * \returns the resulting string. + */ +String String::fromBytes(const ByteArray& bytes) +{ + return String(reinterpret_cast&>(bytes)); +} + +/*! * \returns the MD5-checksum of this string. */ String String::md5() const diff -r 9f71f854474a -r 970d58a01e8b sources/mystring.h --- a/sources/mystring.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/mystring.h Fri Jul 22 17:59:55 2016 +0300 @@ -93,6 +93,7 @@ const std::string& stdString() const; void strip(char unwanted); void strip(const List &unwanted); + const unsigned char* toBytes() const; double toDouble(bool* ok = nullptr) const; float toFloat(bool* ok = nullptr) const; long toInt(bool* ok = nullptr, int base = 10) const; @@ -107,6 +108,7 @@ static String fromNumber(unsigned int a); static String fromNumber(unsigned long int a); static String fromNumber(double a); + static String fromBytes(const ByteArray& bytes); String operator+(const String& data) const; String operator+(const char* data) const; @@ -553,6 +555,14 @@ } /*! + * \returns the underlying char-array representation of this string, casted to unsigned chars. + */ +inline const unsigned char* String::toBytes() const +{ + return reinterpret_cast(chars()); +} + +/*! * \brief Constructs an empty string list. */ inline StringList::StringList() {} diff -r 9f71f854474a -r 970d58a01e8b sources/network/bytestream.cpp --- a/sources/network/bytestream.cpp Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/network/bytestream.cpp Fri Jul 22 17:59:55 2016 +0300 @@ -32,270 +32,224 @@ #include BEGIN_ZFC_NAMESPACE -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (unsigned long length) : - m_data (nullptr) -{ - resize (length); - clear(); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (const unsigned char* data, unsigned long length) : - m_data (nullptr) -{ - init (data, length); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (const Vector& bytes) : - m_data (nullptr) -{ - init (bytes.data(), bytes.size()); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::Bytestream (const Bytestream& other) : - m_data (nullptr) -{ - init (other.data(), other.written_length()); -} - -// ------------------------------------------------------------------------------------------------- -// -Bytestream::~Bytestream() -{ - delete[] m_data; -} - -// ------------------------------------------------------------------------------------------------- -Bytestream& Bytestream::operator= (const Bytestream& other) -{ - init (other.data(), other.written_length()); - return *this; -} +/*! + * \brief Constructs a byte cursor. The cursor is placed to the beginning of the stream. + * \param data + */ +Bytestream::Bytestream(ByteArray& data) : + m_data(data), + m_position(0) {} -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::resize (unsigned long newsize) -{ - Vector olddata; - unsigned long oldsize = 0L; - - if (m_data != nullptr) - { - oldsize = allocated_size(); - olddata.resize (oldsize); - memcpy (olddata.data(), m_data, oldsize); - } - - delete[] m_data; - m_allocatedSize = newsize; - m_data = new unsigned char[newsize]; - - if (oldsize > 0L) - memcpy (m_data, olddata, min (oldsize, newsize)); -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::init (const unsigned char* data, unsigned long length) +/*! + * \brief Ensures that the specified amount of bytes can be read. Raises IOError if this is not the case. + * \param bytes Amount of bytes to check. + */ +void Bytestream::ensureReadSpace(int bytes) { - resize (length); - memcpy (m_data, data, length); - m_cursor = &m_data[0]; - m_writtenLength = length; -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::clear() -{ - m_cursor = &m_data[0]; - m_writtenLength = 0; -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::ensure_read_space (unsigned int bytes) -{ - if (bytes_left() < bytes) + if (bytesLeft() < bytes) { - int bytesPast = bytes - bytes_left(); - + int bytesPast = bytes - bytesLeft(); String message; - message.sprintf ("attempted to read %d byte%s past the end of bytestream", - bytesPast, bytesPast != -1 ? "s" : ""); + message.sprintf("attempted to read %d byte%s past the end of bytestream", bytesPast, plural(bytesPast)); throw IOError (message); } } -// ------------------------------------------------------------------------------------------------- -// -int8_t Bytestream::read_byte() +/*! + * \returns the amount of bytes remaining for reading. + */ +int Bytestream::bytesLeft() const { - ensure_read_space (1); - return *m_cursor++; + return m_data.size() - m_position; +} + +/*! + * \returns an iterator to the current data position. + */ +ByteArray::Iterator Bytestream::getCurrentIterator() +{ + return m_data.begin() + m_position; } -// ------------------------------------------------------------------------------------------------- -// -int16_t Bytestream::read_short() +/*! + * \brief Reads in a byte. + * \returns the read byte. + */ +int8_t Bytestream::readByte() { - ensure_read_space (2); - short int result = 0; + ensureReadSpace(1); + return read(); +} + +/*! + * \brief Reads in two bytes to form an integer value. + * \returns the read value. + */ +int16_t Bytestream::readShort() +{ + ensureReadSpace (2); + int16_t result = 0; for (int i : range(2)) - result |= m_cursor[i] << (i * 8); + result |= read() << (i * 8); - m_cursor += 2; return result; } -// ------------------------------------------------------------------------------------------------- -// -int32_t Bytestream::read_long() +/*! + * \brief Reads in four bytes to form an integer value. + * \returns the read value. + */ +int32_t Bytestream::readLong() { - ensure_read_space (4); - long int result = 0; + ensureReadSpace (4); + int32_t result = 0; for (int i : range(4)) - result |= m_cursor[i] << (i * 8); + result |= read() << (i * 8); - m_cursor += 4; return result; } -// ------------------------------------------------------------------------------------------------- -// -float Bytestream::read_float() +/*! + * \brief Reads in four bytes to form a floating point number. + * \returns the read value. + */ +float Bytestream::readFloat() { float value; - int intvalue = read_long(); - memcpy (&value, &intvalue, sizeof intvalue); + int intvalue = readLong(); + memcpy(&value, &intvalue, sizeof intvalue); return value; } -// ------------------------------------------------------------------------------------------------- -// -String Bytestream::read_string() +/*! + * \brief Reads in characters until a null terminator is encountered. + * \returns the read string. + */ +String Bytestream::readString() { - // Zandronum sends strings of maximum 2048 characters, though it only - // reads 2047-character long ones so I guess we can follow up and do - // the same :-) - static char buffer[MAX_NETWORK_STRING]; - unsigned char* stringEnd; - unsigned char* stringBegin = m_cursor; - unsigned char* end = m_data + allocated_size(); + ByteArray::Iterator stringEndIterator; // Where's the end of the string? - for (stringEnd = m_cursor; *stringEnd != '\0'; ++stringEnd) + for (stringEndIterator = getCurrentIterator(); *stringEndIterator != '\0'; ++stringEndIterator) { - if (stringEnd == end) + if (stringEndIterator == m_data.end()) { // Past the end of the buffer - throw IOError ("unterminated or too long string in packet"); + throw IOError("unterminated or too long string in packet"); } } - unsigned int length = stringEnd - m_cursor; - m_cursor = stringEnd + 1; - memcpy (buffer, stringBegin, length); - buffer[length] = '\0'; - return String (buffer); -} + // Skip past the null terminator. + if (*stringEndIterator == '\0') + stringEndIterator += 1; -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::read (unsigned char* buffer, unsigned long length) -{ - ensure_read_space (length); - memcpy (buffer, m_cursor, length); - m_cursor += length; + // Build and return the string, and advance the position. + int stringStart = m_position; + unsigned int length = stringEndIterator - getCurrentIterator(); + length = min(length, MAX_NETWORK_STRING); + m_position += length; + return String::fromBytes(m_data.splice(stringStart, stringStart + length)); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write (unsigned char val) +/*! + * \brief Reads in a buffer of the specified length. + * \param length Amount of bytes to read. + * \returns the read buffer. + */ +ByteArray Bytestream::readBuffer(int length) { - *m_cursor++ = val; - m_writtenLength++; -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write (const unsigned char* val, unsigned int length) -{ - grow_to_fit (length); - memcpy (m_cursor, val, length); - m_cursor += length; - m_writtenLength += length; + ensureReadSpace(length); + ByteArray result(length); + memcpy(result.data(), m_data.data() + m_position, length); + m_position += length; + return result; } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::grow_to_fit (unsigned long bytes) +/*! + * \brief Writes an integer to the end of the data as one byte. + * \param value Value to write + */ +void Bytestream::writeByte(int8_t value) { - if (space_left() < bytes) - resize (allocated_size() + bytes + 128); -} - -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_byte (int8_t val) -{ - grow_to_fit (1); - write (val); + m_data.append(value); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_short (int16_t val) +/*! + * \brief Writes an integer to the end of the data as 2 bytes. + * \param value Value to write + */ +void Bytestream::writeShort(int16_t value) { - grow_to_fit (2); - for (int i : range(2)) - write ((val >> (i * 8)) & 0xFF); + m_data.append((value >> (i * 8)) & 0xFF); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_long (int32_t val) +/*! + * \brief Writes an integer to the end of the data as 4 bytes. + * \param value Value to write + */ +void Bytestream::writeLong(int32_t value) { - grow_to_fit (4); - for (int i : range(4)) - write ((val >> (i * 8)) & 0xFF); + m_data.append((value >> (i * 8)) & 0xFF); } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_float (float val) +/*! + * \brief Writes a floating-point number to the end of the data. + * \param value Value to write. + */ +void Bytestream::writeFloat(float value) { // I know this is probably dangerous but this is what Zandronum does so yeah int intvalue; - memcpy (&intvalue, &val, sizeof val); - write_long (intvalue); + memcpy (&intvalue, &value, sizeof value); + writeLong (intvalue); +} + +/*! + * \brief Writes the given string to the end of the data. + * \param text String to write. + */ +void Bytestream::writeString(const String& string) +{ + m_data.append(string.toBytes(), string.length()); + m_data.append(0); +} + +/*! + * \returns the current position the stream cursor in the data. + */ +int Bytestream::position() const +{ + return m_position; } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_string (const String& val) +/*! + * \brief Seeks the stream cursor to the beginning of the data. + */ +void Bytestream::rewind() { - grow_to_fit (val.length() + 1); - write (reinterpret_cast (val.chars()), val.length()); - write (0); + m_position = 0; } -// ------------------------------------------------------------------------------------------------- -// -void Bytestream::write_buffer (const Bytestream& other) +/*! + * \brief Seeks the stream cursor to a custom location. + * \param position Position to seek too. + */ +void Bytestream::seek(int position) { - write (other.data(), other.written_length()); + m_position = position; +} + +/*! + * \brief Reads a byte and advances the cursor. No safety checks are done. + * \returns the read byte. + */ +int8_t Bytestream::read() +{ + return m_data[m_position++]; } END_ZFC_NAMESPACE \ No newline at end of file diff -r 9f71f854474a -r 970d58a01e8b sources/network/bytestream.h --- a/sources/network/bytestream.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/network/bytestream.h Fri Jul 22 17:59:55 2016 +0300 @@ -40,119 +40,51 @@ MAX_NETWORK_STRING = 0x800 }; -// TODO: Make able to handle big-endian too +class IOError : public std::exception +{ + String m_message; + +public: + IOError(String message) : + m_message(message) {} + + const char* what() const throw() + { + return m_message; + } +}; + class Bytestream { public: - class IOError : public std::exception - { - String m_message; - - public: - IOError (String message) : - m_message (message) {} - - const char* what() const throw() - { - return m_message; - } - }; - - Bytestream (unsigned long length = 0x800); - Bytestream (const unsigned char* data, unsigned long length); - Bytestream (const Vector& bytes); - Bytestream (const Bytestream& other); - ~Bytestream(); - - void clear(); - void grow_to_fit (unsigned long bytes); - void read (unsigned char* buffer, unsigned long length); - int8_t read_byte(); - int32_t read_long(); - int16_t read_short(); - String read_string(); - float read_float(); - void resize (unsigned long length); - void write (const unsigned char* val, unsigned int length); - void write_buffer (const Bytestream& other); - void write_buffer (const Vector& other); - void write_byte (int8_t val); - void write_double (double val); - void write_float (float val); - void write_long (int32_t val); - void write_short (int16_t val); - void write_string (const String& val); - - Bytestream& operator= (const Bytestream& other); - - unsigned long allocated_size() const - { - return m_allocatedSize; - } + Bytestream(ByteArray& data); - unsigned long bytes_left() const - { - return m_writtenLength - (m_cursor - &m_data[0]); - } - - inline unsigned char* data() - { - return m_data; - } - inline const unsigned char* data() const - { - return m_data; - } - - unsigned long position() const - { - return m_cursor - m_data; - } - - void rewind() - { - m_cursor = m_data; - } - - void seek (unsigned long pos) - { - m_cursor = m_data + pos; - } - - Vector to_vector() const - { - return Vector (m_data, m_writtenLength); - } - - unsigned long written_length() const - { - return m_writtenLength; - } - - unsigned char& operator[] (unsigned long idx) - { - return m_data[idx]; - } - - unsigned char operator[] (unsigned long idx) const - { - return m_data[idx]; - } + int bytesLeft() const; + ByteArray::Iterator getCurrentIterator(); + int position() const; + ByteArray readBuffer(int length); + int8_t readByte(); + int32_t readLong(); + int16_t readShort(); + String readString(); + float readFloat(); + void rewind(); + void seek(int position); + void write(const unsigned char* val, unsigned int length); + void writeBuffer(const ByteArray& other); + void writeByte(int8_t value); + void writeDouble(double val); + void writeFloat(float value); + void writeLong(int32_t value); + void writeShort(int16_t value); + void writeString(const String& string); private: - unsigned char* m_data; - unsigned char* m_cursor; - unsigned long m_allocatedSize; - unsigned long m_writtenLength; + ByteArray& m_data; + int m_position; - void init (const unsigned char* data, unsigned long length); - void write (unsigned char val); - void ensure_read_space (unsigned int bytes); - - unsigned long space_left() const - { - return m_allocatedSize - m_writtenLength; - } + int8_t read(); + void ensureReadSpace(int bytes); }; END_ZFC_NAMESPACE diff -r 9f71f854474a -r 970d58a01e8b sources/network/rconsession.cpp --- a/sources/network/rconsession.cpp Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/network/rconsession.cpp Fri Jul 22 17:59:55 2016 +0300 @@ -36,16 +36,16 @@ // ------------------------------------------------------------------------------------------------- // RCONSession::RCONSession() : - m_state (RCON_DISCONNECTED), - m_lastPing (0), - m_numAdmins (0), - m_interface (nullptr) + m_state(RCON_DISCONNECTED), + m_lastPing(0), + m_adminCount(0), + m_interface(nullptr) { - if (not m_socket.set_blocking (false)) + if (not m_socket.set_blocking(false)) { - fprintf (stderr, "unable to set socket as non-blocking: %s\n", + fprintf(stderr, "unable to set socket as non-blocking: %s\n", m_socket.error_string().chars()); - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } } @@ -55,12 +55,12 @@ // ------------------------------------------------------------------------------------------------- // -void RCONSession::connect (IPAddress address) +void RCONSession::connect(IPAddress address) { m_address = address; m_state = RCON_CONNECTING; m_interface->updateStatusBar(); - send_hello(); + sendHello(); } // ------------------------------------------------------------------------------------------------- @@ -70,9 +70,7 @@ if (m_state > RCON_CONNECTING) { // Say goodbye to remote - Bytestream packet; - packet.write_byte (CLRC_DISCONNECT); - this->send (packet); + send({CLRC_DISCONNECT}); m_interface->disconnected(); } @@ -81,9 +79,9 @@ // ------------------------------------------------------------------------------------------------- // -void RCONSession::send (const Bytestream& packet) +void RCONSession::send(const ByteArray& packet) { - m_socket.send (m_address, packet); + m_socket.send(m_address, packet); } // ------------------------------------------------------------------------------------------------- @@ -94,38 +92,38 @@ return; time_t now; - time (&now); + time(&now); if (m_lastPing < now) { if (m_state == RCON_CONNECTING) { - send_hello(); + sendHello(); } else if (m_state == RCON_AUTHENTICATING) { - send_password(); + sendPassword(); } else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now) { - Bytestream packet; - packet.write_byte (CLRC_PONG); - send (packet); - bump_last_ping(); + send({CLRC_PONG}); + bumpLastPing(); } } - for (Datagram datagram; m_socket.read (datagram);) - handle_packet (datagram); + for (Datagram datagram; m_socket.read(datagram);) + handlePacket(datagram); } // ------------------------------------------------------------------------------------------------- // -void RCONSession::handle_packet (Datagram& datagram) +void RCONSession::handlePacket(Datagram& datagram) { if (datagram.address != m_address) return; + Bytestream stream(datagram.message); + try { int32_t header = datagram.message.read_long(); @@ -134,59 +132,59 @@ while (datagram.message.bytes_left() > 0) { - int header = datagram.message.read_byte(); + int header = stream.readByte(); - switch (ServerResponse (header)) + switch (ServerResponse(header)) { case SVRC_OLDPROTOCOL: - m_interface->printError ("Your RCON client is using outdated protocol.\n"); + m_interface->printError("Your RCON client is using outdated protocol.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_BANNED: - m_interface->printError ("You have been banned from the server.\n"); + m_interface->printError("You have been banned from the server.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_SALT: - m_salt = datagram.message.read_string(); + m_salt = stream.readString(); m_state = RCON_AUTHENTICATING; - send_password(); + sendPassword(); break; case SVRC_INVALIDPASSWORD: - m_interface->printError ("Login failed.\n"); + m_interface->printError("Login failed.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_MESSAGE: { - String message = datagram.message.read_string(); + String message = stream.readString(); message.normalize(); - m_interface->printText ("%s\n", message.chars()); + m_interface->printText("%s\n", message.chars()); } break; case SVRC_LOGGEDIN: - m_interface->print ("Login successful!\n"); - m_serverProtocol = datagram.message.read_byte(); - m_hostname = datagram.message.read_string(); - m_interface->setTitle (m_hostname); + m_interface->print("Login successful!\n"); + m_serverProtocol = stream.readByte(); + m_hostname = stream.readString(); + m_interface->setTitle(m_hostname); m_state = RCON_CONNECTED; - for (int i = datagram.message.read_byte(); i > 0; --i) - process_server_updates (datagram.message); + for (int i = stream.readByte(); i > 0; --i) + processServerUpdates(stream); - m_interface->print ("Previous messages:\n"); + m_interface->print("Previous messages:\n"); - for (int i = datagram.message.read_byte(); i > 0; --i) + for (int i = stream.readByte(); i > 0; --i) { - String message = datagram.message.read_string(); + String message = stream.readString(); message.normalize(); - m_interface->printText ("--- %s\n", message.chars()); + m_interface->printText("--- %s\n", message.chars()); } - m_interface->print ("End of previous messages.\n"); + m_interface->print("End of previous messages.\n"); // Watch sv_hostname so that we can update the titlebar when it changes. request_watch("sv_hostname"); @@ -194,38 +192,38 @@ break; case SVRC_UPDATE: - process_server_updates (datagram.message); + processServerUpdates(stream); break; case SVRC_TOOMANYTABCOMPLETES: { - unsigned int numCompletions = datagram.message.read_short(); - m_interface->print ("%d completions for '%s'.\n", - int (numCompletions), m_lastTabComplete.chars()); + unsigned int numCompletions = stream.readShort(); + m_interface->print("%d completions for '%s'.\n", + int(numCompletions), m_lastTabComplete.chars()); } break; case SVRC_TABCOMPLETE: { StringList completes; - completes.resize(datagram.message.read_byte()); + completes.resize(stream.readByte()); for (String& completion : completes) - completion = datagram.message.read_string(); + completion = stream.readString(); if (completes.size() == 1) { - m_interface->tabComplete (m_lastTabComplete, completes[0]); + m_interface->tabComplete(m_lastTabComplete, completes[0]); } else if (not completes.is_empty()) { - m_interface->print ("Completions for '%s':\n", m_lastTabComplete.chars()); + m_interface->print("Completions for '%s':\n", m_lastTabComplete.chars()); for (int i : range(0, completes.size(), 8)) { - Range spliceRange (i, min (i + 8, completes.size())); - StringList splice (completes.splice (spliceRange)); - m_interface->print ("- %s\n", splice.join (", ").chars()); + Range spliceRange(i, min(i + 8, completes.size())); + StringList splice(completes.splice(spliceRange)); + m_interface->print("- %s\n", splice.join(", ").chars()); } } } @@ -269,117 +267,115 @@ } catch (std::exception& e) { - m_interface->printWarning ("Couldn't process packet: %s\n", e.what()); + m_interface->printWarning("Couldn't process packet: %s\n", e.what()); } } -void RCONSession::process_server_updates (Bytestream& packet) +void RCONSession::processServerUpdates(Bytestream& packet) { - int header = packet.read_byte(); + int header = packet.readByte(); - switch (RCONUpdateType (header)) + switch (RCONUpdateType(header)) { case SVRCU_PLAYERDATA: { StringList players; - for (int i = packet.read_byte(); i > 0; --i) - players.append (packet.read_string()); + for (int i = packet.readByte(); i > 0; --i) + players.append(packet.readString()); - m_interface->setPlayerNames (players); + m_interface->setPlayerNames(players); } break; case SVRCU_ADMINCOUNT: - m_numAdmins = packet.read_byte(); + m_adminCount = packet.readByte(); m_interface->updateStatusBar(); break; case SVRCU_MAP: - m_level = packet.read_string(); + m_level = packet.readString(); m_interface->updateStatusBar(); break; default: - m_interface->printWarning ("Unknown server update type: %d\n", header); + m_interface->printWarning("Unknown server update type: %d\n", header); break; } } // ------------------------------------------------------------------------------------------------- // -UDPSocket* RCONSession::socket() +UDPSocket* RCONSession::getSocket() { return &m_socket; } // ------------------------------------------------------------------------------------------------- // -void RCONSession::send_hello() +void RCONSession::sendHello() { - m_interface->print ("Connecting to %s...\n", - m_address.to_string (IPAddress::WITH_PORT).chars()); - Bytestream packet; - packet.write_byte (CLRC_BEGINCONNECTION); - packet.write_byte (RCON_PROTOCOL_VERSION); - send (packet); - bump_last_ping(); + m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).chars()); + send({CLRC_BEGINCONNECTION, RCON_PROTOCOL_VERSION}); + bumpLastPing(); } // ------------------------------------------------------------------------------------------------- // -void RCONSession::send_password() +void RCONSession::sendPassword() { - m_interface->print ("Authenticating...\n"); - Bytestream packet; - packet.write_byte (CLRC_PASSWORD); - packet.write_string ((m_salt + m_password).md5()); - send (packet); - bump_last_ping(); + m_interface->print("Authenticating...\n"); + ByteArray message; + Bytestream stream(message); + stream.writeByte(CLRC_PASSWORD); + stream.writeString((m_salt + m_password).md5()); + send(message); + bumpLastPing(); } // ------------------------------------------------------------------------------------------------- // -void RCONSession::set_password (const String& password) +void RCONSession::setPassword(const String& password) { m_password = password; } // ------------------------------------------------------------------------------------------------- // -void RCONSession::bump_last_ping() +void RCONSession::bumpLastPing() { time_t now; - time (&now); + time(&now); m_lastPing = now; } // ------------------------------------------------------------------------------------------------- // -bool RCONSession::is_active() const +bool RCONSession::isActive() const { - return state() != RCON_DISCONNECTED; + return getState() != RCON_DISCONNECTED; } // ------------------------------------------------------------------------------------------------- // Returns true if the message was successfully sent. // -bool RCONSession::send_command (const String& message) +bool RCONSession::sendCommand(const String& commandString) { - if (m_state != RCON_CONNECTED or message.isEmpty()) + if (m_state != RCON_CONNECTED or commandString.isEmpty()) return false; - Bytestream packet; - packet.write_byte (CLRC_COMMAND); - packet.write_string (message); - send (packet); - bump_last_ping(); + ByteArray message; + Bytestream stream(message); + stream.writeByte(CLRC_COMMAND); + stream.writeString(commandString); + send(message); + bumpLastPing(); return true; } // ------------------------------------------------------------------------------------------------- // -RCONSessionState RCONSession::state() const +RCONSessionState RCONSession::getState() const { return m_state; } @@ -393,42 +389,43 @@ // ------------------------------------------------------------------------------------------------- // -int RCONSession::num_admins() const +int RCONSession::getAdminCount() const { - return m_numAdmins; + return m_adminCount; } // ------------------------------------------------------------------------------------------------- // -const String& RCONSession::level() const +const String& RCONSession::getLevel() const { return m_level; } // ------------------------------------------------------------------------------------------------- // -void RCONSession::request_tab_complete (const String& part) +void RCONSession::requestTabCompletion(const String& part) { if (m_serverProtocol >= 4) { - Bytestream packet; - packet.write_byte (CLRC_TABCOMPLETE); - packet.write_string (part); - send (packet); - bump_last_ping(); + ByteArray message; + Bytestream stream(message); + stream.writeByte(CLRC_TABCOMPLETE); + stream.writeString(part); + send(message); + bumpLastPing(); m_lastTabComplete = part; } else { - m_interface->print ("This server does not support tab-completion\n", m_serverProtocol); + m_interface->print("This server does not support tab-completion\n", m_serverProtocol); } } // ------------------------------------------------------------------------------------------------- // -void RCONSession::set_interface (Interface* iface) +void RCONSession::setInterface(Interface* interface) { - m_interface = iface; + m_interface = interface; } // ------------------------------------------------------------------------------------------------- diff -r 9f71f854474a -r 970d58a01e8b sources/network/rconsession.h --- a/sources/network/rconsession.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/network/rconsession.h Fri Jul 22 17:59:55 2016 +0300 @@ -20,10 +20,10 @@ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -101,25 +101,25 @@ RCONSession(); ~RCONSession(); - const IPAddress& address() const; - void connect (IPAddress address); - void disconnect(); - void handle_packet (Datagram& datagram); - void process_server_updates (Bytestream& packet); - int num_admins() const; - void send (const Bytestream& packet); - void send_hello(); - void send_password(); - void set_password (const String& password); - UDPSocket* socket(); - void tick(); - void bump_last_ping(); - bool send_command (const String& message); - RCONSessionState state() const; - const String& level() const; - bool is_active() const; - void request_tab_complete (const String& part); - void set_interface (class Interface* iface); + const IPAddress& address() const; + void bumpLastPing(); + void connect(IPAddress address); + void disconnect(); + int getAdminCount() const; + const String& getLevel() const; + UDPSocket* getSocket(); + RCONSessionState getState() const; + void handlePacket(Datagram& datagram); + bool isActive() const; + void processServerUpdates(Bytestream& packet); + void requestTabCompletion(const String& part); + void send(const ByteArray& packet); + bool sendCommand(const String& commandString); + void sendHello(); + void sendPassword(); + void setInterface(class Interface* interface); + void setPassword(const String& password); + void tick(); void request_watch (const String& cvar); void request_watch (const StringList& cvars); @@ -132,7 +132,7 @@ String m_salt; int m_serverProtocol; String m_hostname; - int m_numAdmins; + int m_adminCount; String m_level; String m_lastTabComplete; class Interface* m_interface; diff -r 9f71f854474a -r 970d58a01e8b sources/network/udpsocket.cpp --- a/sources/network/udpsocket.cpp Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/network/udpsocket.cpp Fri Jul 22 17:59:55 2016 +0300 @@ -141,17 +141,16 @@ decodedPacket, length, &decodedLength); datagram.address.host = ntohl (claddr.sin_addr.s_addr); datagram.address.port = ntohs (claddr.sin_port); - datagram.message = Bytestream (decodedPacket, decodedLength); + datagram.message = ByteArray(decodedPacket, decodedLength); return true; } // ------------------------------------------------------------------------------------------------- // -bool UDPSocket::send (const IPAddress& address, const Bytestream& data) +bool UDPSocket::send (const IPAddress& address, const ByteArray& data) { int encodedlength = sizeof HuffmanBuffer; - HUFFMAN_Encode (data.data(), reinterpret_cast (HuffmanBuffer), - data.written_length(), &encodedlength); + HUFFMAN_Encode (data.data(), reinterpret_cast (HuffmanBuffer), data.size(), &encodedlength); sockaddr_in claddr = address.to_sockaddr_in(); int res = ::sendto (m_socket, HuffmanBuffer, encodedlength, 0, reinterpret_cast (&claddr), sizeof claddr); diff -r 9f71f854474a -r 970d58a01e8b sources/network/udpsocket.h --- a/sources/network/udpsocket.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/network/udpsocket.h Fri Jul 22 17:59:55 2016 +0300 @@ -38,7 +38,7 @@ struct Datagram { - Bytestream message; + ByteArray message; IPAddress address; }; @@ -52,7 +52,7 @@ bool bind (unsigned short port); bool read (Datagram& datagram); - bool send (const IPAddress& address, const Bytestream& data); + bool send (const IPAddress& address, const ByteArray& data); bool set_blocking (bool a); const String& error_string() const { return m_error; } int file_descriptor() const { return m_socket; } diff -r 9f71f854474a -r 970d58a01e8b sources/range.h --- a/sources/range.h Wed Jul 20 18:31:19 2016 +0300 +++ b/sources/range.h Fri Jul 22 17:59:55 2016 +0300 @@ -108,6 +108,11 @@ return m_b; } + T step() const + { + return m_step; + } + void check_bounds() { if (m_b < m_a)