Coverage Report

Created: 2026-05-30 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/aprsocket.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/private/aprsocket.h>
19
#include <log4cxx/private/socket_priv.h>
20
#include <log4cxx/helpers/bytebuffer.h>
21
#include <log4cxx/helpers/transcoder.h>
22
23
#include "apr_network_io.h"
24
#include "apr_signal.h"
25
26
namespace LOG4CXX_NS
27
{
28
namespace helpers
29
{
30
31
struct APRSocket::APRSocketPriv : public Socket::SocketPrivate {
32
  APRSocketPriv(LOG4CXX_16_CONST InetAddressPtr& address, int port)
33
0
    : Socket::SocketPrivate(address, port)
34
0
    , socket(nullptr)
35
0
  {}
36
37
  APRSocketPriv(apr_socket_t* sock, apr_pool_t* p) :
38
0
    pool(p, true),
39
0
    socket(sock)
40
0
  {}
41
42
  Pool pool;
43
  apr_socket_t* socket{ NULL };
44
  bool connected{ false };
45
};
46
47
0
#define _priv static_cast<APRSocketPriv*>(m_priv.get())
48
49
APRSocket::APRSocket(LOG4CXX_16_CONST InetAddressPtr& address, int port)
50
0
  : Socket(std::make_unique<APRSocketPriv>(address, port))
51
0
{
52
0
  apr_status_t status =
53
0
    apr_socket_create(&_priv->socket, APR_INET, SOCK_STREAM,
54
0
      APR_PROTO_TCP, _priv->pool.getAPRPool());
55
56
0
  if (status != APR_SUCCESS)
57
0
  {
58
0
    throw SocketException(status);
59
0
  }
60
0
  open();
61
0
}
62
63
void APRSocket::open()
64
0
{
65
0
  LOG4CXX_ENCODE_CHAR(host, _priv->address->getHostAddress());
66
67
  // create socket address (including port)
68
0
  apr_sockaddr_t* client_addr;
69
0
  apr_status_t status = apr_sockaddr_info_get
70
0
    ( &client_addr
71
0
    , host.c_str()
72
0
    , APR_INET
73
0
    , _priv->port
74
0
    , 0
75
0
    , _priv->pool.getAPRPool()
76
0
    );
77
78
0
  if (status != APR_SUCCESS)
79
0
  {
80
0
    throw ConnectException(status);
81
0
  }
82
83
  // connect the socket
84
0
  status =  apr_socket_connect(_priv->socket, client_addr);
85
86
0
  if (status != APR_SUCCESS)
87
0
  {
88
0
    throw ConnectException(status);
89
0
  }
90
0
  _priv->connected = true;
91
0
}
92
93
// Is the socket available for use?
94
bool APRSocket::is_open()
95
0
{
96
0
  return _priv->socket && _priv->connected;
97
0
}
98
99
APRSocket::APRSocket(apr_socket_t* s, apr_pool_t* pool) :
100
0
  Socket(std::make_unique<APRSocketPriv>(s, pool)){
101
0
  apr_sockaddr_t* sa;
102
0
  apr_status_t status = apr_socket_addr_get(&sa, APR_REMOTE, s);
103
104
0
  if (status == APR_SUCCESS)
105
0
  {
106
0
    _priv->port = sa->port;
107
0
    LogString remotename;
108
0
    LogString remoteip;
109
110
0
    if (sa->hostname != NULL)
111
0
    {
112
0
      Transcoder::decode(sa->hostname, remotename);
113
0
    }
114
115
0
    char* buf = 0;
116
0
    status = apr_sockaddr_ip_get(&buf, sa);
117
118
0
    if (status == APR_SUCCESS)
119
0
    {
120
0
      Transcoder::decode(buf, remoteip);
121
0
    }
122
123
0
    _priv->address = std::make_shared<InetAddress>(remotename, remoteip);
124
0
  }
125
0
}
126
127
size_t APRSocket::write(ByteBuffer& buf)
128
0
{
129
0
  if (_priv->socket == 0)
130
0
  {
131
0
    throw ClosedChannelException();
132
0
  }
133
134
0
  size_t totalWritten = 0;
135
136
0
  while (buf.remaining() > 0)
137
0
  {
138
0
    apr_size_t written = buf.remaining();
139
140
    // while writing to the socket, we need to ignore the SIGPIPE
141
    // signal. Otherwise, when the client has closed the connection,
142
    // the send() function would not return an error but call the
143
    // SIGPIPE handler.
144
0
#if APR_HAVE_SIGACTION
145
0
    apr_sigfunc_t* old = apr_signal(SIGPIPE, SIG_IGN);
146
0
    apr_status_t status = apr_socket_send(_priv->socket, buf.current(), &written);
147
0
    apr_signal(SIGPIPE, old);
148
#else
149
    apr_status_t status = apr_socket_send(_priv->socket, buf.current(), &written);
150
#endif
151
152
0
    buf.increment_position(written);
153
0
    totalWritten += written;
154
155
0
    if (status != APR_SUCCESS)
156
0
    {
157
0
      throw SocketException(status);
158
0
    }
159
0
  }
160
161
0
  return totalWritten;
162
0
}
163
164
void APRSocket::setNonBlocking(bool newValue)
165
0
{
166
0
  auto status = apr_socket_opt_set(_priv->socket, APR_SO_NONBLOCK, newValue);
167
0
  if (status != APR_SUCCESS)
168
0
    throw SocketException(status);
169
0
}
170
171
void APRSocket::close()
172
0
{
173
0
  if (_priv->socket != 0)
174
0
  {
175
0
    apr_status_t status = apr_socket_close(_priv->socket);
176
177
0
    if (status != APR_SUCCESS)
178
0
    {
179
0
      throw SocketException(status);
180
0
    }
181
182
0
    _priv->socket = 0;
183
0
  }
184
0
}
185
186
apr_socket_t* APRSocket::getSocketPtr() const
187
0
{
188
0
  return _priv->socket;
189
0
}
190
191
} //namespace helpers
192
} //namespace log4cxx