Coverage Report

Created: 2026-06-30 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oflog/libsrc/socketap.cc
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    socketappender.cxx
3
// Created: 5/2003
4
// Author:  Tad E. Smith
5
//
6
//
7
// Copyright 2003-2010 Tad E. Smith
8
//
9
// Licensed under the Apache License, Version 2.0 (the "License");
10
// you may not use this file except in compliance with the License.
11
// You may obtain a copy of the License at
12
//
13
//     http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software
16
// distributed under the License is distributed on an "AS IS" BASIS,
17
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
// See the License for the specific language governing permissions and
19
// limitations under the License.
20
21
#include <cstdlib>
22
#include "dcmtk/oflog/socketap.h"
23
#include "dcmtk/oflog/layout.h"
24
#include "dcmtk/oflog/spi/logevent.h"
25
#include "dcmtk/oflog/helpers/loglog.h"
26
#include "dcmtk/oflog/helpers/sleep.h"
27
#include "dcmtk/oflog/helpers/property.h"
28
#include "dcmtk/oflog/thread/syncpub.h"
29
30
31
namespace dcmtk {
32
namespace log4cplus {
33
34
int const DCMTK_LOG4CPLUS_MESSAGE_VERSION = 3;
35
36
37
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
38
SocketAppender::ConnectorThread::ConnectorThread (
39
    SocketAppender & socket_appender)
40
0
    : sa (socket_appender)
41
0
    , trigger_ev ()
42
0
    , exit_flag (false)
43
0
{ }
Unexecuted instantiation: dcmtk::log4cplus::SocketAppender::ConnectorThread::ConnectorThread(dcmtk::log4cplus::SocketAppender&)
Unexecuted instantiation: dcmtk::log4cplus::SocketAppender::ConnectorThread::ConnectorThread(dcmtk::log4cplus::SocketAppender&)
44
45
46
SocketAppender::ConnectorThread::~ConnectorThread ()
47
0
{ }
48
49
50
void
51
SocketAppender::ConnectorThread::run ()
52
0
{
53
0
    while (true)
54
0
    {
55
0
        trigger_ev.timed_wait (30 * 1000);
56
57
0
        helpers::getLogLog().debug (
58
0
            DCMTK_LOG4CPLUS_TEXT("SocketAppender::ConnectorThread::run()")
59
0
            DCMTK_LOG4CPLUS_TEXT("- running..."));
60
61
        // Check exit condition as the very first thing.
62
63
0
        {
64
0
            thread::MutexGuard guard (access_mutex);
65
0
            if (exit_flag)
66
0
                return;
67
0
            trigger_ev.reset ();
68
0
        }
69
70
        // Do not try to re-open already open socket.
71
72
0
        {
73
0
            thread::MutexGuard guard (sa.access_mutex);
74
0
            if (sa.socket.isOpen ())
75
0
                continue;
76
0
        }
77
78
        // The socket is not open, try to reconnect.
79
80
0
        helpers::Socket new_socket (sa.host,
81
0
            OFstatic_cast(unsigned short, sa.port));
82
0
        if (! new_socket.isOpen ())
83
0
        {
84
0
            helpers::getLogLog().error(
85
0
                DCMTK_LOG4CPLUS_TEXT("SocketAppender::ConnectorThread::run()")
86
0
                DCMTK_LOG4CPLUS_TEXT("- Cannot connect to server"));
87
88
            // Sleep for a short while after unsuccessful connection attempt
89
            // so that we do not try to reconnect after each logging attempt
90
            // which could be many times per second.
91
0
            helpers::sleep (5);
92
93
0
            continue;
94
0
        }
95
96
        // Connection was successful, move the socket into SocketAppender.
97
98
0
        {
99
0
            thread::MutexGuard guard (sa.access_mutex);
100
0
            sa.socket = new_socket;
101
0
            sa.connected = true;
102
0
        }
103
0
    }
104
0
}
105
106
107
void
108
SocketAppender::ConnectorThread::terminate ()
109
0
{
110
0
    {
111
0
        thread::MutexGuard guard (access_mutex);
112
0
        exit_flag = true;
113
0
        trigger_ev.signal ();
114
0
    }
115
0
    join ();
116
0
}
117
118
119
void
120
SocketAppender::ConnectorThread::trigger ()
121
0
{
122
0
    trigger_ev.signal ();
123
0
}
124
125
#endif
126
127
128
//////////////////////////////////////////////////////////////////////////////
129
// SocketAppender ctors and dtor
130
//////////////////////////////////////////////////////////////////////////////
131
132
SocketAppender::SocketAppender(const tstring& host_,
133
    unsigned short port_, const tstring& serverName_)
134
0
: socket(),
135
0
  host(host_),
136
0
  port(port_),
137
0
  serverName(serverName_)
138
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
139
0
  ,connected(false),
140
0
  connector()
141
#endif
142
0
{
143
0
    openSocket();
144
0
    initConnector ();
145
0
}
Unexecuted instantiation: dcmtk::log4cplus::SocketAppender::SocketAppender(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: dcmtk::log4cplus::SocketAppender::SocketAppender(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
146
147
148
149
SocketAppender::SocketAppender(const helpers::Properties & properties)
150
0
 : Appender(properties),
151
0
   socket(),
152
0
   host(),
153
0
   port(9998),
154
0
   serverName()
155
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
156
0
   ,connected(false),
157
0
   connector()
158
#endif
159
0
{
160
0
    host = properties.getProperty( DCMTK_LOG4CPLUS_TEXT("host") );
161
0
    properties.getUInt (port, DCMTK_LOG4CPLUS_TEXT("port"));
162
0
    serverName = properties.getProperty( DCMTK_LOG4CPLUS_TEXT("ServerName") );
163
164
0
    openSocket();
165
0
    initConnector ();
166
0
}
Unexecuted instantiation: dcmtk::log4cplus::SocketAppender::SocketAppender(dcmtk::log4cplus::helpers::Properties const&)
Unexecuted instantiation: dcmtk::log4cplus::SocketAppender::SocketAppender(dcmtk::log4cplus::helpers::Properties const&)
167
168
169
170
SocketAppender::~SocketAppender()
171
0
{
172
0
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
173
0
    connector->terminate ();
174
0
#endif
175
176
0
    destructorImpl();
177
0
}
178
179
180
181
//////////////////////////////////////////////////////////////////////////////
182
// SocketAppender public methods
183
//////////////////////////////////////////////////////////////////////////////
184
185
void 
186
SocketAppender::close()
187
0
{
188
0
    helpers::getLogLog().debug(
189
0
        DCMTK_LOG4CPLUS_TEXT("Entering SocketAppender::close()..."));
190
191
0
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
192
0
    connector->terminate ();
193
0
#endif
194
195
0
    socket.close();
196
0
    closed = true;
197
0
}
198
199
200
201
//////////////////////////////////////////////////////////////////////////////
202
// SocketAppender protected methods
203
//////////////////////////////////////////////////////////////////////////////
204
205
void
206
SocketAppender::openSocket()
207
0
{
208
0
    if(!socket.isOpen()) {
209
0
        socket = helpers::Socket(host, OFstatic_cast(unsigned short, port));
210
0
    }
211
0
}
212
213
214
void
215
SocketAppender::initConnector ()
216
0
{
217
0
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
218
0
    connected = true;
219
0
    connector = new ConnectorThread (*this);
220
0
    connector->start ();
221
0
#endif
222
0
}
223
224
225
void
226
SocketAppender::append(const spi::InternalLoggingEvent& event)
227
0
{
228
0
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
229
0
    if (! connected)
230
0
    {
231
0
        connector->trigger ();
232
0
        return;
233
0
    }
234
235
#else
236
    if(!socket.isOpen()) {
237
        openSocket();
238
        if(!socket.isOpen()) {
239
            helpers::getLogLog().error(
240
                DCMTK_LOG4CPLUS_TEXT(
241
                    "SocketAppender::append()- Cannot connect to server"));
242
            return;
243
        }
244
    }
245
#endif
246
247
0
    helpers::SocketBuffer buffer(DCMTK_LOG4CPLUS_MAX_MESSAGE_SIZE - sizeof(unsigned int));
248
0
    helpers::convertToBuffer (buffer, event, serverName);
249
0
    helpers::SocketBuffer msgBuffer(DCMTK_LOG4CPLUS_MAX_MESSAGE_SIZE);
250
251
0
    msgBuffer.appendInt(OFstatic_cast(unsigned, buffer.getSize()));
252
0
    msgBuffer.appendBuffer(buffer);
253
254
0
    bool ret = socket.write(msgBuffer);
255
0
    if (! ret)
256
0
    {
257
0
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
258
0
        connected = false;
259
0
        connector->trigger ();
260
0
#endif
261
0
    }
262
0
}
263
264
265
/////////////////////////////////////////////////////////////////////////////
266
// namespace helpers methods
267
/////////////////////////////////////////////////////////////////////////////
268
269
namespace helpers
270
{
271
272
273
void
274
convertToBuffer(SocketBuffer & buffer,
275
    const spi::InternalLoggingEvent& event,
276
    const tstring& serverName)
277
0
{
278
0
    buffer.appendByte(DCMTK_LOG4CPLUS_MESSAGE_VERSION);
279
0
#ifndef DCMTK_OFLOG_UNICODE
280
0
    buffer.appendByte(1);
281
#else
282
    buffer.appendByte(2);
283
#endif
284
285
0
    buffer.appendString(serverName);
286
0
    buffer.appendString(event.getLoggerName());
287
0
    buffer.appendInt(event.getLogLevel());
288
0
    buffer.appendString(event.getNDC());
289
0
    buffer.appendString(event.getMessage());
290
0
    buffer.appendString(event.getThread());
291
0
    buffer.appendInt( OFstatic_cast(unsigned int, event.getTimestamp().sec()) );
292
0
    buffer.appendInt( OFstatic_cast(unsigned int, event.getTimestamp().usec()) );
293
0
    buffer.appendString(event.getFile());
294
0
    buffer.appendInt(event.getLine());
295
0
    buffer.appendString(event.getFunction());
296
0
}
297
298
299
spi::InternalLoggingEvent
300
readFromBuffer(SocketBuffer& buffer)
301
0
{
302
0
    unsigned char msgVersion = buffer.readByte();
303
0
    if(msgVersion != DCMTK_LOG4CPLUS_MESSAGE_VERSION) {
304
0
        LogLog * loglog = LogLog::getLogLog();
305
0
        loglog->warn(DCMTK_LOG4CPLUS_TEXT("readFromBuffer() received socket message with an invalid version"));
306
0
    }
307
308
0
    unsigned char sizeOfChar = buffer.readByte();
309
310
0
    tstring serverName = buffer.readString(sizeOfChar);
311
0
    tstring loggerName = buffer.readString(sizeOfChar);
312
0
    LogLevel ll = buffer.readInt();
313
0
    tstring ndc = buffer.readString(sizeOfChar);
314
0
    if(! serverName.empty ()) {
315
0
        if(ndc.empty ()) {
316
0
            ndc = serverName;
317
0
        }
318
0
        else {
319
0
            ndc = serverName + DCMTK_LOG4CPLUS_TEXT(" - ") + ndc;
320
0
        }
321
0
    }
322
0
    tstring message = buffer.readString(sizeOfChar);
323
0
    tstring thread = buffer.readString(sizeOfChar);
324
0
    long sec = buffer.readInt();
325
0
    long usec = buffer.readInt();
326
0
    tstring file = buffer.readString(sizeOfChar);
327
0
    int line = buffer.readInt();
328
0
    tstring function = buffer.readString(sizeOfChar);
329
330
    // TODO: Pass MDC through.
331
0
    spi::InternalLoggingEvent ev (loggerName, ll, ndc,
332
0
        MappedDiagnosticContextMap (), message, thread, Time(sec, usec), file,
333
0
        line);
334
0
    ev.setFunction (function);
335
0
    return ev;
336
0
}
337
338
339
} // namespace helpers
340
341
342
} // namespace log4cplus
343
} // end namespace dcmtk