/src/logging-log4cxx/src/main/cpp/aprsocket.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/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(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; |
44 | | }; |
45 | | |
46 | 0 | #define _priv static_cast<APRSocketPriv*>(m_priv.get()) |
47 | | |
48 | | APRSocket::APRSocket(InetAddressPtr& address, int port) : |
49 | 0 | Socket(std::make_unique<APRSocketPriv>(address, port)){ |
50 | 0 | apr_status_t status = |
51 | 0 | apr_socket_create(&_priv->socket, APR_INET, SOCK_STREAM, |
52 | 0 | APR_PROTO_TCP, _priv->pool.getAPRPool()); |
53 | |
|
54 | 0 | if (status != APR_SUCCESS) |
55 | 0 | { |
56 | 0 | throw SocketException(status); |
57 | 0 | } |
58 | | |
59 | 0 | LOG4CXX_ENCODE_CHAR(host, address->getHostAddress()); |
60 | | |
61 | | // create socket address (including port) |
62 | 0 | apr_sockaddr_t* client_addr; |
63 | 0 | status = |
64 | 0 | apr_sockaddr_info_get(&client_addr, host.c_str(), APR_INET, |
65 | 0 | port, 0, _priv->pool.getAPRPool()); |
66 | |
|
67 | 0 | if (status != APR_SUCCESS) |
68 | 0 | { |
69 | 0 | throw ConnectException(status); |
70 | 0 | } |
71 | | |
72 | | // connect the socket |
73 | 0 | status = apr_socket_connect(_priv->socket, client_addr); |
74 | |
|
75 | 0 | if (status != APR_SUCCESS) |
76 | 0 | { |
77 | 0 | throw ConnectException(status); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | APRSocket::APRSocket(apr_socket_t* s, apr_pool_t* pool) : |
82 | 0 | Socket(std::make_unique<APRSocketPriv>(s, pool)){ |
83 | 0 | apr_sockaddr_t* sa; |
84 | 0 | apr_status_t status = apr_socket_addr_get(&sa, APR_REMOTE, s); |
85 | |
|
86 | 0 | if (status == APR_SUCCESS) |
87 | 0 | { |
88 | 0 | _priv->port = sa->port; |
89 | 0 | LogString remotename; |
90 | 0 | LogString remoteip; |
91 | |
|
92 | 0 | if (sa->hostname != NULL) |
93 | 0 | { |
94 | 0 | Transcoder::decode(sa->hostname, remotename); |
95 | 0 | } |
96 | |
|
97 | 0 | char* buf = 0; |
98 | 0 | status = apr_sockaddr_ip_get(&buf, sa); |
99 | |
|
100 | 0 | if (status == APR_SUCCESS) |
101 | 0 | { |
102 | 0 | Transcoder::decode(buf, remoteip); |
103 | 0 | } |
104 | |
|
105 | 0 | _priv->address = std::make_shared<InetAddress>(remotename, remoteip); |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | | size_t APRSocket::write(ByteBuffer& buf) |
110 | 0 | { |
111 | 0 | if (_priv->socket == 0) |
112 | 0 | { |
113 | 0 | throw ClosedChannelException(); |
114 | 0 | } |
115 | | |
116 | 0 | size_t totalWritten = 0; |
117 | |
|
118 | 0 | while (buf.remaining() > 0) |
119 | 0 | { |
120 | 0 | apr_size_t written = buf.remaining(); |
121 | | |
122 | | // while writing to the socket, we need to ignore the SIGPIPE |
123 | | // signal. Otherwise, when the client has closed the connection, |
124 | | // the send() function would not return an error but call the |
125 | | // SIGPIPE handler. |
126 | 0 | #if APR_HAVE_SIGACTION |
127 | 0 | apr_sigfunc_t* old = apr_signal(SIGPIPE, SIG_IGN); |
128 | 0 | apr_status_t status = apr_socket_send(_priv->socket, buf.current(), &written); |
129 | 0 | apr_signal(SIGPIPE, old); |
130 | | #else |
131 | | apr_status_t status = apr_socket_send(_priv->socket, buf.current(), &written); |
132 | | #endif |
133 | |
|
134 | 0 | buf.position(buf.position() + written); |
135 | 0 | totalWritten += written; |
136 | |
|
137 | 0 | if (status != APR_SUCCESS) |
138 | 0 | { |
139 | 0 | throw SocketException(status); |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | 0 | return totalWritten; |
144 | 0 | } |
145 | | |
146 | | |
147 | | void APRSocket::close() |
148 | 0 | { |
149 | 0 | if (_priv->socket != 0) |
150 | 0 | { |
151 | 0 | apr_status_t status = apr_socket_close(_priv->socket); |
152 | |
|
153 | 0 | if (status != APR_SUCCESS) |
154 | 0 | { |
155 | 0 | throw SocketException(status); |
156 | 0 | } |
157 | | |
158 | 0 | _priv->socket = 0; |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | | apr_socket_t* APRSocket::getSocketPtr() const |
163 | 0 | { |
164 | 0 | return _priv->socket; |
165 | 0 | } |
166 | | |
167 | | } //namespace helpers |
168 | | } //namespace log4cxx |