| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <log4cxx/helpers/socket.h> |
| #include <log4cxx/helpers/bytebuffer.h> |
| #include <log4cxx/helpers/transcoder.h> |
| #include "apr_network_io.h" |
| #include "apr_signal.h" |
| |
| |
| using namespace log4cxx; |
| using namespace log4cxx::helpers; |
| |
| IMPLEMENT_LOG4CXX_OBJECT(Socket) |
| |
| /** Creates a stream socket and connects it to the specified port |
| number at the specified IP address. |
| */ |
| Socket::Socket(InetAddressPtr& addr, int prt) : pool(), socket(0), address(addr), port(prt) |
| { |
| apr_status_t status = |
| apr_socket_create(&socket, APR_INET, SOCK_STREAM, |
| APR_PROTO_TCP, pool.getAPRPool()); |
| |
| if (status != APR_SUCCESS) |
| { |
| throw SocketException(status); |
| } |
| |
| LOG4CXX_ENCODE_CHAR(host, addr->getHostAddress()); |
| |
| // create socket address (including port) |
| apr_sockaddr_t* client_addr; |
| status = |
| apr_sockaddr_info_get(&client_addr, host.c_str(), APR_INET, |
| prt, 0, pool.getAPRPool()); |
| |
| if (status != APR_SUCCESS) |
| { |
| throw ConnectException(status); |
| } |
| |
| // connect the socket |
| status = apr_socket_connect(socket, client_addr); |
| |
| if (status != APR_SUCCESS) |
| { |
| throw ConnectException(status); |
| } |
| } |
| |
| Socket::Socket(apr_socket_t* s, apr_pool_t* p) : |
| pool(p, true), socket(s) |
| { |
| apr_sockaddr_t* sa; |
| apr_status_t status = apr_socket_addr_get(&sa, APR_REMOTE, s); |
| |
| if (status == APR_SUCCESS) |
| { |
| port = sa->port; |
| LogString remotename; |
| LogString remoteip; |
| |
| if (sa->hostname != NULL) |
| { |
| Transcoder::decode(sa->hostname, remotename); |
| } |
| |
| char* buf = 0; |
| status = apr_sockaddr_ip_get(&buf, sa); |
| |
| if (status == APR_SUCCESS) |
| { |
| Transcoder::decode(buf, remoteip); |
| } |
| |
| address = new InetAddress(remotename, remoteip); |
| } |
| } |
| |
| Socket::~Socket() |
| { |
| } |
| |
| size_t Socket::write(ByteBuffer& buf) |
| { |
| if (socket == 0) |
| { |
| throw ClosedChannelException(); |
| } |
| |
| int totalWritten = 0; |
| |
| while (buf.remaining() > 0) |
| { |
| apr_size_t written = buf.remaining(); |
| |
| // while writing to the socket, we need to ignore the SIGPIPE |
| // signal. Otherwise, when the client has closed the connection, |
| // the send() function would not return an error but call the |
| // SIGPIPE handler. |
| #if APR_HAVE_SIGACTION |
| apr_sigfunc_t* old = apr_signal(SIGPIPE, SIG_IGN); |
| apr_status_t status = apr_socket_send(socket, buf.current(), &written); |
| apr_signal(SIGPIPE, old); |
| #else |
| apr_status_t status = apr_socket_send(socket, buf.current(), &written); |
| #endif |
| |
| buf.position(buf.position() + written); |
| totalWritten += written; |
| |
| if (status != APR_SUCCESS) |
| { |
| throw SocketException(status); |
| } |
| } |
| |
| return totalWritten; |
| } |
| |
| |
| void Socket::close() |
| { |
| if (socket != 0) |
| { |
| apr_status_t status = apr_socket_close(socket); |
| |
| if (status != APR_SUCCESS) |
| { |
| throw SocketException(status); |
| } |
| |
| socket = 0; |
| } |
| } |
| |
| InetAddressPtr Socket::getInetAddress() const |
| { |
| return address; |
| } |
| |
| int Socket::getPort() const |
| { |
| return port; |
| } |
| |
| |