SNode.C
Loading...
Searching...
No Matches
SocketConnection.cpp
Go to the documentation of this file.
1/*
2 * SNode.C - A Slim Toolkit for Network Communication
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2020, 2021, 2022, 2023, 2024, 2025
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * MIT License
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42#include "core/socket/stream/SocketConnection.h"
43
44#include "core/socket/stream/SocketContext.h"
45#include "core/socket/stream/SocketContextFactory.h"
46#include "net/config/ConfigInstance.h"
47
48#ifndef DOXYGEN_SHOULD_SKIP_THIS
49
50#include "log/Logger.h"
51
52#include <ctime>
53#include <iomanip>
54#include <sstream>
55#include <vector>
56struct tm;
57
58#endif // DOXYGEN_SHOULD_SKIP_THIS
59
60namespace core::socket::stream {
61
62 SocketConnection::SocketConnection(int fd, const net::config::ConfigInstance* config)
64 , connectionName("[" + std::to_string(fd) + "]" + (!instanceName.empty() ? " " : "") + instanceName)
65 , onlineSinceTimePoint(std::chrono::system_clock::now())
66 , config(config) {
67 }
68
70 }
71
73 if (socketContext != nullptr) { // Perform a pending SocketContextSwitch
74 this->socketContext = socketContext;
75
76 LOG(DEBUG) << connectionName << ": SocketContext switch completed";
77
78 socketContext->attach();
79 } else {
80 LOG(ERROR) << connectionName << ": SocketContext switch failed: no new SocketContext";
81 }
82 }
83
84 void SocketConnection::sendToPeer(const std::string& data) {
85 sendToPeer(data.data(), data.size());
86 }
87
88 void SocketConnection::sentToPeer(const std::vector<uint8_t>& data) {
89 sendToPeer(reinterpret_cast<const char*>(data.data()), data.size());
90 }
91
92 void SocketConnection::sentToPeer(const std::vector<char>& data) {
93 sendToPeer(data.data(), data.size());
94 }
95
96 const std::string& SocketConnection::getInstanceName() const {
97 return instanceName;
98 }
99
100 const std::string& SocketConnection::getConnectionName() const {
101 return connectionName;
102 }
103
105 return socketContext;
106 }
107
108 std::string SocketConnection::getOnlineSince() const {
110 }
111
112 std::string SocketConnection::getOnlineDuration() const {
114 }
115
116 const net::config::ConfigInstance* SocketConnection::getConfig() const {
117 return config;
118 }
119
120 void SocketConnection::connectSocketContext(const std::shared_ptr<SocketContextFactory>& socketContextFactory) {
121 SocketContext* socketContext = socketContextFactory->create(this);
122
123 if (socketContext != nullptr) {
124 LOG(DEBUG) << connectionName << ": SocketContext created successful";
125 setSocketContext(socketContext);
126 } else {
127 LOG(ERROR) << connectionName << ": SocketContext failed to create";
128 close();
129 }
130 }
131
132 std::string SocketConnection::timePointToString(const std::chrono::time_point<std::chrono::system_clock>& timePoint) {
133 const std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
134 std::tm* tm_ptr = std::gmtime(&time);
135
136 char buffer[100];
137 std::string onlineSince = "Formatting error";
138
139 // Format: "2025-02-02 14:30:00"
140 if (std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_ptr) > 0) {
141 onlineSince = std::string(buffer) + " UTC";
142 }
143
144 return onlineSince;
145 }
146
147 std::string SocketConnection::durationToString(const std::chrono::time_point<std::chrono::system_clock>& bevore,
148 const std::chrono::time_point<std::chrono::system_clock>& later) {
149 using seconds_duration_type = std::chrono::duration<std::chrono::seconds::rep>::rep;
150
151 const seconds_duration_type totalSeconds = std::chrono::duration_cast<std::chrono::seconds>(later - bevore).count();
152
153 // Compute days, hours, minutes, and seconds
154 const seconds_duration_type days = totalSeconds / 86400; // 86400 seconds in a day
155 seconds_duration_type remainder = totalSeconds % 86400;
156 const seconds_duration_type hours = remainder / 3600;
157 remainder = remainder % 3600;
158 const seconds_duration_type minutes = remainder / 60;
159 const seconds_duration_type seconds = remainder % 60;
160
161 // Format the components into a string using stringstream
162 std::ostringstream oss;
163 if (days > 0) {
164 oss << days << " day" << (days == 1 ? "" : "s") << ", ";
165 }
166 oss << std::setw(2) << std::setfill('0') << hours << ":" << std::setw(2) << std::setfill('0') << minutes << ":" << std::setw(2)
167 << std::setfill('0') << seconds;
168
169 return oss.str();
170 }
171
172} // namespace core::socket::stream
virtual void sendToPeer(const char *chunk, std::size_t chunkLen)=0
SocketConnection(int fd, const net::config::ConfigInstance *config)
core::socket::stream::SocketContext * socketContext
void connectSocketContext(const std::shared_ptr< SocketContextFactory > &socketContextFactory)
static std::string timePointToString(const std::chrono::time_point< std::chrono::system_clock > &timePoint)
void sentToPeer(const std::vector< char > &data)
void sentToPeer(const std::vector< uint8_t > &data)
static std::string durationToString(const std::chrono::time_point< std::chrono::system_clock > &bevore, const std::chrono::time_point< std::chrono::system_clock > &later=std::chrono::system_clock::now())
const std::string & getConnectionName() const
void setSocketContext(SocketContext *socketContext)
void sendToPeer(const std::string &data)
std::chrono::time_point< std::chrono::system_clock > onlineSinceTimePoint
const net::config::ConfigInstance * getConfig() const
const std::string & getInstanceName() const
virtual core::socket::stream::SocketContext * create(core::socket::stream::SocketConnection *socketConnection)=0
const std::string & getInstanceName() const