mirror of
https://github.com/debauchee/barrier.git
synced 2026-05-11 00:58:14 +08:00
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:
430
lib/net/CNetwork.cpp
Normal file
430
lib/net/CNetwork.cpp
Normal 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
185
lib/net/CNetwork.h
Normal 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
172
lib/net/CNetworkAddress.cpp
Normal 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
81
lib/net/CNetworkAddress.h
Normal 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
|
||||
76
lib/net/CTCPListenSocket.cpp
Normal file
76
lib/net/CTCPListenSocket.cpp
Normal 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;
|
||||
}
|
||||
27
lib/net/CTCPListenSocket.h
Normal file
27
lib/net/CTCPListenSocket.h
Normal 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
321
lib/net/CTCPSocket.cpp
Normal 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
53
lib/net/CTCPSocket.h
Normal 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
49
lib/net/IDataSocket.h
Normal 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
34
lib/net/IListenSocket.h
Normal 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
32
lib/net/ISocket.h
Normal 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
27
lib/net/Makefile.am
Normal 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
79
lib/net/XNetwork.cpp
Normal 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
80
lib/net/XNetwork.h
Normal 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
102
lib/net/XSocket.cpp
Normal 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
109
lib/net/XSocket.h
Normal 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
150
lib/net/net.dsp
Normal 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
|
||||
Reference in New Issue
Block a user