/*************************************************************************** * 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 #include #include #include #include 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; } };