source: nscp/include/Socket.h @ 394f7a1

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

+ Added propper output handling to process subsystem (now you can execute programs tat return "much" data.

+ Added select support for SSL_write (now you can send "any amount of data" to the (SSL) socket.

Since check_nrpe doesn't do this it wont work in that end, but still...

  • Property mode set to 100644
File size: 23.3 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(socket_, (SOCKADDR*) &to_, sizeof(to_));
214                        }
215                        return SOCKET_ERROR;
216                }
217
218                virtual void close() {
219                        if (socket_)
220                                closesocket(socket_);
221                        socket_ = NULL;
222                }
223                virtual void setNonBlock() {
224                        unsigned long NoBlock = 1;
225                        FD_SET(socket_, &read_);
226                        FD_SET(socket_, &write_);
227                        FD_SET(socket_, &excp_);
228                        this->ioctlsocket(FIONBIO, &NoBlock);
229                }
230                virtual bool canRead(long timeout = -1) {
231                        timeval timeout_;
232                        timeout_.tv_sec = timeout;
233                        FD_SET(socket_, &read_);
234                        FD_SET(socket_, &write_);
235                        FD_SET(socket_, &excp_);
236                        if (timeout == -1)
237                                ::select(NULL, &read_, &write_, &excp_, NULL);
238                        else
239                                ::select(NULL, &read_, &write_, &excp_, &timeout_);
240                        if (FD_ISSET(socket_, &read_))
241                                return true;
242                        return false;
243                }
244                virtual bool canWrite(long timeout = -1) {
245                        timeval timeout_;
246                        timeout_.tv_sec = timeout;
247                        FD_SET(socket_, &read_);
248                        FD_SET(socket_, &write_);
249                        FD_SET(socket_, &excp_);
250                        if (timeout == -1)
251                                ::select(NULL, &read_, &write_, &excp_, NULL);
252                        else
253                                ::select(NULL, &read_, &write_, &excp_, &timeout_);
254                        return FD_ISSET(socket_, &write_);
255                }
256
257                static unsigned long inet_addr(std::wstring addr) {
258                        return ::inet_addr(strEx::wstring_to_string(addr).c_str());
259                }
260                static std::wstring inet_ntoa(unsigned long addr) {
261                        struct in_addr a;
262                        a.S_un.S_addr = addr;
263                        return strEx::string_to_wstring(::inet_ntoa(a));
264                }
265                static std::wstring getHostByName(std::wstring ip) {
266                        hostent* remoteHost;
267                        remoteHost = gethostbyname(strEx::wstring_to_string(ip).c_str());
268                        if (remoteHost == NULL)
269                                throw SocketException(_T("gethostbyname failed for ") + ip + _T(": "), ::WSAGetLastError());
270                        // @todo investigate it this is "correct" and dont use before!
271                        return strEx::string_to_wstring(::inet_ntoa(*reinterpret_cast<in_addr*>(remoteHost->h_addr)));
272                }
273                static struct in_addr getHostByNameAsIN(std::wstring ip) {
274                        hostent* remoteHost;
275                        remoteHost = gethostbyname(strEx::wstring_to_string(ip).c_str());
276                        if (remoteHost == NULL)
277                                throw SocketException(_T("gethostbyname failed for ") + ip + _T(": "), ::WSAGetLastError());
278                        if (remoteHost->h_addrtype != AF_INET) {
279                                throw SocketException(_T("gethostbyname failed for ") + ip + _T(": "), ::WSAGetLastError());
280                        }
281                        struct in_addr ret;
282                        ret.S_un.S_addr = (reinterpret_cast<in_addr*>(remoteHost->h_addr_list[0]))->S_un.S_addr;
283                        return ret;
284                }
285                static std::wstring getHostByAddr(std::wstring ip) {
286                        hostent* remoteHost;
287                        remoteHost = gethostbyaddr(strEx::wstring_to_string(ip).c_str(), static_cast<int>(ip.length()), AF_INET);
288                        if (remoteHost == NULL)
289                                throw SocketException(_T("gethostbyaddr failed for ") + ip + _T(": "), ::WSAGetLastError());
290                        return strEx::string_to_wstring(remoteHost->h_name);
291                }
292                static struct in_addr getHostByAddrAsIN(std::wstring ip) {
293                        hostent* remoteHost;
294                        unsigned int addr = ::inet_addr(strEx::wstring_to_string(ip).c_str());
295                        std::cerr << "addr: " << addr << std::endl;
296                        remoteHost = ::gethostbyaddr(reinterpret_cast<char*>(&addr), 4, AF_INET);
297                        if (remoteHost == NULL)
298                                throw SocketException(_T("gethostbyaddr failed for ") + ip + _T(": "), ::WSAGetLastError());
299                        if (remoteHost->h_addrtype != AF_INET)
300                                throw SocketException(_T("gethostbyname returned the wrong type ") + ip + _T(": "), ::WSAGetLastError());
301                        struct in_addr ret;
302                        ret.S_un.S_addr = (reinterpret_cast<in_addr*>(remoteHost->h_addr_list[0]))->S_un.S_addr;
303                        return ret;
304                }
305                virtual bool readAll(DataBuffer &buffer, unsigned int tmpBufferLength = 1024, int maxLength = -1);
306                virtual bool sendAll(const char * buffer, unsigned int len);
307
308                int inline sendAll(DataBuffer &buffer) {
309                        return sendAll(buffer.getBuffer(), buffer.getLength());
310                }
311
312                virtual int send(const char * buf, unsigned int len, int flags = 0) {
313                        assert(socket_);
314                        return ::send(socket_, buf, len, flags);
315                }
316                int inline send(DataBuffer &buffer, int flags = 0) {
317                        return send(buffer.getBuffer(), buffer.getLength(), flags);
318                }
319
320                virtual void socket(int af, int type, int protocol ) {
321                        socket_ = ::socket(af, type, protocol);
322                        assert(socket_ != INVALID_SOCKET);
323                }
324                virtual void bind() {
325                        assert(socket_);
326                        int fromlen=sizeof(from_);
327                        if (::bind(socket_, (sockaddr*)&from_, fromlen) == SOCKET_ERROR)
328                                throw SocketException(_T("bind failed: "), ::WSAGetLastError());
329                }
330                virtual void listen(int backlog = SOMAXCONN) {
331                        assert(socket_);
332                        if (::listen(socket_, backlog) == SOCKET_ERROR)
333                                throw SocketException(_T("listen failed: "), ::WSAGetLastError());
334                }
335                virtual bool accept(Socket &client) {
336                        int fromlen=sizeof(client.from_);
337                        SOCKET s = ::accept(socket_, (sockaddr*)&client.from_, &fromlen);
338                        if(s == INVALID_SOCKET) {
339                                int err = ::WSAGetLastError();
340                                if (err == WSAEWOULDBLOCK)
341                                        return false;
342                                throw SocketException(_T("accept failed: "), ::WSAGetLastError());
343                        }
344                        client.attach(s);
345                        return true;
346                }
347                virtual void setAddr(short family, u_long addr, u_short port) {
348                        from_.sin_family=family;
349                        from_.sin_addr.s_addr=addr;
350                        from_.sin_port=port;
351                }
352                virtual void ioctlsocket(long cmd, u_long *argp) {
353                        assert(socket_);
354                        if (::ioctlsocket(socket_, cmd, argp) == SOCKET_ERROR)
355                                throw SocketException(_T("ioctlsocket failed: "), ::WSAGetLastError());
356                }
357                virtual std::wstring getAddrString() {
358                        return strEx::string_to_wstring(::inet_ntoa(from_.sin_addr));
359                }
360                virtual struct in_addr getAddr() {
361                        return from_.sin_addr;
362                }
363                virtual void printError(std::wstring file, int line, std::wstring error);
364        };
365
366        class ListenerHandler {
367        public:
368                virtual void onAccept(Socket *client) = 0;
369                virtual void onClose() = 0;
370        };
371
372
373        /**
374        * @ingroup NSClient++
375        * Socket responder class.
376        * This is a background thread that listens to the socket and executes incoming commands.
377        *
378        * @version 1.0
379        * first version
380        *
381        * @date 02-12-2005
382        *
383        * @author mickem
384        *
385        * @par license
386        * This code is absolutely free to use and modify. The code is provided "as is" with
387        * no expressed or implied warranty. The author accepts no liability if it causes
388        * any damage to your computer, causes your pet to fall ill, increases baldness
389        * or makes your car start emitting strange noises when you start it up.
390        * This code has no bugs, just undocumented features!
391        *
392        * @todo This is not very well written and should probably be reworked.
393        *
394        * @bug
395        *
396        */
397        template <class TListenerType = simpleSocket::Socket, class TSocketType = TListenerType>
398        class Listener : public TListenerType {
399        public:
400                typedef TListenerType tListener;
401                typedef TSocketType tSocket;
402        private:
403                struct simpleResponderBundle {
404                        bool terminated;
405                        HANDLE hThread;
406                        unsigned dwThreadID;
407                };
408                typedef std::list<simpleResponderBundle> socketResponses;
409                typedef TListenerType tBase;
410                class ListenerThread;
411                typedef Thread<ListenerThread> listenThreadManager;
412
413                u_short bindPort_;
414                u_long bindAddres_;
415                unsigned int listenQue_;
416                listenThreadManager threadManager_;
417                socketResponses responderList_;
418                MutexHandler responderMutex_;
419
420        public:
421                class ListenerThread {
422                private:
423                        typedef TListenerType tParentBase;
424                        typedef TSocketType tSocket;
425
426                        HANDLE hStopEvent_;
427                public:
428                        ListenerThread() : hStopEvent_(NULL) {}
429                        DWORD threadProc(LPVOID lpParameter);
430                        bool hasThread() const {
431                                return hStopEvent_ != NULL;
432                        }
433                        void exitThread(void) {
434                                assert(hStopEvent_ != NULL);
435                                if (!SetEvent(hStopEvent_))
436                                        throw SocketException(_T("SetEvent failed."));
437                        }
438                };
439        private:
440                ListenerHandler *pHandler_;
441
442        public:
443                Listener() : pHandler_(NULL), bindPort_(0), bindAddres_(INADDR_ANY), listenQue_(0), threadManager_(_T("listenThreadManager")) {};
444                virtual ~Listener() {
445                        if (responderList_.size() > 0) {
446                                MutexLock lock(responderMutex_);
447                                if (!lock.hasMutex()) {
448                                        printError(_T(__FILE__), __LINE__, _T("Failed to get responder mutex (cannot terminate socket threads)."));
449                                } else {
450                                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end(); ++it) {
451                                                if (WaitForSingleObject( (*it).hThread, 1000) == WAIT_OBJECT_0) {
452                                                } else {
453                                                        if (!TerminateThread((*it).hThread, -1)) {
454                                                                printError(_T(__FILE__), __LINE__, _T("We failed to terminate check thread."));
455                                                        } else {
456                                                                if (WaitForSingleObject( (*it).hThread, 5000) == WAIT_OBJECT_0) {
457                                                                        CloseHandle((*it).hThread);
458                                                                } else {
459                                                                        printError(_T(__FILE__), __LINE__, _T("We failed to terminate check thread (wait timed out)."));
460                                                                }
461                                                        }
462                                                }
463                                        }
464                                        responderList_.clear();
465                                }
466                        }
467                };
468/*
469                virtual void StartListener(int port) {
470                        bindPort_ = port;
471                        threadManager_.createThread(this);
472                }
473                */
474                bool hasListener() {
475                        try {
476                                if (threadManager_.hasActiveThread()) {
477                                        const ListenerThread *t = threadManager_.getThreadConst();
478                                        if (t!=NULL)
479                                                return t->hasThread();
480                                }
481                        } catch (ThreadException e) {
482                                printError(_T(__FILE__), __LINE__, _T("Could not access listener thread!"));
483                                return false;
484                        }
485                        return false;
486                }
487                virtual void StartListener(std::wstring host, int port, int queLength) {
488                        bindPort_ = port;
489                        if (!host.empty())
490                                bindAddres_ = TListenerType::inet_addr(host);
491                        if (bindAddres_ == INADDR_NONE)
492                                bindAddres_ = INADDR_ANY;
493                        listenQue_ = queLength;
494                        threadManager_.createThread(this);
495                }
496                virtual void StopListener() {
497                        try {
498                                if (threadManager_.hasActiveThread())
499                                        if (!threadManager_.exitThread()) {
500                                                tBase::close();
501                                                throw SocketException(_T("Could not terminate thread."));
502                                        }
503                        } catch (ThreadException e) {
504                                tBase::close();
505                                throw SocketException(_T("Could not terminate thread (got exception in thread)."));
506                        }
507                        tBase::close();
508                }
509                void setHandler(ListenerHandler* pHandler) {
510                        pHandler_ = pHandler;
511                }
512                void removeHandler(ListenerHandler* pHandler) {
513                        if (pHandler != pHandler_)
514                                throw SocketException(_T("Not a registered handler!"));
515                        pHandler_ = NULL;
516                }
517                static unsigned __stdcall socketResponceProc(void* lpParameter);
518                struct srp_data {
519                        Listener *pCore;
520                        tSocket *client;
521                };
522                void addResponder(tSocket *client) {
523                        MutexLock lock(responderMutex_);
524                        if (!lock.hasMutex()) {
525                                printError(_T(__FILE__), __LINE__, _T("Failed to get responder mutex."));
526                                return;
527                        }
528                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end();) {
529                                if ( (*it).terminated) {
530                                        if (WaitForSingleObject( (*it).hThread, 500) == WAIT_OBJECT_0) {
531                                                CloseHandle((*it).hThread);
532                                                responderList_.erase(it++);
533                                        }
534                                } else
535                                        ++it;
536                        }
537                        simpleResponderBundle data;
538                        srp_data *lpData = new srp_data;
539                        lpData->pCore = this;
540                        lpData->client = client;
541
542                        data.hThread = reinterpret_cast<HANDLE>(::_beginthreadex( NULL, 0, &socketResponceProc, lpData, 0, &data.dwThreadID));
543                        data.terminated = false;
544                        responderList_.push_back(data);
545                }
546                bool removeResponder(DWORD dwThreadID) {
547                        MutexLock lock(responderMutex_);
548                        if (!lock.hasMutex()) {
549                                printError(_T(__FILE__), __LINE__, _T("Failed to get responder mutex when trying to free thread."));
550                                return false;
551                        }
552                        for (socketResponses::iterator it = responderList_.begin(); it != responderList_.end(); ++it) {
553                                if ( (*it).dwThreadID == dwThreadID) {
554                                        (*it).terminated = true;
555                                        return true;
556                                }
557                        }
558                        printError(_T(__FILE__), __LINE__, _T("Failed to remove socket-responder."));
559                        return false;
560                }
561
562
563        private:
564                void onAccept(tSocket *client) {
565                        if (pHandler_)
566                                pHandler_->onAccept(client);
567                }
568                void onClose() {
569                        if (pHandler_)
570                                pHandler_->onClose();
571                }
572                virtual bool accept(tSocket &client) {
573                        return tBase::accept(client);
574                }
575        };
576
577        WSADATA WSAStartup(WORD wVersionRequested = 0x202);
578        void WSACleanup();
579
580}
581
582template <class TListenerType, class TSocketType>
583unsigned simpleSocket::Listener<TListenerType, TSocketType>::socketResponceProc(void* lpParameter)
584{
585        // @todo make sure this terminates after X seconds!
586
587        srp_data *data = reinterpret_cast<srp_data*>(lpParameter);
588        Listener *pCore = data->pCore;
589        tSocket *client = data->client;
590        delete data;
591        try {
592                pCore->onAccept(client);
593        } catch (SocketException e) {
594                pCore->printError(_T(__FILE__), __LINE__, e.getMessage() + _T(" killing socket..."));
595        }
596        client->close();
597        delete client;
598        if (!pCore->removeResponder(GetCurrentThreadId())) {
599                pCore->printError(_T(__FILE__), __LINE__, _T("Could not remove thread: ") + strEx::itos(GetCurrentThreadId()));
600        }
601        _endthreadex(0);
602        return 0;
603}
604
605
606template <class TListenerType, class TSocketType>
607DWORD simpleSocket::Listener<TListenerType, TSocketType>::ListenerThread::threadProc(LPVOID lpParameter)
608{
609        Listener *core = reinterpret_cast<Listener*>(lpParameter);
610
611        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
612        if (!hStopEvent_) {
613                core->printError(_T(__FILE__), __LINE__, _T("Create StopEvent failed: ") + error::lookup::last_error());
614                return 0;
615        }
616
617        bool socketOk = false;
618        try {
619                core->socket(AF_INET,SOCK_STREAM,0);
620                core->setAddr(AF_INET, core->bindAddres_, htons(core->bindPort_));
621                core->bind();
622                NSC_DEBUG_MSG_STD(_T("Bound to: ") + TListenerType::inet_ntoa(core->bindAddres_) + _T(":") + strEx::itos(core->bindPort_));
623                if (core->listenQue_ != 0)
624                        core->listen(core->listenQue_);
625                else
626                        core->listen();
627                core->setNonBlock();
628                socketOk = true;
629        } catch (SocketException e) {
630                core->printError(_T(__FILE__), __LINE__, e.getMessage());
631        } catch (...) {
632                core->printError(_T(__FILE__), __LINE__, _T("Unhandeled exception in the socket thread..."));
633        }
634        if (socketOk) {
635                try {
636                        //NSC_DEBUG_MSG_STD("Socket ready...");
637                        while (!(WaitForSingleObject(hStopEvent_, 100) == WAIT_OBJECT_0)) {
638                                try {
639                                        tSocket client;
640                                        if (core->accept(client)) {
641                                                core->addResponder(new tSocket(client));
642                                        }
643                                } catch (SocketException e) {
644                                        core->printError(_T(__FILE__), __LINE__, e.getMessage() + _T(", attempting to resume..."));
645                                }
646                        }
647                } catch (SocketException e) {
648                        core->printError(_T(__FILE__), __LINE__, e.getMessage());
649                } catch (...) {
650                        core->printError(_T(__FILE__), __LINE__, _T("Unhandeled exception in the socket thread..."));
651                }
652        } else {
653                core->printError(_T(__FILE__), __LINE__, _T("Socket did not start properly, we will now do nothing..."));
654                WaitForSingleObject(hStopEvent_, INFINITE);
655        }
656        NSC_DEBUG_MSG_STD(_T("Socket listener is preparing to shutdown..."));
657        core->shutdown(SD_BOTH);
658        core->close();
659        core->onClose();
660        HANDLE hTmp = hStopEvent_;
661        hStopEvent_ = NULL;
662        if (!CloseHandle(hTmp)) {
663                core->printError(_T(__FILE__), __LINE__, _T("CloseHandle StopEvent failed: ") + error::lookup::last_error());
664        }
665        return 0;
666}
667
668
669
670namespace socketHelpers {
671        class allowedHosts {
672                struct host_record {
673                        host_record() : mask(0) {}
674                        host_record(std::wstring r) : mask(0), record(r) {}
675                        std::wstring record;
676                        std::wstring host;
677                        u_long in_addr;
678                        unsigned long mask;
679                };
680        public:
681                typedef std::list<host_record> host_list;
682        private:
683                host_list allowedHosts_;
684                bool cachedAddresses_;
685        public:
686                allowedHosts() : cachedAddresses_(true) {}
687
688                unsigned int lookupMask(std::wstring mask) {
689                        unsigned int masklen = 32;
690                        if (!mask.empty()) {
691                                std::wstring::size_type pos = mask.find_first_of(_T("0123456789"));
692                                if (pos != std::wstring::npos) {
693                                        masklen = strEx::stoi(mask.substr(pos));
694                                }
695                        }
696                        if (masklen > 32)
697                                masklen = 32;
698                        return (~((unsigned int)0))>>(32-masklen);
699                }
700                void lookupList() {
701                        for (host_list::iterator it = allowedHosts_.begin();it!=allowedHosts_.end();++it) {
702                                std::wstring record = (*it).record;
703                                if (record.length() > 0) {
704                                        try {
705                                                std::wstring::size_type pos = record.find('/');
706                                                if (pos == std::wstring::npos) {
707                                                        (*it).host = record;
708                                                        (*it).mask = lookupMask(_T(""));
709                                                } else {
710                                                        (*it).host = record.substr(0, pos);
711                                                        (*it).mask = lookupMask(record.substr(pos));
712                                                }
713                                                if (isalpha((*it).host[0]))
714                                                        (*it).in_addr = simpleSocket::Socket::getHostByNameAsIN((*it).host).S_un.S_addr;
715                                                else
716                                                        (*it).in_addr = ::inet_addr(strEx::wstring_to_string((*it).host).c_str()); // simpleSocket::Socket::getHostByAddrAsIN((*it).host);
717                                                /*
718                                                std::cerr << "Added: "
719                                                        + simpleSocket::Socket::inet_ntoa((*it).in_addr)
720                                                        + " with mask "
721                                                        + simpleSocket::Socket::inet_ntoa((*it).mask)
722                                                        + " from "
723                                                        + (*it).record <<
724                                                        std::endl;
725                                                        */
726                                        } catch (simpleSocket::SocketException e) {
727                                                std::wcerr << _T("Filed to lookup host: ") << e.getMessage() << std::endl;
728                                        }
729                                }
730                        }
731                }
732
733                void setAllowedHosts(const std::list<std::wstring> list, bool cachedAddresses) {
734                        for (std::list<std::wstring>::const_iterator it = list.begin(); it != list.end(); ++it) {
735                                allowedHosts_.push_back(host_record(*it));
736                        }
737                        cachedAddresses_ = cachedAddresses;
738//                      if ((!allowedHosts.empty()) && (allowedHosts.front() == "") )
739//                              allowedHosts.pop_front();
740                        //allowedHosts_ = allowedHosts;
741                        lookupList();
742                }
743                bool matchHost(host_record allowed, struct in_addr remote) {
744                        /*
745                        if ((allowed.in_addr&allowed.mask)==(remote.S_un.S_addr&allowed.mask)) {
746                                std::cerr << "Matched: " << simpleSocket::Socket::inet_ntoa(allowed.in_addr)  << " with " <<
747                                        simpleSocket::Socket::inet_ntoa(remote.S_un.S_addr) << std::endl;
748                        }
749                        */
750                        return ((allowed.in_addr&allowed.mask)==(remote.S_un.S_addr&allowed.mask));
751                }
752                bool inAllowedHosts(struct in_addr remote) {
753                        if (allowedHosts_.empty())
754                                return true;
755                        host_list::const_iterator cit;
756                        if (!cachedAddresses_) {
757                                lookupList();
758                        }
759                        for (cit = allowedHosts_.begin();cit!=allowedHosts_.end();++cit) {
760                                if (matchHost((*cit), remote))
761                                        return true;
762                        }
763                        return false;
764                }
765        };
766}
Note: See TracBrowser for help on using the repository browser.