/*
* C++ sockets on Unix and Windows
* Copyright (C) 2002
*
* 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 "PracticalSocket.h"
#ifdef WIN32
#include // For socket(), connect(), send(), and recv()
typedef int socklen_t;
typedef char raw_type; // Type used for raw data on this platform
#else
#include // For socket(), connect(), send(), and recv()
#include // For gethostbyname()
#include // For inet_addr()
#include // For close()
typedef void raw_type; // Type used for raw data on this platform
#endif
#include
#include
#include
#include
//using namespace std;
#ifdef WIN32
static bool initialized = false;
#endif
// SocketException Code
SocketException::SocketException(const std::string &message, bool inclSysMsg)
throw() : userMessage(message) {
if (inclSysMsg) {
userMessage.append(": ");
userMessage.append(strerror(errno));
}
}
SocketException::~SocketException() throw() {
}
const char *SocketException::what() const throw() {
return userMessage.c_str();
}
// Function to fill in address structure given an address and port
static void fillAddr(const std::string &address, unsigned short port, addrinfo **addr) {
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
std::stringstream p;
p << port;
int rv;
if ((rv = getaddrinfo(address.c_str(), p.str().c_str(), &hints, addr)) != 0) {
std::cout << gai_strerror(rv) << std::endl;
throw SocketException("Failed to resolve name (gethostbyname())");
}
std::cout << "Address filled" << std::endl;
//freeaddrinfo(&hints);
}
// Socket Code
Socket::Socket(int type, int protocol) throw(SocketException) {
#ifdef WIN32
if (!initialized) {
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 0); // Request WinSock v2.0
if (WSAStartup(wVersionRequested, &wsaData) != 0) { // Load WinSock DLL
throw SocketException("Unable to load WinSock DLL");
}
initialized = true;
}
#endif
// Make a new socket
if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
throw SocketException("Socket creation failed (socket())", true);
}
}
Socket::Socket(int sockDesc) {
this->sockDesc = sockDesc;
}
Socket::~Socket() {
#ifdef WIN32
::closesocket(sockDesc);
#else
::close(sockDesc);
#endif
sockDesc = -1;
}
std::string Socket::getLocalAddress() throw(SocketException) {
sockaddr_in addr;
unsigned int addr_len = sizeof(addr);
if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
throw SocketException("Fetch of local address failed (getsockname())", true);
}
return inet_ntoa(addr.sin_addr);
}
unsigned short Socket::getLocalPort() throw(SocketException) {
sockaddr_in addr;
unsigned int addr_len = sizeof(addr);
if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
throw SocketException("Fetch of local port failed (getsockname())", true);
}
return ntohs(addr.sin_port);
}
void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
// Bind the socket to its port
sockaddr_in localAddr;
memset(&localAddr, 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = htons(localPort);
if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
throw SocketException("Set of local port failed (bind())", true);
}
}
void Socket::setLocalAddressAndPort(const std::string &localAddress,
unsigned short localPort) throw(SocketException) {
// Get the address of the requested host
addrinfo *localAddr;
fillAddr(localAddress, localPort, &localAddr);
if (bind(sockDesc, localAddr->ai_addr, localAddr->ai_addrlen) < 0) {
throw SocketException("Set of local address and port failed (bind())", true);
}
freeaddrinfo(localAddr);
}
void Socket::cleanUp() throw(SocketException) {
#ifdef WIN32
if (WSACleanup() != 0) {
throw SocketException("WSACleanup() failed");
}
#endif
}
unsigned short Socket::resolveService(const std::string &service,
const std::string &protocol) {
struct servent *serv; /* Structure containing service information */
if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
return atoi(service.c_str()); /* Service is port number */
else
return ntohs(serv->s_port); /* Found port (network byte order) by name */
}
// CommunicatingSocket Code
CommunicatingSocket::CommunicatingSocket(int type, int protocol)
throw(SocketException) : Socket(type, protocol) {
}
CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
}
void CommunicatingSocket::connect(const std::string &foreignAddress,
unsigned short foreignPort) throw(SocketException) {
// Get the address of the requested host
struct addrinfo *servinfo, *p;
fillAddr(foreignAddress, foreignPort, &servinfo);
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockDesc = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
std::cerr << "Socket" << std::endl;
continue;
}
if (::connect(sockDesc, p->ai_addr, p->ai_addrlen) == -1) {
std::cerr << "Error connecting" << std::endl;
close(sockDesc);
// throw SocketException("Connect failed (connect())", true);
continue;
}
break;
}
freeaddrinfo(servinfo);
}
void CommunicatingSocket::send(const void *buffer, int bufferLen)
throw(SocketException) {
if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
throw SocketException("Send failed (send())", true);
}
}
int CommunicatingSocket::recv(void *buffer, int bufferLen)
throw(SocketException) {
int rtn;
if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
throw SocketException("Received failed (recv())", true);
}
return rtn;
}
std::string CommunicatingSocket::getForeignAddress()
throw(SocketException) {
sockaddr_in addr;
unsigned int addr_len = sizeof(addr);
if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
throw SocketException("Fetch of foreign address failed (getpeername())", true);
}
return inet_ntoa(addr.sin_addr);
}
unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
sockaddr_in addr;
unsigned int addr_len = sizeof(addr);
if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
throw SocketException("Fetch of foreign port failed (getpeername())", true);
}
return ntohs(addr.sin_port);
}
// TCPSocket Code
TCPSocket::TCPSocket()
throw(SocketException) : CommunicatingSocket(SOCK_STREAM,
IPPROTO_TCP) {
}
TCPSocket::TCPSocket(const std::string &foreignAddress, unsigned short foreignPort)
throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
connect(foreignAddress, foreignPort);
}
TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) {
}
// TCPServerSocket Code
TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen)
throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
setLocalPort(localPort);
setListen(queueLen);
}
TCPServerSocket::TCPServerSocket(const std::string &localAddress,
unsigned short localPort, int queueLen)
throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
setLocalAddressAndPort(localAddress, localPort);
setListen(queueLen);
}
TCPSocket *TCPServerSocket::accept() throw(SocketException) {
int newConnSD;
if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
throw SocketException("Accept failed (accept())", true);
}
return new TCPSocket(newConnSD);
}
void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
if (listen(sockDesc, queueLen) < 0) {
throw SocketException("Set listening socket failed (listen())", true);
}
}