diff --git a/server/src/Configuration.cpp b/server/src/Configuration.cpp index 61b6b4c..42f77ca 100644 --- a/server/src/Configuration.cpp +++ b/server/src/Configuration.cpp @@ -986,18 +986,18 @@ std::deque> config::create_bindings() { BIND_GROUP(query); { CREATE_BINDING("nl_char", 0); - BIND_STRING(config::query::newlineCharacter, "\n\r"); + BIND_STRING(config::query::newlineCharacter, "\r\n"); ADD_DESCRIPTION("Change the query newline character"); } { CREATE_BINDING("motd", 0); - BIND_STRING(config::query::motd, "TeaSpeak\n\rWelcome on the TeaSpeak ServerQuery interface.\n\r"); + BIND_STRING(config::query::motd, "TeaSpeak\r\nWelcome on the TeaSpeak ServerQuery interface.\r\n"); ADD_DESCRIPTION("The query welcome message"); ADD_NOTE("If not like TeamSpeak then some applications may not recognize the Query"); ADD_NOTE("Default TeamSpeak 3 MOTD:"); - ADD_NOTE("TS3\n\rWelcome to the TeamSpeak 3 ServerQuery interface, type \"help\" for a list of commands and \"help \" for information on a specific command.\n\r"); - ADD_NOTE("NOTE: Sometimes you have to append one \n\r more!"); + ADD_NOTE("TS3\r\nWelcome to the TeamSpeak 3 ServerQuery interface, type \"help\" for a list of commands and \"help \" for information on a specific command.\r\n"); + ADD_NOTE("NOTE: Sometimes you have to append one \r\n more!"); } { CREATE_BINDING("enableSSL", 0); diff --git a/server/src/client/ConnectedClient.cpp b/server/src/client/ConnectedClient.cpp index 2bb0df8..ad82054 100644 --- a/server/src/client/ConnectedClient.cpp +++ b/server/src/client/ConnectedClient.cpp @@ -784,7 +784,7 @@ bool ConnectedClient::handleCommandFull(Command& cmd, bool disconnectOnFail) { system_clock::time_point start, end; start = system_clock::now(); #ifdef PKT_LOG_CMD - logTrace(this->getServerId(), "{}[Command][Client -> Server] Processing command: {}", CLIENT_STR_LOG_PREFIX, cmd.build(false)); + logTrace(this->getServerId() == 0 ? LOG_QUERY : this->getServerId(), "{}[Command][Client -> Server] Processing command: {}", CLIENT_STR_LOG_PREFIX, cmd.build(false)); #endif CommandResult result; diff --git a/server/src/client/query/QueryClient.cpp b/server/src/client/query/QueryClient.cpp index e24e623..eacd78d 100644 --- a/server/src/client/query/QueryClient.cpp +++ b/server/src/client/query/QueryClient.cpp @@ -167,7 +167,7 @@ bool QueryClient::closeConnection(const std::chrono::system_clock::time_point& f this->flushThread = new threads::Thread(THREAD_SAVE_OPERATIONS | THREAD_EXECUTE_LATER, [ownLock, flushTimeout](){ while(ownLock->state == ConnectionState::DISCONNECTING && flushTimeout > system_clock::now()){ { - lock_guard l(ownLock->bufferLock); + std::lock_guard buffer_lock(ownLock->buffer_lock); if(ownLock->readQueue.empty() && ownLock->writeQueue.empty()) break; } usleep(10 * 1000); @@ -192,7 +192,7 @@ void QueryClient::disconnectFinal() { lock_guard lock_tick(this->lock_query_tick); lock_guard lock_handle(this->lock_packet_handle); threads::MutexLock lock_close(this->closeLock); - threads::MutexLock lock_buffer(this->bufferLock); + std::unique_lock buffer_lock(this->buffer_lock, try_to_lock); if(final_disconnected) { logError(LOG_QUERY, "Tried to disconnect a client twice!"); @@ -247,7 +247,7 @@ void QueryClient::disconnectFinal() { void QueryClient::writeRawMessage(const std::string &message) { { - threads::MutexLock lock(this->bufferLock); + std::lock_guard lock(this->buffer_lock); this->writeQueue.push_back(message); } if(this->writeEvent) event_add(this->writeEvent, nullptr); @@ -255,10 +255,12 @@ void QueryClient::writeRawMessage(const std::string &message) { void QueryClient::handleMessageWrite(int fd, short, void *) { auto ownLock = _this.lock(); - threads::MutexTryLock lock(this->bufferLock); + + std::unique_lock buffer_lock(this->buffer_lock, try_to_lock); if(this->state == ConnectionState::DISCONNECTED) return; - if(!lock) { - if(this->writeEvent) event_add(this->writeEvent, nullptr); + if(!buffer_lock.owns_lock()) { + if(this->writeEvent) + event_add(this->writeEvent, nullptr); return; } @@ -314,7 +316,13 @@ void QueryClient::handleMessageRead(int fd, short, void *) { if(length <= 0){ if(errno == EINTR || errno == EAGAIN) ;//event_add(this->readEvent, nullptr); - else { + else if(length == 0 && errno == 0) { + logMessage(LOG_QUERY, "{} Connection closed. Client disconnected.", CLIENT_STR_LOG_PREFIX); + event_del_noblock(this->readEvent); + std::thread([ownLock]{ + ownLock->closeConnection(); + }).detach(); + } else { logError(LOG_QUERY, "{} Failed to read! Code: {} errno: {} message: {}", CLIENT_STR_LOG_PREFIX, length, errno, strerror(errno)); event_del_noblock(this->readEvent); threads::Thread(THREAD_SAVE_OPERATIONS, [ownLock](){ ownLock->closeConnection(); }).detach(); @@ -324,7 +332,7 @@ void QueryClient::handleMessageRead(int fd, short, void *) { buffer.resize(length); { - threads::MutexLock l(this->bufferLock); + std::lock_guard buffer_lock(this->buffer_lock); if(this->state == ConnectionState::DISCONNECTED) return; this->readQueue.push_back(std::move(buffer)); @@ -348,7 +356,7 @@ bool QueryClient::tickIOMessageProgress() { string message; bool next = false; { - threads::MutexLock l(this->bufferLock); + std::lock_guard buffer_lock(this->buffer_lock); if(this->readQueue.empty()) return false; message = std::move(this->readQueue.front()); this->readQueue.pop_front(); @@ -386,7 +394,7 @@ bool QueryClient::tickIOMessageProgress() { } next = true; { - threads::MutexLock l(this->bufferLock); + std::lock_guard buffer_lock(this->buffer_lock); this->readQueue.push_front(std::move(message)); } } @@ -465,18 +473,40 @@ bool QueryClient::handleMessage(const pipes::buffer_view& message) { CMD_RESET_IDLE; //if idle time over 5 min than connection drop return true; } - logTrace(LOG_QUERY, "[{}:{}] Got query command {}", this->getLoggingPeerIp(), this->getPeerPort(), command); + + if((uint8_t) command[0] == 255) { + string commands{}; + + /* we got a telnet command here */ + while(command.size() >= 2 && (uint8_t) command[0] == 255) { + uint8_t code = command[1]; + uint8_t option = command[2]; + + if(!commands.empty()) + commands += ", "; + commands += to_string(code) + ":" + to_string(option); + command = command.substr(3); + } + + logTrace(LOG_QUERY, "[{}:{}] Received telnet command(s): {}. Ignoring it.",this->getLoggingPeerIp(), this->getPeerPort(), commands); + CMD_RESET_IDLE; + if(command.empty()) + return true; + } unique_ptr cmd; try { cmd = make_unique(Command::parse(pipes::buffer_view{(void*) command.data(), command.length()}, true, !ts::config::server::strict_ut8_mode)); } catch(std::invalid_argument& ex) { + logTrace(LOG_QUERY, "[{}:{}] Failed to parse command (invalid argument): {}", this->getLoggingPeerIp(), this->getPeerPort(), command); this->notifyError(CommandResult{findError("parameter_convert"), ex.what()}); return false; } catch(command_malformed_exception& ex) { + logTrace(LOG_QUERY, "[{}:{}] Failed to parse command (malformed command at {}): {}", this->getLoggingPeerIp(), this->getPeerPort(), ex.index(), command); this->notifyError(CommandResult{findError("parameter_convert"), "invalid character @" + to_string(ex.index())}); return false; } catch(std::exception& ex) { + logTrace(LOG_QUERY, "[{}:{}] Failed to parse command (exception: {}): {}", this->getLoggingPeerIp(), this->getPeerPort(), ex.what(), command); this->notifyError(CommandResult{ErrorType::VSError, ex.what()}); return false; } diff --git a/server/src/client/query/QueryClient.h b/server/src/client/query/QueryClient.h index 27bf8bf..947e8b0 100644 --- a/server/src/client/query/QueryClient.h +++ b/server/src/client/query/QueryClient.h @@ -69,7 +69,7 @@ namespace ts { pipes::SSL ssl_handler; - threads::Mutex bufferLock; + std::mutex buffer_lock; std::deque writeQueue; std::deque readQueue;