Coverage Report

Created: 2025-07-01 06:08

/src/logging-log4cxx/src/main/cpp/aprserversocket.cpp
Line
Count
Source (jump to first uncovered line)
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/aprserversocket.h>
19
#include <log4cxx/private/serversocket_priv.h>
20
#include <log4cxx/private/aprsocket.h>
21
#include <log4cxx/helpers/transcoder.h>
22
#include "apr_network_io.h"
23
#include "apr_pools.h"
24
#include "apr_poll.h"
25
26
namespace LOG4CXX_NS
27
{
28
namespace helpers
29
{
30
31
0
#define _priv static_cast<APRServerSocketPriv*>(m_priv.get())
32
33
struct APRServerSocket::APRServerSocketPriv : public ServerSocketPrivate {
34
  Pool pool;
35
  std::mutex mutex;
36
  apr_socket_t* socket;
37
};
38
39
#if LOG4CXX_ABI_VERSION <= 15
40
APRServerSocket::APRServerSocket(int port) : 
41
0
  APRServerSocket(port, false, {}) {}
42
#endif
43
44
APRServerSocket::APRServerSocket(int port, bool reuseAddress, const LogString& hostname) :
45
0
  ServerSocket(std::make_unique<APRServerSocketPriv>()){
46
0
  apr_status_t status =
47
0
    apr_socket_create(&_priv->socket, APR_INET, SOCK_STREAM,
48
0
      APR_PROTO_TCP, _priv->pool.getAPRPool());
49
50
0
  if (status != APR_SUCCESS)
51
0
  {
52
0
    throw SocketException(status);
53
0
  }
54
55
0
  status = apr_socket_opt_set(_priv->socket, APR_SO_NONBLOCK, 1);
56
57
0
  if (status != APR_SUCCESS)
58
0
  {
59
0
    throw SocketException(status);
60
0
  }
61
62
0
  if (reuseAddress) {
63
0
    apr_status_t status = apr_socket_opt_set(_priv->socket, APR_SO_REUSEADDR, 1);
64
65
0
    if (status != APR_SUCCESS)
66
0
    {
67
0
      throw SocketException(status);
68
0
    }
69
0
  }
70
71
  // Create server socket address (including port number)
72
0
  std::string hostname_str;
73
0
  const char* hostname_ptr = NULL;
74
0
  if (!hostname.empty()) {
75
0
    Transcoder::encode(hostname, hostname_str);
76
0
    hostname_ptr = hostname_str.c_str();
77
0
  }
78
79
0
  apr_sockaddr_t* server_addr;
80
0
  status =
81
0
    apr_sockaddr_info_get(&server_addr, hostname_ptr, APR_INET,
82
0
      port, 0, _priv->pool.getAPRPool());
83
84
0
  if (status != APR_SUCCESS)
85
0
  {
86
0
    throw ConnectException(status);
87
0
  }
88
89
  // bind the socket to the address
90
0
  status = apr_socket_bind(_priv->socket, server_addr);
91
92
0
  if (status != APR_SUCCESS)
93
0
  {
94
0
    throw BindException(status);
95
0
  }
96
97
98
0
  status = apr_socket_listen(_priv->socket, 50);
99
100
0
  if (status != APR_SUCCESS)
101
0
  {
102
0
    throw SocketException(status);
103
0
  }
104
0
}
105
106
void APRServerSocket::close()
107
0
{
108
0
  std::lock_guard<std::mutex> lock(_priv->mutex);
109
110
0
  if (_priv->socket != 0)
111
0
  {
112
0
    apr_status_t status = apr_socket_close(_priv->socket);
113
114
0
    if (status != APR_SUCCESS)
115
0
    {
116
0
      throw SocketException(status);
117
0
    }
118
119
0
    _priv->socket = 0;
120
0
  }
121
0
}
122
123
124
/** Listens for a connection to be made to this socket and
125
accepts it
126
*/
127
SocketPtr APRServerSocket::accept()
128
0
{
129
0
  apr_socket_t* s;
130
0
  {
131
0
    std::lock_guard<std::mutex> lock(_priv->mutex);
132
0
    s = _priv->socket;
133
0
  }
134
0
  if (s == 0)
135
0
  {
136
0
    throw NullPointerException(LOG4CXX_STR("socket"));
137
0
  }
138
139
0
  apr_pollfd_t poll;
140
0
  poll.p = _priv->pool.getAPRPool();
141
0
  poll.desc_type = APR_POLL_SOCKET;
142
0
  poll.reqevents = APR_POLLIN;
143
0
  poll.rtnevents = 0;
144
0
  poll.desc.s = s;
145
0
  poll.client_data = NULL;
146
147
0
  apr_int32_t signaled;
148
0
  apr_interval_time_t to = _priv->timeout * 1000;
149
0
  apr_status_t status = apr_poll(&poll, 1, &signaled, to);
150
151
0
  if (APR_STATUS_IS_TIMEUP(status))
152
0
  {
153
0
    throw SocketTimeoutException();
154
0
  }
155
0
  else if (status != APR_SUCCESS)
156
0
  {
157
0
    throw SocketException(status);
158
0
  }
159
160
0
  apr_pool_t* newPool;
161
0
  status = apr_pool_create(&newPool, 0);
162
163
0
  if (status != APR_SUCCESS)
164
0
  {
165
0
    throw PoolException(status);
166
0
  }
167
168
0
  apr_socket_t* newSocket;
169
0
  status = apr_socket_accept(&newSocket, s, newPool);
170
171
0
  if (status != APR_SUCCESS)
172
0
  {
173
0
    apr_pool_destroy(newPool);
174
0
    throw SocketException(status);
175
0
  }
176
177
0
  status = apr_socket_opt_set(newSocket, APR_SO_NONBLOCK, 0);
178
179
0
  if (status != APR_SUCCESS)
180
0
  {
181
0
    apr_pool_destroy(newPool);
182
0
    throw SocketException(status);
183
0
  }
184
185
0
  return std::make_shared<APRSocket>(newSocket, newPool);
186
0
}
187
188
} //namespace helpers
189
} //namespace log4cxx