Started over.

This commit is contained in:
crs
2001-10-06 14:13:28 +00:00
parent 27ead1f713
commit ff81f708e2
132 changed files with 7634 additions and 3960 deletions

65
net/CNetworkAddress.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "CNetworkAddress.h"
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//
// CNetworkAddress
//
CNetworkAddress::CNetworkAddress(UInt16 port) throw(XSocketAddress)
{
if (port == 0)
throw XSocketAddress(XSocketAddress::kBadPort, CString(), port);
struct sockaddr_in* inetAddress = reinterpret_cast<struct sockaddr_in*>(&m_address);
inetAddress->sin_family = AF_INET;
inetAddress->sin_port = htons(port);
inetAddress->sin_addr.s_addr = INADDR_ANY;
::memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
}
CNetworkAddress::CNetworkAddress(const CString& hostname, UInt16 port)
throw(XSocketAddress)
{
if (port == 0)
throw XSocketAddress(XSocketAddress::kBadPort, hostname, port);
struct hostent* hent = gethostbyname(hostname.c_str());
if (hent == NULL) {
switch (h_errno) {
case HOST_NOT_FOUND:
throw XSocketAddress(XSocketAddress::kNotFound, hostname, port);
case NO_DATA:
throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port);
case NO_RECOVERY:
case TRY_AGAIN:
default:
throw XSocketAddress(XSocketAddress::kUnknown, hostname, port);
}
}
struct sockaddr_in* inetAddress = reinterpret_cast<struct sockaddr_in*>(&m_address);
inetAddress->sin_family = hent->h_addrtype;
inetAddress->sin_port = htons(port);
::memcpy(&inetAddress->sin_addr, hent->h_addr_list[0], hent->h_length);
::memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
}
CNetworkAddress::~CNetworkAddress()
{
// do nothing
}
const struct sockaddr* CNetworkAddress::getAddress() const throw()
{
return &m_address;
}
int CNetworkAddress::getAddressLength() const throw()
{
return sizeof(m_address);
}

27
net/CNetworkAddress.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef CNETWORKADDRESS_H
#define CNETWORKADDRESS_H
#include "BasicTypes.h"
#include "XSocket.h"
#include <sys/socket.h>
class CString;
class CNetworkAddress {
public:
CNetworkAddress(UInt16 port) throw(XSocketAddress);
CNetworkAddress(const CString& hostname, UInt16 port) throw(XSocketAddress);
~CNetworkAddress();
// manipulators
// accessors
const struct sockaddr* getAddress() const throw();
int getAddressLength() const throw();
private:
struct sockaddr m_address;
};
#endif

View File

@@ -0,0 +1,93 @@
#include "CSocketInputStream.h"
#include "CLock.h"
#include "CMutex.h"
#include "CThread.h"
#include "IJob.h"
#include "XIO.h"
#include <string.h>
#include <assert.h>
//
// CSocketInputStream
//
CSocketInputStream::CSocketInputStream(CMutex* mutex, IJob* closeCB) :
m_mutex(mutex),
m_empty(mutex, true),
m_closeCB(closeCB),
m_closed(false),
m_hungup(false)
{
assert(m_mutex != NULL);
}
CSocketInputStream::~CSocketInputStream()
{
delete m_closeCB;
}
void CSocketInputStream::write(
const void* data, UInt32 n) throw()
{
if (!m_hungup && n > 0) {
m_buffer.write(data, n);
m_empty = (m_buffer.getSize() == 0);
m_empty.broadcast();
}
}
void CSocketInputStream::hangup() throw()
{
m_hungup = true;
m_empty.broadcast();
}
void CSocketInputStream::close() throw(XIO)
{
CLock lock(m_mutex);
if (m_closed) {
throw XIOClosed();
}
m_closed = true;
if (m_closeCB) {
m_closeCB->run();
}
}
UInt32 CSocketInputStream::read(
void* dst, UInt32 n) throw(XIO)
{
CLock lock(m_mutex);
if (m_closed) {
throw XIOClosed();
}
// wait for data (or hangup)
while (!m_hungup && m_empty == true) {
m_empty.wait();
}
// read data
const UInt32 count = m_buffer.getSize();
if (n > count) {
n = count;
}
if (n > 0) {
::memcpy(dst, m_buffer.peek(n), n);
m_buffer.pop(n);
}
// update empty state
if (m_buffer.getSize() == 0) {
m_empty = true;
m_empty.broadcast();
}
return n;
}
UInt32 CSocketInputStream::getSize() const throw()
{
CLock lock(m_mutex);
return m_buffer.getSize();
}

42
net/CSocketInputStream.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef CSOCKETINPUTSTREAM_H
#define CSOCKETINPUTSTREAM_H
#include "CSocketStreamBuffer.h"
#include "CCondVar.h"
#include "IInputStream.h"
class CMutex;
class IJob;
class CSocketInputStream : public IInputStream {
public:
CSocketInputStream(CMutex*, IJob* adoptedCloseCB);
~CSocketInputStream();
// manipulators
// write() appends n bytes to the buffer
void write(const void*, UInt32 n) throw();
// causes read() to always return immediately. if there is no
// more data then it returns 0. further writes are discarded.
void hangup() throw();
// accessors
// IInputStream overrides
// these all lock the mutex for their duration
virtual void close() throw(XIO);
virtual UInt32 read(void*, UInt32 count) throw(XIO);
virtual UInt32 getSize() const throw();
private:
CMutex* m_mutex;
CCondVar<bool> m_empty;
IJob* m_closeCB;
CSocketStreamBuffer m_buffer;
bool m_closed;
bool m_hungup;
};
#endif

View File

@@ -0,0 +1,78 @@
#include "CSocketOutputStream.h"
#include "CLock.h"
#include "CMutex.h"
#include "CThread.h"
#include "IJob.h"
#include "XIO.h"
#include <assert.h>
//
// CSocketOutputStream
//
CSocketOutputStream::CSocketOutputStream(CMutex* mutex, IJob* closeCB) :
m_mutex(mutex),
m_closeCB(closeCB),
m_closed(false)
{
assert(m_mutex != NULL);
}
CSocketOutputStream::~CSocketOutputStream()
{
delete m_closeCB;
}
const void* CSocketOutputStream::peek(UInt32 n) throw()
{
return m_buffer.peek(n);
}
void CSocketOutputStream::pop(UInt32 n) throw()
{
m_buffer.pop(n);
}
UInt32 CSocketOutputStream::getSize() const throw()
{
return m_buffer.getSize();
}
void CSocketOutputStream::close() throw(XIO)
{
CLock lock(m_mutex);
if (m_closed) {
throw XIOClosed();
}
m_closed = true;
if (m_closeCB) {
m_closeCB->run();
}
}
UInt32 CSocketOutputStream::write(
const void* data, UInt32 n) throw(XIO)
{
CLock lock(m_mutex);
if (m_closed) {
throw XIOClosed();
}
m_buffer.write(data, n);
return n;
}
void CSocketOutputStream::flush() throw(XIO)
{
// wait until all data is written
while (getSizeWithLock() > 0) {
CThread::sleep(0.05);
}
}
UInt32 CSocketOutputStream::getSizeWithLock() const throw()
{
CLock lock(m_mutex);
return m_buffer.getSize();
}

43
net/CSocketOutputStream.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef CSOCKETOUTPUTSTREAM_H
#define CSOCKETOUTPUTSTREAM_H
#include "CSocketStreamBuffer.h"
#include "IOutputStream.h"
class CMutex;
class IJob;
class CSocketOutputStream : public IOutputStream {
public:
CSocketOutputStream(CMutex*, IJob* adoptedCloseCB);
~CSocketOutputStream();
// manipulators
// peek() returns a buffer of n bytes (which must be <= getSize()).
// pop() discards the next n bytes.
const void* peek(UInt32 n) throw();
void pop(UInt32 n) throw();
// accessors
// return the number of bytes in the buffer
UInt32 getSize() const throw();
// IOutputStream overrides
// these all lock the mutex for their duration
virtual void close() throw(XIO);
virtual UInt32 write(const void*, UInt32 count) throw(XIO);
virtual void flush() throw(XIO);
private:
UInt32 getSizeWithLock() const throw();
private:
CMutex* m_mutex;
IJob* m_closeCB;
CSocketStreamBuffer m_buffer;
bool m_closed;
};
#endif

106
net/CSocketStreamBuffer.cpp Normal file
View File

@@ -0,0 +1,106 @@
#include "CSocketStreamBuffer.h"
#include <assert.h>
//
// CSocketStreamBuffer
//
const UInt32 CSocketStreamBuffer::kChunkSize = 4096;
CSocketStreamBuffer::CSocketStreamBuffer() : m_size(0)
{
// do nothing
}
CSocketStreamBuffer::~CSocketStreamBuffer()
{
// do nothing
}
const void* CSocketStreamBuffer::peek(UInt32 n) throw()
{
assert(n <= m_size);
// reserve space in first chunk
ChunkList::iterator head = m_chunks.begin();
head->reserve(n);
// consolidate chunks into the first chunk until it has n bytes
ChunkList::iterator scan = head;
++scan;
while (head->size() < n && scan != m_chunks.end()) {
head->insert(head->end(), scan->begin(), scan->end());
scan = m_chunks.erase(scan);
}
return reinterpret_cast<const void*>(head->begin());
}
void CSocketStreamBuffer::pop(UInt32 n) throw()
{
m_size -= n;
// discard chunks until more than n bytes would've been discarded
ChunkList::iterator scan = m_chunks.begin();
while (scan->size() <= n && scan != m_chunks.end()) {
n -= scan->size();
scan = m_chunks.erase(scan);
}
// if there's anything left over then remove it from the head chunk.
// if there's no head chunk then we're already empty.
if (scan == m_chunks.end()) {
m_size = 0;
}
else if (n > 0) {
scan->erase(scan->begin(), scan->begin() + n);
}
}
void CSocketStreamBuffer::write(
const void* vdata, UInt32 n) throw()
{
assert(vdata != NULL);
if (n == 0) {
return;
}
m_size += n;
// cast data to bytes
const UInt8* data = reinterpret_cast<const UInt8*>(vdata);
// point to last chunk if it has space, otherwise append an empty chunk
ChunkList::iterator scan = m_chunks.end();
if (scan != m_chunks.begin()) {
--scan;
if (scan->size() >= kChunkSize)
++scan;
}
if (scan == m_chunks.end()) {
scan = m_chunks.insert(scan);
}
// append data in chunks
while (n > 0) {
// choose number of bytes for next chunk
UInt32 count = kChunkSize - scan->size();
if (count > n)
count = n;
// transfer data
scan->insert(scan->end(), data, data + count);
n -= count;
data += count;
// append another empty chunk if we're not done yet
if (n > 0) {
scan = m_chunks.insert(scan);
}
}
}
UInt32 CSocketStreamBuffer::getSize() const throw()
{
return m_size;
}

38
net/CSocketStreamBuffer.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef CSOCKETSTREAMBUFFER_H
#define CSOCKETSTREAMBUFFER_H
#include "BasicTypes.h"
#include <list>
#include <vector>
class CSocketStreamBuffer {
public:
CSocketStreamBuffer();
~CSocketStreamBuffer();
// manipulators
// peek() returns a buffer of n bytes (which must be <= getSize()).
// pop() discards the next n bytes.
const void* peek(UInt32 n) throw();
void pop(UInt32 n) throw();
// write() appends n bytes to the buffer
void write(const void*, UInt32 n) throw();
// accessors
// return the number of bytes in the buffer
UInt32 getSize() const throw();
private:
static const UInt32 kChunkSize;
typedef std::vector<UInt8> Chunk;
typedef std::list<Chunk> ChunkList;
ChunkList m_chunks;
UInt32 m_size;
};
#endif

72
net/CTCPListenSocket.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "CTCPListenSocket.h"
#include "CTCPSocket.h"
#include "CNetworkAddress.h"
#include "CThread.h"
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//
// CTCPListenSocket
//
CTCPListenSocket::CTCPListenSocket()
{
m_fd = socket(PF_INET, SOCK_STREAM, 0);
if (m_fd == -1) {
throw XSocketCreate();
}
}
CTCPListenSocket::~CTCPListenSocket()
{
try {
close();
}
catch (...) {
// ignore
}
}
void CTCPListenSocket::bind(
const CNetworkAddress& addr) throw(XSocket)
{
if (::bind(m_fd, addr.getAddress(), addr.getAddressLength()) == -1) {
if (errno == EADDRINUSE) {
throw XSocketAddressInUse();
}
throw XSocketBind();
}
if (listen(m_fd, 3) == -1) {
throw XSocketBind();
}
}
ISocket* CTCPListenSocket::accept() throw(XSocket)
{
for (;;) {
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
CThread::testCancel();
int fd = ::accept(m_fd, &addr, &addrlen);
if (fd == -1) {
CThread::testCancel();
}
else {
return new CTCPSocket(fd);
}
}
}
void CTCPListenSocket::close() throw(XIO)
{
if (m_fd == -1) {
throw XIOClosed();
}
if (::close(m_fd) == -1) {
throw XIOClose();
}
m_fd = -1;
}

24
net/CTCPListenSocket.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef CTCPLISTENSOCKET_H
#define CTCPLISTENSOCKET_H
#include "IListenSocket.h"
class CTCPListenSocket : public IListenSocket {
public:
CTCPListenSocket();
~CTCPListenSocket();
// manipulators
// accessors
// IListenSocket overrides
virtual void bind(const CNetworkAddress&) throw(XSocket);
virtual ISocket* accept() throw(XSocket);
virtual void close() throw(XIO);
private:
int m_fd;
};
#endif

226
net/CTCPSocket.cpp Normal file
View File

@@ -0,0 +1,226 @@
#include "CTCPSocket.h"
#include "CBufferedInputStream.h"
#include "CBufferedOutputStream.h"
#include "CNetworkAddress.h"
#include "CLock.h"
#include "CMutex.h"
#include "CCondVar.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CStopwatch.h"
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <assert.h>
//
// CTCPSocket
//
CTCPSocket::CTCPSocket() throw(XSocket)
{
m_fd = socket(PF_INET, SOCK_STREAM, 0);
if (m_fd == -1) {
throw XSocketCreate();
}
init();
}
CTCPSocket::CTCPSocket(int fd) throw() :
m_fd(fd)
{
assert(m_fd != -1);
init();
// socket starts in connected state
m_connected = kReadWrite;
// start handling socket
m_thread = new CThread(new TMethodJob<CTCPSocket>(
this, &CTCPSocket::service));
}
CTCPSocket::~CTCPSocket()
{
try {
close();
}
catch (...) {
// ignore failures
}
// clean up
delete m_mutex;
delete m_input;
delete m_output;
}
void CTCPSocket::bind(const CNetworkAddress& addr)
throw(XSocket)
{
if (::bind(m_fd, addr.getAddress(), addr.getAddressLength()) == -1) {
if (errno == EADDRINUSE) {
throw XSocketAddressInUse();
}
throw XSocketBind();
}
}
void CTCPSocket::connect(const CNetworkAddress& addr)
throw(XSocket)
{
CThread::testCancel();
if (::connect(m_fd, addr.getAddress(), addr.getAddressLength()) == -1) {
CThread::testCancel();
throw XSocketConnect();
}
// start servicing the socket
m_connected = kReadWrite;
m_thread = new CThread(new TMethodJob<CTCPSocket>(
this, &CTCPSocket::service));
}
void CTCPSocket::close() throw(XIO)
{
// shutdown I/O thread before close
if (m_thread != NULL) {
// flush if output buffer not empty and output buffer not closed
bool doFlush;
{
CLock lock(m_mutex);
doFlush = ((m_connected & kWrite) != 0);
}
if (doFlush) {
m_output->flush();
}
m_thread->cancel();
m_thread->wait();
delete m_thread;
m_thread = NULL;
}
CLock lock(m_mutex);
if (m_fd != -1) {
if (::close(m_fd) == -1) {
throw XIOClose();
}
m_fd = -1;
}
}
IInputStream* CTCPSocket::getInputStream() throw()
{
return m_input;
}
IOutputStream* CTCPSocket::getOutputStream() throw()
{
return m_output;
}
void CTCPSocket::init() throw(XIO)
{
m_mutex = new CMutex;
m_thread = NULL;
m_connected = kClosed;
m_input = new CBufferedInputStream(m_mutex,
new TMethodJob<CTCPSocket>(
this, &CTCPSocket::closeInput));
m_output = new CBufferedOutputStream(m_mutex,
new TMethodJob<CTCPSocket>(
this, &CTCPSocket::closeOutput));
}
void CTCPSocket::service(void*) throw(XThread)
{
assert(m_fd != -1);
// now service the connection
struct pollfd pfds[1];
pfds[0].fd = m_fd;
for (;;) {
{
// choose events to poll for
CLock lock(m_mutex);
pfds[0].events = 0;
if ((m_connected & kRead) != 0) {
// still open for reading
pfds[0].events |= POLLIN;
}
if ((m_connected & kWrite) != 0 && m_output->getSize() > 0) {
// data queued for writing
pfds[0].events |= POLLOUT;
}
}
// check for status
CThread::testCancel();
const int status = poll(pfds, 1, 50);
CThread::testCancel();
// transfer data and handle errors
if (status == 1) {
if ((pfds[0].revents & (POLLERR | POLLNVAL)) != 0) {
// stream is no good anymore so bail
m_input->hangup();
return;
}
// read some data
if (pfds[0].revents & POLLIN) {
UInt8 buffer[4096];
ssize_t n = read(m_fd, buffer, sizeof(buffer));
if (n > 0) {
CLock lock(m_mutex);
m_input->write(buffer, n);
}
else if (n == 0) {
// stream hungup
m_input->hangup();
return;
}
}
// write some data
if (pfds[0].revents & POLLOUT) {
CLock lock(m_mutex);
// get amount of data to write
UInt32 n = m_output->getSize();
if (n > 4096) {
// limit write size
n = 4096;
}
// write data
const void* buffer = m_output->peek(n);
n = write(m_fd, buffer, n);
// discard written data
if (n > 0) {
m_output->pop(n);
}
}
}
}
}
void CTCPSocket::closeInput(void*) throw()
{
// note -- m_mutex should already be locked
shutdown(m_fd, 0);
m_connected &= ~kRead;
}
void CTCPSocket::closeOutput(void*) throw()
{
// note -- m_mutex should already be locked
shutdown(m_fd, 1);
m_connected &= ~kWrite;
}

49
net/CTCPSocket.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef CTCPSOCKET_H
#define CTCPSOCKET_H
#include "ISocket.h"
#include "XThread.h"
class CMutex;
template <class T>
class CCondVar;
class CThread;
class CBufferedInputStream;
class CBufferedOutputStream;
class CTCPSocket : public ISocket {
public:
CTCPSocket() throw(XSocket);
CTCPSocket(int fd) throw();
~CTCPSocket();
// manipulators
// accessors
// ISocket overrides
virtual void bind(const CNetworkAddress&) throw(XSocket);
virtual void connect(const CNetworkAddress&) throw(XSocket);
virtual void close() throw(XIO);
virtual IInputStream* getInputStream() throw();
virtual IOutputStream* getOutputStream() throw();
private:
void init() throw(XIO);
void service(void*) throw(XThread);
void closeInput(void*) throw();
void closeOutput(void*) throw();
private:
enum { kClosed = 0, kRead = 1, kWrite = 2, kReadWrite = 3 };
int m_fd;
CBufferedInputStream* m_input;
CBufferedOutputStream* m_output;
CMutex* m_mutex;
CThread* m_thread;
UInt32 m_connected;
};
#endif

27
net/IListenSocket.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef ILISTENSOCKET_H
#define ILISTENSOCKET_H
#include "IInterface.h"
#include "XIO.h"
#include "XSocket.h"
class CNetworkAddress;
class ISocket;
class IListenSocket : public IInterface {
public:
// manipulators
// bind the socket to a particular address
virtual void bind(const CNetworkAddress&) throw(XSocket) = 0;
// wait for a connection
virtual ISocket* accept() throw(XSocket) = 0;
// close the socket
virtual void close() throw(XIO) = 0;
// accessors
};
#endif

35
net/ISocket.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef ISOCKET_H
#define ISOCKET_H
#include "IInterface.h"
#include "BasicTypes.h"
#include "XSocket.h"
#include "XIO.h"
class CNetworkAddress;
class IInputStream;
class IOutputStream;
class ISocket : public IInterface {
public:
// manipulators
// bind the socket to a particular address
virtual void bind(const CNetworkAddress&) throw(XSocket) = 0;
// connect the socket
virtual void connect(const CNetworkAddress&) throw(XSocket) = 0;
// close the socket. this will flush the output stream if it
// hasn't been closed yet.
virtual void close() throw(XIO) = 0;
// get the input and output streams for the socket. closing
// these streams closes the appropriate half of the socket.
virtual IInputStream* getInputStream() throw() = 0;
virtual IOutputStream* getOutputStream() throw() = 0;
// accessors
};
#endif

28
net/Makefile Normal file
View File

@@ -0,0 +1,28 @@
DEPTH=..
include $(DEPTH)/Makecommon
#
# target file
#
TARGET = net
#
# source files
#
LCXXINCS = \
-I$(DEPTH)/base \
-I$(DEPTH)/mt \
-I$(DEPTH)/io \
$(NULL)
CXXFILES = \
XSocket.cpp \
CNetworkAddress.cpp \
CTCPSocket.cpp \
CTCPListenSocket.cpp \
$(NULL)
targets: $(LIBTARGET)
$(LIBTARGET): $(OBJECTS)
if test ! -d $(LIBDIR); then $(MKDIR) $(LIBDIR); fi
$(ARF) $(LIBTARGET) $(OBJECTS)

84
net/XSocket.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "XSocket.h"
//
// XSocketAddress
//
XSocketAddress::XSocketAddress(Error error,
const CString& hostname, SInt16 port) throw() :
m_error(error),
m_hostname(hostname),
m_port(port)
{
// do nothing
}
XSocketAddress::Error XSocketAddress::getError() const throw()
{
return m_error;
}
CString XSocketAddress::getHostname() const throw()
{
return m_hostname;
}
SInt16 XSocketAddress::getPort() const throw()
{
return m_port;
}
CString XSocketAddress::getWhat() const throw()
{
return "no address";
/*
return format("XSocketAddress", "no address: %1:%2",
m_hostname.t_str(),
CString::sprintf("%d", m_port).t_str());
*/
}
//
// XSocketErrno
//
XSocketErrno::XSocketErrno() : MXErrno()
{
// do nothing
}
XSocketErrno::XSocketErrno(int err) : MXErrno(err)
{
// do nothing
}
//
// XSocketBind
//
CString XSocketBind::getWhat() const throw()
{
return format("XSocketBind", "cannot bind address");
}
//
// XSocketConnect
//
CString XSocketConnect::getWhat() const throw()
{
return format("XSocketConnect", "cannot connect socket");
}
//
// XSocketCreate
//
CString XSocketCreate::getWhat() const throw()
{
return format("XSocketCreate", "cannot create socket");
}

58
net/XSocket.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef XSOCKET_H
#define XSOCKET_H
#include "CString.h"
#include "XBase.h"
#include "BasicTypes.h"
class XSocket : public XBase { };
class XSocketAddress : public XSocket {
public:
enum Error { kUnknown, kNotFound, kNoAddress, kBadPort };
XSocketAddress(Error, const CString& hostname, SInt16 port) throw();
// accessors
virtual Error getError() const throw();
virtual CString getHostname() const throw();
virtual SInt16 getPort() const throw();
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
Error m_error;
CString m_hostname;
SInt16 m_port;
};
class XSocketErrno : public XSocket, public MXErrno {
public:
XSocketErrno();
XSocketErrno(int);
};
class XSocketBind : public XSocketErrno {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
class XSocketAddressInUse : public XSocketBind { };
class XSocketConnect : public XSocketErrno {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
class XSocketCreate : public XSocketErrno {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
#endif