jsocket.cpp 7.22 KB
/***************************************************************************
 *   Copyright (C) 2005 by Jeff Ferr                                       *
 *   root@sat                                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "jsocket.h"
#include "jsocketexception.h"
#include "jsockettimeoutexception.h"

#include <string>
#include <errno.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>

namespace jsocket {

Socket::Socket(InetAddress *addr_, uint16_t port_)
{
    _buffer = NULL;
    _sock_opt = NULL;
    _is = NULL;
    _os = NULL;
    _local = NULL;
    _address = NULL;

	CreateSocket();
	ConnectSocket(addr_, port_);
	InitStreams();

	_sent_bytes = 0;
	_receive_bytes = 0;
}

Socket::Socket(InetAddress *addr_, uint16_t port_, InetAddress *local_addr_, uint16_t local_port_)
{
    _buffer = NULL;
    _sock_opt = NULL;
    _is = NULL;
    _os = NULL;
    _local = NULL;
    _address = NULL;

	CreateSocket();
	BindSocket(local_addr_, local_port_);
	ConnectSocket(addr_, port_);
	InitStreams();

	_sent_bytes = 0;
	_receive_bytes = 0;
}

Socket::Socket(std::string host_, uint16_t port_)
{
    _buffer = NULL;
    _sock_opt = NULL;
    _is = NULL;
    _os = NULL;
    _local = NULL;
    _address = NULL;

	InetAddress *address = InetAddress::GetByName(host_);

	if (address == NULL) {
		// TODO:: throw
	}
	
	CreateSocket();
	ConnectSocket(address, port_);
	InitStreams();

	_sent_bytes = 0;
	_receive_bytes = 0;
}

Socket::Socket(std::string host_, uint16_t port_, InetAddress *local_addr_, uint16_t local_port_)
{
    _buffer = NULL;
    _sock_opt = NULL;
    _is = NULL;
    _os = NULL;
    _local = NULL;
    _address = NULL;

	InetAddress *address = InetAddress::GetByName(host_);
  
	if (address == NULL) {
		// TODO:: throw
	}
	
	CreateSocket();
	BindSocket(local_addr_, local_port_);
	ConnectSocket(address, port_);
	InitStreams();

	_sent_bytes = 0;
	_receive_bytes = 0;
}

Socket::~Socket()
{
    try {
    	Close();
    } catch (...) {
    }

    if (_buffer != NULL) {
        delete _buffer;
    }

    if (_sock_opt != NULL) {
        delete _sock_opt;
    }

    if (_is != NULL) {
        delete _is;
    }

    if (_os != NULL) {
        delete _os;
    }

    if (_local != NULL) {
        delete _local;
    }

    if (_address != NULL) {
        delete _address;
    }
}

/** Private */

Socket::Socket(uint16_t handler_, sockaddr_in server_)
{
	socklen_t len;
    
	_lsock.sin_family = AF_INET;
    
	if (getpeername(handler_, (sockaddr *)&_lsock, &len) < 0) {
        throw SocketException("Connetion error !");
	}
        
	if (getsockname(handler_, (sockaddr *)&_lsock, &len) < 0) {
		throw SocketException("Connection error !");
    }
    
	InitStreams();
   
	_fd = handler_;
	_server_sock = server_;
    
	_address = InetAddress::GetByName((std::string)inet_ntoa(server_.sin_addr));
	_local = InetAddress::GetLocalHost();
}

void Socket::CreateSocket()
{
	_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   
	if (_fd < 0) {
		throw SocketException("Create socket error !");
    }
}

void Socket::BindSocket(InetAddress *local_addr_, uint16_t local_port_)
{
	_local = local_addr_;
   
	bzero(&_lsock, sizeof(_lsock));

	_lsock.sin_family = AF_INET;

	if (local_addr_ == NULL) {
		_lsock.sin_addr.s_addr = INADDR_ANY;
	} else {
		_lsock.sin_addr.s_addr = inet_addr(local_addr_->GetHostAddress().c_str());
	}
    
	_lsock.sin_port = htons(local_port_);

	if (bind(_fd, (sockaddr *)&_lsock, sizeof(_lsock)) < 0) {
		throw SocketException("Bind socket error !");
	}
}

void Socket::ConnectSocket(InetAddress *addr_, u_int16_t port_)
{
	_address = addr_;
   
	bzero(&_server_sock, sizeof(_server_sock));
   
	_server_sock.sin_family = AF_INET;
	_server_sock.sin_addr.s_addr  = inet_addr(addr_->GetHostAddress().c_str());
	_server_sock.sin_port = htons(port_);

	if (connect(_fd, (sockaddr *)&_server_sock, sizeof(_server_sock)) < 0) {
		throw SocketException("Connect socket error !");
	}
}

void Socket::InitStreams()
{
	_buffer = new SocketBuffer(_fd);
	
	_is = new std::istream(_buffer);
	_os = new std::ostream(_buffer);
}

/** End */

uint16_t Socket::Send(char *data_, int size_)
{
	int n;
    
	n = ::send(_fd, data_, size_, 0);
    
	if (n < 0 && errno == EAGAIN) {
		throw SocketTimeoutException("Socket send timeout exception !");
	} else if (n < 0) {
		throw SocketException("Send socket error !");
	}

	_sent_bytes += n;
    
	return n;
}

/**
 *	If return is 0, then peer has shutdown
 */
uint16_t Socket::Receive(char *b_, int size_)
{
	int n;      
  
	n = ::recv(_fd, b_, size_, 0);

	if (n < 0 && errno == EAGAIN) {
		throw SocketTimeoutException("Socket receive timeout exception !");
	} else if (n < 0) {
		throw SocketException("Read socket error !");
	}
	
	_receive_bytes += n;
    
	return n;
}

int16_t Socket::GetHandler()
{
	return _fd;
}

void Socket::Close()
{
	if (close(_fd) < 0) {
		throw SocketException("Close socket error !");
	}
}

std::istream & Socket::GetInputStream()
{
	return *_is;
}

std::ostream & Socket::GetOutputStream()
{
	return *_os;
}

InetAddress * Socket::GetInetAddress()
{
	return _address;
}

InetAddress * Socket::GetLocalAddress()
{
	return _local;
}

uint16_t Socket::GetLocalPort()
{
	return ntohs(_lsock.sin_port);
}

uint16_t Socket::GetPort()
{
	return ntohs(_server_sock.sin_port);
}

uint64_t Socket::GetSentBytes()
{
	if (_sent_bytes != 0) {
		return _sent_bytes;
	} else {
		return _buffer->GetSentBytes();
	}
}

uint64_t Socket::GetReceiveBytes()
{
	if (_receive_bytes != 0) {
		return _receive_bytes;
	} else {
		return _buffer->GetReceiveBytes();
	}
}

SocketOption * Socket::GetSocketOption()
{
	return new SocketOption(_fd, SOCK_TCP);
}

std::string Socket::what()
{
	char *port = (char *)malloc(10);

	sprintf(port, "%u", GetPort());

	return GetInetAddress()->GetHostName() + ":" + port;
}

};