Reorganized source tree. Moved client.cpp into cmd/synergy as

synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp.
Moved and renamed related files.  Moved remaining source files
into lib/....  Modified and added makefiles as appropriate.
Result is that library files are under lib with each library
in its own directory and program files are under cmd with each
command in its own directory.
This commit is contained in:
crs
2002-07-30 16:52:46 +00:00
parent 9792d35a6b
commit fee4095624
201 changed files with 367 additions and 375 deletions

430
lib/net/CNetwork.cpp Normal file
View File

@@ -0,0 +1,430 @@
#include "CNetwork.h"
#include "XNetwork.h"
#include "CLog.h"
//
// CNetwork
//
CNetwork::Socket (PASCAL FAR *CNetwork::accept)(CNetwork::Socket s, CNetwork::Address FAR *addr, CNetwork::AddressLength FAR *addrlen);
int (PASCAL FAR *CNetwork::bind)(CNetwork::Socket s, const CNetwork::Address FAR *addr, CNetwork::AddressLength namelen);
int (PASCAL FAR *CNetwork::close)(CNetwork::Socket s);
int (PASCAL FAR *CNetwork::connect)(CNetwork::Socket s, const CNetwork::Address FAR *name, CNetwork::AddressLength namelen);
int (PASCAL FAR *CNetwork::ioctl)(CNetwork::Socket s, int cmd, void FAR *);
int (PASCAL FAR *CNetwork::getpeername)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen);
int (PASCAL FAR *CNetwork::getsockname)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen);
int (PASCAL FAR *CNetwork::getsockopt)(CNetwork::Socket s, int level, int optname, void FAR * optval, CNetwork::AddressLength FAR *optlen);
unsigned long (PASCAL FAR *CNetwork::inet_addr)(const char FAR * cp);
char FAR * (PASCAL FAR *CNetwork::inet_ntoa)(struct in_addr in);
int (PASCAL FAR *CNetwork::listen)(CNetwork::Socket s, int backlog);
ssize_t (PASCAL FAR *CNetwork::read)(CNetwork::Socket s, void FAR * buf, size_t len);
ssize_t (PASCAL FAR *CNetwork::recv)(CNetwork::Socket s, void FAR * buf, size_t len, int flags);
ssize_t (PASCAL FAR *CNetwork::recvfrom)(CNetwork::Socket s, void FAR * buf, size_t len, int flags, CNetwork::Address FAR *from, CNetwork::AddressLength FAR * fromlen);
int (PASCAL FAR *CNetwork::poll)(CNetwork::PollEntry fds[], int nfds, int timeout);
ssize_t (PASCAL FAR *CNetwork::send)(CNetwork::Socket s, const void FAR * buf, size_t len, int flags);
ssize_t (PASCAL FAR *CNetwork::sendto)(CNetwork::Socket s, const void FAR * buf, size_t len, int flags, const CNetwork::Address FAR *to, CNetwork::AddressLength tolen);
int (PASCAL FAR *CNetwork::setsockopt)(CNetwork::Socket s, int level, int optname, const void FAR * optval, CNetwork::AddressLength optlen);
int (PASCAL FAR *CNetwork::shutdown)(CNetwork::Socket s, int how);
CNetwork::Socket (PASCAL FAR *CNetwork::socket)(int af, int type, int protocol);
ssize_t (PASCAL FAR *CNetwork::write)(CNetwork::Socket s, const void FAR * buf, size_t len);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyaddr)(const char FAR * addr, int len, int type);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyname)(const char FAR * name);
int (PASCAL FAR *CNetwork::gethostname)(char FAR * name, int namelen);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyport)(int port, const char FAR * proto);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyname)(const char FAR * name, const char FAR * proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobynumber)(int proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobyname)(const char FAR * name);
int (PASCAL FAR *CNetwork::getsockerror)(void);
int (PASCAL FAR *CNetwork::gethosterror)(void);
int (PASCAL FAR *CNetwork::setblocking)(CNetwork::Socket s, bool blocking);
#if WINDOWS_LIKE
int (PASCAL FAR *CNetwork::select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
int (PASCAL FAR *CNetwork::WSACleanup)(void);
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
const int CNetwork::Error = SOCKET_ERROR;
const CNetwork::Socket CNetwork::Null = INVALID_SOCKET;
#undef FD_ISSET
#define FD_ISSET(fd, set) CNetwork::__WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))
static HMODULE s_networkModule = NULL;
static
FARPROC
netGetProcAddress(HMODULE module, LPCSTR name)
{
FARPROC func = ::GetProcAddress(module, name);
if (!func) {
throw XNetworkFunctionUnavailable(name);
}
return func;
}
void
CNetwork::init()
{
assert(WSACleanup == NULL);
assert(s_networkModule == NULL);
// try winsock 2
HMODULE module = (HMODULE)::LoadLibrary("ws2_32.dll");
if (module == NULL) {
log((CLOG_NOTE "ws2_32.dll not found"));
}
else {
try {
init2(module);
return;
}
catch (XNetwork& e) {
log((CLOG_NOTE "ws2_32.dll error: %s", e.what()));
}
}
// try winsock 1
module = (HMODULE)::LoadLibrary("wsock32.dll");
if (module == NULL) {
log((CLOG_NOTE "wsock32.dll not found"));
}
else {
try {
init2(module);
return;
}
catch (XNetwork& e) {
log((CLOG_NOTE "wsock32.dll error: %s", e.what()));
}
}
// no networking
throw XNetworkUnavailable();
}
void
CNetwork::cleanup()
{
if (s_networkModule != NULL) {
WSACleanup();
::FreeLibrary(s_networkModule);
WSACleanup = NULL;
s_networkModule = NULL;
}
}
UInt32
CNetwork::swaphtonl(UInt32 v)
{
static const union { UInt16 s; UInt8 b[2]; } s_endian = { 0x1234 };
if (s_endian.b[0] == 0x34) {
return ((v & 0xff000000lu) >> 24) |
((v & 0x00ff0000lu) >> 8) |
((v & 0x0000ff00lu) << 8) |
((v & 0x000000fflu) << 24);
}
else {
return v;
}
}
UInt16
CNetwork::swaphtons(UInt16 v)
{
static const union { UInt16 s; UInt8 b[2]; } s_endian = { 0x1234 };
if (s_endian.b[0] == 0x34) {
return static_cast<UInt16>( ((v & 0xff00u) >> 8) |
((v & 0x00ffu) << 8));
}
else {
return v;
}
}
UInt32
CNetwork::swapntohl(UInt32 v)
{
return swaphtonl(v);
}
UInt16
CNetwork::swapntohs(UInt16 v)
{
return swaphtons(v);
}
#define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
void
CNetwork::init2(
HMODULE module)
{
assert(module != NULL);
// get startup function address
int (PASCAL FAR *startup)(WORD, LPWSADATA);
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
// startup network library
WORD version = MAKEWORD(1 /*major*/, 1 /*minor*/);
WSADATA data;
int err = startup(version, &data);
if (data.wVersion != version) {
throw XNetworkVersion(LOBYTE(data.wVersion), HIBYTE(data.wVersion));
}
if (err != 0) {
throw XNetworkFailed();
}
// get function addresses
setfunc(accept, accept, Socket (PASCAL FAR *)(Socket s, Address FAR *addr, AddressLength FAR *addrlen));
setfunc(bind, bind, int (PASCAL FAR *)(Socket s, const Address FAR *addr, AddressLength namelen));
setfunc(close, closesocket, int (PASCAL FAR *)(Socket s));
setfunc(connect, connect, int (PASCAL FAR *)(Socket s, const Address FAR *name, AddressLength namelen));
setfunc(ioctl, ioctlsocket, int (PASCAL FAR *)(Socket s, int cmd, void FAR *));
setfunc(getpeername, getpeername, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen));
setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags));
setfunc(recvfrom, recvfrom, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen));
setfunc(send, send, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags));
setfunc(sendto, sendto, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags, const Address FAR *to, AddressLength tolen));
setfunc(setsockopt, setsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen));
setfunc(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol));
setfunc(gethostbyaddr, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(gethostname, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
setfunc(getservbyport, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getsockerror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(gethosterror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(WSACleanup, WSACleanup, int (PASCAL FAR *)(void));
setfunc(__WSAFDIsSet, __WSAFDIsSet, int (PASCAL FAR *)(CNetwork::Socket, fd_set FAR *));
setfunc(select, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
poll = poll2;
read = read2;
write = write2;
setblocking = setblocking2;
s_networkModule = module;
}
int PASCAL FAR
CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
{
int i;
// prepare sets for select
fd_set readSet, writeSet, errSet;
fd_set* readSetP = NULL;
fd_set* writeSetP = NULL;
fd_set* errSetP = NULL;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_ZERO(&errSet);
for (i = 0; i < nfds; ++i) {
if (fd[i].events & kPOLLIN) {
FD_SET(fd[i].fd, &readSet);
readSetP = &readSet;
}
if (fd[i].events & kPOLLOUT) {
FD_SET(fd[i].fd, &writeSet);
writeSetP = &writeSet;
}
if (true) {
FD_SET(fd[i].fd, &errSet);
errSetP = &errSet;
}
}
// prepare timeout for select
struct timeval timeout2;
struct timeval* timeout2P;
if (timeout < 0) {
timeout2P = NULL;
}
else {
timeout2P = &timeout2;
timeout2.tv_sec = timeout / 1000;
timeout2.tv_usec = 1000 * (timeout % 1000);
}
// do the select. note that winsock ignores the first argument.
int n = select(0, readSetP, writeSetP, errSetP, timeout2P);
// handle results
if (n == Error) {
return Error;
}
if (n == 0) {
return 0;
}
n = 0;
for (i = 0; i < nfds; ++i) {
fd[i].revents = 0;
if (FD_ISSET(fd[i].fd, &readSet)) {
fd[i].revents |= kPOLLIN;
}
if (FD_ISSET(fd[i].fd, &writeSet)) {
fd[i].revents |= kPOLLOUT;
}
if (FD_ISSET(fd[i].fd, &errSet)) {
fd[i].revents |= kPOLLERR;
}
if (fd[i].revents != 0) {
++n;
}
}
return n;
}
ssize_t PASCAL FAR
CNetwork::read2(Socket s, void FAR* buf, size_t len)
{
return recv(s, buf, len, 0);
}
ssize_t PASCAL FAR
CNetwork::write2(Socket s, const void FAR* buf, size_t len)
{
return send(s, buf, len, 0);
}
int PASCAL FAR
CNetwork::setblocking2(CNetwork::Socket s, bool blocking)
{
int flag = blocking ? 0 : 1;
return ioctl(s, FIONBIO, &flag);
}
#endif
#if UNIX_LIKE
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
// FIXME -- use reentrant versions of non-reentrant functions
#define setfunc(var, name, type) var = (type)::name
UInt32
CNetwork::swaphtonl(UInt32 v)
{
return htonl(v);
}
UInt16
CNetwork::swaphtons(UInt16 v)
{
return htons(v);
}
UInt32
CNetwork::swapntohl(UInt32 v)
{
return ntohl(v);
}
UInt16
CNetwork::swapntohs(UInt16 v)
{
return ntohs(v);
}
static
int
myerrno()
{
return errno;
}
static
int
myherrno()
{
return h_errno;
}
static
int
mygethostname(char* name, int namelen)
{
return gethostname(name, namelen);
}
static
int
mysetblocking(CNetwork::Socket s, bool blocking)
{
int mode = fcntl(s, F_GETFL, 0);
if (mode == -1) {
return -1;
}
if (blocking) {
mode &= ~O_NDELAY;
}
else {
mode |= O_NDELAY;
}
if (fcntl(s, F_SETFL, mode) < 0) {
return -1;
}
return 0;
}
const int CNetwork::Error = -1;
const CNetwork::Socket CNetwork::Null = -1;
void
CNetwork::init()
{
setfunc(accept, accept, Socket (PASCAL FAR *)(Socket s, Address FAR *addr, AddressLength FAR *addrlen));
setfunc(bind, bind, int (PASCAL FAR *)(Socket s, const Address FAR *addr, AddressLength namelen));
setfunc(close, close, int (PASCAL FAR *)(Socket s));
setfunc(connect, connect, int (PASCAL FAR *)(Socket s, const Address FAR *name, AddressLength namelen));
setfunc(ioctl, ioctl, int (PASCAL FAR *)(Socket s, int cmd, void FAR *));
setfunc(getpeername, getpeername, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen));
setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
setfunc(poll, poll, int (PASCAL FAR *)(CNetwork::PollEntry fds[], int nfds, int timeout));
setfunc(read, read, ssize_t (PASCAL FAR *)(CNetwork::Socket s, void FAR * buf, size_t len));
setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags));
setfunc(recvfrom, recvfrom, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen));
setfunc(send, send, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags));
setfunc(sendto, sendto, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags, const Address FAR *to, AddressLength tolen));
setfunc(setsockopt, setsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen));
setfunc(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol));
setfunc(write, write, ssize_t (PASCAL FAR *)(CNetwork::Socket s, const void FAR * buf, size_t len));
setfunc(gethostbyaddr, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(gethostname, mygethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
setfunc(getservbyport, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getsockerror, myerrno, int (PASCAL FAR *)(void));
setfunc(gethosterror, myherrno, int (PASCAL FAR *)(void));
setfunc(setblocking, mysetblocking, int (PASCAL FAR *)(Socket, bool));
}
void
CNetwork::cleanup()
{
// do nothing
}
#endif

185
lib/net/CNetwork.h Normal file
View File

@@ -0,0 +1,185 @@
#ifndef CNETWORK_H
#define CNETWORK_H
#include "BasicTypes.h"
#if WINDOWS_LIKE
// declare no functions in winsock2
# define INCL_WINSOCK_API_PROTOTYPES 0
# define INCL_WINSOCK_API_TYPEDEFS 0
# include <winsock2.h>
typedef int ssize_t;
# if !defined(SOL_TCP)
# define SOL_TCP IPPROTO_TCP
# endif
#else
# undef FAR
# undef PASCAL
# define FAR
# define PASCAL
#endif
#if UNIX_LIKE
# include <sys/types.h>
# include <sys/poll.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <errno.h>
# if !defined(TCP_NODELAY) || !defined(SOL_TCP)
# include <netinet/tcp.h>
# endif
#endif
//! Networking functions
class CNetwork {
public:
// platform dependent types
#if WINDOWS_LIKE
typedef SOCKET Socket;
typedef struct sockaddr Address;
typedef int AddressLength;
typedef BOOL TCPNoDelayType;
class PollEntry {
public:
Socket fd;
short events;
short revents;
};
enum {
kPOLLIN = 1,
kPOLLOUT = 2,
kPOLLERR = 4,
kPOLLNVAL = 8
};
#elif UNIX_LIKE
typedef int Socket;
typedef struct sockaddr Address;
typedef socklen_t AddressLength;
typedef struct pollfd PollEntry;
typedef int TCPNoDelayType;
enum {
kPOLLIN = POLLIN,
kPOLLOUT = POLLOUT,
kPOLLERR = POLLERR,
kPOLLNVAL = POLLNVAL
};
#endif
//! @name manipulators
//@{
//! Initialize network subsystem
/*!
This \b must be called before any other calls to the network subsystem.
*/
static void init();
//! Clean up network subsystem
/*!
This should be called when the network subsystem is no longer needed
and no longer in use.
*/
static void cleanup();
// byte swapping functions
//! Swap bytes to network order
static UInt32 swaphtonl(UInt32 hostlong);
//! Swap bytes to network order
static UInt16 swaphtons(UInt16 hostshort);
//! Swap bytes to host order
static UInt32 swapntohl(UInt32 netlong);
//! Swap bytes to host order
static UInt16 swapntohs(UInt16 netshort);
//@}
//! @name constants
//@{
//! The error type
static const int Error;
//! The non-socket
static const Socket Null;
// getsockerror() constants
enum {
#if WINDOWS_LIKE
kEADDRINUSE = WSAEADDRINUSE,
kECONNECTING = WSAEWOULDBLOCK,
#elif UNIX_LIKE
kEADDRINUSE = EADDRINUSE,
kECONNECTING = EINPROGRESS,
#endif
kNone = 0
};
// gethosterror() constants
enum {
#if WINDOWS_LIKE
kHOST_NOT_FOUND = WSAHOST_NOT_FOUND,
kNO_DATA = WSANO_DATA,
kNO_RECOVERY = WSANO_RECOVERY,
kTRY_AGAIN = WSATRY_AGAIN,
#elif UNIX_LIKE
kHOST_NOT_FOUND = HOST_NOT_FOUND,
kNO_DATA = NO_DATA,
kNO_RECOVERY = NO_RECOVERY,
kTRY_AGAIN = TRY_AGAIN,
#endif
kHNone = 0
};
//@}
// socket interface (only available after init())
static Socket (PASCAL FAR *accept)(Socket s, Address FAR *addr, AddressLength FAR *addrlen);
static int (PASCAL FAR *bind)(Socket s, const Address FAR *addr, AddressLength namelen);
static int (PASCAL FAR *close)(Socket s);
static int (PASCAL FAR *connect)(Socket s, const Address FAR *name, AddressLength namelen);
static int (PASCAL FAR *ioctl)(Socket s, int cmd, void FAR *);
static int (PASCAL FAR *getpeername)(Socket s, Address FAR *name, AddressLength FAR * namelen);
static int (PASCAL FAR *getsockname)(Socket s, Address FAR *name, AddressLength FAR * namelen);
static int (PASCAL FAR *getsockopt)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen);
static unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp);
static char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in);
static int (PASCAL FAR *listen)(Socket s, int backlog);
static ssize_t (PASCAL FAR *read)(Socket s, void FAR * buf, size_t len);
static ssize_t (PASCAL FAR *recv)(Socket s, void FAR * buf, size_t len, int flags);
static ssize_t (PASCAL FAR *recvfrom)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen);
static int (PASCAL FAR *poll)(PollEntry[], int nfds, int timeout);
static ssize_t (PASCAL FAR *send)(Socket s, const void FAR * buf, size_t len, int flags);
static ssize_t (PASCAL FAR *sendto)(Socket s, const void FAR * buf, size_t len, int flags, const Address FAR *to, AddressLength tolen);
static int (PASCAL FAR *setsockopt)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen);
static int (PASCAL FAR *shutdown)(Socket s, int how);
static Socket (PASCAL FAR *socket)(int af, int type, int protocol);
static ssize_t (PASCAL FAR *write)(Socket s, const void FAR * buf, size_t len);
static struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR * addr, int len, int type);
static struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name);
static int (PASCAL FAR *gethostname)(char FAR * name, int namelen);
static struct servent FAR * (PASCAL FAR *getservbyport)(int port, const char FAR * proto);
static struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name, const char FAR * proto);
static struct protoent FAR * (PASCAL FAR *getprotobynumber)(int proto);
static struct protoent FAR * (PASCAL FAR *getprotobyname)(const char FAR * name);
static int (PASCAL FAR *getsockerror)(void);
static int (PASCAL FAR *gethosterror)(void);
// convenience functions (only available after init())
//! Set socket to (non-)blocking operation
static int (PASCAL FAR *setblocking)(CNetwork::Socket s, bool blocking);
#if WINDOWS_LIKE
private:
static void init2(HMODULE);
static int PASCAL FAR poll2(PollEntry[], int nfds, int timeout);
static ssize_t PASCAL FAR read2(Socket s, void FAR * buf, size_t len);
static ssize_t PASCAL FAR write2(Socket s, const void FAR * buf, size_t len);
static int PASCAL FAR setblocking2(CNetwork::Socket s, bool blocking);
static int (PASCAL FAR *WSACleanup)(void);
static int (PASCAL FAR *__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
static int (PASCAL FAR *select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
#endif
};
#endif

172
lib/net/CNetworkAddress.cpp Normal file
View File

@@ -0,0 +1,172 @@
#include "CNetworkAddress.h"
#include "XSocket.h"
#include <cstdlib>
#include <cstring>
//
// CNetworkAddress
//
CNetworkAddress::CNetworkAddress() :
m_port(0)
{
// note -- make no calls to CNetwork socket interface here;
// we're often called prior to CNetwork::init().
struct sockaddr_in* inetAddress = reinterpret_cast<
struct sockaddr_in*>(&m_address);
inetAddress->sin_family = AF_INET;
inetAddress->sin_port = CNetwork::swaphtons(m_port);
inetAddress->sin_addr.s_addr = INADDR_ANY;
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
}
CNetworkAddress::CNetworkAddress(UInt16 port) :
m_port(port)
{
if (port == 0) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
}
struct sockaddr_in* inetAddress = reinterpret_cast<
struct sockaddr_in*>(&m_address);
inetAddress->sin_family = AF_INET;
inetAddress->sin_port = CNetwork::swaphtons(m_port);
inetAddress->sin_addr.s_addr = INADDR_ANY;
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
}
CNetworkAddress::CNetworkAddress(const CString& hostname_, UInt16 port) :
m_hostname(hostname_),
m_port(port)
{
CString hostname(m_hostname);
if (port == 0) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
}
// check for port suffix
CString::size_type i = hostname.rfind(':');
if (i != CString::npos && i + 1 < hostname.size()) {
// found a colon. see if it looks like an IPv6 address.
bool colonNotation = false;
bool dotNotation = false;
bool doubleColon = false;
for (CString::size_type j = 0; j < i; ++j) {
if (hostname[j] == ':') {
colonNotation = true;
dotNotation = false;
if (hostname[j + 1] == ':') {
doubleColon = true;
}
}
else if (hostname[j] == '.' && colonNotation) {
dotNotation = true;
}
}
// port suffix is ambiguous with IPv6 notation if there's
// a double colon and the end of the address is not in dot
// notation. in that case we assume it's not a port suffix.
// the user can replace the double colon with zeros to
// disambiguate.
if ((!doubleColon || dotNotation) || !colonNotation) {
char* end;
long suffixPort = strtol(hostname.c_str() + i + 1, &end, 10);
if (end == hostname.c_str() + i + 1 || *end != '\0' ||
suffixPort <= 0 || suffixPort > 65535) {
// bogus port
throw XSocketAddress(XSocketAddress::kBadPort,
m_hostname, m_port);
}
else {
// good port
port = static_cast<UInt16>(suffixPort);
hostname.erase(i);
}
}
}
// if hostname is empty then use wildcard address
if (hostname.empty()) {
struct sockaddr_in* inetAddress = reinterpret_cast<
struct sockaddr_in*>(&m_address);
inetAddress->sin_family = AF_INET;
inetAddress->sin_port = CNetwork::swaphtons(port);
inetAddress->sin_addr.s_addr = INADDR_ANY;
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
return;
}
// convert dot notation to address
unsigned long addr = CNetwork::inet_addr(hostname.c_str());
if (addr != INADDR_NONE) {
struct sockaddr_in* inetAddress = reinterpret_cast<
struct sockaddr_in*>(&m_address);
inetAddress->sin_family = AF_INET;
inetAddress->sin_port = CNetwork::swaphtons(port);
inetAddress->sin_addr.s_addr = addr;
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
return;
}
// look up name
struct hostent* hent = CNetwork::gethostbyname(hostname.c_str());
if (hent == NULL) {
switch (CNetwork::gethosterror()) {
case CNetwork::kHOST_NOT_FOUND:
throw XSocketAddress(XSocketAddress::kNotFound, hostname, port);
case CNetwork::kNO_DATA:
throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port);
case CNetwork::kNO_RECOVERY:
case CNetwork::kTRY_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 = CNetwork::swaphtons(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
}
bool
CNetworkAddress::isValid() const
{
return (m_port != 0);
}
const CNetwork::Address*
CNetworkAddress::getAddress() const
{
return &m_address;
}
CNetwork::AddressLength
CNetworkAddress::getAddressLength() const
{
return sizeof(m_address);
}
CString
CNetworkAddress::getHostname() const
{
return m_hostname;
}
UInt16
CNetworkAddress::getPort() const
{
return m_port;
}

81
lib/net/CNetworkAddress.h Normal file
View File

@@ -0,0 +1,81 @@
#ifndef CNETWORKADDRESS_H
#define CNETWORKADDRESS_H
#include "CNetwork.h"
#include "CString.h"
#include "BasicTypes.h"
//! Network address type
/*!
This class represents a network address.
*/
class CNetworkAddress {
public:
/*!
Constructs the invalid address
*/
CNetworkAddress();
/*!
Construct the wildcard address with the given port. \c port must
not be zero.
*/
CNetworkAddress(UInt16 port);
/*!
Construct the network address for the given \c hostname and \c port.
If \c hostname can be parsed as a numerical address then that's how
it's used, otherwise the host name is looked up. If the lookup fails
then this throws XSocketAddress. If \c hostname ends in ":[0-9]+" then
that suffix is extracted and used as the port, overridding the port
parameter. Neither the extracted port or \c port may be zero.
*/
CNetworkAddress(const CString& hostname, UInt16 port);
~CNetworkAddress();
//! @name accessors
//@{
//! Check address validity
/*!
Returns true if this is not the invalid address.
*/
bool isValid() const;
//! Get address
/*!
Returns the address in the platform's native network address
structure.
*/
const CNetwork::Address* getAddress() const;
//! Get address length
/*!
Returns the length of the address in the platform's native network
address structure.
*/
CNetwork::AddressLength getAddressLength() const;
//! Get hostname
/*!
Returns the hostname passed to the c'tor sans the port suffix.
*/
CString getHostname() const;
//! Get port
/*!
Returns the port passed to the c'tor as a suffix to the hostname,
if that existed, otherwise as passed directly to the c'tor.
*/
UInt16 getPort() const;
//@}
private:
CNetwork::Address m_address;
CString m_hostname;
UInt16 m_port;
};
#endif

View File

@@ -0,0 +1,76 @@
#include "CTCPListenSocket.h"
#include "CTCPSocket.h"
#include "CNetworkAddress.h"
#include "XIO.h"
#include "XSocket.h"
#include "CThread.h"
//
// CTCPListenSocket
//
CTCPListenSocket::CTCPListenSocket()
{
m_fd = CNetwork::socket(PF_INET, SOCK_STREAM, 0);
if (m_fd == CNetwork::Null) {
throw XSocketCreate();
}
}
CTCPListenSocket::~CTCPListenSocket()
{
try {
close();
}
catch (...) {
// ignore
}
}
void
CTCPListenSocket::bind(const CNetworkAddress& addr)
{
if (CNetwork::bind(m_fd, addr.getAddress(),
addr.getAddressLength()) == CNetwork::Error) {
if (CNetwork::getsockerror() == CNetwork::kEADDRINUSE) {
throw XSocketAddressInUse();
}
throw XSocketBind();
}
if (CNetwork::listen(m_fd, 3) == CNetwork::Error) {
throw XSocketBind();
}
}
IDataSocket*
CTCPListenSocket::accept()
{
// accept asynchronously so we can check for cancellation
CNetwork::PollEntry pfds[1];
pfds[0].fd = m_fd;
pfds[0].events = CNetwork::kPOLLIN;
for (;;) {
CThread::testCancel();
const int status = CNetwork::poll(pfds, 1, 10);
if (status > 0 && (pfds[0].revents & CNetwork::kPOLLIN) != 0) {
CNetwork::Address addr;
CNetwork::AddressLength addrlen = sizeof(addr);
CNetwork::Socket fd = CNetwork::accept(m_fd, &addr, &addrlen);
if (fd != CNetwork::Null) {
return new CTCPSocket(fd);
}
}
}
}
void
CTCPListenSocket::close()
{
if (m_fd == CNetwork::Null) {
throw XIOClosed();
}
if (CNetwork::close(m_fd) == CNetwork::Error) {
throw XIOClose();
}
m_fd = CNetwork::Null;
}

View File

@@ -0,0 +1,27 @@
#ifndef CTCPLISTENSOCKET_H
#define CTCPLISTENSOCKET_H
#include "IListenSocket.h"
#include "CNetwork.h"
//! TCP listen socket
/*!
A listen socket using TCP.
*/
class CTCPListenSocket : public IListenSocket {
public:
CTCPListenSocket();
~CTCPListenSocket();
// ISocket overrides
virtual void bind(const CNetworkAddress&);
virtual void close();
// IListenSocket overrides
virtual IDataSocket* accept();
private:
CNetwork::Socket m_fd;
};
#endif

321
lib/net/CTCPSocket.cpp Normal file
View File

@@ -0,0 +1,321 @@
#include "CTCPSocket.h"
#include "CBufferedInputStream.h"
#include "CBufferedOutputStream.h"
#include "CNetworkAddress.h"
#include "XIO.h"
#include "XSocket.h"
#include "CCondVar.h"
#include "CLock.h"
#include "CMutex.h"
#include "CThread.h"
#include "CStopwatch.h"
#include "TMethodJob.h"
//
// CTCPSocket
//
CTCPSocket::CTCPSocket()
{
m_fd = CNetwork::socket(PF_INET, SOCK_STREAM, 0);
if (m_fd == CNetwork::Null) {
throw XSocketCreate();
}
init();
}
CTCPSocket::CTCPSocket(CNetwork::Socket fd) :
m_fd(fd)
{
assert(m_fd != CNetwork::Null);
init();
// socket starts in connected state
m_connected = kReadWrite;
// start handling socket
m_thread = new CThread(new TMethodJob<CTCPSocket>(
this, &CTCPSocket::ioThread));
}
CTCPSocket::~CTCPSocket()
{
try {
close();
}
catch (...) {
// ignore failures
}
// clean up
delete m_input;
delete m_output;
delete m_mutex;
}
void
CTCPSocket::bind(const CNetworkAddress& addr)
{
if (CNetwork::bind(m_fd, addr.getAddress(),
addr.getAddressLength()) == CNetwork::Error) {
if (errno == CNetwork::kEADDRINUSE) {
throw XSocketAddressInUse();
}
throw XSocketBind();
}
}
void
CTCPSocket::close()
{
// see if buffers should be flushed
bool doFlush = false;
{
CLock lock(m_mutex);
doFlush = (m_thread != NULL && (m_connected & kWrite) != 0);
}
// flush buffers
if (doFlush) {
m_output->flush();
}
// cause ioThread to exit
{
CLock lock(m_mutex);
if (m_fd != CNetwork::Null) {
CNetwork::shutdown(m_fd, 2);
m_connected = kClosed;
}
}
// wait for thread
if (m_thread != NULL) {
m_thread->wait();
delete m_thread;
m_thread = NULL;
}
// close socket
if (m_fd != CNetwork::Null) {
if (CNetwork::close(m_fd) == CNetwork::Error) {
throw XIOClose();
}
m_fd = CNetwork::Null;
}
}
void
CTCPSocket::connect(const CNetworkAddress& addr)
{
// connect asynchronously so we can check for cancellation
CNetwork::setblocking(m_fd, false);
if (CNetwork::connect(m_fd, addr.getAddress(),
addr.getAddressLength()) == CNetwork::Error) {
// check for failure
if (CNetwork::getsockerror() != CNetwork::kECONNECTING) {
XSocketConnect e;
CNetwork::setblocking(m_fd, true);
throw e;
}
// wait for connection or failure
CNetwork::PollEntry pfds[1];
pfds[0].fd = m_fd;
pfds[0].events = CNetwork::kPOLLOUT;
for (;;) {
CThread::testCancel();
const int status = CNetwork::poll(pfds, 1, 10);
if (status > 0) {
if ((pfds[0].revents & (CNetwork::kPOLLERR |
CNetwork::kPOLLNVAL)) != 0) {
// connection failed
int error = 0;
CNetwork::AddressLength size = sizeof(error);
CNetwork::setblocking(m_fd, true);
CNetwork::getsockopt(m_fd, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error), &size);
throw XSocketConnect(error);
}
if ((pfds[0].revents & CNetwork::kPOLLOUT) != 0) {
int error;
CNetwork::AddressLength size = sizeof(error);
if (CNetwork::getsockopt(m_fd, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error),
&size) == CNetwork::Error ||
error != 0) {
// connection failed
CNetwork::setblocking(m_fd, true);
throw XSocketConnect(error);
}
// connected!
break;
}
}
}
}
// back to blocking
CNetwork::setblocking(m_fd, true);
// start servicing the socket
m_connected = kReadWrite;
m_thread = new CThread(new TMethodJob<CTCPSocket>(
this, &CTCPSocket::ioThread));
}
IInputStream*
CTCPSocket::getInputStream()
{
return m_input;
}
IOutputStream*
CTCPSocket::getOutputStream()
{
return m_output;
}
void
CTCPSocket::init()
{
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));
// turn off Nagle algorithm. we send lots of very short messages
// that should be sent without (much) delay. for example, the
// mouse motion messages are much less useful if they're delayed.
CNetwork::TCPNoDelayType flag = 1;
CNetwork::setsockopt(m_fd, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
}
void
CTCPSocket::ioThread(void*)
{
try {
ioService();
ioCleanup();
}
catch (...) {
ioCleanup();
throw;
}
}
void
CTCPSocket::ioCleanup()
{
try {
m_input->close();
}
catch (...) {
// ignore
}
try {
m_output->close();
}
catch (...) {
// ignore
}
}
void
CTCPSocket::ioService()
{
assert(m_fd != CNetwork::Null);
// now service the connection
CNetwork::PollEntry pfds[1];
pfds[0].fd = m_fd;
for (;;) {
{
// choose events to poll for
CLock lock(m_mutex);
pfds[0].events = 0;
if (m_connected == 0) {
return;
}
if ((m_connected & kRead) != 0) {
// still open for reading
pfds[0].events |= CNetwork::kPOLLIN;
}
if ((m_connected & kWrite) != 0 && m_output->getSize() > 0) {
// data queued for writing
pfds[0].events |= CNetwork::kPOLLOUT;
}
}
// check for status
const int status = CNetwork::poll(pfds, 1, 10);
// transfer data and handle errors
if (status == 1) {
if ((pfds[0].revents & (CNetwork::kPOLLERR |
CNetwork::kPOLLNVAL)) != 0) {
// stream is no good anymore so bail
m_input->hangup();
return;
}
// read some data
if (pfds[0].revents & CNetwork::kPOLLIN) {
UInt8 buffer[4096];
ssize_t n = CNetwork::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();
m_connected &= ~kRead;
}
}
// write some data
if (pfds[0].revents & CNetwork::kPOLLOUT) {
CLock lock(m_mutex);
// get amount of data to write
UInt32 n = m_output->getSize();
// write data
const void* buffer = m_output->peek(n);
n = (UInt32)CNetwork::write(m_fd, buffer, n);
// discard written data
if (n > 0) {
m_output->pop(n);
}
else if (n == (UInt32)-1 && CNetwork::getsockerror() == EPIPE) {
return;
}
}
}
}
}
void
CTCPSocket::closeInput(void*)
{
// note -- m_mutex should already be locked
CNetwork::shutdown(m_fd, 0);
m_connected &= ~kRead;
}
void
CTCPSocket::closeOutput(void*)
{
// note -- m_mutex should already be locked
CNetwork::shutdown(m_fd, 1);
m_connected &= ~kWrite;
}

53
lib/net/CTCPSocket.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef CTCPSOCKET_H
#define CTCPSOCKET_H
#include "IDataSocket.h"
#include "CNetwork.h"
class CMutex;
template <class T>
class CCondVar;
class CThread;
class CBufferedInputStream;
class CBufferedOutputStream;
//! TCP data socket
/*!
A data socket using TCP.
*/
class CTCPSocket : public IDataSocket {
public:
CTCPSocket();
CTCPSocket(CNetwork::Socket);
~CTCPSocket();
// ISocket overrides
virtual void bind(const CNetworkAddress&);
virtual void close();
// IDataSocket overrides
virtual void connect(const CNetworkAddress&);
virtual IInputStream* getInputStream();
virtual IOutputStream* getOutputStream();
private:
void init();
void ioThread(void*);
void ioCleanup();
void ioService();
void closeInput(void*);
void closeOutput(void*);
private:
enum { kClosed = 0, kRead = 1, kWrite = 2, kReadWrite = 3 };
CNetwork::Socket m_fd;
CBufferedInputStream* m_input;
CBufferedOutputStream* m_output;
CMutex* m_mutex;
CThread* m_thread;
UInt32 m_connected;
};
#endif

49
lib/net/IDataSocket.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef IDATASOCKET_H
#define IDATASOCKET_H
#include "ISocket.h"
class IInputStream;
class IOutputStream;
//! Data stream socket interface
/*!
This interface defines the methods common to all network sockets that
represent a full-duplex data stream.
*/
class IDataSocket : public ISocket {
public:
//! @name manipulators
//@{
//! Connect socket
/*!
Attempt to connect to a remote endpoint. This waits until the
connection is established or fails. If it fails it throws an
XSocketConnect exception.
(cancellation point)
*/
virtual void connect(const CNetworkAddress&) = 0;
//! Get input stream
/*!
Returns the input stream for reading from the socket. Closing this
stream will shutdown the socket for reading.
*/
virtual IInputStream* getInputStream() = 0;
//! Get output stream
/*!
Returns the output stream for writing to the socket. Closing this
stream will shutdown the socket for writing.
*/
virtual IOutputStream* getOutputStream() = 0;
//@}
// ISocket overrides
virtual void bind(const CNetworkAddress&) = 0;
virtual void close() = 0;
};
#endif

34
lib/net/IListenSocket.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef ILISTENSOCKET_H
#define ILISTENSOCKET_H
#include "ISocket.h"
class IDataSocket;
//! Listen socket interface
/*!
This interface defines the methods common to all network sockets that
listen for incoming connections.
*/
class IListenSocket : public ISocket {
public:
//! @name manipulators
//@{
//! Accept connection
/*!
Wait for and accept a connection, returning a socket representing
the full-duplex data stream.
(cancellation point)
*/
virtual IDataSocket* accept() = 0;
//@}
// ISocket overrides
virtual void bind(const CNetworkAddress&) = 0;
virtual void close() = 0;
};
#endif

32
lib/net/ISocket.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef ISOCKET_H
#define ISOCKET_H
#include "IInterface.h"
class CNetworkAddress;
//! Generic socket interface
/*!
This interface defines the methods common to all network sockets.
*/
class ISocket : public IInterface {
public:
//! @name manipulators
//@{
//! Bind socket to address
/*!
Binds the socket to a particular address.
*/
virtual void bind(const CNetworkAddress&) = 0;
//! Close socket
/*!
Closes the socket. This should flush the output stream.
*/
virtual void close() = 0;
//@}
};
#endif

27
lib/net/Makefile.am Normal file
View File

@@ -0,0 +1,27 @@
## Process this file with automake to produce Makefile.in
NULL =
DEPTH = ../..
noinst_LIBRARIES = libnet.a
libnet_a_SOURCES = \
CNetwork.cpp \
CNetworkAddress.cpp \
CTCPSocket.cpp \
CTCPListenSocket.cpp \
XNetwork.cpp \
XSocket.cpp \
CNetwork.h \
CNetworkAddress.h \
CTCPListenSocket.h \
CTCPSocket.h \
IDataSocket.h \
IListenSocket.h \
ISocket.h \
XNetwork.h \
XSocket.h \
$(NULL)
INCLUDES = \
-I$(DEPTH)/lib/base \
-I$(DEPTH)/lib/mt \
-I$(DEPTH)/lib/io \
$(NULL)

79
lib/net/XNetwork.cpp Normal file
View File

@@ -0,0 +1,79 @@
#include "XNetwork.h"
//
// XNetworkUnavailable
//
CString
XNetworkUnavailable::getWhat() const throw()
{
return format("XNetworkUnavailable", "network library is not available");
}
//
// XNetworkFailed
//
CString
XNetworkFailed::getWhat() const throw()
{
return format("XNetworkFailed", "cannot initialize network library");
}
//
// XNetworkVersion
//
XNetworkVersion::XNetworkVersion(int major, int minor) throw() :
m_major(major),
m_minor(minor)
{
// do nothing
}
int
XNetworkVersion::getMajor() const throw()
{
return m_major;
}
int
XNetworkVersion::getMinor() const throw()
{
return m_minor;
}
CString
XNetworkVersion::getWhat() const throw()
{
return format("XNetworkVersion",
"unsupported network version %{1}.%{2}",
CStringUtil::print("%d", m_major).c_str(),
CStringUtil::print("%d", m_minor).c_str());
}
//
// XNetworkFunctionUnavailable
//
XNetworkFunctionUnavailable::XNetworkFunctionUnavailable(
const char* name) throw()
{
try {
m_name = name;
}
catch (...) {
// ignore
}
}
CString
XNetworkFunctionUnavailable::getWhat() const throw()
{
return format("XNetworkFunctionUnavailable",
"missing network function %{1}",
m_name.c_str());
}

80
lib/net/XNetwork.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef XNETWORK_H
#define XNETWORK_H
#include "XBase.h"
#include "CString.h"
//! Generic network exception
/*!
Network exceptions are thrown when initializing the network subsystem
and not during normal network use.
*/
class XNetwork : public XBase { };
//! Network subsystem not available exception
/*!
Thrown when the network subsystem is unavailable, typically because
the necessary shared library is unavailable.
*/
class XNetworkUnavailable : public XNetwork {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
//! Network subsystem failed exception
/*!
Thrown when the network subsystem cannot be initialized.
*/
class XNetworkFailed : public XNetwork {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
//! Network subsystem vesion unsupported exception
/*!
Thrown when the network subsystem has a version incompatible with
what's expected.
*/
class XNetworkVersion : public XNetwork {
public:
XNetworkVersion(int major, int minor) throw();
//! @name accessors
//@{
//! Get the network subsystem's major version
int getMajor() const throw();
//! Get the network subsystem's minor version
int getMinor() const throw();
//@}
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
int m_major;
int m_minor;
};
//! Network subsystem incomplete exception
/*!
Thrown when the network subsystem is missing an expected and required
function.
*/
class XNetworkFunctionUnavailable : public XNetwork {
public:
XNetworkFunctionUnavailable(const char* name) throw();
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
CString m_name;
};
#endif

102
lib/net/XSocket.cpp Normal file
View File

@@ -0,0 +1,102 @@
#include "XSocket.h"
//
// XSocketAddress
//
XSocketAddress::XSocketAddress(EError error,
const CString& hostname, UInt16 port) throw() :
m_error(error),
m_hostname(hostname),
m_port(port)
{
// do nothing
}
XSocketAddress::EError
XSocketAddress::getError() const throw()
{
return m_error;
}
CString
XSocketAddress::getHostname() const throw()
{
return m_hostname;
}
UInt16
XSocketAddress::getPort() const throw()
{
return m_port;
}
CString
XSocketAddress::getWhat() const throw()
{
static const char* s_errorID[] = {
"XSocketAddressUnknown",
"XSocketAddressNotFound",
"XSocketAddressNoAddress",
"XSocketAddressBadPort"
};
static const char* s_errorMsg[] = {
"unknown error for: %{1}:%{2}",
"address not found for: %{1}",
"no address for: %{1}",
"invalid port" // m_port may not be set to the bad port
};
return format(s_errorID[m_error], s_errorMsg[m_error],
m_hostname.c_str(),
CStringUtil::print("%d", m_port).c_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");
}

109
lib/net/XSocket.h Normal file
View File

@@ -0,0 +1,109 @@
#ifndef XSOCKET_H
#define XSOCKET_H
#include "XBase.h"
#include "CString.h"
#include "BasicTypes.h"
//! Generic socket exception
class XSocket : public XBase { };
//! Socket bad address exception
/*!
Thrown when attempting to create an invalid network address.
*/
class XSocketAddress : public XSocket {
public:
//! Failure codes
enum EError {
kUnknown, //!< Unknown error
kNotFound, //!< The hostname is unknown
kNoAddress, //!< The hostname is valid but has no IP address
kBadPort //!< The port is invalid
};
XSocketAddress(EError, const CString& hostname, UInt16 port) throw();
//! @name accessors
//@{
//! Get the error code
EError getError() const throw();
//! Get the hostname
CString getHostname() const throw();
//! Get the port
UInt16 getPort() const throw();
//@}
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
EError m_error;
CString m_hostname;
UInt16 m_port;
};
//! Generic socket exception using \c errno
class XSocketErrno : public XSocket, public MXErrno {
public:
XSocketErrno();
XSocketErrno(int);
};
//! Socket cannot bind address exception
/*!
Thrown when a socket cannot be bound to an address.
*/
class XSocketBind : public XSocketErrno {
public:
XSocketBind() { }
XSocketBind(int e) : XSocketErrno(e) { }
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
//! Socket address in use exception
/*!
Thrown when a socket cannot be bound to an address because the address
is already in use.
*/
class XSocketAddressInUse : public XSocketBind {
public:
XSocketAddressInUse() { }
XSocketAddressInUse(int e) : XSocketBind(e) { }
};
//! Cannot connect socket exception
/*!
Thrown when a socket cannot connect to a remote endpoint.
*/
class XSocketConnect : public XSocketErrno {
public:
XSocketConnect() { }
XSocketConnect(int e) : XSocketErrno(e) { }
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
//! Cannot create socket exception
/*!
Thrown when a socket cannot be created (by the operating system).
*/
class XSocketCreate : public XSocketErrno {
public:
XSocketCreate() { }
XSocketCreate(int e) : XSocketErrno(e) { }
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
#endif

150
lib/net/net.dsp Normal file
View File

@@ -0,0 +1,150 @@
# Microsoft Developer Studio Project File - Name="net" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=net - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "net.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "net.mak" CFG="net - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "net - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "net - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "net - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "net - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "net - Win32 Release"
# Name "net - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CNetwork.cpp
# End Source File
# Begin Source File
SOURCE=.\CNetworkAddress.cpp
# End Source File
# Begin Source File
SOURCE=.\CTCPListenSocket.cpp
# End Source File
# Begin Source File
SOURCE=.\CTCPSocket.cpp
# End Source File
# Begin Source File
SOURCE=.\XNetwork.cpp
# End Source File
# Begin Source File
SOURCE=.\XSocket.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CNetwork.h
# End Source File
# Begin Source File
SOURCE=.\CNetworkAddress.h
# End Source File
# Begin Source File
SOURCE=.\CTCPListenSocket.h
# End Source File
# Begin Source File
SOURCE=.\CTCPSocket.h
# End Source File
# Begin Source File
SOURCE=.\IListenSocket.h
# End Source File
# Begin Source File
SOURCE=.\ISocket.h
# End Source File
# Begin Source File
SOURCE=.\XNetwork.h
# End Source File
# Begin Source File
SOURCE=.\XSocket.h
# End Source File
# End Group
# End Target
# End Project