@@ -42,6 +42,8 @@ class socket_init {
4242};
4343#endif
4444
45+ enum class log_server_status { LOG_SERVER_AWAITING_STARTUP, LOG_SERVER_RUNNING, LOG_SERVER_FINISHED };
46+
4547int main (int argc, char **argv) {
4648#ifdef _WIN32
4749 socket_init ws_init{};
@@ -96,10 +98,8 @@ void set_socket_recv_timeout(log4cpp::common::socket_fd sockfd) {
9698#endif
9799}
98100
99- void tcp_log_server_loop (std::atomic<bool > &srv_running, log4cpp::common::prefer_stack prefer, unsigned short port,
100- unsigned int expected_log_count) {
101- std::string prefer_str;
102- log4cpp::common::to_string (prefer, prefer_str);
101+ void tcp_log_server_loop (std::atomic<log_server_status> &status, log4cpp::common::prefer_stack prefer,
102+ unsigned short port, unsigned int expected_log_count) {
103103 log4cpp::common::socket_fd server_fd =
104104 socket (prefer == log4cpp::common::prefer_stack::IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
105105 if (log4cpp::common::INVALID_FD == server_fd) {
@@ -108,25 +108,40 @@ void tcp_log_server_loop(std::atomic<bool> &srv_running, log4cpp::common::prefer
108108 }
109109
110110 sockaddr_storage local_addr{};
111+ socklen_t addr_len = 0 ;
112+ #ifdef _DEBUG
113+ char addr_str[INET6_ADDRSTRLEN];
114+ #endif
111115 if (prefer == log4cpp::common::prefer_stack::IPv6) {
112116 // NOLINTNEXTLINE
113117 sockaddr_in6 &local_addr6 = reinterpret_cast <sockaddr_in6 &>(local_addr);
114118 local_addr6.sin6_family = AF_INET6;
115119 local_addr6.sin6_addr = in6addr_any;
116120 local_addr6.sin6_port = htons (port);
121+ addr_len = sizeof (sockaddr_in6);
122+ #ifdef _DEBUG
123+ inet_ntop (AF_INET6, &local_addr6.sin6_addr , addr_str, sizeof (addr_str));
124+ #endif
117125 }
118126 else {
119127 // NOLINTNEXTLINE
120128 sockaddr_in &local_addr4 = reinterpret_cast <sockaddr_in &>(local_addr);
121129 local_addr4.sin_family = AF_INET;
122130 local_addr4.sin_addr .s_addr = INADDR_ANY;
123131 local_addr4.sin_port = htons (port);
132+ addr_len = sizeof (sockaddr_in);
133+ #ifdef _DEBUG
134+ inet_ntop (AF_INET, &local_addr4.sin_addr , addr_str, sizeof (addr_str));
135+ #endif
124136 }
125137
138+ #ifdef _DEBUG
139+ log4cpp::common::log4c_debug (stdout, " [tcp_socket_appender_test] bind %s@%u\n " , addr_str, port);
140+ #endif
141+
126142 set_reuse_addr_port (server_fd);
127143
128- int val = bind (server_fd, reinterpret_cast <sockaddr *>(&local_addr),
129- prefer == log4cpp::common::prefer_stack::IPv6 ? sizeof (sockaddr_in6) : sizeof (sockaddr_in));
144+ int val = bind (server_fd, reinterpret_cast <sockaddr *>(&local_addr), addr_len);
130145 if (-1 == val) {
131146#ifdef _WIN32
132147 int wsa_error = WSAGetLastError ();
@@ -154,13 +169,6 @@ void tcp_log_server_loop(std::atomic<bool> &srv_running, log4cpp::common::prefer
154169 }
155170
156171 sockaddr_storage remote_addr{};
157- socklen_t addr_len = 0 ;
158- if (prefer == log4cpp::common::prefer_stack::IPv6) {
159- addr_len = sizeof (sockaddr_in6);
160- }
161- else {
162- addr_len = sizeof (sockaddr_in);
163- }
164172 log4cpp::common::socket_fd client_fd = accept (server_fd, reinterpret_cast <sockaddr *>(&remote_addr), &addr_len);
165173 if (log4cpp::common::INVALID_FD == client_fd) {
166174#ifdef _WIN32
@@ -175,36 +183,90 @@ void tcp_log_server_loop(std::atomic<bool> &srv_running, log4cpp::common::prefer
175183 return ;
176184 }
177185 char buffer[1024 ];
186+ std::string pending;
178187 unsigned int actual_log_count = 0 ;
179188 set_socket_recv_timeout (client_fd);
180- srv_running .store (true );
181- while (srv_running. load () ) {
189+ status .store (log_server_status::LOG_SERVER_RUNNING );
190+ for (actual_log_count = 0 ; actual_log_count < expected_log_count; ) {
182191 ssize_t len = recv (client_fd, buffer, sizeof (buffer) - 1 , 0 );
183192 if (len > 0 ) {
184193 buffer[len] = 0 ;
185- ++actual_log_count;
186- printf (" [tcp_socket_appender_test] [%u]: %s" , actual_log_count, buffer);
194+ pending.append (buffer, static_cast <size_t >(len));
195+
196+ size_t pos = 0 ;
197+ while (true ) {
198+ size_t nl = pending.find (' \n ' , pos);
199+ if (nl == std::string::npos) break ;
200+
201+ std::string line = pending.substr (pos, nl - pos);
202+ if (!line.empty () && line.back () == ' \r ' ) line.pop_back ();
203+
204+ ++actual_log_count;
205+ printf (" [tcp_socket_appender_test] [%u]: %s\n " , actual_log_count, line.c_str ());
206+
207+ pos = nl + 1 ;
208+ }
209+ pending.erase (0 , pos);
187210 }
188211 else if (len == -1 ) {
189212 if (errno != EINTR) {
213+ #ifdef _DEBUG
214+ log4cpp::common::log4c_debug (stderr, " [tcp_socket_appender_test] interrupted" );
215+ #endif
190216 break ;
191217 }
192218 }
193219 else {
194220 // Connection closed by peer
221+ #ifdef _DEBUG
222+ log4cpp::common::log4c_debug (stderr, " [tcp_socket_appender_test] recv failed! errno:%d,%s\n " , errno,
223+ strerror (errno));
224+ #endif
195225 break ;
196226 }
197227 }
228+ status.store (log_server_status::LOG_SERVER_FINISHED);
198229 log4cpp::common::shutdown_socket (client_fd);
199230 log4cpp::common::close_socket (client_fd);
200231 log4cpp::common::close_socket (server_fd);
201- ASSERT_GE (expected_log_count, actual_log_count);
202- ASSERT_GT (actual_log_count, 0U );
232+ ASSERT_EQ (expected_log_count, actual_log_count);
203233 fflush (stdout);
204234}
205235
206- void udp_log_server_loop (std::atomic<bool > &srv_running, log4cpp::common::prefer_stack prefer, unsigned short port,
207- unsigned int expected_log_count) {
236+ TEST (socket_appender_test, tcp_socket_appender_test) {
237+ const std::string config_file = " tcp_socket_appender_test.json" ;
238+ auto &log_mgr = log4cpp::supervisor::get_logger_manager ();
239+ ASSERT_NO_THROW (log_mgr.load_config (config_file));
240+ const log4cpp::config::log4cpp *config = log_mgr.get_config ();
241+ const log4cpp::config::socket_appender &socker_appender_cfg = config->appenders .socket .value ();
242+ unsigned short port = socker_appender_cfg.port ;
243+ log4cpp::common::prefer_stack prefer = socker_appender_cfg.prefer ;
244+
245+ std::atomic status (log_server_status::LOG_SERVER_AWAITING_STARTUP);
246+
247+ const std::shared_ptr<log4cpp::log::logger> log = log4cpp::logger_manager::get_logger ();
248+ log4cpp::log_level max_level = log->get_level ();
249+ unsigned int expected_log_count = static_cast <int >(max_level) + 1 ; // enum is zero-indexed
250+
251+ std::thread log_server_thread =
252+ std::thread (&tcp_log_server_loop, std::ref (status), prefer, port, expected_log_count);
253+
254+ while (log_server_status::LOG_SERVER_RUNNING != status.load ()) {
255+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
256+ }
257+
258+ log->trace (" this is a trace" );
259+ log->debug (" this is a debug" );
260+ log->info (" this is a info" );
261+ log->warn (" this is an warning" );
262+ log->error (" this is an error" );
263+ log->fatal (" this is a fatal" );
264+
265+ log_server_thread.join ();
266+ }
267+
268+ void udp_log_server_loop (std::atomic<log_server_status> &status, log4cpp::common::prefer_stack prefer,
269+ unsigned short port, unsigned int expected_log_count) {
208270 log4cpp::common::socket_fd server_fd =
209271 socket (prefer == log4cpp::common::prefer_stack::IPv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
210272 if (log4cpp::common::INVALID_FD == server_fd) {
@@ -266,8 +328,8 @@ void udp_log_server_loop(std::atomic<bool> &srv_running, log4cpp::common::prefer
266328 unsigned int actual_log_count = 0 ;
267329 sockaddr_storage remote_addr{};
268330 socklen_t remote_addr_len = sizeof (remote_addr);
269- srv_running .store (true );
270- while (srv_running. load () ) {
331+ status .store (log_server_status::LOG_SERVER_RUNNING );
332+ for (actual_log_count = 0 ; actual_log_count < expected_log_count; ) {
271333 ssize_t len = recvfrom (server_fd, buffer, sizeof (buffer) - 1 , 0 ,
272334 reinterpret_cast <struct sockaddr *>(&remote_addr), &remote_addr_len);
273335 if (len > 0 ) {
@@ -283,48 +345,13 @@ void udp_log_server_loop(std::atomic<bool> &srv_running, log4cpp::common::prefer
283345 // Since UDP is connectionless, a recvfrom return value of 0 signifies the successful receipt of a zero-length
284346 // datagram, and the program should continue its loop
285347 }
348+ status.store (log_server_status::LOG_SERVER_FINISHED);
286349 log4cpp::common::shutdown_socket (server_fd);
287350 log4cpp::common::close_socket (server_fd);
288- ASSERT_GE (expected_log_count, actual_log_count);
289- ASSERT_GT (actual_log_count, 0U );
351+ ASSERT_EQ (expected_log_count, actual_log_count);
290352 fflush (stdout);
291353}
292354
293- TEST (socket_appender_test, tcp_socket_appender_test) {
294- const std::string config_file = " tcp_socket_appender_test.json" ;
295- auto &log_mgr = log4cpp::supervisor::get_logger_manager ();
296- ASSERT_NO_THROW (log_mgr.load_config (config_file));
297- const log4cpp::config::log4cpp *config = log_mgr.get_config ();
298- const log4cpp::config::socket_appender &socker_appender_cfg = config->appenders .socket .value ();
299- unsigned short port = socker_appender_cfg.port ;
300- log4cpp::common::prefer_stack prefer = socker_appender_cfg.prefer ;
301-
302- std::atomic<bool > running (false );
303-
304- const std::shared_ptr<log4cpp::log::logger> log = log4cpp::logger_manager::get_logger ();
305- log4cpp::log_level max_level = log->get_level ();
306- unsigned int expected_log_count = static_cast <int >(max_level) + 1 ; // enum is zero-indexed
307-
308- std::thread log_server_thread =
309- std::thread (&tcp_log_server_loop, std::ref (running), prefer, port, expected_log_count);
310-
311- while (!running.load ()) {
312- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
313- }
314-
315- log->trace (" this is a trace" );
316- log->debug (" this is a debug" );
317- log->info (" this is a info" );
318- log->warn (" this is an warning" );
319- log->error (" this is an error" );
320- log->fatal (" this is a fatal" );
321-
322- std::this_thread::sleep_for (std::chrono::seconds (1 ));
323-
324- running.store (false );
325- log_server_thread.join ();
326- }
327-
328355TEST (socket_appender_test, udp_socket_appender_test) {
329356 const std::string config_file = " udp_socket_appender_test.json" ;
330357 auto &log_mgr = log4cpp::supervisor::get_logger_manager ();
@@ -334,14 +361,14 @@ TEST(socket_appender_test, udp_socket_appender_test) {
334361 unsigned short port = socker_appender_cfg.port ;
335362 log4cpp::common::prefer_stack prefer = socker_appender_cfg.prefer ;
336363
337- std::atomic< bool > running ( false );
364+ std::atomic status (log_server_status::LOG_SERVER_AWAITING_STARTUP );
338365 const std::shared_ptr<log4cpp::log::logger> log = log4cpp::logger_manager::get_logger ();
339366 log4cpp::log_level max_level = log->get_level ();
340367 unsigned int expected_log_count = static_cast <int >(max_level) + 1 ; // enum is zero-indexed
341368
342369 std::thread log_server_thread =
343- std::thread (&udp_log_server_loop, std::ref (running ), prefer, port, expected_log_count);
344- while (!running .load ()) {
370+ std::thread (&udp_log_server_loop, std::ref (status ), prefer, port, expected_log_count);
371+ while (log_server_status::LOG_SERVER_RUNNING != status .load ()) {
345372 std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
346373 }
347374 log->trace (" this is a trace" );
@@ -350,6 +377,6 @@ TEST(socket_appender_test, udp_socket_appender_test) {
350377 log->warn (" this is an warning" );
351378 log->error (" this is an error" );
352379 log->fatal (" this is a fatal" );
353- running. store ( false );
380+
354381 log_server_thread.join ();
355382}
0 commit comments