Coverage Report

Created: 2026-06-05 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oflog/libsrc/unixsock.cc
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    socket-unix.cxx
3
// Created: 4/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
22
#include "dcmtk/oflog/config.h"
23
#if defined (DCMTK_LOG4CPLUS_USE_BSD_SOCKETS)
24
25
#include <cstring>
26
#include "dcmtk/ofstd/ofvector.h"
27
#include <algorithm>
28
#include <cerrno>
29
#include "dcmtk/oflog/internal/socket.h"
30
#include "dcmtk/oflog/helpers/loglog.h"
31
#include "dcmtk/oflog/thread/syncpub.h"
32
#include "dcmtk/oflog/spi/logevent.h"
33
#include "dcmtk/oflog/helpers/strhelp.h"
34
35
#ifdef DCMTK_LOG4CPLUS_HAVE_SYS_TYPES_H
36
#include <sys/types.h>
37
#endif
38
39
#ifdef DCMTK_LOG4CPLUS_HAVE_SYS_SOCKET_H
40
#include <sys/socket.h>
41
#endif
42
43
#if defined (DCMTK_LOG4CPLUS_HAVE_NETINET_IN_H)
44
#include <netinet/in.h>
45
#endif
46
47
#if defined (DCMTK_LOG4CPLUS_HAVE_NETINET_TCP_H)
48
#include <netinet/tcp.h>
49
#endif
50
51
#if defined (DCMTK_LOG4CPLUS_HAVE_ARPA_INET_H)
52
#include <arpa/inet.h>
53
#endif
54
 
55
#if defined (DCMTK_LOG4CPLUS_HAVE_ERRNO_H)
56
#include <errno.h>
57
#endif
58
59
#ifdef DCMTK_LOG4CPLUS_HAVE_NETDB_H
60
#include <netdb.h>
61
#endif
62
63
#ifdef DCMTK_LOG4CPLUS_HAVE_UNISTD_H
64
#include <unistd.h>
65
#endif
66
67
// helper methods to fix old-style casts warnings
68
BEGIN_EXTERN_C
69
0
static unsigned short OFhtons(unsigned short us) { return htons(us); }
70
0
static in_addr_t OFinaddr_any() { return INADDR_ANY; }
71
END_EXTERN_C
72
73
namespace dcmtk {
74
namespace log4cplus { namespace helpers {
75
76
77
namespace
78
{
79
80
81
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
82
// We need to use log4cplus::thread here to work around compilation
83
// problem on AIX.
84
static log4cplus::thread::Mutex ghbn_mutex;
85
86
#endif
87
88
89
static
90
int
91
get_host_by_name (char const * hostname, STD_NAMESPACE string * name,
92
    struct sockaddr_in * addr)
93
0
{
94
0
#if defined (DCMTK_LOG4CPLUS_HAVE_GETADDRINFO)
95
0
    struct addrinfo hints;
96
0
    memset (&hints, 0, sizeof (hints));
97
0
    hints.ai_family = AF_INET;
98
0
    hints.ai_socktype = SOCK_STREAM;
99
0
    hints.ai_protocol = IPPROTO_TCP;
100
0
    hints.ai_flags = AI_CANONNAME;
101
102
0
    if (inet_addr (hostname) != OFstatic_cast(in_addr_t, -1))
103
0
        hints.ai_flags |= AI_NUMERICHOST;
104
105
0
    struct addrinfo * res = 0;
106
0
    int ret = getaddrinfo (hostname, 0, &hints, &res);
107
0
    if (ret != 0)
108
0
        return ret;
109
110
0
    struct addrinfo const & ai = *res;
111
0
    assert (ai.ai_family == AF_INET);
112
    
113
0
    if (name)
114
0
        *name = ai.ai_canonname;
115
116
0
    if (addr)
117
0
        memcpy (addr, ai.ai_addr, ai.ai_addrlen);
118
119
0
    freeaddrinfo (res);
120
121
#else
122
    #if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED)
123
    // We need to use log4cplus::thread here to work around
124
    // compilation problem on AIX.
125
    log4cplus::thread::MutexGuard guard (ghbn_mutex);
126
127
    #endif
128
129
    struct ::hostent * hp = gethostbyname (hostname);
130
    if (! hp)
131
        return 1;
132
    assert (hp->h_addrtype == AF_INET);
133
134
    if (name)
135
        *name = hp->h_name;
136
137
    if (addr)
138
    {
139
        assert (hp->h_length <= sizeof (addr->sin_addr));
140
        memcpy (&addr->sin_addr, hp->h_addr_list[0], hp->h_length);
141
    }
142
143
#endif
144
145
0
    return 0;
146
0
}
147
148
149
} // namespace
150
151
152
/////////////////////////////////////////////////////////////////////////////
153
// Global Methods
154
/////////////////////////////////////////////////////////////////////////////
155
156
SOCKET_TYPE
157
openSocket(unsigned short port, SocketState& state)
158
0
{
159
0
    int sock = ::socket(AF_INET, SOCK_STREAM, 0);
160
0
    if(sock < 0) {
161
0
        return INVALID_SOCKET_VALUE;
162
0
    }
163
164
0
    struct sockaddr_in server = sockaddr_in ();
165
0
    server.sin_family = AF_INET;
166
0
    server.sin_addr.s_addr = OFinaddr_any();
167
0
    server.sin_port = OFhtons(port);
168
169
0
    int optval = 1;
170
0
    socklen_t optlen = sizeof (optval);
171
0
    int ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen );
172
0
    if (ret != 0)
173
0
    {
174
0
        helpers::getLogLog ().warn ("setsockopt() failed: "
175
0
            + helpers::convertIntegerToString (errno));
176
0
    }
177
178
0
    int retval = bind(sock, OFreinterpret_cast(struct sockaddr*, &server),
179
0
        sizeof(server));
180
0
    if (retval < 0)
181
0
        goto error;
182
183
0
    if (::listen(sock, 10))
184
0
        goto error;
185
186
0
    state = ok;
187
0
    return to_log4cplus_socket (sock);
188
189
0
error:
190
0
    close (sock);
191
0
    return INVALID_SOCKET_VALUE;
192
0
}
193
194
195
SOCKET_TYPE
196
connectSocket(const tstring& hostn, unsigned short port, bool udp, SocketState& state)
197
0
{
198
0
    struct sockaddr_in server;
199
0
    int sock;
200
0
    int retval;
201
202
0
    memset (&server, 0, sizeof (server));
203
0
    retval = get_host_by_name (DCMTK_LOG4CPLUS_TSTRING_TO_STRING(hostn).c_str(),
204
0
        0, &server);
205
0
    if (retval != 0)
206
0
        return INVALID_SOCKET_VALUE;
207
208
0
    server.sin_port = OFhtons(port);
209
0
    server.sin_family = AF_INET;
210
211
0
    sock = ::socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
212
0
    if(sock < 0) {
213
0
        return INVALID_SOCKET_VALUE;
214
0
    }
215
216
0
    socklen_t namelen = sizeof (server);
217
0
    while (
218
0
        (retval = ::connect(sock, OFreinterpret_cast(struct sockaddr*, &server),
219
0
            namelen))
220
0
        == -1
221
0
        && (errno == EINTR))
222
0
        ;
223
0
    if (retval == INVALID_OS_SOCKET_VALUE) 
224
0
    {
225
0
        ::close(sock);
226
0
        return INVALID_SOCKET_VALUE;
227
0
    }
228
229
0
    state = ok;
230
0
    return to_log4cplus_socket (sock);
231
0
}
232
233
234
namespace
235
{
236
237
//! Helper for accept_wrap().
238
template <typename T, typename U>
239
struct socklen_var
240
{
241
    typedef T type;
242
};
243
244
245
template <typename U>
246
struct socklen_var<void, U>
247
{
248
    typedef U type;
249
};
250
251
252
// Some systems like HP-UX have socklen_t but accept() does not use it
253
// as type of its 3rd parameter. This wrapper works around this
254
// incompatibility.
255
template <typename accept_sockaddr_ptr_type, typename accept_socklen_type>
256
static
257
SOCKET_TYPE
258
accept_wrap (
259
    int (* accept_func) (int, accept_sockaddr_ptr_type, accept_socklen_type *),
260
    SOCKET_TYPE sock, struct sockaddr * sa, socklen_t * len)
261
0
{
262
0
    typedef typename socklen_var<accept_socklen_type, socklen_t>::type
263
0
        socklen_var_type;
264
0
    socklen_var_type l = OFstatic_cast(socklen_var_type, *len);
265
0
    SOCKET_TYPE result
266
0
        = OFstatic_cast(SOCKET_TYPE,
267
0
            accept_func (to_os_socket(sock), sa,
268
0
                OFreinterpret_cast(accept_socklen_type *, &l)));
269
0
    *len = OFstatic_cast(socklen_t, l);
270
0
    return result;
271
0
}
272
273
274
} // namespace
275
276
277
SOCKET_TYPE
278
acceptSocket(SOCKET_TYPE sock, SocketState& state)
279
0
{
280
0
    struct sockaddr_in net_client;
281
0
    socklen_t len = sizeof(struct sockaddr);
282
0
    int clientSock;
283
284
0
    while(
285
0
        (clientSock = OFstatic_cast(int, accept_wrap (accept, sock,
286
0
            OFreinterpret_cast(struct sockaddr*, &net_client), &len)))
287
0
        == -1
288
0
        && (errno == EINTR))
289
0
        ;
290
291
0
    if(clientSock != INVALID_OS_SOCKET_VALUE) {
292
0
        state = ok;
293
0
    }
294
295
0
    return to_log4cplus_socket (clientSock);
296
0
}
297
298
299
300
int
301
closeSocket(SOCKET_TYPE sock)
302
0
{
303
0
    return ::close(to_os_socket (sock));
304
0
}
305
306
307
308
long
309
read(SOCKET_TYPE sock, SocketBuffer& buffer)
310
0
{
311
0
    long res, readbytes = 0;
312
 
313
0
    do
314
0
    { 
315
0
        res = ::read(to_os_socket (sock), buffer.getBuffer() + readbytes,
316
0
            buffer.getMaxSize() - readbytes);
317
0
        if( res <= 0 ) {
318
0
            return res;
319
0
        }
320
0
        readbytes += res;
321
0
    } while( readbytes < OFstatic_cast(long, buffer.getMaxSize()) );
322
 
323
0
    return readbytes;
324
0
}
325
326
327
328
long
329
write(SOCKET_TYPE sock, const SocketBuffer& buffer)
330
0
{
331
0
#if defined(MSG_NOSIGNAL)
332
0
    int flags = MSG_NOSIGNAL;
333
#else
334
    int flags = 0;
335
#endif
336
0
    return ::send( to_os_socket (sock), buffer.getBuffer(), buffer.getSize(),
337
0
        flags );
338
0
}
339
340
341
long
342
write(SOCKET_TYPE sock, const STD_NAMESPACE string & buffer)
343
0
{
344
0
#if defined(MSG_NOSIGNAL)
345
0
    int flags = MSG_NOSIGNAL;
346
#else
347
    int flags = 0;
348
#endif
349
0
    return ::send (to_os_socket (sock), buffer.c_str (), buffer.size (),
350
0
        flags);
351
0
}
352
353
354
tstring
355
getHostname (bool fqdn)
356
0
{
357
0
    char const * hostname = "unknown";
358
0
    int ret;
359
0
    OFVector<char> hn (1024, 0);
360
361
0
    while (true)
362
0
    {
363
0
        ret = ::gethostname (&hn[0], OFstatic_cast(int, hn.size ()) - 1);
364
0
        if (ret == 0)
365
0
        {
366
0
            hostname = &hn[0];
367
0
            break;
368
0
        }
369
0
#if defined (DCMTK_LOG4CPLUS_HAVE_ENAMETOOLONG)
370
0
        else if (ret != 0 && errno == ENAMETOOLONG)
371
            // Out buffer was too short. Retry with buffer twice the size.
372
0
            hn.resize (hn.size () * 2, 0);
373
0
#endif
374
0
        else
375
0
            break;
376
0
    }
377
378
0
    if (ret != 0 || (ret == 0 && ! fqdn))
379
0
        return DCMTK_LOG4CPLUS_STRING_TO_TSTRING (hostname);
380
381
0
    STD_NAMESPACE string full_hostname;
382
0
    ret = get_host_by_name (hostname, &full_hostname, 0);
383
0
    if (ret == 0)
384
0
        hostname = full_hostname.c_str ();
385
386
0
    return DCMTK_LOG4CPLUS_STRING_TO_TSTRING (hostname);
387
0
}
388
389
390
int
391
setTCPNoDelay (SOCKET_TYPE sock, bool val)
392
0
{
393
0
#if (defined (SOL_TCP) || defined (IPPROTO_TCP)) && defined (TCP_NODELAY)
394
0
#if defined (SOL_TCP)
395
0
    int level = SOL_TCP;
396
397
#elif defined (IPPROTO_TCP)
398
    int level = IPPROTO_TCP;
399
400
#endif
401
402
0
    int result;
403
0
    int enabled = OFstatic_cast(int, val);
404
0
    if ((result = setsockopt(to_os_socket(sock), level, TCP_NODELAY, &enabled,
405
0
                sizeof(enabled))) != 0)
406
0
        set_last_socket_error (errno);
407
    
408
0
    return result;
409
410
#else
411
    // No recognizable TCP_NODELAY option.
412
    return 0;
413
414
#endif
415
0
}
416
417
418
} } // namespace log4cplus
419
} // end namespace dcmtk
420
421
#endif // DCMTK_LOG4CPLUS_USE_BSD_SOCKETS