From ca354dce7f77927f4d09336d320fa0df9f17e04d Mon Sep 17 00:00:00 2001 From: lotodore Date: Tue, 13 Mar 2007 23:27:17 +0000 Subject: [PATCH] Started to implement server state engine. --- pokerth.pro | 11 +- .../connecttoserverdialogimpl.cpp | 20 +++ src/net/clientcallback.h | 3 - src/net/clientcontext.h | 71 ++++++++ src/net/clientthread.h | 14 +- src/net/common/clientcontext.cpp | 52 ++++++ src/net/common/clientstate.cpp | 60 +++---- src/net/common/clientthread.cpp | 79 ++++++--- .../{clientdata.cpp => connectdata.cpp} | 14 +- src/net/common/netcontext.cpp | 25 +++ src/net/common/receiverhelper.cpp | 8 +- src/net/common/resolverthread.cpp | 44 ++--- src/net/common/sendercallback.cpp | 26 +++ src/net/common/senderthread.cpp | 48 +++--- src/net/common/servercontext.cpp | 52 ++++++ src/net/common/serverexception.cpp | 26 +++ src/net/common/serverrecvstate.cpp | 63 +++++++ src/net/common/serverrecvthread.cpp | 129 ++++++++++++++ src/net/common/serverthread.cpp | 159 +++++++++++++++--- src/net/connectdata.h | 46 +++++ src/net/{clientdata.h => netcontext.h} | 25 +-- src/net/receiverhelper.h | 3 +- src/net/resolverthread.h | 12 +- src/net/sendercallback.h | 34 ++++ src/net/senderthread.h | 17 +- src/net/servercontext.h | 66 ++++++++ src/net/serverexception.h | 36 ++++ src/net/serverrecvstate.h | 65 +++++++ src/net/serverrecvthread.h | 72 ++++++++ src/net/serverthread.h | 19 ++- src/net/socket_helper.h | 1 + src/net/socket_msg.h | 18 +- src/session.cpp | 5 +- 33 files changed, 1130 insertions(+), 193 deletions(-) create mode 100644 src/net/clientcontext.h create mode 100644 src/net/common/clientcontext.cpp rename src/net/common/{clientdata.cpp => connectdata.cpp} (83%) create mode 100644 src/net/common/netcontext.cpp create mode 100644 src/net/common/sendercallback.cpp create mode 100644 src/net/common/servercontext.cpp create mode 100644 src/net/common/serverexception.cpp create mode 100644 src/net/common/serverrecvstate.cpp create mode 100644 src/net/common/serverrecvthread.cpp create mode 100644 src/net/connectdata.h rename src/net/{clientdata.h => netcontext.h} (77%) create mode 100644 src/net/sendercallback.h create mode 100644 src/net/servercontext.h create mode 100644 src/net/serverexception.h create mode 100644 src/net/serverrecvstate.h create mode 100644 src/net/serverrecvthread.h diff --git a/pokerth.pro b/pokerth.pro index 2a23f56d..c7ef13c9 100755 --- a/pokerth.pro +++ b/pokerth.pro @@ -64,7 +64,7 @@ HEADERS += src/game.h \ src/engine/turninterface.h \ src/gui/guiinterface.h \ src/net/clientcallback.h \ - src/net/clientdata.h \ + src/net/clientcontext.h \ src/net/clientexception.h \ src/net/clientstate.h \ src/net/clientthread.h \ @@ -139,17 +139,24 @@ SOURCES += src/game.cpp \ src/engine/local_engine/localturn.cpp \ src/engine/local_engine/tools.cpp \ src/gui/qt/guiwrapper.cpp \ + src/net/common/connectdata.cpp \ src/net/common/clientcallback.cpp \ - src/net/common/clientdata.cpp \ + src/net/common/clientcontext.cpp \ src/net/common/clientstate.cpp \ src/net/common/clientthread.cpp \ src/net/common/netpacket.cpp \ src/net/common/resolverthread.cpp \ src/net/common/senderthread.cpp \ + src/net/common/sendercallback.cpp \ src/net/common/serverthread.cpp \ + src/net/common/servercontext.cpp \ + src/net/common/serverexception.cpp \ + src/net/common/serverrecvthread.cpp \ + src/net/common/serverrecvstate.cpp \ src/net/common/socket_helper_cmn.cpp \ src/net/common/clientexception.cpp \ src/net/common/netcallback.cpp \ + src/net/common/netcontext.cpp \ src/net/common/netexception.cpp \ src/net/common/receiverhelper.cpp \ src/gui/qt/aboutpokerth/aboutpokerthimpl.cpp \ diff --git a/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp b/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp index 908dc8a8..822622c3 100644 --- a/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp +++ b/src/gui/qt/connecttoserverdialog/connecttoserverdialogimpl.cpp @@ -69,6 +69,11 @@ void connectToServerDialogImpl::error(int errorID, int osErrorID) { tr("Could not create a socket for TCP communication."), QMessageBox::Close); } break; + case ERR_SOCK_SET_ADDR_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Could not set the IP address."), + QMessageBox::Close); } + break; case ERR_SOCK_SET_PORT_FAILED: { QMessageBox::warning(this, tr("Network Error"), tr("Could not set the port for this type of address."), @@ -79,6 +84,21 @@ void connectToServerDialogImpl::error(int errorID, int osErrorID) { tr("The server name could not be resolved."), QMessageBox::Close); } break; + case ERR_SOCK_BIND_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Bind failed - please choose a different port."), + QMessageBox::Close); } + break; + case ERR_SOCK_LISTEN_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Internal network error: \"listen\" failed."), + QMessageBox::Close); } + break; + case ERR_SOCK_ACCEPT_FAILED: + { QMessageBox::warning(this, tr("Network Error"), + tr("Server execution was terminated."), + QMessageBox::Close); } + break; case ERR_SOCK_CONNECT_FAILED: { QMessageBox::warning(this, tr("Network Error"), tr("Could not connect to the server."), diff --git a/src/net/clientcallback.h b/src/net/clientcallback.h index 47699484..8e75fe82 100644 --- a/src/net/clientcallback.h +++ b/src/net/clientcallback.h @@ -27,9 +27,6 @@ class ClientCallback : public NetCallback { public: virtual ~ClientCallback(); - - virtual void SignalNetSuccess(int actionID) = 0; - virtual void SignalNetError(int errorID, int osErrorID) = 0; }; #endif diff --git a/src/net/clientcontext.h b/src/net/clientcontext.h new file mode 100644 index 00000000..829ae217 --- /dev/null +++ b/src/net/clientcontext.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Context of network client. */ + +#ifndef _CLIENTCONTEXT_H_ +#define _CLIENTCONTEXT_H_ + +#include + + +class ClientContext : public NetContext +{ +public: + ClientContext(); + virtual ~ClientContext(); + + virtual SOCKET GetSocket() const; + virtual u_int32_t GetId() const; + + void SetSocket(SOCKET sockfd); + + int GetAddrFamily() const + {return m_addrFamily;} + void SetAddrFamily(int addrFamily) + {m_addrFamily = addrFamily;} + const std::string &GetServerAddr() const + {return m_serverAddr;} + void SetServerAddr(const std::string &serverAddr) + {m_serverAddr = serverAddr;} + unsigned GetServerPort() const + {return m_serverPort;} + void SetServerPort(unsigned serverPort) + {m_serverPort = serverPort;} + const std::string &GetPassword() const + {return m_password;} + void SetPassword(const std::string &password) + {m_password = password;} + const sockaddr_storage *GetClientSockaddr() const + {return &m_clientSockaddr;} + sockaddr_storage *GetClientSockaddr() + {return &m_clientSockaddr;} + + int GetClientSockaddrSize() const + {return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);} + +private: + SOCKET m_sockfd; + int m_addrFamily; + std::string m_serverAddr; + unsigned m_serverPort; + std::string m_password; + sockaddr_storage m_clientSockaddr; +}; + +#endif diff --git a/src/net/clientthread.h b/src/net/clientthread.h index 7b75a574..b53c38d5 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -25,11 +25,12 @@ #include #include -class ClientData; +class ClientContext; class ClientState; class ClientCallback; class SenderThread; class ReceiverHelper; +class ClientSenderCallback; class ClientThread : public Thread { @@ -42,13 +43,15 @@ public: // (i.e. after starting the thread). void Init(const std::string &serverAddress, unsigned serverPort, bool ipv6, const std::string &pwd); + ClientCallback &GetCallback(); + protected: // Main function of the thread. virtual void Main(); - const ClientData &GetData() const; - ClientData &GetData(); + const ClientContext &GetContext() const; + ClientContext &GetContext(); ClientState &GetState(); void SetState(ClientState &newState); @@ -56,9 +59,12 @@ protected: SenderThread &GetSender(); ReceiverHelper &GetReceiver(); + ClientSenderCallback &GetSenderCallback(); + private: - std::auto_ptr m_data; + std::auto_ptr m_context; + std::auto_ptr m_senderCallback; ClientState *m_curState; ClientCallback &m_callback; std::auto_ptr m_sender; diff --git a/src/net/common/clientcontext.cpp b/src/net/common/clientcontext.cpp new file mode 100644 index 00000000..6dea8917 --- /dev/null +++ b/src/net/common/clientcontext.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + +ClientContext::ClientContext() +: m_sockfd(INVALID_SOCKET), m_addrFamily(AF_INET), m_serverPort(0) +{ + bzero(&m_clientSockaddr, sizeof(m_clientSockaddr)); +} + +ClientContext::~ClientContext() +{ + if (m_sockfd != INVALID_SOCKET) + CLOSESOCKET(m_sockfd); +} + +SOCKET +ClientContext::GetSocket() const +{ + return m_sockfd; +} + +u_int32_t +ClientContext::GetId() const +{ + // Id is unused for clients. + return 0; +} + +void +ClientContext::SetSocket(SOCKET sockfd) +{ + m_sockfd = sockfd; +} + diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 92709435..401460a2 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -28,11 +28,9 @@ #include #include -#include - using namespace std; -#define CLIENT_WAIT_TIMEOUT_MSEC 100 +#define CLIENT_WAIT_TIMEOUT_MSEC 50 ClientState::~ClientState() @@ -59,20 +57,20 @@ ClientStateInit::~ClientStateInit() int ClientStateInit::Process(ClientThread &client) { - ClientData &data = client.GetData(); + ClientContext &context = client.GetContext(); - if (data.serverAddr.empty()) + if (context.GetServerAddr().empty()) throw ClientException(ERR_SOCK_SERVERADDR_NOT_SET, 0); -// if (data.serverPort < 1024) +// if (context.GetServerPort() < 1024) // throw ClientException(ERR_SOCK_INVALID_PORT, 0); - data.sockfd = socket(data.addrFamily, SOCK_STREAM, 0); - if (!IS_VALID_SOCKET(data.sockfd)) + context.SetSocket(socket(context.GetAddrFamily(), SOCK_STREAM, 0)); + if (!IS_VALID_SOCKET(context.GetSocket())) throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO()); unsigned long mode = 1; - if (IOCTLSOCKET(data.sockfd, FIONBIO, &mode) == SOCKET_ERROR) + if (IOCTLSOCKET(context.GetSocket(), FIONBIO, &mode) == SOCKET_ERROR) throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO()); client.SetState(ClientStateStartResolve::Instance()); @@ -102,19 +100,19 @@ ClientStateStartResolve::Process(ClientThread &client) { int retVal; - ClientData &data = client.GetData(); + ClientContext &context = client.GetContext(); - data.clientAddr.ss_family = data.addrFamily; + context.GetClientSockaddr()->ss_family = context.GetAddrFamily(); // Treat the server address as numbers first. if (socket_string_to_addr( - data.serverAddr.c_str(), - data.addrFamily, - (struct sockaddr *)&data.clientAddr, - data.GetServerAddrSize())) + context.GetServerAddr().c_str(), + context.GetAddrFamily(), + (struct sockaddr *)context.GetClientSockaddr(), + context.GetClientSockaddrSize())) { // Success - but we still need to set the port. - if (!socket_set_port(data.serverPort, data.addrFamily, (struct sockaddr *)&data.clientAddr, data.GetServerAddrSize())) + if (!socket_set_port(context.GetServerPort(), context.GetAddrFamily(), (struct sockaddr *)context.GetClientSockaddr(), context.GetClientSockaddrSize())) throw ClientException(ERR_SOCK_SET_PORT_FAILED, 0); // No need to resolve - start connecting. @@ -126,7 +124,7 @@ ClientStateStartResolve::Process(ClientThread &client) // Start name resolution in a separate thread, since it is blocking // for up to about 30 seconds. std::auto_ptr resolver(new ResolverThread); - resolver->Init(data); + resolver->Init(context); resolver->Run(); ClientStateResolving::Instance().SetResolver(resolver.release()); @@ -175,8 +173,8 @@ ClientStateResolving::Process(ClientThread &client) if (m_resolver->Join(CLIENT_WAIT_TIMEOUT_MSEC)) { - ClientData &data = client.GetData(); - bool success = m_resolver->GetResult(data); + ClientContext &context = client.GetContext(); + bool success = m_resolver->GetResult(context); Cleanup(); // Not required, but better keep things clean. if (!success) @@ -226,9 +224,9 @@ int ClientStateStartConnect::Process(ClientThread &client) { int retVal; - ClientData &data = client.GetData(); + ClientContext &context = client.GetContext(); - int connectResult = connect(data.sockfd, (struct sockaddr *)&data.clientAddr, data.GetServerAddrSize()); + int connectResult = connect(context.GetSocket(), (struct sockaddr *)context.GetClientSockaddr(), context.GetClientSockaddrSize()); if (IS_VALID_CONNECT(connectResult)) { @@ -271,24 +269,24 @@ int ClientStateConnecting::Process(ClientThread &client) { int retVal; - ClientData &data = client.GetData(); + ClientContext &context = client.GetContext(); fd_set writeSet; struct timeval timeout; FD_ZERO(&writeSet); - FD_SET(data.sockfd, &writeSet); + FD_SET(context.GetSocket(), &writeSet); timeout.tv_sec = 0; timeout.tv_usec = CLIENT_WAIT_TIMEOUT_MSEC * 1000; - int selectResult = select(data.sockfd + 1, NULL, &writeSet, NULL, &timeout); + int selectResult = select(context.GetSocket() + 1, NULL, &writeSet, NULL, &timeout); if (selectResult > 0) // success { // Check whether the connect call succeeded. int connectResult = 0; socklen_t tmpSize = sizeof(connectResult); - getsockopt(data.sockfd, SOL_SOCKET, SO_ERROR, (char *)&connectResult, &tmpSize); + getsockopt(context.GetSocket(), SOL_SOCKET, SO_ERROR, (char *)&connectResult, &tmpSize); if (connectResult != 0) throw ClientException(ERR_SOCK_CONNECT_FAILED, connectResult); client.SetState(ClientStateStartSession::Instance()); @@ -323,12 +321,8 @@ ClientStateStartSession::~ClientStateStartSession() int ClientStateStartSession::Process(ClientThread &client) { - client.GetReceiver().Init(client.GetData().sockfd); - client.GetSender().Init(client.GetData().sockfd); - client.GetSender().Run(); - boost::shared_ptr packet(new TestNetPacket(10)); - client.GetSender().Send(packet); + client.GetSender().Send(packet, client.GetContext().GetSocket()); client.SetState(ClientStateWaitSession::Instance()); @@ -356,11 +350,11 @@ int ClientStateWaitSession::Process(ClientThread &client) { int retVal; - ClientData &data = client.GetData(); + ClientContext &context = client.GetContext(); // delegate to receiver helper class - boost::shared_ptr tmpPacket = client.GetReceiver().Recv(); + boost::shared_ptr tmpPacket = client.GetReceiver().Recv(context.GetSocket()); if (tmpPacket.get()) { diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index bf38c513..326e1b2f 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -32,10 +32,30 @@ using namespace std; +class ClientSenderCallback : public SenderCallback +{ +public: + ClientSenderCallback(ClientThread &client) : m_client(client) {} + virtual ~ClientSenderCallback() {} + + virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) + { + // For now, we ignore the socket. + // Just signal the error. + // We assume that the client thread will be terminated. + m_client.GetCallback().SignalNetError(errorID, osErrorID); + } + +private: + ClientThread &m_client; +}; + + ClientThread::ClientThread(ClientCallback &cb) : m_curState(NULL), m_callback(cb) { - m_data.reset(new ClientData); + m_context.reset(new ClientContext); + m_senderCallback.reset(new ClientSenderCallback(*this)); } ClientThread::~ClientThread() @@ -48,47 +68,57 @@ ClientThread::Init(const string &serverAddress, unsigned serverPort, bool ipv6, if (IsRunning()) return; // TODO: throw exception - ClientData &data = GetData(); + ClientContext &context = GetContext(); - data.addrFamily = ipv6 ? AF_INET6 : AF_INET; - data.serverAddr = serverAddress; - data.serverPort = serverPort; - data.password = pwd; + context.SetAddrFamily(ipv6 ? AF_INET6 : AF_INET); + context.SetServerAddr(serverAddress); + context.SetServerPort(serverPort); + context.SetPassword(pwd); +} + +ClientCallback & +ClientThread::GetCallback() +{ + return m_callback; } void ClientThread::Main() { - m_sender.reset(new SenderThread(m_callback)); - m_receiver.reset(new ReceiverHelper); SetState(CLIENT_INITIAL_STATE::Instance()); - try { + + m_sender.reset(new SenderThread(GetSenderCallback())); + m_receiver.reset(new ReceiverHelper); + GetSender().Run(); + + try + { while (!ShouldTerminate()) { int msg = GetState().Process(*this); if (msg != MSG_SOCK_INTERNAL_PENDING) - m_callback.SignalNetSuccess(msg); + GetCallback().SignalNetSuccess(msg); } } catch (const NetException &e) { - m_callback.SignalNetError(e.GetErrorId(), e.GetOsErrorCode()); + GetCallback().SignalNetError(e.GetErrorId(), e.GetOsErrorCode()); } GetSender().SignalTermination(); - GetSender().Join(100); + GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); } -const ClientData & -ClientThread::GetData() const +const ClientContext & +ClientThread::GetContext() const { - assert(m_data.get()); - return *m_data; + assert(m_context.get()); + return *m_context; } -ClientData & -ClientThread::GetData() +ClientContext & +ClientThread::GetContext() { - assert(m_data.get()); - return *m_data; + assert(m_context.get()); + return *m_context; } ClientState & @@ -118,3 +148,10 @@ ClientThread::GetReceiver() return *m_receiver; } +ClientSenderCallback & +ClientThread::GetSenderCallback() +{ + assert(m_senderCallback.get()); + return *m_senderCallback; +} + diff --git a/src/net/common/clientdata.cpp b/src/net/common/connectdata.cpp similarity index 83% rename from src/net/common/clientdata.cpp rename to src/net/common/connectdata.cpp index 6b697b3e..5ed53ab1 100644 --- a/src/net/common/clientdata.cpp +++ b/src/net/common/connectdata.cpp @@ -17,17 +17,17 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include +#include -ClientData::ClientData() -: sockfd(INVALID_SOCKET), addrFamily(AF_INET), serverPort(0) +ConnectData::ConnectData() +: m_sockfd(INVALID_SOCKET) { - bzero(&clientAddr, sizeof(clientAddr)); + bzero(&m_sockaddr, sizeof(m_sockaddr)); } -ClientData::~ClientData() +ConnectData::~ConnectData() { - if (sockfd != INVALID_SOCKET) - CLOSESOCKET(sockfd); + if (m_sockfd != INVALID_SOCKET) + CLOSESOCKET(m_sockfd); } diff --git a/src/net/common/netcontext.cpp b/src/net/common/netcontext.cpp new file mode 100644 index 00000000..611c6340 --- /dev/null +++ b/src/net/common/netcontext.cpp @@ -0,0 +1,25 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + +NetContext::~NetContext() +{ +} + diff --git a/src/net/common/receiverhelper.cpp b/src/net/common/receiverhelper.cpp index 7f929574..228651dc 100644 --- a/src/net/common/receiverhelper.cpp +++ b/src/net/common/receiverhelper.cpp @@ -45,7 +45,7 @@ ReceiverHelper::Init(SOCKET socket) } boost::shared_ptr -ReceiverHelper::Recv() +ReceiverHelper::Recv(SOCKET sock) { boost::shared_ptr tmpPacket(InternalGetPacket()); @@ -59,18 +59,18 @@ ReceiverHelper::Recv() struct timeval timeout; FD_ZERO(&readSet); - FD_SET(m_socket, &readSet); + FD_SET(sock, &readSet); timeout.tv_sec = 0; timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000; - int selectResult = select(m_socket + 1, &readSet, NULL, NULL, &timeout); + int selectResult = select(sock + 1, &readSet, NULL, NULL, &timeout); if (!IS_VALID_SELECT(selectResult)) { throw NetException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); } if (selectResult > 0) // recv is possible { - int bytesRecvd = recv(m_socket, m_tmpInBuf + m_tmpInBufSize, bufSize, 0); + int bytesRecvd = recv(sock, m_tmpInBuf + m_tmpInBufSize, bufSize, 0); if (!IS_VALID_RECV(bytesRecvd)) { diff --git a/src/net/common/resolverthread.cpp b/src/net/common/resolverthread.cpp index c1027938..c2f076e3 100644 --- a/src/net/common/resolverthread.cpp +++ b/src/net/common/resolverthread.cpp @@ -18,7 +18,7 @@ ***************************************************************************/ #include -#include +#include #include #include @@ -30,7 +30,7 @@ using namespace std; ResolverThread::ResolverThread() : m_retVal(false) { - m_data.reset(new ClientData); + m_context.reset(new ClientContext); } ResolverThread::~ResolverThread() @@ -38,24 +38,24 @@ ResolverThread::~ResolverThread() } void -ResolverThread::Init(const ClientData &data) +ResolverThread::Init(const ClientContext &context) { if (IsRunning()) return; // TODO: throw exception - m_data->addrFamily = data.addrFamily; - m_data->serverAddr = data.serverAddr; - m_data->serverPort = data.serverPort; + GetContext().SetAddrFamily(context.GetAddrFamily()); + GetContext().SetServerAddr(context.GetServerAddr()); + GetContext().SetServerPort(context.GetServerPort()); } bool -ResolverThread::GetResult(ClientData &data) +ResolverThread::GetResult(ClientContext &context) const { if (IsRunning()) return false; // TODO: throw exception if (m_retVal) - memcpy(&data.clientAddr, &GetData().clientAddr, GetData().GetServerAddrSize()); + memcpy(context.GetClientSockaddr(), GetContext().GetClientSockaddr(), GetContext().GetClientSockaddrSize()); return m_retVal; } @@ -63,34 +63,34 @@ ResolverThread::GetResult(ClientData &data) void ResolverThread::Main() { - const ClientData &data = GetData(); + const ClientContext &context = GetContext(); // Convert the port to a string. ostringstream tmpStr; - tmpStr << data.serverPort; + tmpStr << context.GetServerPort(); // Start the name resolution. m_retVal = socket_resolve( - data.serverAddr.c_str(), + context.GetServerAddr().c_str(), tmpStr.str().c_str(), - data.addrFamily, + context.GetAddrFamily(), SOCK_STREAM, 0, - (struct sockaddr *)&data.clientAddr, - data.GetServerAddrSize()); + (struct sockaddr *)context.GetClientSockaddr(), + context.GetClientSockaddrSize()); } -const ClientData & -ResolverThread::GetData() const +const ClientContext & +ResolverThread::GetContext() const { - assert(m_data.get()); - return *m_data; + assert(m_context.get()); + return *m_context; } -ClientData & -ResolverThread::GetData() +ClientContext & +ResolverThread::GetContext() { - assert(m_data.get()); - return *m_data; + assert(m_context.get()); + return *m_context; } diff --git a/src/net/common/sendercallback.cpp b/src/net/common/sendercallback.cpp new file mode 100644 index 00000000..e6f451b6 --- /dev/null +++ b/src/net/common/sendercallback.cpp @@ -0,0 +1,26 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + + +SenderCallback::~SenderCallback() +{ +} + diff --git a/src/net/common/senderthread.cpp b/src/net/common/senderthread.cpp index b3689c33..3fd34e2d 100644 --- a/src/net/common/senderthread.cpp +++ b/src/net/common/senderthread.cpp @@ -18,7 +18,7 @@ ***************************************************************************/ #include -#include +#include #include #include @@ -26,8 +26,8 @@ using namespace std; #define SEND_TIMEOUT_MSEC 50 -SenderThread::SenderThread(NetCallback &cb) -: m_tmpOutBufSize(0), m_callback(cb) +SenderThread::SenderThread(SenderCallback &cb) +: m_curSocket(INVALID_SOCKET), m_tmpOutBufSize(0), m_callback(cb) { } @@ -36,19 +36,13 @@ SenderThread::~SenderThread() } void -SenderThread::Init(SOCKET socket) +SenderThread::Send(boost::shared_ptr packet, SOCKET sock) { - if (!IS_VALID_SOCKET(socket) || IsRunning()) - return; // TODO: throw exception - - m_socket = socket; -} - -void -SenderThread::Send(boost::shared_ptr packet) -{ - boost::mutex::scoped_lock lock(m_outBufMutex); - m_outBuf.push_back(packet); + if (packet.get() && IS_VALID_SOCKET(sock)) + { + boost::mutex::scoped_lock lock(m_outBufMutex); + m_outBuf.push_back(std::make_pair(packet, sock)); + } } void @@ -61,22 +55,26 @@ SenderThread::Main() // For reasons of simplicity, only one packet is sent at a time. if (!m_tmpOutBufSize) { - boost::shared_ptr tmpPacket; + SendData tmpData; { boost::mutex::scoped_lock lock(m_outBufMutex); if (!m_outBuf.empty()) { - tmpPacket = m_outBuf.front(); + tmpData = m_outBuf.front(); m_outBuf.pop_front(); } } - if (tmpPacket.get()) + + if (tmpData.first.get()) { - u_int16_t tmpLen = ntohs(tmpPacket->GetData()->length); + if (IS_VALID_SOCKET(tmpData.second)) + m_curSocket = tmpData.second; + + u_int16_t tmpLen = ntohs(tmpData.first->GetData()->length); if (tmpLen <= MAX_PACKET_SIZE) { m_tmpOutBufSize = tmpLen; - memcpy(m_tmpOutBuf, tmpPacket->GetData(), m_tmpOutBufSize); + memcpy(m_tmpOutBuf, tmpData.first->GetData(), m_tmpOutBufSize); } } } @@ -86,25 +84,25 @@ SenderThread::Main() struct timeval timeout; FD_ZERO(&writeSet); - FD_SET(m_socket, &writeSet); + FD_SET(m_curSocket, &writeSet); timeout.tv_sec = 0; timeout.tv_usec = SEND_TIMEOUT_MSEC * 1000; - int selectResult = select(m_socket + 1, NULL, &writeSet, NULL, &timeout); + int selectResult = select(m_curSocket + 1, NULL, &writeSet, NULL, &timeout); if (!IS_VALID_SELECT(selectResult)) { - m_callback.SignalNetError(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); + m_callback.SignalNetError(m_curSocket, ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); // Assume that this is a fatal error, terminate thread. return; } if (selectResult > 0) // send is possible { // send next chunk of data - int bytesSent = send(m_socket, m_tmpOutBuf, m_tmpOutBufSize, 0); + int bytesSent = send(m_curSocket, m_tmpOutBuf, m_tmpOutBufSize, 0); if (!IS_VALID_SEND(bytesSent)) { - m_callback.SignalNetError(ERR_SOCK_SEND_FAILED, SOCKET_ERRNO()); + m_callback.SignalNetError(m_curSocket, ERR_SOCK_SEND_FAILED, SOCKET_ERRNO()); // Assume that this is a fatal error, terminate thread. return; } diff --git a/src/net/common/servercontext.cpp b/src/net/common/servercontext.cpp new file mode 100644 index 00000000..612002f6 --- /dev/null +++ b/src/net/common/servercontext.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + +ServerContext::ServerContext() +: m_sockfd(INVALID_SOCKET), m_addrFamily(AF_INET), m_serverPort(0) +{ + bzero(&m_serverSockaddr, sizeof(m_serverSockaddr)); +} + +ServerContext::~ServerContext() +{ + if (m_sockfd != INVALID_SOCKET) + CLOSESOCKET(m_sockfd); +} + +SOCKET +ServerContext::GetSocket() const +{ + return m_sockfd; +} + +u_int32_t +ServerContext::GetId() const +{ + // Id is unused for main server thread. + return 0; +} + +void +ServerContext::SetSocket(SOCKET sockfd) +{ + m_sockfd = sockfd; +} + diff --git a/src/net/common/serverexception.cpp b/src/net/common/serverexception.cpp new file mode 100644 index 00000000..b707d611 --- /dev/null +++ b/src/net/common/serverexception.cpp @@ -0,0 +1,26 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + + +ServerException::~ServerException() +{ +} + diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp new file mode 100644 index 00000000..1f38d47b --- /dev/null +++ b/src/net/common/serverrecvstate.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include + +using namespace std; + +#define SERVER_WAIT_TIMEOUT_MSEC 50 + + +ServerRecvState::~ServerRecvState() +{ +} + +//----------------------------------------------------------------------------- + +ServerRecvStateInit & +ServerRecvStateInit::Instance() +{ + static ServerRecvStateInit state; + return state; +} + +ServerRecvStateInit::ServerRecvStateInit() +{ +} + +ServerRecvStateInit::~ServerRecvStateInit() +{ +} + +void +ServerRecvStateInit::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr data) +{ +} + +int +ServerRecvStateInit::Process(ServerRecvThread &server) +{ + Thread::Msleep(SERVER_WAIT_TIMEOUT_MSEC); + return MSG_SOCK_INIT_DONE; +} + +//----------------------------------------------------------------------------- + diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp new file mode 100644 index 00000000..798e718d --- /dev/null +++ b/src/net/common/serverrecvthread.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +class ServerSenderCallback : public SenderCallback +{ +public: + ServerSenderCallback(ServerRecvThread &server) : m_server(server) {} + virtual ~ServerSenderCallback() {} + + virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) + { + // TODO + } + +private: + ServerRecvThread &m_server; +}; + + +ServerRecvThread::ServerRecvThread() +{ + m_senderCallback.reset(new ServerSenderCallback(*this)); +} + +ServerRecvThread::~ServerRecvThread() +{ +} + +void +ServerRecvThread::AddConnection(boost::shared_ptr data) +{ + boost::mutex::scoped_lock lock(m_connectQueueMutex); + m_connectQueue.push_back(data); +} + +void +ServerRecvThread::Main() +{ + SetState(SERVER_INITIAL_STATE::Instance()); + + m_sender.reset(new SenderThread(GetSenderCallback())); + m_receiver.reset(new ReceiverHelper); + GetSender().Run(); + + try + { + while (!ShouldTerminate()) + { + { + boost::shared_ptr tmpData; + { + boost::mutex::scoped_lock lock(m_connectQueueMutex); + if (!m_connectQueue.empty()) + { + tmpData = m_connectQueue.front(); + m_connectQueue.pop_front(); + } + } + if (tmpData.get()) + GetState().HandleNewConnection(*this, tmpData); + } + GetState().Process(*this); + } + } catch (const NetException &) + { + // TODO + } + GetSender().SignalTermination(); + GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); +} + +ServerRecvState & +ServerRecvThread::GetState() +{ + assert(m_curState); + return *m_curState; +} + +void +ServerRecvThread::SetState(ServerRecvState &newState) +{ + m_curState = &newState; +} + +SenderThread & +ServerRecvThread::GetSender() +{ + assert(m_sender.get()); + return *m_sender; +} + +ReceiverHelper & +ServerRecvThread::GetReceiver() +{ + assert(m_receiver.get()); + return *m_receiver; +} + +ServerSenderCallback & +ServerRecvThread::GetSenderCallback() +{ + assert(m_senderCallback.get()); + return *m_senderCallback; +} + diff --git a/src/net/common/serverthread.cpp b/src/net/common/serverthread.cpp index 05603214..7badf16b 100644 --- a/src/net/common/serverthread.cpp +++ b/src/net/common/serverthread.cpp @@ -18,11 +18,20 @@ ***************************************************************************/ #include +#include +#include +#include #include +#include +#include + +#define ACCEPT_TIMEOUT_MSEC 50 +#define NET_SERVER_LISTEN_BACKLOG 5 ServerThread::ServerThread() { + m_context.reset(new ServerContext); } ServerThread::~ServerThread() @@ -30,44 +39,138 @@ ServerThread::~ServerThread() } void -ServerThread::Init() +ServerThread::Init(unsigned serverPort, bool ipv6, const std::string &pwd) { if (IsRunning()) return; // TODO: throw exception + + ServerContext &context = GetContext(); + + context.SetAddrFamily(ipv6 ? AF_INET6 : AF_INET); + context.SetServerPort(serverPort); + context.SetPassword(pwd); } void ServerThread::Main() { - while (!ShouldTerminate()) + m_recvThread.reset(new ServerRecvThread); + try { - // Simple hacked server for testing. - SOCKET sockfd; - char buf[1024]; - struct sockaddr_storage servaddr, clientaddr; - int sockaddr_size = sizeof(struct sockaddr_in); - int addrFamily = AF_INET; - socklen_t addrSize; + Listen(); + GetRecvThread().Run(); - sockfd = socket(addrFamily, SOCK_STREAM, 0); - bzero(&servaddr, sizeof(servaddr)); - servaddr.ss_family = addrFamily; - - socket_string_to_addr("0.0.0.0", addrFamily, (struct sockaddr *)&servaddr, sockaddr_size); - socket_set_port(7234, addrFamily, (struct sockaddr *)&servaddr, sockaddr_size); - - bind(sockfd, (const struct sockaddr *)&servaddr, sockaddr_size); - listen(sockfd, 1); - - bzero(&clientaddr, sizeof(clientaddr)); - addrSize = sockaddr_size; - SOCKET conn = accept(sockfd, (struct sockaddr *)&clientaddr, &addrSize); - CLOSESOCKET(sockfd); - int ret = recv(conn, buf, sizeof(buf), 0); - - send(conn, buf, ret, 0); - - CLOSESOCKET(conn); + while (!ShouldTerminate()) + { + // The main server thread is simple. It only accepts connections. + AcceptLoop(); + } + } catch (const NetException &) + { + // TODO: callback. } } +void +ServerThread::Listen() +{ + ServerContext &context = GetContext(); + +// if (context.GetServerPort() < 1024) +// throw ServerException(ERR_SOCK_INVALID_PORT, 0); + + context.SetSocket(socket(context.GetAddrFamily(), SOCK_STREAM, 0)); + if (!IS_VALID_SOCKET(context.GetSocket())) + throw ServerException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO()); + + unsigned long mode = 1; + if (IOCTLSOCKET(context.GetSocket(), FIONBIO, &mode) == SOCKET_ERROR) + throw ServerException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO()); + + context.GetServerSockaddr()->ss_family = context.GetAddrFamily(); + + if (!socket_string_to_addr( + "0.0.0.0", + context.GetAddrFamily(), + (struct sockaddr *)context.GetServerSockaddr(), + context.GetServerSockaddrSize())) + { + throw ServerException(ERR_SOCK_SET_ADDR_FAILED, 0); + } + if (!socket_set_port( + context.GetServerPort(), + context.GetAddrFamily(), + (struct sockaddr *)context.GetServerSockaddr(), + context.GetServerSockaddrSize())) + { + throw ServerException(ERR_SOCK_SET_PORT_FAILED, 0); + } + + if (!IS_VALID_BIND(bind( + context.GetSocket(), + (const struct sockaddr *)context.GetServerSockaddr(), + context.GetServerSockaddrSize()))) + { + throw ServerException(ERR_SOCK_BIND_FAILED, SOCKET_ERRNO()); + } + + if (!IS_VALID_LISTEN(listen(context.GetSocket(), NET_SERVER_LISTEN_BACKLOG))) + { + throw ServerException(ERR_SOCK_LISTEN_FAILED, SOCKET_ERRNO()); + } +} + +void +ServerThread::AcceptLoop() +{ + ServerContext &context = GetContext(); + + fd_set readSet; + struct timeval timeout; + + FD_ZERO(&readSet); + FD_SET(context.GetSocket(), &readSet); + + timeout.tv_sec = 0; + timeout.tv_usec = ACCEPT_TIMEOUT_MSEC * 1000; + int selectResult = select(context.GetSocket() + 1, &readSet, NULL, NULL, &timeout); + if (!IS_VALID_SELECT(selectResult)) + { + throw ServerException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); + } + if (selectResult > 0) // accept is possible + { + boost::shared_ptr tmpData(new ConnectData); + socklen_t addrSize = sizeof(*tmpData->GetSockaddr()); + tmpData->SetSocket(accept(context.GetSocket(), (struct sockaddr *)tmpData->GetSockaddr(), &addrSize)); + + if (!IS_VALID_SOCKET(tmpData->GetSocket())) + { + throw ServerException(ERR_SOCK_ACCEPT_FAILED, SOCKET_ERRNO()); + } + + GetRecvThread().AddConnection(tmpData); + } +} + +const ServerContext & +ServerThread::GetContext() const +{ + assert(m_context.get()); + return *m_context; +} + +ServerContext & +ServerThread::GetContext() +{ + assert(m_context.get()); + return *m_context; +} + +ServerRecvThread & +ServerThread::GetRecvThread() +{ + assert(m_recvThread.get()); + return *m_recvThread; +} + diff --git a/src/net/connectdata.h b/src/net/connectdata.h new file mode 100644 index 00000000..f1caee34 --- /dev/null +++ b/src/net/connectdata.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Connection data. */ + +#ifndef _CONNECTDATA_H_ +#define _CONNECTDATA_H_ + +#include + +class ConnectData +{ +public: + ConnectData(); + ~ConnectData(); + + SOCKET GetSocket() const + {return m_sockfd;} + void SetSocket(SOCKET sockfd) + {m_sockfd = sockfd;} + const sockaddr_storage *GetSockaddr() const + {return &m_sockaddr;} + sockaddr_storage *GetSockaddr() + {return &m_sockaddr;} + +private: + SOCKET m_sockfd; + sockaddr_storage m_sockaddr; +}; + +#endif diff --git a/src/net/clientdata.h b/src/net/netcontext.h similarity index 77% rename from src/net/clientdata.h rename to src/net/netcontext.h index 50593142..7087d9bd 100644 --- a/src/net/clientdata.h +++ b/src/net/netcontext.h @@ -16,31 +16,22 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -/* State of network client. */ +/* Network context data. */ -#ifndef _CLIENTDATA_H_ -#define _CLIENTDATA_H_ +#ifndef _NETCONTEXT_H_ +#define _NETCONTEXT_H_ -#include #include +#include -class ClientData +class NetContext { public: - ClientData(); - ~ClientData(); - int GetServerAddrSize() const - { - return addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); - } + virtual ~NetContext(); - SOCKET sockfd; - int addrFamily; - std::string serverAddr; - unsigned serverPort; - std::string password; - sockaddr_storage clientAddr; + virtual SOCKET GetSocket() const = 0; + virtual u_int32_t GetId() const = 0; }; #endif diff --git a/src/net/receiverhelper.h b/src/net/receiverhelper.h index 4b51f95c..42a515d4 100644 --- a/src/net/receiverhelper.h +++ b/src/net/receiverhelper.h @@ -30,6 +30,7 @@ // MUST be larger than MAX_PACKET_SIZE #define RECV_BUF_SIZE 10 * MAX_PACKET_SIZE + class ReceiverHelper { public: @@ -39,7 +40,7 @@ public: // Set the socket from which to receive data. void Init(SOCKET socket); - boost::shared_ptr Recv(); + boost::shared_ptr Recv(SOCKET sock); protected: boost::shared_ptr InternalGetPacket(); diff --git a/src/net/resolverthread.h b/src/net/resolverthread.h index b0923127..6aa1b5ec 100644 --- a/src/net/resolverthread.h +++ b/src/net/resolverthread.h @@ -25,7 +25,7 @@ #include #include -class ClientData; +class ClientContext; class ResolverThread : public Thread { @@ -36,24 +36,24 @@ public: // Set the parameters. Does not do any error checking. // To prevent access faults if this thread cannot be // terminated, the data is not modified. - void Init(const ClientData &data); + void Init(const ClientContext &context); // Retrieve the result of the name resolution. // ONLY CALL THIS FUNCTION AFTER THE THREAD TERMINATED. // You have been warned... - bool GetResult(ClientData &data); + bool GetResult(ClientContext &context) const; protected: // Main function of the thread. virtual void Main(); - const ClientData &GetData() const; - ClientData &GetData(); + const ClientContext &GetContext() const; + ClientContext &GetContext(); private: - std::auto_ptr m_data; + std::auto_ptr m_context; bool m_retVal; }; diff --git a/src/net/sendercallback.h b/src/net/sendercallback.h new file mode 100644 index 00000000..a4f37f05 --- /dev/null +++ b/src/net/sendercallback.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Callback interface for the sender thread. */ + +#ifndef _SENDERCALLBACK_H_ +#define _SENDERCALLBACK_H_ + +#include + +class SenderCallback +{ +public: + virtual ~SenderCallback(); + + virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) = 0; +}; + +#endif diff --git a/src/net/senderthread.h b/src/net/senderthread.h index e2d2f6b6..65002a00 100644 --- a/src/net/senderthread.h +++ b/src/net/senderthread.h @@ -24,22 +24,20 @@ #include #include #include +#include #include #include -class NetCallback; +#define SENDER_THREAD_TERMINATE_TIMEOUT 100 class SenderThread : public Thread { public: - SenderThread(NetCallback &cb); + SenderThread(SenderCallback &cb); virtual ~SenderThread(); - // Set the socket used to send data. - void Init(SOCKET socket); - - void Send(boost::shared_ptr packet); + void Send(boost::shared_ptr packet, SOCKET sock); protected: @@ -48,15 +46,16 @@ protected: private: - SOCKET m_socket; + SOCKET m_curSocket; - std::deque > m_outBuf; + typedef std::pair, SOCKET> SendData; + std::deque m_outBuf; mutable boost::mutex m_outBufMutex; char m_tmpOutBuf[MAX_PACKET_SIZE]; unsigned m_tmpOutBufSize; - NetCallback &m_callback; + SenderCallback &m_callback; }; #endif diff --git a/src/net/servercontext.h b/src/net/servercontext.h new file mode 100644 index 00000000..f79ef1da --- /dev/null +++ b/src/net/servercontext.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Context of network server. */ + +#ifndef _SERVERCONTEXT_H_ +#define _SERVERCONTEXT_H_ + +#include + + +class ServerContext : public NetContext +{ +public: + ServerContext(); + virtual ~ServerContext(); + + virtual SOCKET GetSocket() const; + virtual u_int32_t GetId() const; + + void SetSocket(SOCKET sockfd); + + int GetAddrFamily() const + {return m_addrFamily;} + void SetAddrFamily(int addrFamily) + {m_addrFamily = addrFamily;} + unsigned GetServerPort() const + {return m_serverPort;} + void SetServerPort(unsigned serverPort) + {m_serverPort = serverPort;} + const std::string &GetPassword() const + {return m_password;} + void SetPassword(const std::string &password) + {m_password = password;} + const sockaddr_storage *GetServerSockaddr() const + {return &m_serverSockaddr;} + sockaddr_storage *GetServerSockaddr() + {return &m_serverSockaddr;} + + int GetServerSockaddrSize() const + {return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);} + +private: + SOCKET m_sockfd; + int m_addrFamily; + unsigned m_serverPort; + std::string m_password; + sockaddr_storage m_serverSockaddr; +}; + +#endif diff --git a/src/net/serverexception.h b/src/net/serverexception.h new file mode 100644 index 00000000..8b98d393 --- /dev/null +++ b/src/net/serverexception.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Exception class for server errors. */ + +#ifndef _SERVEREXCEPTION_H_ +#define _SERVEREXCEPTION_H_ + +#include + +class ServerException : public NetException +{ +public: + + ServerException(int errorId, int osErrorCode) + : NetException(errorId, osErrorCode) {} + + virtual ~ServerException(); +}; + +#endif diff --git a/src/net/serverrecvstate.h b/src/net/serverrecvstate.h new file mode 100644 index 00000000..50c5da51 --- /dev/null +++ b/src/net/serverrecvstate.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* State of network server. */ + +#ifndef _SERVERRECVSTATE_H_ +#define _SERVERRECVSTATE_H_ + +#include +#include + +#define SERVER_INITIAL_STATE ServerRecvStateInit + +class ServerRecvThread; +class ServerCallback; + +class ServerRecvState +{ +public: + virtual ~ServerRecvState(); + + // Handling of a new TCP connection. + virtual void HandleNewConnection(ServerRecvThread &server, boost::shared_ptr data) = 0; + + // Main processing function of the current state. + virtual int Process(ServerRecvThread &server) = 0; +}; + +// State: Initialization. +class ServerRecvStateInit : public ServerRecvState +{ +public: + // Access the state singleton. + static ServerRecvStateInit &Instance(); + + virtual ~ServerRecvStateInit(); + + // + virtual void HandleNewConnection(ServerRecvThread &server, boost::shared_ptr data); + + // + virtual int Process(ServerRecvThread &server); + +protected: + + // Protected constructor - this is a singleton. + ServerRecvStateInit(); +}; + +#endif diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h new file mode 100644 index 00000000..70a1247b --- /dev/null +++ b/src/net/serverrecvthread.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Network server receive thread. */ + +#ifndef _SERVERRECVTHREAD_H_ +#define _SERVERRECVTHREAD_H_ + +#include +#include +#include + +#include + +class ServerRecvState; +class SenderThread; +class ReceiverHelper; +class ServerSenderCallback; + +class ServerRecvThread : public Thread +{ +public: + ServerRecvThread(); + virtual ~ServerRecvThread(); + + void AddConnection(boost::shared_ptr data); + +protected: + + // Main function of the thread. + virtual void Main(); + + ServerRecvState &GetState(); + void SetState(ServerRecvState &newState); + + //const ServerRecvContext &GetContext() const; + //ServerRecvContext &GetContext(); + + SenderThread &GetSender(); + ReceiverHelper &GetReceiver(); + + ServerSenderCallback &GetSenderCallback(); + +private: + //std::auto_ptr m_context; + + std::deque > m_connectQueue; + mutable boost::mutex m_connectQueueMutex; + ServerRecvState *m_curState; + + std::auto_ptr m_receiver; + std::auto_ptr m_sender; + + std::auto_ptr m_senderCallback; +}; + +#endif diff --git a/src/net/serverthread.h b/src/net/serverthread.h index 5f3935ec..dcbf53cd 100644 --- a/src/net/serverthread.h +++ b/src/net/serverthread.h @@ -25,6 +25,10 @@ #include #include +class ServerContext; +class ServerRecvThread; +class ServerSenderCallback; +class SenderThread; class ServerThread : public Thread { @@ -32,16 +36,25 @@ public: ServerThread(/*ServerCallback &gui*/); virtual ~ServerThread(); - // Set the parameters. TODO - void Init(); + // Set the parameters. + void Init(unsigned serverPort, bool ipv6, const std::string &pwd); protected: // Main function of the thread. virtual void Main(); -private: + void Listen(); + void AcceptLoop(); + const ServerContext &GetContext() const; + ServerContext &GetContext(); + + ServerRecvThread &GetRecvThread(); + +private: + std::auto_ptr m_context; + std::auto_ptr m_recvThread; }; #endif diff --git a/src/net/socket_helper.h b/src/net/socket_helper.h index 3a1b3e2f..1bedd43f 100644 --- a/src/net/socket_helper.h +++ b/src/net/socket_helper.h @@ -51,6 +51,7 @@ typedef unsigned char u_char; #define IS_VALID_SOCKET(_s) ((_s) != INVALID_SOCKET) #define IS_VALID_CONNECT(_c) ((_c) == 0) #define IS_VALID_BIND(_b) ((_b) != SOCKET_ERROR) +#define IS_VALID_LISTEN(_l) ((_l) != SOCKET_ERROR) #define IS_VALID_RECV(_r) ((_r) != SOCKET_ERROR) #define IS_VALID_SEND(_s) ((_s) != SOCKET_ERROR) #define IS_VALID_SELECT(_s) ((_s) != SOCKET_ERROR) diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index 68bf65b4..93b93f31 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -24,13 +24,17 @@ #define ERR_SOCK_SERVERADDR_NOT_SET 2 #define ERR_SOCK_INVALID_PORT 3 #define ERR_SOCK_CREATION_FAILED 4 -#define ERR_SOCK_SET_PORT_FAILED 5 -#define ERR_SOCK_RESOLVE_FAILED 6 -#define ERR_SOCK_CONNECT_FAILED 7 -#define ERR_SOCK_SELECT_FAILED 8 -#define ERR_SOCK_RECV_FAILED 9 -#define ERR_SOCK_SEND_FAILED 10 -#define ERR_SOCK_CONN_RESET 11 +#define ERR_SOCK_SET_ADDR_FAILED 5 +#define ERR_SOCK_SET_PORT_FAILED 6 +#define ERR_SOCK_RESOLVE_FAILED 7 +#define ERR_SOCK_BIND_FAILED 8 +#define ERR_SOCK_LISTEN_FAILED 9 +#define ERR_SOCK_ACCEPT_FAILED 10 +#define ERR_SOCK_CONNECT_FAILED 11 +#define ERR_SOCK_SELECT_FAILED 12 +#define ERR_SOCK_RECV_FAILED 13 +#define ERR_SOCK_SEND_FAILED 14 +#define ERR_SOCK_CONN_RESET 15 // This is an internal message which is not reported. #define MSG_SOCK_INTERNAL_PENDING 0 diff --git a/src/session.cpp b/src/session.cpp index 75c5b806..7b065898 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -86,7 +86,10 @@ void Session::startNetworkServer() if (myNetServer) return; // TODO: throw exception myNetServer = new ServerThread(); - myNetServer->Init(); + myNetServer->Init( + myConfig->readConfigInt("ServerPort"), + myConfig->readConfigInt("ServerUseIpv6") == 1, + ""); myNetServer->Run(); }