Repo-Init
Loading...
Searching...
No Matches
TelnetServer Class Reference

#include <TelnetServer.hpp>

Inheritance diagram for TelnetServer:
Collaboration diagram for TelnetServer:

Public Member Functions

 TelnetServer ()=default
 Constructor for server.
 TelnetServer (const TelnetServer &)=delete
 Copy constructor.
 TelnetServer (TelnetServer &&)=delete
 Move constructor.
TelnetServer & operator= (TelnetServer)=delete
 Copy assignment operator.
TelnetServer & operator= (TelnetServer &&)=delete
 Move assignment operator.
 ~TelnetServer ()
 Destructor for server.
bool initialise (unsigned long listenPort, const std::shared_ptr< std::atomic_flag > &checkFlag, std::string promptString="", const std::shared_ptr< prometheus::Registry > &reg=nullptr, const std::string &prependName="")
void shutdown ()
 Closes the Telnet Server.
void connectedCallback (FPTR_ConnectedCallback func)
FPTR_ConnectedCallback connectedCallback () const
void newLineCallback (FPTR_NewLineCallback func)
FPTR_NewLineCallback newLineCallBack () const
void tabCallback (FPTR_TabCallback func)
FPTR_TabCallback tabCallback () const
const VEC_SP_TelnetSession & sessions () const
bool interactivePrompt () const
void promptString (const std::string_view &prompt)
const std::string & promptString () const

Private Member Functions

bool acceptConnection ()
void threadFunc (const std::stop_token &stopToken) noexcept
void update ()
 Process new connections and messages.

Private Attributes

FPTR_ConnectedCallback m_connectedCallback
FPTR_NewLineCallback m_newlineCallback
FPTR_TabCallback m_tabCallback
unsigned long m_listenPort {}
Socket m_listenSocket {-1}
VEC_SP_TelnetSession m_sessions
bool m_initialised {false}
std::string m_promptString
std::unique_ptr< TelnetStats > m_stats
std::shared_ptr< std::atomic_flag > m_checkFlag
std::unique_ptr< std::jthread > m_serverThread

Detailed Description

Definition at line 132 of file TelnetServer.hpp.

Constructor & Destructor Documentation

◆ TelnetServer() [1/3]

TelnetServer::TelnetServer ( )
default

Constructor for server.

Here is the caller graph for this function:

◆ TelnetServer() [2/3]

TelnetServer::TelnetServer ( const TelnetServer & )
delete

Copy constructor.

Here is the call graph for this function:

◆ TelnetServer() [3/3]

TelnetServer::TelnetServer ( TelnetServer && )
delete

Move constructor.

Here is the call graph for this function:

◆ ~TelnetServer()

TelnetServer::~TelnetServer ( )

Destructor for server.

Definition at line 546 of file TelnetServer.cpp.

547{
548 try
549 {
550 shutdown();
551 }
552 catch (const std::exception &e)
553 {
554 try
555 {
556 spdlog::error("Telnet server destructor thrown an exception: {}", e.what());
557 }
558 catch (const std::exception &e2)
559 {
560 (void)std::fprintf(stderr, "Telnet server destructor and also logger thrown an exception: %s %s\n",
561 e.what(), e2.what());
562 }
563 }
564}
void shutdown()
Closes the Telnet Server.
Here is the call graph for this function:

Member Function Documentation

◆ acceptConnection()

bool TelnetServer::acceptConnection ( )
private

Definition at line 636 of file TelnetServer.cpp.

637{
638 const Socket ClientSocket = accept(m_listenSocket, nullptr, nullptr);
639 if (ClientSocket == INVALID_SOCKET)
640 {
641 return false;
642 }
643 if (m_sessions.size() >= MAX_AVAILABLE_SESSION)
644 {
645 // Create for only sending error
646 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
647 session->initialise();
648
649 session->sendLine("Too many active connections. Please try again later. \r\nClosing...");
650 session->closeClient();
651 return false;
652 }
653
654 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
655 m_sessions.push_back(session);
656 session->initialise();
657 return true;
658}
constexpr int MAX_AVAILABLE_SESSION
constexpr int INVALID_SOCKET
int Socket
VEC_SP_TelnetSession m_sessions
Socket m_listenSocket
Here is the caller graph for this function:

◆ connectedCallback() [1/2]

FPTR_ConnectedCallback TelnetServer::connectedCallback ( ) const
inline

Definition at line 169 of file TelnetServer.hpp.

169{ return m_connectedCallback; }
FPTR_ConnectedCallback m_connectedCallback

◆ connectedCallback() [2/2]

void TelnetServer::connectedCallback ( FPTR_ConnectedCallback func)
inline

Definition at line 168 of file TelnetServer.hpp.

168{ m_connectedCallback = std::move(func); }

◆ initialise()

bool TelnetServer::initialise ( unsigned long listenPort,
const std::shared_ptr< std::atomic_flag > & checkFlag,
std::string promptString = "",
const std::shared_ptr< prometheus::Registry > & reg = nullptr,
const std::string & prependName = "" )

Initializes a new Telnet server

Parameters
[in]listenPortPort to listen
[in]promptStringPrompt string for connected users
[in]regPrometheus registry for stats
[in]prependNamePrefix for Prometheus stats
Returns
true If initialized
false otherwise

Definition at line 566 of file TelnetServer.cpp.

569{
570 if (m_initialised)
571 {
572 return false;
573 }
574
575 m_checkFlag = checkFlag;
576 m_listenPort = listenPort;
577 m_promptString = std::move(promptString);
578
579 addrinfo hints{};
580 memset(&hints, 0, sizeof(hints));
581
582 hints.ai_family = AF_INET;
583 hints.ai_socktype = SOCK_STREAM;
584 hints.ai_protocol = IPPROTO_TCP;
585 hints.ai_flags = AI_PASSIVE;
586
587 // Resolve the server address and port
588 addrinfo *result = nullptr;
589 if (getaddrinfo(nullptr, std::to_string(m_listenPort).c_str(), &hints, &result) != 0)
590 {
591 return false;
592 }
593
594 // Create a SOCKET for connecting to server
595 m_listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
597 {
598 freeaddrinfo(result);
599 return false;
600 }
601
602 if (int optionVal = 1; setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &optionVal, sizeof(optionVal)) < 0)
603 {
604 freeaddrinfo(result);
605 close(m_listenSocket);
606 return false;
607 }
608
609 // Setup the TCP listening socket
610 if (bind(m_listenSocket, result->ai_addr, result->ai_addrlen) < 0)
611 {
612 freeaddrinfo(result);
613 close(m_listenSocket);
614 return false;
615 }
616 freeaddrinfo(result);
617
618 if (listen(m_listenSocket, SOMAXCONN) < 0)
619 {
620 close(m_listenSocket);
621 return false;
622 }
623
624 // If prometheus registry is provided prepare statistics
625 if (reg)
626 {
627 m_stats = std::make_unique<TelnetStats>(reg, listenPort, prependName);
628 }
629
630 m_serverThread = std::make_unique<std::jthread>([this](const std::stop_token &sToken) { threadFunc(sToken); });
631
632 m_initialised = true;
633 return true;
634}
void promptString(const std::string_view &prompt)
std::unique_ptr< TelnetStats > m_stats
unsigned long m_listenPort
std::string m_promptString
void threadFunc(const std::stop_token &stopToken) noexcept
std::shared_ptr< std::atomic_flag > m_checkFlag
std::unique_ptr< std::jthread > m_serverThread
Here is the call graph for this function:

◆ interactivePrompt()

bool TelnetServer::interactivePrompt ( ) const
inline

Definition at line 179 of file TelnetServer.hpp.

179{ return !m_promptString.empty(); }

◆ newLineCallBack()

FPTR_NewLineCallback TelnetServer::newLineCallBack ( ) const
inline

Definition at line 172 of file TelnetServer.hpp.

172{ return m_newlineCallback; }
FPTR_NewLineCallback m_newlineCallback

◆ newLineCallback()

void TelnetServer::newLineCallback ( FPTR_NewLineCallback func)
inline

Definition at line 171 of file TelnetServer.hpp.

171{ m_newlineCallback = std::move(func); }

◆ operator=() [1/2]

TelnetServer & TelnetServer::operator= ( TelnetServer && )
delete

Move assignment operator.

Here is the call graph for this function:

◆ operator=() [2/2]

TelnetServer & TelnetServer::operator= ( TelnetServer )
delete

Copy assignment operator.

Here is the call graph for this function:

◆ promptString() [1/2]

const std::string & TelnetServer::promptString ( ) const
inline

Definition at line 181 of file TelnetServer.hpp.

181{ return m_promptString; }

◆ promptString() [2/2]

void TelnetServer::promptString ( const std::string_view & prompt)
inline

Definition at line 180 of file TelnetServer.hpp.

180{ m_promptString = prompt; }
Here is the caller graph for this function:

◆ sessions()

const VEC_SP_TelnetSession & TelnetServer::sessions ( ) const
inline

Definition at line 177 of file TelnetServer.hpp.

177{ return m_sessions; }

◆ shutdown()

void TelnetServer::shutdown ( )

Closes the Telnet Server.

Definition at line 747 of file TelnetServer.cpp.

748{
749 // Attempt to cleanly close every telnet session in flight.
750 for (const SP_TelnetSession &tSession : m_sessions)
751 {
752 tSession->closeClient();
753 }
754 m_sessions.clear();
755
756 // No longer need server socket so close it.
757 close(m_listenSocket);
759 m_initialised = false;
760
761 if (m_serverThread)
762 {
763 m_serverThread.reset();
764 }
765}
std::shared_ptr< TelnetSession > SP_TelnetSession
Here is the caller graph for this function:

◆ tabCallback() [1/2]

FPTR_TabCallback TelnetServer::tabCallback ( ) const
inline

Definition at line 175 of file TelnetServer.hpp.

175{ return m_tabCallback; }
FPTR_TabCallback m_tabCallback

◆ tabCallback() [2/2]

void TelnetServer::tabCallback ( FPTR_TabCallback func)
inline

Definition at line 174 of file TelnetServer.hpp.

174{ m_tabCallback = std::move(func); }

◆ threadFunc()

void TelnetServer::threadFunc ( const std::stop_token & stopToken)
privatenoexcept

Definition at line 660 of file TelnetServer.cpp.

661{
662 spdlog::info("Telnet server started");
663 while (!stopToken.stop_requested())
664 {
665 try
666 {
667 update();
668 if (m_checkFlag)
669 {
670 m_checkFlag->test_and_set();
671 }
672 }
673 catch (const std::exception &e)
674 {
675 spdlog::error("Telnet server failed: {}", e.what());
676 }
677 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_INTERVAL_MS));
678 }
679 spdlog::info("Telnet server stopped");
680}
constexpr int SLEEP_INTERVAL_MS
void update()
Process new connections and messages.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ update()

void TelnetServer::update ( )
private

Process new connections and messages.

Definition at line 682 of file TelnetServer.cpp.

683{
684 // See if connection pending on the listening socket
685 fd_set readSet;
686 FD_ZERO(&readSet);
687 FD_SET(m_listenSocket, &readSet);
688 timeval timeout{};
689 timeout.tv_sec = 0; // Zero timeout (poll)
690 timeout.tv_usec = 0;
691
692 bool newConnectionAccept = false;
693 bool newConnectionRefused = false;
694
695 TelnetServerStats serverStats;
696 serverStats.processingTimeStart = std::chrono::high_resolution_clock::now();
697
698 // If there is a connection pending, accept it.
699 if (select(m_listenSocket + 1, &readSet, nullptr, nullptr, &timeout) > 0)
700 {
701 if (acceptConnection())
702 {
703 newConnectionAccept = true;
704 }
705 else
706 {
707 newConnectionRefused = true;
708 }
709 }
710
711 // Update all the telnet Sessions that are currently in flight.
712 for (size_t idx = 0; idx < m_sessions.size(); ++idx)
713 {
714 // Update session
715 m_sessions[idx]->update();
716
717 // Close session if needed
718 if (m_sessions[idx]->checkTimeout())
719 {
720 m_sessions[idx]->closeClient();
721 if (m_stats)
722 {
723 m_stats->consumeStats(m_sessions[idx]->stats, true);
724 }
725 m_sessions.erase(m_sessions.begin() + static_cast<int>(idx));
726 --idx;
727 }
728 else
729 {
730 if (m_stats)
731 {
732 m_stats->consumeStats(m_sessions[idx]->stats, false);
733 }
734 }
735 }
736
737 serverStats.activeConnectionCtr = m_sessions.size();
738 serverStats.acceptedConnectionCtr = static_cast<uint64_t>(newConnectionAccept);
739 serverStats.refusedConnectionCtr = static_cast<uint64_t>(newConnectionRefused);
740 serverStats.processingTimeEnd = std::chrono::high_resolution_clock::now();
741 if (m_stats)
742 {
743 m_stats->consumeStats(serverStats);
744 }
745}
bool acceptConnection()
std::chrono::high_resolution_clock::time_point processingTimeStart
Processing time start.
uint64_t activeConnectionCtr
Number of active connections.
std::chrono::high_resolution_clock::time_point processingTimeEnd
Processing time end.
uint64_t refusedConnectionCtr
Number of refused connections.
uint64_t acceptedConnectionCtr
Number of accepted connections.
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_checkFlag

std::shared_ptr<std::atomic_flag> TelnetServer::m_checkFlag
private

Runtime check flag

Definition at line 207 of file TelnetServer.hpp.

◆ m_connectedCallback

FPTR_ConnectedCallback TelnetServer::m_connectedCallback
private

Definition at line 185 of file TelnetServer.hpp.

◆ m_initialised

bool TelnetServer::m_initialised {false}
private

Definition at line 200 of file TelnetServer.hpp.

200{false};

◆ m_listenPort

unsigned long TelnetServer::m_listenPort {}
private

Definition at line 197 of file TelnetServer.hpp.

197{};

◆ m_listenSocket

Socket TelnetServer::m_listenSocket {-1}
private

Definition at line 198 of file TelnetServer.hpp.

198{-1};

◆ m_newlineCallback

FPTR_NewLineCallback TelnetServer::m_newlineCallback
private

Definition at line 187 of file TelnetServer.hpp.

◆ m_promptString

std::string TelnetServer::m_promptString
private

Definition at line 202 of file TelnetServer.hpp.

◆ m_serverThread

std::unique_ptr<std::jthread> TelnetServer::m_serverThread
private

Thread handler

Definition at line 208 of file TelnetServer.hpp.

◆ m_sessions

VEC_SP_TelnetSession TelnetServer::m_sessions
private

Definition at line 199 of file TelnetServer.hpp.

◆ m_stats

std::unique_ptr<TelnetStats> TelnetServer::m_stats
private

Definition at line 205 of file TelnetServer.hpp.

◆ m_tabCallback

FPTR_TabCallback TelnetServer::m_tabCallback
private

Definition at line 189 of file TelnetServer.hpp.


The documentation for this class was generated from the following files: