summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebServer/Socket.cpp416
-rw-r--r--WebServer/Socket.h86
2 files changed, 291 insertions, 211 deletions
diff --git a/WebServer/Socket.cpp b/WebServer/Socket.cpp
index 1c48172ed..6a5f51ee7 100644
--- a/WebServer/Socket.cpp
+++ b/WebServer/Socket.cpp
@@ -35,9 +35,9 @@
#include <iostream>
#ifndef _WIN32
-#include <cstring>
-#include <sys/time.h>
-#define SD_SEND 0x01
+ #include <cstring>
+ #include <sys/time.h>
+ #define SD_SEND 0x01
#else
#define MSG_NOSIGNAL (0)
#endif
@@ -50,80 +50,135 @@ using namespace std;
int Socket::nofSockets_= 0;
-void Socket::Start() {
-#ifdef _WIN32
- if (!nofSockets_) {
- WSADATA info;
- if (WSAStartup(MAKEWORD(2,0), &info)) {
- throw "Could not start WSA";
- }
- }
-#endif
- ++nofSockets_;
+
+
+
+
+void Socket::Start()
+{
+ #ifdef _WIN32
+ if (!nofSockets_)
+ {
+ WSADATA info;
+ if (WSAStartup(MAKEWORD(2,0), &info))
+ {
+ throw "Could not start WSA";
+ }
+ }
+ #endif
+ ++nofSockets_;
}
-void Socket::End() {
+
+
+
+
+void Socket::End()
+{
#ifdef _WIN32
- WSACleanup();
+ WSACleanup();
#endif
}
-Socket::Socket() : s_(0) {
- Start();
- // UDP: use SOCK_DGRAM instead of SOCK_STREAM
- s_ = socket(AF_INET,SOCK_STREAM,0);
-#ifdef _WIN32
- if(s_ ==INVALID_SOCKET)
-#else
- if(s_ < 0)
-#endif
- {
- throw "INVALID_SOCKET";
- }
- refCounter_ = new int(1);
+
+
+Socket::Socket() :
+ s_(INVALID_SOCKET)
+{
+ Start();
+ // UDP: use SOCK_DGRAM instead of SOCK_STREAM
+ s_ = socket(AF_INET,SOCK_STREAM,0);
+
+ if (!IsValid())
+ {
+ throw "INVALID_SOCKET";
+ }
+
+ refCounter_ = new int(1);
}
-Socket::Socket(SOCKET s) : s_(s) {
- Start();
- refCounter_ = new int(1);
+
+
+
+
+Socket::Socket(SOCKET s) : s_(s)
+{
+ Start();
+ refCounter_ = new int(1);
};
-Socket::~Socket() {
- if (! --(*refCounter_)) {
- Close();
- delete refCounter_;
- }
- --nofSockets_;
- if (!nofSockets_) End();
+
+
+
+Socket::~Socket()
+{
+ if (! --(*refCounter_))
+ {
+ Close();
+ delete refCounter_;
+ }
+
+ --nofSockets_;
+ if (!nofSockets_)
+ {
+ End();
+ }
}
-Socket::Socket(const Socket& o) {
- refCounter_=o.refCounter_;
- (*refCounter_)++;
- s_ =o.s_;
- nofSockets_++;
+
+
+
+Socket::Socket(const Socket& o)
+{
+ refCounter_=o.refCounter_;
+ (*refCounter_)++;
+ s_ =o.s_;
+
+ nofSockets_++;
}
-Socket& Socket::operator=(Socket& o) {
- (*o.refCounter_)++;
- refCounter_=o.refCounter_;
- s_ =o.s_;
- nofSockets_++;
- return *this;
+
+Socket& Socket::operator=(Socket& o)
+{
+ (*o.refCounter_)++;
+
+ refCounter_ = o.refCounter_;
+ s_ = o.s_;
+
+ nofSockets_++;
+
+ return *this;
}
+
+
+
+
+bool Socket::IsValid(void) const
+{
+ #ifdef _WIN32
+ return (s_ != INVALID_SOCKET);
+ #else
+ return (s_ >= 0);
+ #endif
+}
+
+
+
+
+
void Socket::Close( bool a_WaitSend /* = false */ )
{
- if( s_ )
+ if (IsValid())
{
- if( a_WaitSend )
+ if (a_WaitSend)
{
assert( shutdown(s_, SD_SEND ) == 0 );
char c;
@@ -131,28 +186,50 @@ void Socket::Close( bool a_WaitSend /* = false */ )
{}
}
+ #ifndef _WIN32
+ // Linux needs to shut the socket down first, otherwise the socket keeps blocking accept() and select() calls!
+ // Ref.: http://forum.mc-server.org/showthread.php?tid=344
+ if (shutdown(s_, SHUT_RDWR) != 0)
+ {
+ LOGWARN("Error on shutting down socket %d", s_);
+ }
+ #endif // _WIN32
+
closesocket(s_);
- s_ = 0;
+
+ s_ = INVALID_SOCKET;
}
}
-std::string Socket::ReceiveLine() {
- std::string ret;
- while (1) {
- char r;
-
- if (recv(s_, &r, 1, 0) <= 0 )
- {
- return "";
- }
- ret += r;
- if (r == '\n') return ret;
- }
+
+
+
+
+std::string Socket::ReceiveLine()
+{
+ std::string ret;
+ while (1)
+ {
+ char r;
+
+ if (recv(s_, &r, 1, 0) <= 0 )
+ {
+ return "";
+ }
+ ret += r;
+ if (r == '\n') return ret;
+ }
}
-std::string Socket::ReceiveBytes( unsigned int a_Length ) {
+
+
+
+
+std::string Socket::ReceiveBytes( unsigned int a_Length )
+{
std::string ret;
- while( ret.size() < a_Length ) {
+ while( ret.size() < a_Length )
+ {
char r;
if (recv(s_, &r, 1, 0) <= 0 )
@@ -164,138 +241,127 @@ std::string Socket::ReceiveBytes( unsigned int a_Length ) {
return ret;
}
-void Socket::SendLine(std::string s) {
- s += '\n';
- if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 )
- {
- //printf("SendLine Socket error!! \n" );
- Close();
- }
+
+
+
+
+void Socket::SendLine(std::string s)
+{
+ s += '\n';
+ if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 )
+ {
+ //printf("SendLine Socket error!! \n" );
+ Close();
+ }
}
-void Socket::SendBytes(const std::string& s) {
- if( send(s_,s.c_str(),s.length(), MSG_NOSIGNAL) <= 0 )
- {
- //printf("SendBytes Socket error!! \n" );
- Close();
- }
+
+
+
+
+void Socket::SendBytes(const std::string& s)
+{
+ if( send(s_,s.c_str(),s.length(), MSG_NOSIGNAL) <= 0 )
+ {
+ //printf("SendBytes Socket error!! \n" );
+ Close();
+ }
}
-SocketServer::SocketServer(int port, int connections, TypeSocket type) {
- sockaddr_in sa;
- memset(&sa, 0, sizeof(sa));
- sa.sin_family = PF_INET;
- sa.sin_port = htons(port);
- s_ = socket(AF_INET, SOCK_STREAM, 0);
-#ifdef _WIN32
- if(s_ ==INVALID_SOCKET)
-#else
- if(s_ < 0)
-#endif
- {
- LOG("WebServer: INVALID_SOCKET");
- }
- if(type==NonBlockingSocket) {
- return;
- }
+SocketServer::SocketServer(int port, int connections, TypeSocket type)
+{
+ sockaddr_in sa;
-#ifdef _WIN32
- char yes = 1;
-#else
- int yes = 1;
-#endif
- if (setsockopt(s_,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
- LOG("WebServer: setsockopt == -1");
- return;
- }
-
- /* bind the socket to the internet address */
- if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) {
- closesocket(s_);
- LOG("WebServer: INVALID_SOCKET");
- }
-
- listen(s_, connections);
+ memset(&sa, 0, sizeof(sa));
+
+ sa.sin_family = PF_INET;
+ sa.sin_port = htons(port);
+ s_ = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (!IsValid())
+ {
+ LOG("WebServer: INVALID_SOCKET");
+ }
+
+ if(type==NonBlockingSocket)
+ {
+ return;
+ }
+
+ #ifdef _WIN32
+ char yes = 1;
+ #else
+ int yes = 1;
+ #endif
+
+ if (setsockopt(s_,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
+ {
+ LOG("WebServer: setsockopt == -1");
+ return;
+ }
+
+ /* bind the socket to the internet address */
+ if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR)
+ {
+ closesocket(s_);
+ LOG("WebServer: INVALID_SOCKET");
+ }
+
+ listen(s_, connections);
}
+
+
+
+
Socket* SocketServer::Accept()
{
+ Socket * r = new Socket(accept(s_, 0, 0));
+ if (!r->IsValid())
+ {
+ delete r;
+ r = NULL;
+ }
- SOCKET new_sock = accept(s_, 0, 0);
-#ifdef _WIN32
- if(new_sock==INVALID_SOCKET || s_ == 0)
-#else
- if(new_sock < 0 || s_ == 0)
-#endif
- {
- #ifdef _WIN32
- int rc = WSAGetLastError();
- if(rc==WSAEWOULDBLOCK) {
- return 0; // non-blocking call, no request pending
- }
- else
- #endif
- {
- //throw "Invalid Socket";
- return 0;
- }
- }
-
- Socket* r = new Socket(new_sock);
- return r;
+ return r;
}
-SocketClient::SocketClient(const std::string& host, int port) : Socket() {
- std::string error;
- hostent *he;
- if ((he = gethostbyname(host.c_str())) == 0) {
-#ifdef _WIN32
- error = strerror(errno);
-#endif
- throw error;
- }
- sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr = *((in_addr *)he->h_addr);
- memset(&(addr.sin_zero), 0, 8);
- if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) {
-#ifdef _WIN32
- error = strerror(WSAGetLastError());
-#endif
- throw error;
- }
+
+SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type)
+{
+ FD_ZERO(&fds_);
+ SOCKET Highest = s1->s_;
+ FD_SET(const_cast<Socket*>(s1)->s_,&fds_);
+ if(s2)
+ {
+ FD_SET(const_cast<Socket*>(s2)->s_,&fds_);
+ if (s2->s_ > Highest)
+ {
+ Highest = s2->s_;
+ }
+ }
+ if (select(Highest + 1, &fds_, NULL, NULL, NULL) == SOCKET_ERROR)
+ {
+ throw "Error in select";
+ }
}
-#ifndef _WIN32
-struct timeval;
-#endif
-SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) {
- FD_ZERO(&fds_);
- FD_SET(const_cast<Socket*>(s1)->s_,&fds_);
- if(s2) {
- FD_SET(const_cast<Socket*>(s2)->s_,&fds_);
- }
-#ifdef _WIN32
- TIMEVAL *ptval = 0;
-#else
- timeval *ptval = 0;
-#endif
- if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR)
- throw "Error in select";
-}
-bool SocketSelect::Readable(Socket const* const s) {
- if (FD_ISSET(s->s_,&fds_)) return true;
- return false;
+bool SocketSelect::Readable(Socket const* const s)
+{
+ return (FD_ISSET(s->s_,&fds_));
}
+
+
+
+
diff --git a/WebServer/Socket.h b/WebServer/Socket.h
index e38df69ea..5f1248107 100644
--- a/WebServer/Socket.h
+++ b/WebServer/Socket.h
@@ -39,6 +39,7 @@
#ifndef _WIN32
typedef int SOCKET;
#define SOCKET_ERROR (-1)
+ #define INVALID_SOCKET (-1)
#define closesocket close
#endif // !_WIN32
@@ -48,66 +49,79 @@
enum TypeSocket {BlockingSocket, NonBlockingSocket};
-class Socket {
+
+
+
+
+class Socket
+{
public:
- virtual ~Socket();
- Socket(const Socket&);
- Socket& operator=(Socket&);
+ virtual ~Socket();
+ Socket(const Socket&);
+ Socket& operator=(Socket&);
- std::string ReceiveLine();
- std::string ReceiveBytes( unsigned int a_Length );
+ std::string ReceiveLine();
+ std::string ReceiveBytes( unsigned int a_Length );
+
+ bool IsValid(void) const;
- void Close( bool a_WaitSend = false );
+ void Close( bool a_WaitSend = false );
- // The parameter of SendLine is not a const reference
- // because SendLine modifes the std::string passed.
- void SendLine (std::string);
+ // The parameter of SendLine is not a const reference
+ // because SendLine modifes the std::string passed.
+ void SendLine (std::string);
- // The parameter of SendBytes is a const reference
- // because SendBytes does not modify the std::string passed
- // (in contrast to SendLine).
- void SendBytes(const std::string&);
+ // The parameter of SendBytes is a const reference
+ // because SendBytes does not modify the std::string passed
+ // (in contrast to SendLine).
+ void SendBytes(const std::string&);
protected:
- friend class SocketServer;
- friend class SocketSelect;
+ friend class SocketServer;
+ friend class SocketSelect;
- Socket(SOCKET s);
- Socket();
+ Socket(SOCKET s);
+ Socket();
- SOCKET s_;
+ SOCKET s_;
- int* refCounter_;
+ int* refCounter_;
private:
- static void Start();
- static void End();
- static int nofSockets_;
+ static void Start();
+ static void End();
+ static int nofSockets_;
};
-class SocketClient : public Socket {
-public:
- SocketClient(const std::string& host, int port);
-};
-class SocketServer : public Socket {
+
+
+
+class SocketServer :
+ public Socket
+{
public:
- SocketServer(int port, int connections, TypeSocket type=BlockingSocket);
+ SocketServer(int port, int connections, TypeSocket type=BlockingSocket);
- Socket* Accept();
+ Socket* Accept();
};
+
+
+
+
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/wsapiref_2tiq.asp
-class SocketSelect {
- public:
- SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket);
+class SocketSelect
+{
+public:
+ SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket);
- bool Readable(Socket const * const s);
+ bool Readable(Socket const * const s);
- private:
- fd_set fds_;
+private:
+ fd_set fds_;
};
#endif