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.
 
TelnetServeroperator= (TelnetServer)=delete
 Copy assignment operator.
 
TelnetServeroperator= (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_TelnetSessionsessions () 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< TelnetStatsm_stats
 
std::shared_ptr< std::atomic_flag > m_checkFlag
 
std::unique_ptr< std::jthread > m_serverThread
 

Detailed Description

Definition at line 130 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 533 of file TelnetServer.cpp.

534{
535 try
536 {
537 shutdown();
538 }
539 catch (const std::exception &e)
540 {
541 try
542 {
543 spdlog::error("Telnet server destructor thrown an exception: {}", e.what());
544 }
545 catch (const std::exception &e2)
546 {
547 std::cerr << "Telnet server destructor and also logger thrown an exception: " << e.what() << '\n'
548 << e2.what() << '\n';
549 }
550 }
551}
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 623 of file TelnetServer.cpp.

624{
625 const Socket ClientSocket = accept(m_listenSocket, nullptr, nullptr);
626 if (ClientSocket == INVALID_SOCKET)
627 {
628 return false;
629 }
630 if (m_sessions.size() >= MAX_AVAILABLE_SESSION)
631 {
632 // Create for only sending error
633 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
634 session->initialise();
635
636 session->sendLine("Too many active connections. Please try again later. \r\nClosing...");
637 session->closeClient();
638 return false;
639 }
640
641 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
642 m_sessions.push_back(session);
643 session->initialise();
644 return true;
645}
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 167 of file TelnetServer.hpp.

167{ return m_connectedCallback; }
FPTR_ConnectedCallback m_connectedCallback

◆ connectedCallback() [2/2]

void TelnetServer::connectedCallback ( FPTR_ConnectedCallback func)
inline

Definition at line 166 of file TelnetServer.hpp.

166{ 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 553 of file TelnetServer.cpp.

556{
557 if (m_initialised)
558 {
559 return false;
560 }
561
562 m_checkFlag = checkFlag;
563 m_listenPort = listenPort;
564 m_promptString = std::move(promptString);
565
566 addrinfo hints{};
567 memset(&hints, 0, sizeof(hints));
568
569 hints.ai_family = AF_INET;
570 hints.ai_socktype = SOCK_STREAM;
571 hints.ai_protocol = IPPROTO_TCP;
572 hints.ai_flags = AI_PASSIVE;
573
574 // Resolve the server address and port
575 addrinfo *result = nullptr;
576 if (getaddrinfo(nullptr, std::to_string(m_listenPort).c_str(), &hints, &result) != 0)
577 {
578 return false;
579 }
580
581 // Create a SOCKET for connecting to server
582 m_listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
584 {
585 freeaddrinfo(result);
586 return false;
587 }
588
589 if (int optionVal = 1; setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &optionVal, sizeof(optionVal)) < 0)
590 {
591 freeaddrinfo(result);
592 close(m_listenSocket);
593 return false;
594 }
595
596 // Setup the TCP listening socket
597 if (bind(m_listenSocket, result->ai_addr, result->ai_addrlen) < 0)
598 {
599 freeaddrinfo(result);
600 close(m_listenSocket);
601 return false;
602 }
603 freeaddrinfo(result);
604
605 if (listen(m_listenSocket, SOMAXCONN) < 0)
606 {
607 close(m_listenSocket);
608 return false;
609 }
610
611 // If prometheus registry is provided prepare statistics
612 if (reg)
613 {
614 m_stats = std::make_unique<TelnetStats>(reg, listenPort, prependName);
615 }
616
617 m_serverThread = std::make_unique<std::jthread>([this](const std::stop_token &sToken) { threadFunc(sToken); });
618
619 m_initialised = true;
620 return true;
621}
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 177 of file TelnetServer.hpp.

177{ return !m_promptString.empty(); }

◆ newLineCallBack()

FPTR_NewLineCallback TelnetServer::newLineCallBack ( ) const
inline

Definition at line 170 of file TelnetServer.hpp.

170{ return m_newlineCallback; }
FPTR_NewLineCallback m_newlineCallback

◆ newLineCallback()

void TelnetServer::newLineCallback ( FPTR_NewLineCallback func)
inline

Definition at line 169 of file TelnetServer.hpp.

169{ 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 179 of file TelnetServer.hpp.

179{ return m_promptString; }

◆ promptString() [2/2]

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

Definition at line 178 of file TelnetServer.hpp.

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

◆ sessions()

const VEC_SP_TelnetSession & TelnetServer::sessions ( ) const
inline

Definition at line 175 of file TelnetServer.hpp.

175{ return m_sessions; }

◆ shutdown()

void TelnetServer::shutdown ( )

Closes the Telnet Server.

Definition at line 734 of file TelnetServer.cpp.

735{
736 // Attempt to cleanly close every telnet session in flight.
737 for (const SP_TelnetSession &tSession : m_sessions)
738 {
739 tSession->closeClient();
740 }
741 m_sessions.clear();
742
743 // No longer need server socket so close it.
744 close(m_listenSocket);
746 m_initialised = false;
747
748 if (m_serverThread)
749 {
750 m_serverThread.reset();
751 }
752}
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 173 of file TelnetServer.hpp.

173{ return m_tabCallback; }
FPTR_TabCallback m_tabCallback

◆ tabCallback() [2/2]

void TelnetServer::tabCallback ( FPTR_TabCallback func)
inline

Definition at line 172 of file TelnetServer.hpp.

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

◆ threadFunc()

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

Definition at line 647 of file TelnetServer.cpp.

648{
649 spdlog::info("Telnet server started");
650 while (!stopToken.stop_requested())
651 {
652 try
653 {
654 update();
655 if (m_checkFlag)
656 {
657 m_checkFlag->test_and_set();
658 }
659 }
660 catch (const std::exception &e)
661 {
662 spdlog::error("Telnet server failed: {}", e.what());
663 }
664 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_INTERVAL_MS));
665 }
666 spdlog::info("Telnet server stopped");
667}
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 669 of file TelnetServer.cpp.

670{
671 // See if connection pending on the listening socket
672 fd_set readSet;
673 FD_ZERO(&readSet);
674 FD_SET(m_listenSocket, &readSet);
675 timeval timeout{};
676 timeout.tv_sec = 0; // Zero timeout (poll)
677 timeout.tv_usec = 0;
678
679 bool newConnectionAccept = false;
680 bool newConnectionRefused = false;
681
682 TelnetServerStats serverStats;
683 serverStats.processingTimeStart = std::chrono::high_resolution_clock::now();
684
685 // If there is a connection pending, accept it.
686 if (select(m_listenSocket + 1, &readSet, nullptr, nullptr, &timeout) > 0)
687 {
688 if (acceptConnection())
689 {
690 newConnectionAccept = true;
691 }
692 else
693 {
694 newConnectionRefused = true;
695 }
696 }
697
698 // Update all the telnet Sessions that are currently in flight.
699 for (size_t idx = 0; idx < m_sessions.size(); ++idx)
700 {
701 // Update session
702 m_sessions[idx]->update();
703
704 // Close session if needed
705 if (m_sessions[idx]->checkTimeout())
706 {
707 m_sessions[idx]->closeClient();
708 if (m_stats)
709 {
710 m_stats->consumeStats(m_sessions[idx]->stats, true);
711 }
712 m_sessions.erase(m_sessions.begin() + static_cast<int>(idx));
713 --idx;
714 }
715 else
716 {
717 if (m_stats)
718 {
719 m_stats->consumeStats(m_sessions[idx]->stats, false);
720 }
721 }
722 }
723
724 serverStats.activeConnectionCtr = m_sessions.size();
725 serverStats.acceptedConnectionCtr = static_cast<uint64_t>(newConnectionAccept);
726 serverStats.refusedConnectionCtr = static_cast<uint64_t>(newConnectionRefused);
727 serverStats.processingTimeEnd = std::chrono::high_resolution_clock::now();
728 if (m_stats)
729 {
730 m_stats->consumeStats(serverStats);
731 }
732}
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 205 of file TelnetServer.hpp.

◆ m_connectedCallback

FPTR_ConnectedCallback TelnetServer::m_connectedCallback
private

Definition at line 183 of file TelnetServer.hpp.

◆ m_initialised

bool TelnetServer::m_initialised {false}
private

Definition at line 198 of file TelnetServer.hpp.

198{false};

◆ m_listenPort

unsigned long TelnetServer::m_listenPort {}
private

Definition at line 195 of file TelnetServer.hpp.

195{};

◆ m_listenSocket

Socket TelnetServer::m_listenSocket {-1}
private

Definition at line 196 of file TelnetServer.hpp.

196{-1};

◆ m_newlineCallback

FPTR_NewLineCallback TelnetServer::m_newlineCallback
private

Definition at line 185 of file TelnetServer.hpp.

◆ m_promptString

std::string TelnetServer::m_promptString
private

Definition at line 200 of file TelnetServer.hpp.

◆ m_serverThread

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

Thread handler

Definition at line 206 of file TelnetServer.hpp.

◆ m_sessions

VEC_SP_TelnetSession TelnetServer::m_sessions
private

Definition at line 197 of file TelnetServer.hpp.

◆ m_stats

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

Definition at line 203 of file TelnetServer.hpp.

◆ m_tabCallback

FPTR_TabCallback TelnetServer::m_tabCallback
private

Definition at line 187 of file TelnetServer.hpp.


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