source: nscp/include/Socket.h @ 1d9338a

0.4.00.4.10.4.2stable
Last change on this file since 1d9338a was 1d9338a, checked in by Michael Medin <michael@…>, 8 years ago

2005-05-23 MickeM

+ Added obfuscated password support
+ Added some more debug info on commands (returncode, and input args)
+ Added some more comments ot the NSC.ini
+ Added central password "override"
+ Added central "host override"
+ Fixed bug with external commands always getting WARNING state

2005-05-22 MickeM

+ Added debug outout for command
+ Added timestamps for log-to-file (date_mask to configure format)
+ Added support for "no password" with check_nt
+ Added log of bad password on NSClient requests.

  • Some threading issues fixed (I hate threading :)
  • Property mode set to 100644
File size: 10.7 KB
Line 
1#pragma once
2#include "resource.h"
3#include <Thread.h>
4#include <Mutex.h>
5#include <WinSock2.h>
6
7
8namespace simpleSocket {
9        class SocketException {
10        private:
11                std::string error_;
12        public:
13                SocketException(std::string error) : error_(error) {}
14                SocketException(std::string error, int errorCode) : error_(error) {
15                        error_ += strEx::itos(errorCode);
16                }
17                std::string getMessage() const {
18                        return error_;
19                }
20
21        };
22        class DataBuffer {
23        private:
24                char *buffer_;
25                unsigned int length_;
26        public:
27                DataBuffer() : buffer_(NULL), length_(0){
28                }
29                DataBuffer(const DataBuffer &other) {
30                        buffer_ = new char[other.getLength()];
31                        memcpy(buffer_, other.getBuffer(), other.getLength());
32                        length_ = other.getLength();
33                }
34                virtual ~DataBuffer() {
35                        delete [] buffer_;
36                        length_ = 0;
37                }
38                void append(const char* buffer, const unsigned int length) {
39                        char *tBuf = new char[length_+length+1];
40                        memcpy(tBuf, buffer_, length_);
41                        memcpy(&tBuf[length_], buffer, length);
42                        delete [] buffer_;
43                        buffer_ = tBuf;
44                        length_ += length;
45                }
46                const char * getBuffer() const {
47                        return buffer_;
48                }
49                unsigned int getLength() const {
50                        return length_;
51                }
52                void copyFrom(const char* buffer, const unsigned int length) {
53                        delete [] buffer_;
54                        buffer_ = new char[length+1];
55                        memcpy(buffer_, buffer, length);
56                        length_ = length;
57                }
58        };
59
60        class Socket {
61        protected:
62                SOCKET socket_;
63                sockaddr_in from_;
64
65        public:
66                Socket() : socket_(NULL) {
67                }
68                Socket(SOCKET socket) : socket_(socket) {
69                }
70                Socket(Socket &other) {
71                        socket_ = other.socket_;
72                        from_ = other.from_;
73                        other.socket_ = NULL;
74                }
75                virtual ~Socket() {
76                        if (socket_)
77                                closesocket(socket_);
78                        socket_ = NULL;
79                }
80                virtual SOCKET detach() {
81                        SOCKET s = socket_;
82                        socket_ = NULL;
83                        return s;
84                }
85                virtual void attach(SOCKET s) {
86                        assert(socket_ == NULL);
87                        socket_ = s;
88                }
89                virtual void shutdown(int how = SD_BOTH) {
90                        if (socket_)
91                                ::shutdown(socket_, how);
92                }
93
94                virtual void close() {
95                        if (socket_)
96                                closesocket(socket_);
97                        socket_ = NULL;
98                }
99                virtual void setNonBlock() {
100                        unsigned long NoBlock = 1;
101                        this->ioctlsocket(FIONBIO, &NoBlock);
102                }
103                virtual void readAll(DataBuffer &buffer, unsigned int tmpBufferLength = 1024);
104
105                virtual void socket(int af, int type, int protocol ) {
106                        socket_ = ::socket(af, type, protocol);
107                        assert(socket_ != INVALID_SOCKET);
108                }
109                virtual void bind() {
110                        assert(socket_);
111                        int fromlen=sizeof(from_);
112                        if (::bind(socket_, (sockaddr*)&from_, fromlen) == SOCKET_ERROR)
113                                throw SocketException("bind failed: ", ::WSAGetLastError());
114                }
115                virtual void listen(int backlog = 0) {
116                        assert(socket_);
117                        if (::listen(socket_, backlog) == SOCKET_ERROR)
118                                throw SocketException("listen failed: ", ::WSAGetLastError());
119                }
120                virtual bool accept(Socket &client) {
121                        int fromlen=sizeof(client.from_);
122                        SOCKET s = ::accept(socket_, (sockaddr*)&client.from_, &fromlen);
123                        if(s == INVALID_SOCKET) {
124                                int err = ::WSAGetLastError();
125                                if (err == WSAEWOULDBLOCK)
126                                        return false;
127                                throw SocketException("accept failed: ", ::WSAGetLastError());
128                        }
129                        client.attach(s);
130                        return true;
131                }
132                virtual void setAddr(short family, u_long addr, u_short port) {
133                        from_.sin_family=family;
134                        from_.sin_addr.s_addr=addr;
135                        from_.sin_port=port;
136                }
137                virtual int send(const char * buf, unsigned int len, int flags = 0) {
138                        assert(socket_);
139                        return ::send(socket_, buf, len, flags);
140                }
141                int inline send(DataBuffer &buffer, int flags = 0) {
142                        return send(buffer.getBuffer(), buffer.getLength(), flags);
143                }
144                virtual void ioctlsocket(long cmd, u_long *argp) {
145                        assert(socket_);
146                        if (::ioctlsocket(socket_, cmd, argp) == SOCKET_ERROR)
147                                throw SocketException("ioctlsocket failed: ", ::WSAGetLastError());
148                }
149                virtual std::string getAddrString() {
150                        return inet_ntoa(from_.sin_addr);
151                }
152                virtual void printError(std::string file, int line, std::string error);
153        };
154
155        class ListenerHandler {
156        public:
157                virtual void onAccept(Socket *client) = 0;
158                virtual void onClose() = 0;
159        };
160
161
162        /**
163        * @ingroup NSClient++
164        * Socket responder class.
165        * This is a background thread that listens to the socket and executes incoming commands.
166        *
167        * @version 1.0
168        * first version
169        *
170        * @date 02-12-2005
171        *
172        * @author mickem
173        *
174        * @par license
175        * This code is absolutely free to use and modify. The code is provided "as is" with
176        * no expressed or implied warranty. The author accepts no liability if it causes
177        * any damage to your computer, causes your pet to fall ill, increases baldness
178        * or makes your car start emitting strange noises when you start it up.
179        * This code has no bugs, just undocumented features!
180        *
181        * @todo This is not very well written and should probably be reworked.
182        *
183        * @bug
184        *
185        */
186        template <class TListenerType = simpleSocket::Socket, class TSocketType = TListenerType>
187        class Listener : public TListenerType {
188        public:
189                typedef TListenerType tListener;
190                typedef TSocketType tSocket;
191        private:
192                struct simpleResponderBundle {
193                        bool terminated;
194                        HANDLE hThread;
195                        unsigned dwThreadID;
196                };
197                typedef std::list<simpleResponderBundle> socketResponses;
198                typedef TListenerType tBase;
199                class ListenerThread;
200                typedef Thread<ListenerThread> listenThreadManager;
201
202                u_short port_;
203                listenThreadManager threadManager_;
204                socketResponses responderList_;
205                MutexHandler responderMutex_;
206
207        public:
208                class ListenerThread {
209                private:
210                        typedef TListenerType tParentBase;
211                        typedef TSocketType tSocket;
212
213                        HANDLE hStopEvent_;
214                public:
215                        ListenerThread() : hStopEvent_(NULL) {}
216                        DWORD threadProc(LPVOID lpParameter);
217                        void exitThread(void) {
218                                assert(hStopEvent_ != NULL);
219                                if (!SetEvent(hStopEvent_))
220                                        throw new SocketException("SetEvent failed.");
221                        }
222                };
223        private:
224                ListenerHandler *pHandler_;
225
226        public:
227                Listener() : pHandler_(NULL) {};
228                virtual ~Listener() {
229                        if (responderList_.size() > 0) {
230                                MutexLock lock(responderMutex_);
231                                if (!lock.hasMutex()) {
232                                        printError(__FILE__, __LINE__, "Failed to get responder mutex (cannot terminate socket threads).");
233                                } else {
234                                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end(); ++it) {
235                                                if (WaitForSingleObject( (*it).hThread, 1000) == WAIT_OBJECT_0) {
236                                                } else {
237                                                        if (!TerminateThread((*it).hThread, -1)) {
238                                                                printError(__FILE__, __LINE__, "We failed to terminate check thread.");
239                                                        } else {
240                                                                if (WaitForSingleObject( (*it).hThread, 5000) == WAIT_OBJECT_0) {
241                                                                        CloseHandle((*it).hThread);
242                                                                } else {
243                                                                        printError(__FILE__, __LINE__, "We failed to terminate check thread (wait timed out).");
244                                                                }
245                                                        }
246                                                }
247                                        }
248                                        responderList_.clear();
249                                }
250                        }
251                };
252
253                virtual void StartListener(int port) {
254                        port_ = port;
255                        threadManager_.createThread(this);
256                }
257                virtual void StopListener() {
258                        if (threadManager_.hasActiveThread())
259                                if (!threadManager_.exitThread())
260                                        throw new SocketException("Could not terminate thread.");
261                        tBase::close();
262                }
263                void setHandler(ListenerHandler* pHandler) {
264                        pHandler_ = pHandler;
265                }
266                void removeHandler(ListenerHandler* pHandler) {
267                        if (pHandler != pHandler_)
268                                throw SocketException("Not a registered handler!");
269                        pHandler_ = NULL;
270                }
271                static unsigned __stdcall socketResponceProc(void* lpParameter);
272                struct srp_data {
273                        Listener *pCore;
274                        tSocket *client;
275                };
276                void addResponder(tSocket *client) {
277                        MutexLock lock(responderMutex_);
278                        if (!lock.hasMutex()) {
279                                printError(__FILE__, __LINE__, "Failed to get responder mutex.");
280                                return;
281                        }
282                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end();) {
283                                if ( (*it).terminated) {
284                                        if (WaitForSingleObject( (*it).hThread, 500) == WAIT_OBJECT_0) {
285                                                CloseHandle((*it).hThread);
286                                                responderList_.erase(it++);
287                                        }
288                                } else
289                                        ++it;
290                        }
291                        simpleResponderBundle data;
292                        srp_data *lpData = new srp_data;
293                        lpData->pCore = this;
294                        lpData->client = client;
295
296                        data.hThread = reinterpret_cast<HANDLE>(::_beginthreadex( NULL, 0, &socketResponceProc, lpData, 0, &data.dwThreadID));
297                        data.terminated = false;
298                        responderList_.push_back(data);
299                }
300                bool removeResponder(DWORD dwThreadID) {
301                        MutexLock lock(responderMutex_);
302                        if (!lock.hasMutex()) {
303                                printError(__FILE__, __LINE__, "Failed to get responder mutex when trying to free thread.");
304                                return false;
305                        }
306                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end(); ++it) {
307                                if ( (*it).dwThreadID == dwThreadID) {
308                                        (*it).terminated = true;
309                                        return true;
310                                }
311                        }
312                        return false;
313                }
314
315
316        private:
317                void onAccept(tSocket *client) {
318                        if (pHandler_)
319                                pHandler_->onAccept(client);
320                }
321                void onClose() {
322                        if (pHandler_)
323                                pHandler_->onClose();
324                }
325                virtual bool accept(tSocket &client) {
326                        return tBase::accept(client);
327                }
328        };
329
330        WSADATA WSAStartup(WORD wVersionRequested = 0x202);
331        void WSACleanup();
332
333}
334
335template <class TListenerType, class TSocketType>
336unsigned simpleSocket::Listener<TListenerType, TSocketType>::socketResponceProc(void* lpParameter)
337{
338        // @todo make sure this terminates after X seconds!
339
340        srp_data *data = reinterpret_cast<srp_data*>(lpParameter);
341        Listener *pCore = data->pCore;
342        tSocket *client = data->client;
343        delete data;
344        try {
345                pCore->onAccept(client);
346        } catch (SocketException e) {
347                pCore->printError(__FILE__, __LINE__, e.getMessage() + " killing socket...");
348        }
349        client->close();
350        delete client;
351        if (!pCore->removeResponder(GetCurrentThreadId())) {
352                pCore->printError(__FILE__, __LINE__, "Could not remove thread: " + strEx::itos(GetCurrentThreadId()));
353        }
354        _endthreadex(0);
355        return 0;
356}
357
358
359template <class TListenerType, class TSocketType>
360DWORD simpleSocket::Listener<TListenerType, TSocketType>::ListenerThread::threadProc(LPVOID lpParameter)
361{
362        Listener *core = reinterpret_cast<Listener*>(lpParameter);
363
364        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
365        if (!hStopEvent_) {
366                core->printError(__FILE__, __LINE__, "Create StopEvent failed: " + strEx::itos(GetLastError()));
367                return 0;
368        }
369
370        try {
371                core->socket(AF_INET,SOCK_STREAM,0);
372                core->setAddr(AF_INET, INADDR_ANY, htons(core->port_));
373                core->bind();
374                core->listen(10);
375                core->setNonBlock();
376                while (!(WaitForSingleObject(hStopEvent_, 100) == WAIT_OBJECT_0)) {
377                        try {
378                                tSocket client;
379                                if (core->accept(client)) {
380                                        core->addResponder(new tSocket(client));
381                                }
382                        } catch (SocketException e) {
383                                core->printError(__FILE__, __LINE__, e.getMessage() + ", attempting to resume...");
384                        }
385                }
386        } catch (SocketException e) {
387                core->printError(__FILE__, __LINE__, e.getMessage());
388        }
389        core->shutdown(SD_BOTH);
390        core->close();
391        core->onClose();
392        HANDLE hTmp = hStopEvent_;
393        hStopEvent_ = NULL;
394        if (!CloseHandle(hTmp)) {
395                core->printError(__FILE__, __LINE__, "CloseHandle StopEvent failed: " + strEx::itos(GetLastError()));
396        }
397        return 0;
398}
Note: See TracBrowser for help on using the repository browser.