blob: d4f1a7452eee4d90765b31242ebfe79ce0274ef5 [file] [log] [blame]
/*
* 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 "Socket.h"
#include <decaf/net/SocketImpl.h>
#include <decaf/net/SocketImplFactory.h>
#include <decaf/internal/net/tcp/TcpSocket.h>
using namespace decaf;
using namespace decaf::net;
using namespace decaf::io;
using namespace decaf::internal;
using namespace decaf::internal::net;
using namespace decaf::internal::net::tcp;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
////////////////////////////////////////////////////////////////////////////////
SocketImplFactory* Socket::factory = NULL;
////////////////////////////////////////////////////////////////////////////////
Socket::Socket() : impl(NULL), created(false), connected(false), closed(false),
bound(false), inputShutdown(false), outputShutdown(false) {
if( this->factory != NULL ) {
this->impl = factory->createSocketImpl();
return;
}
this->impl = new TcpSocket();
}
////////////////////////////////////////////////////////////////////////////////
Socket::Socket( SocketImpl* impl ) : impl(impl), created(false), connected(false), closed(false),
bound(false), inputShutdown(false), outputShutdown(false) {
if( impl == NULL ) {
throw NullPointerException(
__FILE__, __LINE__, "SocketImpl pointer passed was Null." );
}
}
////////////////////////////////////////////////////////////////////////////////
Socket::Socket( const InetAddress* address, int port ) : impl(NULL), created(false), connected(false),
closed(false), bound(false),
inputShutdown(false), outputShutdown(false){
if( address == NULL ) {
throw NullPointerException(
__FILE__, __LINE__, "The InetAddress to connect to cannot be NULL" );
}
if( port < 0 || port > 65535 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Port specified is out of range: %d", port );
}
try{
if( this->factory != NULL ) {
this->impl = factory->createSocketImpl();
} else {
this->impl = new TcpSocket();
}
this->initSocketImpl( address->getHostAddress(), port, NULL, 0 );
}
DECAF_CATCH_RETHROW( UnknownHostException )
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
Socket::Socket( const InetAddress* address, int port, const InetAddress* localAddress, int localPort ) :
impl(NULL), created(false), connected(false), closed(false), bound(false),
inputShutdown(false), outputShutdown(false) {
if( address == NULL ) {
throw NullPointerException(
__FILE__, __LINE__, "The InetAddress to connect to cannot be NULL" );
}
if( port < 0 || port > 65535 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Port specified is out of range: %d", port );
}
try{
if( this->factory != NULL ) {
this->impl = factory->createSocketImpl();
} else {
this->impl = new TcpSocket();
}
this->initSocketImpl( address->getHostAddress(), port, localAddress, localPort );
}
DECAF_CATCH_RETHROW( UnknownHostException )
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
Socket::Socket( const std::string& host, int port ) : impl(NULL), created(false), connected(false),
closed(false), bound(false),
inputShutdown(false), outputShutdown(false){
if( port < 0 || port > 65535 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Port specified is out of range: %d", port );
}
try{
if( this->factory != NULL ) {
this->impl = factory->createSocketImpl();
} else {
this->impl = new TcpSocket();
}
this->initSocketImpl( host, port, NULL, 0 );
}
DECAF_CATCH_RETHROW( UnknownHostException )
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
Socket::Socket( const std::string& host, int port, const InetAddress* localAddress, int localPort ) :
impl(NULL), created(false), connected(false), closed(false), bound(false),
inputShutdown(false), outputShutdown(false) {
if( port < 0 || port > 65535 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Port specified is out of range: %d", port );
}
try{
if( this->factory != NULL ) {
this->impl = factory->createSocketImpl();
} else {
this->impl = new TcpSocket();
}
this->initSocketImpl( host, port, localAddress, localPort );
}
DECAF_CATCH_RETHROW( UnknownHostException )
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
Socket::~Socket() {
try{
close();
delete this->impl;
}
DECAF_CATCH_NOTHROW( Exception )
DECAF_CATCHALL_NOTHROW()
}
////////////////////////////////////////////////////////////////////////////////
void Socket::initSocketImpl( const std::string& host, int port, const InetAddress* localAddress, int localPort ) {
try{
ensureCreated();
std::string bindAddress = "0.0.0.0";
if( localAddress != NULL ) {
bindAddress = localAddress->getHostAddress();
}
try {
this->impl->bind( bindAddress, localPort );
this->bound = true;
this->impl->connect( host, port, -1 );
this->connected = true;
} catch( IOException& ex ) {
this->impl->close();
delete this->impl;
this->impl = NULL;
throw ex;
}
}
DECAF_CATCH_RETHROW( UnknownHostException )
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getPort() const {
return this->connected ? this->impl->getPort() : 0;
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getLocalPort() const {
return this->bound ? this->impl->getLocalPort() : -1;
}
////////////////////////////////////////////////////////////////////////////////
std::string Socket::getInetAddress() const {
return this->connected ? this->impl->getInetAddress() : "";
}
////////////////////////////////////////////////////////////////////////////////
std::string Socket::getLocalAddress() const {
return this->bound ? this->impl->getLocalAddress() : "0.0.0.0";
}
////////////////////////////////////////////////////////////////////////////////
void Socket::bind( const std::string& ipaddress, int port ) {
checkClosed();
if( isBound() ) {
throw IOException(
__FILE__, __LINE__, "The Socket is already bound." );
}
try{
ensureCreated();
try {
this->impl->bind( ipaddress, port );
this->bound = true;
} catch( IOException& e ) {
this->impl->close();
throw e;
}
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::close() {
try{
this->closed = true;
this->impl->close();
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::connect( const std::string& host, int port ) {
if( port < 0 || port > 65535 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Port specified is out of range: %d", port );
}
try{
this->connect( host, port, 0 );
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::connect( const std::string& host, int port, int timeout ) {
checkClosed();
if( timeout < 0 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Timeout value specified is invalid: %d", timeout );
}
if( isConnected() ) {
throw SocketException(
__FILE__, __LINE__, "The Socket is already connected." );
}
if( host.empty() ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Host cannot be empty." );
}
try{
ensureCreated();
try {
if( !isBound() ) {
this->impl->bind( "", 0 );
this->bound = true;
}
this->impl->connect( host, port, timeout );
this->connected = true;
} catch( IOException& ex ) {
this->impl->close();
throw ex;
}
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
InputStream* Socket::getInputStream() {
checkClosed();
try{
if( isInputShutdown() ) {
throw IOException( __FILE__, __LINE__, "Input was shutdown on this Socket." );
}
return this->impl->getInputStream();
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
OutputStream* Socket::getOutputStream() {
checkClosed();
try{
if( isOutputShutdown() ) {
throw IOException( __FILE__, __LINE__, "Output was shutdown on this Socket." );
}
return this->impl->getOutputStream();
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::shutdownInput() {
if( isInputShutdown() ) {
throw IOException( __FILE__, __LINE__, "Socket input has already been shutdown." );
}
checkClosed();
try{
this->impl->shutdownInput();
this->inputShutdown = true;
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::shutdownOutput() {
if( isOutputShutdown() ) {
throw IOException( __FILE__, __LINE__, "Socket output has already been shutdown." );
}
checkClosed();
try{
this->impl->shutdownOutput();
this->outputShutdown = true;
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getSoLinger() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_LINGER );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setSoLinger( bool state, int timeout ) {
checkClosed();
try{
ensureCreated();
if( state && timeout < 0 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Timeout value passed is invalid: %d", timeout );
}
int value = state ? ( 65535 > timeout ? timeout : 65535 ) : -1;
this->impl->setOption( SocketOptions::SOCKET_OPTION_LINGER, value );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
bool Socket::getKeepAlive() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_KEEPALIVE ) == 0 ? false : true;
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setKeepAlive( bool keepAlive ) {
checkClosed();
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_KEEPALIVE, keepAlive ? 1 : 0 );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getReceiveBufferSize() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_RCVBUF );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setReceiveBufferSize( int size ) {
checkClosed();
if( size <= 0 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Buffer size given was invalid: %d", size );
}
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_RCVBUF, size );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
bool Socket::getReuseAddress() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_REUSEADDR ) == 0 ? false : true;
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setReuseAddress( bool reuse ) {
checkClosed();
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_REUSEADDR, reuse ? 1 : 0 );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getSendBufferSize() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_SNDBUF );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setSendBufferSize( int size ) {
checkClosed();
if( size <= 0 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Buffer size given was invalid: %d", size );
}
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_SNDBUF, size );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getSoTimeout() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_TIMEOUT );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setSoTimeout( int timeout ) {
checkClosed();
if( timeout < 0 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Socket timeout given was invalid: %d", timeout );
}
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_TIMEOUT, timeout );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
bool Socket::getTcpNoDelay() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_TCP_NODELAY ) == 0 ? false : true;
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setTcpNoDelay( bool value ) {
checkClosed();
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_TCP_NODELAY, value ? 1 : 0 );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
int Socket::getTrafficClass() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_IP_TOS );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setTrafficClass( int value ) {
checkClosed();
if( value < 0 || value > 255 ) {
throw IllegalArgumentException(
__FILE__, __LINE__, "Value of the Traffic class option was invalid: %d", value );
}
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_IP_TOS, value );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_RETHROW( IllegalArgumentException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
bool Socket::getOOBInline() const {
checkClosed();
try{
ensureCreated();
return this->impl->getOption( SocketOptions::SOCKET_OPTION_OOBINLINE ) == 0 ? false : true;
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setOOBInline( bool value ) {
checkClosed();
try{
ensureCreated();
this->impl->setOption( SocketOptions::SOCKET_OPTION_OOBINLINE, value ? 1 : 0 );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::sendUrgentData( int data ) {
checkClosed();
try{
ensureCreated();
this->impl->sendUrgentData( data & 0xFF );
}
DECAF_CATCH_RETHROW( SocketException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, SocketException )
DECAF_CATCHALL_THROW( SocketException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::checkClosed() const {
if( this->closed ) {
throw IOException( __FILE__, __LINE__, "Socket already closed." );
}
}
////////////////////////////////////////////////////////////////////////////////
void Socket::ensureCreated() const {
try{
if( !this->created ) {
this->impl->create();
this->created = true;
}
}
DECAF_CATCH_RETHROW( IOException )
DECAF_CATCH_EXCEPTION_CONVERT( Exception, IOException )
DECAF_CATCHALL_THROW( IOException )
}
////////////////////////////////////////////////////////////////////////////////
void Socket::setSocketImplFactory( SocketImplFactory* factory ) {
if( Socket::factory != NULL ) {
throw SocketException(
__FILE__, __LINE__, "A SocketInplFactory was already set." );
}
Socket::factory = factory;
}
////////////////////////////////////////////////////////////////////////////////
void Socket::accepted() {
this->created = true;
this->bound = true;
this->connected = true;
}
////////////////////////////////////////////////////////////////////////////////
std::string Socket::toString() const {
if( !isConnected() ) {
return "Socket[unconnected]";
}
return impl->toString();
}