source: nscp/include/Socket.h @ 2f01f93

0.4.00.4.10.4.2stable
Last change on this file since 2f01f93 was 2f01f93, checked in by Michael Medin <michael@…>, 5 years ago

+ Added new module NRPEClient that can act as a NRPE client, might be useful for testing things and

eventually for relaying events.
Usage: nsclient++ -noboot NRPEClient -H 192.168.0.1 -p 5666 -c check_something -a foo bar
This is an early concept so don't expect much...

  • Property mode set to 100644
File size: 23.4 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2004-2007 by Michael Medin <michael@medin.name>         *
3*                                                                         *
4*   This code is part of NSClient++ - http://trac.nakednuns.org/nscp      *
5*                                                                         *
6*   This program is free software; you can redistribute it and/or modify  *
7*   it under the terms of the GNU General Public License as published by  *
8*   the Free Software Foundation; either version 2 of the License, or     *
9*   (at your option) any later version.                                   *
10*                                                                         *
11*   This program is distributed in the hope that it will be useful,       *
12*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14*   GNU General Public License for more details.                          *
15*                                                                         *
16*   You should have received a copy of the GNU General Public License     *
17*   along with this program; if not, write to the                         *
18*   Free Software Foundation, Inc.,                                       *
19*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20***************************************************************************/
21#pragma once
22#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers
23//#include <windows.h>
24#include <WinSock2.h>
25#include <Thread.h>
26#include <Mutex.h>
27#include <error.hpp>
28#include <NSCHelper.h>
29
30
31namespace simpleSocket {
32        class SocketException {
33        private:
34                std::wstring error_;
35        public:
36                SocketException(std::wstring error) : error_(error) {}
37                SocketException(std::wstring error, unsigned int errorCode) : error_(error) {
38                        error_ += error::format::from_system(errorCode);
39                }
40                std::wstring getMessage() const {
41                        return error_;
42                }
43
44        };
45        class DataBuffer {
46        private:
47                char *buffer_;
48                unsigned int length_;
49        public:
50                DataBuffer() : buffer_(NULL), length_(0){
51                }
52                DataBuffer(const DataBuffer &other) {
53                        buffer_ = new char[other.getLength()+2];
54                        memcpy(buffer_, other.getBuffer(), other.getLength()+1);
55                        length_ = other.getLength();
56                }
57                DataBuffer(const char* buffer, unsigned int length) {
58                        buffer_ = new char[length+2];
59                        memcpy(buffer_, buffer, length+1);
60                        length_ = length;
61                }
62                DataBuffer(const unsigned char* buffer, unsigned int length) {
63                        buffer_ = new char[length+2];
64                        memcpy(buffer_, buffer, length+1);
65                        length_ = length;
66                }
67                virtual ~DataBuffer() {
68                        delete [] buffer_;
69                        length_ = 0;
70                        buffer_ = NULL;
71                }
72                void append(const char* buffer, const unsigned int length) {
73                        char *tBuf = new char[length_+length+2];
74                        memcpy(tBuf, buffer_, length_);
75                        memcpy(&tBuf[length_], buffer, length);
76                        delete [] buffer_;
77                        buffer_ = tBuf;
78                        length_ += length;
79                        buffer_[length_] = 0;
80                }
81                /**
82                 * returns a const reference to the internal buffer
83                 * Use with care!
84                 *
85                 * @access public
86                 * @returns const char *
87                 * @qualifier const
88                 */
89                const char * getBuffer() const {
90                        return buffer_;
91                }
92                unsigned int getLength() const {
93                        return length_;
94                }
95                /**
96                 * Eats a specified number of bytes from the beginning of the buffer
97                 * @access public
98                 * @returns void
99                 * @qualifier
100                 * @param const unsigned int length the amount of bytes to eat
101                 */
102                void nibble(const unsigned int length) {
103                        if (length > length_)
104                                return;
105                        unsigned int newLen = length_-length;
106                        char *tBuf = new char[newLen+2];
107                        memcpy(tBuf, &buffer_[length], newLen+1);
108                        char *oldBuf = buffer_;
109                        buffer_ = tBuf;
110                        length_ = newLen;
111                        delete [] oldBuf;
112                }
113
114                DataBuffer unshift(const unsigned int length) {
115                        DataBuffer ret;
116                        if (length > length_)
117                                return ret;
118                        ret.copyFrom(buffer_, length);
119                        unsigned int newLen = length_-length;
120                        char *tBuf = new char[newLen+2];
121                        memcpy(tBuf, &buffer_[length], newLen+1);
122                        char *oldBuf = buffer_;
123                        buffer_ = tBuf;
124                        length_ = newLen;
125                        delete [] oldBuf;
126                        return ret;
127                }
128                const unsigned long long find(char c) {
129                        if (buffer_ == NULL)
130                                return -1;
131                        if (length_ == 0)
132                                return -1;
133                        const char *pos = strchr(buffer_, c);
134                        if (pos == NULL)
135                                return -1;
136                        return pos-buffer_;
137                }
138                void copyFrom(const char* buffer, const unsigned int length) {
139                        delete [] buffer_;
140                        buffer_ = new char[length+2];
141                        memcpy(buffer_, buffer, length);
142                        length_ = length;
143                        buffer_[length_] = 0;
144                }
145                std::string toString() {
146                        return strEx::format_buffer(buffer_, length_);
147                }
148        };
149
150        class Socket {
151        protected:
152                SOCKET socket_;
153                sockaddr_in from_;
154                sockaddr_in to_;
155                fd_set read_, write_, excp_;
156
157        public:
158                Socket() : socket_(NULL) {
159                        FD_ZERO(&read_);
160                        FD_ZERO(&write_);
161                        FD_ZERO(&excp_);
162                }
163                Socket(SOCKET socket) : socket_(socket) {
164                        FD_ZERO(&read_);
165                        FD_ZERO(&write_);
166                        FD_ZERO(&excp_);
167                }
168                Socket(int type, int protocol) : socket_(NULL) {
169                        socket_ = ::socket(AF_INET, type, protocol);
170                        FD_ZERO(&read_);
171                        FD_ZERO(&write_);
172                        FD_ZERO(&excp_);
173                }
174                Socket(bool create) : socket_(NULL) {
175                        if (create)
176                                socket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
177                        FD_ZERO(&read_);
178                        FD_ZERO(&write_);
179                        FD_ZERO(&excp_);
180                }
181
182                Socket(Socket &other) {
183                        socket_ = other.socket_;
184                        from_ = other.from_;
185                        other.socket_ = NULL;
186                        read_ = other.read_;
187                        write_ = other.write_;
188                        excp_ = other.excp_;
189                }
190                virtual ~Socket() {
191                        if (socket_)
192                                closesocket(socket_);
193                        socket_ = NULL;
194                }
195                virtual SOCKET detach() {
196                        SOCKET s = socket_;
197                        socket_ = NULL;
198                        return s;
199                }
200                virtual void attach(SOCKET s) {
201                        assert(socket_ == NULL);
202                        socket_ = s;
203                }
204                virtual void shutdown(int how = SD_BOTH) {
205                        if (socket_)
206                                ::shutdown(socket_, how);
207                }
208                virtual int connect(std::wstring host, u_short port) {
209                        if (socket_) {
210                                to_.sin_family = AF_INET;
211                                to_.sin_port = htons(port);
212                                to_.sin_addr.s_addr = inet_addr(host);
213                                return connect_();
214                        }
215                        return SOCKET_ERROR;
216                }
217                virtual int connect_() {
218                        return ::connect(socket_, (SOCKADDR*) &to_, sizeof(to_));
219                }
220
221                virtual void close() {
222                        if (socket_)
223                                closesocket(socket_);
224                        socket_ = NULL;
225                }
226                virtual void setNonBlock() {
227                        unsigned long NoBlock = 1;
228                        FD_SET(socket_, &read_);
229                        FD_SET(socket_, &write_);
230                        FD_SET(socket_, &excp_);
231                        this->ioctlsocket(FIONBIO, &NoBlock);
232                }
233                virtual bool canRead(long timeout = -1) {
234                        timeval timeout_;
235                        timeout_.tv_sec = timeout;
236                        FD_SET(socket_, &read_);
237                        FD_SET(socket_, &write_);
238                        FD_SET(socket_, &excp_);
239                        if (timeout == -1)
240                                ::select(NULL, &read_, &write_, &excp_, NULL);
241                        else
242                                ::select(NULL, &read_, &write_, &excp_, &timeout_);
243                        if (FD_ISSET(socket_, &read_))
244                                return true;
245                        return false;
246                }
247                virtual bool canWrite(long timeout = -1) {
248                        timeval timeout_;
249                        timeout_.tv_sec = timeout;
250                        FD_SET(socket_, &read_);
251                        FD_SET(socket_, &write_);
252                        FD_SET(socket_, &excp_);
253                        if (timeout == -1)
254                                ::select(NULL, &read_, &write_, &excp_, NULL);
255                        else
256                                ::select(NULL, &read_, &write_, &excp_, &timeout_);
257                        if (FD_ISSET(socket_, &write_))
258                                return true;
259                        return false;
260                }
261
262                static unsigned long inet_addr(std::wstring addr) {
263                        return ::inet_addr(strEx::wstring_to_string(addr).c_str());
264                }
265                static std::wstring inet_ntoa(unsigned long addr) {
266                        struct in_addr a;
267                        a.S_un.S_addr = addr;
268                        return strEx::string_to_wstring(::inet_ntoa(a));
269                }
270                static std::wstring getHostByName(std::wstring ip) {
271                        hostent* remoteHost;
272                        remoteHost = gethostbyname(strEx::wstring_to_string(ip).c_str());
273                        if (remoteHost == NULL)
274                                throw SocketException(_T("gethostbyname failed for ") + ip + _T(": "), ::WSAGetLastError());
275                        // @todo investigate it this is "correct" and dont use before!
276                        return strEx::string_to_wstring(::inet_ntoa(*reinterpret_cast<in_addr*>(remoteHost->h_addr)));
277                }
278                static struct in_addr getHostByNameAsIN(std::wstring ip) {
279                        hostent* remoteHost;
280                        remoteHost = gethostbyname(strEx::wstring_to_string(ip).c_str());
281                        if (remoteHost == NULL)
282                                throw SocketException(_T("gethostbyname failed for ") + ip + _T(": "), ::WSAGetLastError());
283                        if (remoteHost->h_addrtype != AF_INET) {
284                                throw SocketException(_T("gethostbyname failed for ") + ip + _T(": "), ::WSAGetLastError());
285                        }
286                        struct in_addr ret;
287                        ret.S_un.S_addr = (reinterpret_cast<in_addr*>(remoteHost->h_addr_list[0]))->S_un.S_addr;
288                        return ret;
289                }
290                static std::wstring getHostByAddr(std::wstring ip) {
291                        hostent* remoteHost;
292                        remoteHost = gethostbyaddr(strEx::wstring_to_string(ip).c_str(), static_cast<int>(ip.length()), AF_INET);
293                        if (remoteHost == NULL)
294                                throw SocketException(_T("gethostbyaddr failed for ") + ip + _T(": "), ::WSAGetLastError());
295                        return strEx::string_to_wstring(remoteHost->h_name);
296                }
297                static struct in_addr getHostByAddrAsIN(std::wstring ip) {
298                        hostent* remoteHost;
299                        unsigned int addr = ::inet_addr(strEx::wstring_to_string(ip).c_str());
300                        std::cerr << "addr: " << addr << std::endl;
301                        remoteHost = ::gethostbyaddr(reinterpret_cast<char*>(&addr), 4, AF_INET);
302                        if (remoteHost == NULL)
303                                throw SocketException(_T("gethostbyaddr failed for ") + ip + _T(": "), ::WSAGetLastError());
304                        if (remoteHost->h_addrtype != AF_INET)
305                                throw SocketException(_T("gethostbyname returned the wrong type ") + ip + _T(": "), ::WSAGetLastError());
306                        struct in_addr ret;
307                        ret.S_un.S_addr = (reinterpret_cast<in_addr*>(remoteHost->h_addr_list[0]))->S_un.S_addr;
308                        return ret;
309                }
310                virtual bool readAll(DataBuffer &buffer, unsigned int tmpBufferLength = 1024, int maxLength = -1);
311                virtual bool sendAll(const char * buffer, unsigned int len);
312
313                int inline sendAll(DataBuffer &buffer) {
314                        return sendAll(buffer.getBuffer(), buffer.getLength());
315                }
316
317                virtual int send(const char * buf, unsigned int len, int flags = 0) {
318                        assert(socket_);
319                        return ::send(socket_, buf, len, flags);
320                }
321                int inline send(DataBuffer &buffer, int flags = 0) {
322                        return send(buffer.getBuffer(), buffer.getLength(), flags);
323                }
324
325                virtual void socket(int af, int type, int protocol ) {
326                        socket_ = ::socket(af, type, protocol);
327                        assert(socket_ != INVALID_SOCKET);
328                }
329                virtual void bind() {
330                        assert(socket_);
331                        int fromlen=sizeof(from_);
332                        if (::bind(socket_, (sockaddr*)&from_, fromlen) == SOCKET_ERROR)
333                                throw SocketException(_T("bind failed: "), ::WSAGetLastError());
334                }
335                virtual void listen(int backlog = SOMAXCONN) {
336                        assert(socket_);
337                        if (::listen(socket_, backlog) == SOCKET_ERROR)
338                                throw SocketException(_T("listen failed: "), ::WSAGetLastError());
339                }
340                virtual bool accept(Socket &client) {
341                        int fromlen=sizeof(client.from_);
342                        SOCKET s = ::accept(socket_, (sockaddr*)&client.from_, &fromlen);
343                        if(s == INVALID_SOCKET) {
344                                int err = ::WSAGetLastError();
345                                if (err == WSAEWOULDBLOCK)
346                                        return false;
347                                throw SocketException(_T("accept failed: "), ::WSAGetLastError());
348                        }
349                        client.attach(s);
350                        return true;
351                }
352                virtual void setAddr(short family, u_long addr, u_short port) {
353                        from_.sin_family=family;
354                        from_.sin_addr.s_addr=addr;
355                        from_.sin_port=port;
356                }
357                virtual void ioctlsocket(long cmd, u_long *argp) {
358                        assert(socket_);
359                        if (::ioctlsocket(socket_, cmd, argp) == SOCKET_ERROR)
360                                throw SocketException(_T("ioctlsocket failed: "), ::WSAGetLastError());
361                }
362                virtual std::wstring getAddrString() {
363                        return strEx::string_to_wstring(::inet_ntoa(from_.sin_addr));
364                }
365                virtual struct in_addr getAddr() {
366                        return from_.sin_addr;
367                }
368                virtual void printError(std::wstring file, int line, std::wstring error);
369        };
370
371        class ListenerHandler {
372        public:
373                virtual void onAccept(Socket *client) = 0;
374                virtual void onClose() = 0;
375        };
376
377
378        /**
379        * @ingroup NSClient++
380        * Socket responder class.
381        * This is a background thread that listens to the socket and executes incoming commands.
382        *
383        * @version 1.0
384        * first version
385        *
386        * @date 02-12-2005
387        *
388        * @author mickem
389        *
390        * @par license
391        * This code is absolutely free to use and modify. The code is provided "as is" with
392        * no expressed or implied warranty. The author accepts no liability if it causes
393        * any damage to your computer, causes your pet to fall ill, increases baldness
394        * or makes your car start emitting strange noises when you start it up.
395        * This code has no bugs, just undocumented features!
396        *
397        * @todo This is not very well written and should probably be reworked.
398        *
399        * @bug
400        *
401        */
402        template <class TListenerType = simpleSocket::Socket, class TSocketType = TListenerType>
403        class Listener : public TListenerType {
404        public:
405                typedef TListenerType tListener;
406                typedef TSocketType tSocket;
407        private:
408                struct simpleResponderBundle {
409                        bool terminated;
410                        HANDLE hThread;
411                        unsigned dwThreadID;
412                };
413                typedef std::list<simpleResponderBundle> socketResponses;
414                typedef TListenerType tBase;
415                class ListenerThread;
416                typedef Thread<ListenerThread> listenThreadManager;
417
418                u_short bindPort_;
419                u_long bindAddres_;
420                unsigned int listenQue_;
421                listenThreadManager threadManager_;
422                socketResponses responderList_;
423                MutexHandler responderMutex_;
424
425        public:
426                class ListenerThread {
427                private:
428                        typedef TListenerType tParentBase;
429                        typedef TSocketType tSocket;
430
431                        HANDLE hStopEvent_;
432                public:
433                        ListenerThread() : hStopEvent_(NULL) {}
434                        DWORD threadProc(LPVOID lpParameter);
435                        bool hasThread() const {
436                                return hStopEvent_ != NULL;
437                        }
438                        void exitThread(void) {
439                                assert(hStopEvent_ != NULL);
440                                if (!SetEvent(hStopEvent_))
441                                        throw SocketException(_T("SetEvent failed."));
442                        }
443                };
444        private:
445                ListenerHandler *pHandler_;
446
447        public:
448                Listener() : pHandler_(NULL), bindPort_(0), bindAddres_(INADDR_ANY), listenQue_(0), threadManager_(_T("listenThreadManager")) {};
449                virtual ~Listener() {
450                        if (responderList_.size() > 0) {
451                                MutexLock lock(responderMutex_);
452                                if (!lock.hasMutex()) {
453                                        printError(_T(__FILE__), __LINE__, _T("Failed to get responder mutex (cannot terminate socket threads)."));
454                                } else {
455                                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end(); ++it) {
456                                                if (WaitForSingleObject( (*it).hThread, 1000) == WAIT_OBJECT_0) {
457                                                } else {
458                                                        if (!TerminateThread((*it).hThread, -1)) {
459                                                                printError(_T(__FILE__), __LINE__, _T("We failed to terminate check thread."));
460                                                        } else {
461                                                                if (WaitForSingleObject( (*it).hThread, 5000) == WAIT_OBJECT_0) {
462                                                                        CloseHandle((*it).hThread);
463                                                                } else {
464                                                                        printError(_T(__FILE__), __LINE__, _T("We failed to terminate check thread (wait timed out)."));
465                                                                }
466                                                        }
467                                                }
468                                        }
469                                        responderList_.clear();
470                                }
471                        }
472                };
473/*
474                virtual void StartListener(int port) {
475                        bindPort_ = port;
476                        threadManager_.createThread(this);
477                }
478                */
479                bool hasListener() {
480                        try {
481                                if (threadManager_.hasActiveThread()) {
482                                        const ListenerThread *t = threadManager_.getThreadConst();
483                                        if (t!=NULL)
484                                                return t->hasThread();
485                                }
486                        } catch (ThreadException e) {
487                                printError(_T(__FILE__), __LINE__, _T("Could not access listener thread!"));
488                                return false;
489                        }
490                        return false;
491                }
492                virtual void StartListener(std::wstring host, int port, int queLength) {
493                        bindPort_ = port;
494                        if (!host.empty())
495                                bindAddres_ = TListenerType::inet_addr(host);
496                        if (bindAddres_ == INADDR_NONE)
497                                bindAddres_ = INADDR_ANY;
498                        listenQue_ = queLength;
499                        threadManager_.createThread(this);
500                }
501                virtual void StopListener() {
502                        try {
503                                if (threadManager_.hasActiveThread())
504                                        if (!threadManager_.exitThread()) {
505                                                tBase::close();
506                                                throw SocketException(_T("Could not terminate thread."));
507                                        }
508                        } catch (ThreadException e) {
509                                tBase::close();
510                                throw SocketException(_T("Could not terminate thread (got exception in thread)."));
511                        }
512                        tBase::close();
513                }
514                void setHandler(ListenerHandler* pHandler) {
515                        pHandler_ = pHandler;
516                }
517                void removeHandler(ListenerHandler* pHandler) {
518                        if (pHandler != pHandler_)
519                                throw SocketException(_T("Not a registered handler!"));
520                        pHandler_ = NULL;
521                }
522                static unsigned __stdcall socketResponceProc(void* lpParameter);
523                struct srp_data {
524                        Listener *pCore;
525                        tSocket *client;
526                };
527                void addResponder(tSocket *client) {
528                        MutexLock lock(responderMutex_);
529                        if (!lock.hasMutex()) {
530                                printError(_T(__FILE__), __LINE__, _T("Failed to get responder mutex."));
531                                return;
532                        }
533                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end();) {
534                                if ( (*it).terminated) {
535                                        if (WaitForSingleObject( (*it).hThread, 500) == WAIT_OBJECT_0) {
536                                                CloseHandle((*it).hThread);
537                                                responderList_.erase(it++);
538                                        }
539                                } else
540                                        ++it;
541                        }
542                        simpleResponderBundle data;
543                        srp_data *lpData = new srp_data;
544                        lpData->pCore = this;
545                        lpData->client = client;
546
547                        data.hThread = reinterpret_cast<HANDLE>(::_beginthreadex( NULL, 0, &socketResponceProc, lpData, 0, &data.dwThreadID));
548                        data.terminated = false;
549                        responderList_.push_back(data);
550                }
551                bool removeResponder(DWORD dwThreadID) {
552                        MutexLock lock(responderMutex_);
553                        if (!lock.hasMutex()) {
554                                printError(_T(__FILE__), __LINE__, _T("Failed to get responder mutex when trying to free thread."));
555                                return false;
556                        }
557                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end(); ++it) {
558                                if ( (*it).dwThreadID == dwThreadID) {
559                                        (*it).terminated = true;
560                                        return true;
561                                }
562                        }
563                        printError(_T(__FILE__), __LINE__, _T("Failed to remove socket-responder."));
564                        return false;
565                }
566
567
568        private:
569                void onAccept(tSocket *client) {
570                        if (pHandler_)
571                                pHandler_->onAccept(client);
572                }
573                void onClose() {
574                        if (pHandler_)
575                                pHandler_->onClose();
576                }
577                virtual bool accept(tSocket &client) {
578                        return tBase::accept(client);
579                }
580        };
581
582        WSADATA WSAStartup(WORD wVersionRequested = 0x202);
583        void WSACleanup();
584
585}
586
587template <class TListenerType, class TSocketType>
588unsigned simpleSocket::Listener<TListenerType, TSocketType>::socketResponceProc(void* lpParameter)
589{
590        // @todo make sure this terminates after X seconds!
591
592        srp_data *data = reinterpret_cast<srp_data*>(lpParameter);
593        Listener *pCore = data->pCore;
594        tSocket *client = data->client;
595        delete data;
596        try {
597                pCore->onAccept(client);
598        } catch (SocketException e) {
599                pCore->printError(_T(__FILE__), __LINE__, e.getMessage() + _T(" killing socket..."));
600        }
601        client->close();
602        delete client;
603        if (!pCore->removeResponder(GetCurrentThreadId())) {
604                pCore->printError(_T(__FILE__), __LINE__, _T("Could not remove thread: ") + strEx::itos(GetCurrentThreadId()));
605        }
606        _endthreadex(0);
607        return 0;
608}
609
610
611template <class TListenerType, class TSocketType>
612DWORD simpleSocket::Listener<TListenerType, TSocketType>::ListenerThread::threadProc(LPVOID lpParameter)
613{
614        Listener *core = reinterpret_cast<Listener*>(lpParameter);
615
616        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
617        if (!hStopEvent_) {
618                core->printError(_T(__FILE__), __LINE__, _T("Create StopEvent failed: ") + error::lookup::last_error());
619                return 0;
620        }
621
622        bool socketOk = false;
623        try {
624                core->socket(AF_INET,SOCK_STREAM,0);
625                core->setAddr(AF_INET, core->bindAddres_, htons(core->bindPort_));
626                core->bind();
627                NSC_DEBUG_MSG_STD(_T("Bound to: ") + TListenerType::inet_ntoa(core->bindAddres_) + _T(":") + strEx::itos(core->bindPort_));
628                if (core->listenQue_ != 0)
629                        core->listen(core->listenQue_);
630                else
631                        core->listen();
632                core->setNonBlock();
633                socketOk = true;
634        } catch (SocketException e) {
635                core->printError(_T(__FILE__), __LINE__, e.getMessage());
636        } catch (...) {
637                core->printError(_T(__FILE__), __LINE__, _T("Unhandeled exception in the socket thread..."));
638        }
639        if (socketOk) {
640                try {
641                        //NSC_DEBUG_MSG_STD("Socket ready...");
642                        while (!(WaitForSingleObject(hStopEvent_, 100) == WAIT_OBJECT_0)) {
643                                try {
644                                        tSocket client;
645                                        if (core->accept(client)) {
646                                                core->addResponder(new tSocket(client));
647                                        }
648                                } catch (SocketException e) {
649                                        core->printError(_T(__FILE__), __LINE__, e.getMessage() + _T(", attempting to resume..."));
650                                }
651                        }
652                } catch (SocketException e) {
653                        core->printError(_T(__FILE__), __LINE__, e.getMessage());
654                } catch (...) {
655                        core->printError(_T(__FILE__), __LINE__, _T("Unhandeled exception in the socket thread..."));
656                }
657        } else {
658                core->printError(_T(__FILE__), __LINE__, _T("Socket did not start properly, we will now do nothing..."));
659                WaitForSingleObject(hStopEvent_, INFINITE);
660        }
661        NSC_DEBUG_MSG_STD(_T("Socket listener is preparing to shutdown..."));
662        core->shutdown(SD_BOTH);
663        core->close();
664        core->onClose();
665        HANDLE hTmp = hStopEvent_;
666        hStopEvent_ = NULL;
667        if (!CloseHandle(hTmp)) {
668                core->printError(_T(__FILE__), __LINE__, _T("CloseHandle StopEvent failed: ") + error::lookup::last_error());
669        }
670        return 0;
671}
672
673
674
675namespace socketHelpers {
676        class allowedHosts {
677                struct host_record {
678                        host_record() : mask(0) {}
679                        host_record(std::wstring r) : mask(0), record(r) {}
680                        std::wstring record;
681                        std::wstring host;
682                        u_long in_addr;
683                        unsigned long mask;
684                };
685        public:
686                typedef std::list<host_record> host_list;
687        private:
688                host_list allowedHosts_;
689                bool cachedAddresses_;
690        public:
691                allowedHosts() : cachedAddresses_(true) {}
692
693                unsigned int lookupMask(std::wstring mask) {
694                        unsigned int masklen = 32;
695                        if (!mask.empty()) {
696                                std::wstring::size_type pos = mask.find_first_of(_T("0123456789"));
697                                if (pos != std::wstring::npos) {
698                                        masklen = strEx::stoi(mask.substr(pos));
699                                }
700                        }
701                        if (masklen > 32)
702                                masklen = 32;
703                        return (~((unsigned int)0))>>(32-masklen);
704                }
705                void lookupList() {
706                        for (host_list::iterator it = allowedHosts_.begin();it!=allowedHosts_.end();++it) {
707                                std::wstring record = (*it).record;
708                                if (record.length() > 0) {
709                                        try {
710                                                std::wstring::size_type pos = record.find('/');
711                                                if (pos == std::wstring::npos) {
712                                                        (*it).host = record;
713                                                        (*it).mask = lookupMask(_T(""));
714                                                } else {
715                                                        (*it).host = record.substr(0, pos);
716                                                        (*it).mask = lookupMask(record.substr(pos));
717                                                }
718                                                if (isalpha((*it).host[0]))
719                                                        (*it).in_addr = simpleSocket::Socket::getHostByNameAsIN((*it).host).S_un.S_addr;
720                                                else
721                                                        (*it).in_addr = ::inet_addr(strEx::wstring_to_string((*it).host).c_str()); // simpleSocket::Socket::getHostByAddrAsIN((*it).host);
722                                                /*
723                                                std::cerr << "Added: "
724                                                        + simpleSocket::Socket::inet_ntoa((*it).in_addr)
725                                                        + " with mask "
726                                                        + simpleSocket::Socket::inet_ntoa((*it).mask)
727                                                        + " from "
728                                                        + (*it).record <<
729                                                        std::endl;
730                                                        */
731                                        } catch (simpleSocket::SocketException e) {
732                                                std::wcerr << _T("Filed to lookup host: ") << e.getMessage() << std::endl;
733                                        }
734                                }
735                        }
736                }
737
738                void setAllowedHosts(const std::list<std::wstring> list, bool cachedAddresses) {
739                        for (std::list<std::wstring>::const_iterator it = list.begin(); it != list.end(); ++it) {
740                                allowedHosts_.push_back(host_record(*it));
741                        }
742                        cachedAddresses_ = cachedAddresses;
743//                      if ((!allowedHosts.empty()) && (allowedHosts.front() == "") )
744//                              allowedHosts.pop_front();
745                        //allowedHosts_ = allowedHosts;
746                        lookupList();
747                }
748                bool matchHost(host_record allowed, struct in_addr remote) {
749                        /*
750                        if ((allowed.in_addr&allowed.mask)==(remote.S_un.S_addr&allowed.mask)) {
751                                std::cerr << "Matched: " << simpleSocket::Socket::inet_ntoa(allowed.in_addr)  << " with " <<
752                                        simpleSocket::Socket::inet_ntoa(remote.S_un.S_addr) << std::endl;
753                        }
754                        */
755                        return ((allowed.in_addr&allowed.mask)==(remote.S_un.S_addr&allowed.mask));
756                }
757                bool inAllowedHosts(struct in_addr remote) {
758                        if (allowedHosts_.empty())
759                                return true;
760                        host_list::const_iterator cit;
761                        if (!cachedAddresses_) {
762                                lookupList();
763                        }
764                        for (cit = allowedHosts_.begin();cit!=allowedHosts_.end();++cit) {
765                                if (matchHost((*cit), remote))
766                                        return true;
767                        }
768                        return false;
769                }
770        };
771}
Note: See TracBrowser for help on using the repository browser.