diff options
Diffstat (limited to 'tdecore/network/kresolver_p.h')
-rw-r--r-- | tdecore/network/kresolver_p.h | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/tdecore/network/kresolver_p.h b/tdecore/network/kresolver_p.h new file mode 100644 index 000000000..7f74c6fe6 --- /dev/null +++ b/tdecore/network/kresolver_p.h @@ -0,0 +1,353 @@ +/* -*- C++ -*- + * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net> + * + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef KRESOLVER_P_H +#define KRESOLVER_P_H + +#include <config.h> +#include <sys/types.h> + +#include <tqstring.h> +#include <tqcstring.h> +#include <tqvaluelist.h> +#include <tqptrlist.h> +#include <tqptrqueue.h> +#include <tqthread.h> +#include <tqmutex.h> +#include <tqwaitcondition.h> +#include <tqsemaphore.h> +#include <tqevent.h> + +#include "kresolver.h" + +/* decide whether we need a mutex */ +#if !defined(HAVE_GETPROTOBYNAME_R) || !defined(HAVE_GETSERVBYNAME_R) || !defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETSERVBYPORT_R) +# define NEED_MUTEX +extern TQMutex getXXbyYYmutex; +#endif + +/* some systems have the functions, but don't declare them */ +#if defined(HAVE_GETSERVBYNAME_R) && !HAVE_DECL_GETSERVBYNAME_R +extern "C" { + struct servent; + extern int getservbyname_r(const char* serv, const char* proto, + struct servent* servbuf, + char* buf, size_t buflen, + struct servent** result); + extern int getservbyport_r(int port, const char* proto, + struct servent* servbuf, + char* buf, size_t buflen, + struct servent** result); + + struct protoent; + extern int getprotobyname_r(const char* proto, struct protoent* protobuf, + char *buf, size_t buflen, + struct protoent** result); + extern int getprotobynumber_r(int proto, struct protoent* protobuf, + char *buf, size_t buflen, + struct protoent** result); +} +#endif + +/* decide whether res_init is thread-safe or not */ +#if defined(__GLIBC__) +# undef RES_INIT_THREADSAFE +#endif + +namespace KNetwork +{ + // defined in network/qresolverworkerbase.h + class KResolverWorkerBase; + class KResolverWorkerFactoryBase; + class KResolverPrivate; + + namespace Internal + { + class KResolverManager; + class KResolverThread; + struct RequestData; + + struct InputData + { + TQString node, service; + TQCString protocolName; + int flags; + int familyMask; + int socktype; + int protocol; + }; + } + + class KResolverPrivate + { + public: + // parent class. Should never be changed! + KResolver* parent; + bool deleteWhenDone : 1; + bool waiting : 1; + + // class status. Should not be changed by worker threads! + volatile int status; + volatile int errorcode, syserror; + + // input data. Should not be changed by worker threads! + Internal::InputData input; + + // mutex + TQMutex mutex; + + // output data + KResolverResults results; + + KResolverPrivate(KResolver* _parent, + const TQString& _node = TQString::null, + const TQString& _service = TQString::null) + : parent(_parent), deleteWhenDone(false), waiting(false), + status(0), errorcode(0), syserror(0) + { + input.node = _node; + input.service = _service; + input.flags = 0; + input.familyMask = KResolver::AnyFamily; + input.socktype = 0; + input.protocol = 0; + + results.setAddress(_node, _service); + } + }; + + namespace Internal + { + struct RequestData + { + // worker threads should not change values in the input data + KNetwork::KResolverPrivate *obj; + const KNetwork::Internal::InputData *input; + KNetwork::KResolverWorkerBase *worker; // worker class + RequestData *requestor; // class that requested us + + volatile int nRequests; // how many requests that we made we still have left + }; + + /* + * @internal + * This class is the resolver manager + */ + class KResolverManager + { + public: + enum EventTypes + { ResolutionCompleted = 1576 }; // arbitrary value; + + /* + * This wait condition is used to notify wait states (KResolver::wait) that + * the resolver manager has finished processing one or more objects. All + * objects in wait state will be woken up and will check if they are done. + * If they aren't, they will go back to sleeping. + */ + TQWaitCondition notifyWaiters; + + private: + /* + * This variable is used to count the number of threads that are running + */ + volatile unsigned short runningThreads; + + /* + * This variable is used to count the number of threads that are currently + * waiting for data. + */ + unsigned short availableThreads; + + /* + * This wait condition is used to notify worker threads that there is new + * data available that has to be processed. All worker threads wait on this + * waitcond for a limited amount of time. + */ + TQWaitCondition feedWorkers; + + // this mutex protects the data in this object + TQMutex mutex; + + // hold a list of all the current threads we have + TQPtrList<KResolverThread> workers; + + // hold a list of all the new requests we have + TQPtrList<RequestData> newRequests; + + // hold a list of all the requests in progress we have + TQPtrList<RequestData> currentRequests; + + // hold a list of all the workers we have + TQPtrList<KNetwork::KResolverWorkerFactoryBase> workerFactories; + + // private constructor + KResolverManager(); + + public: + static KResolverManager* manager() KDE_NO_EXPORT; // creates and returns the global manager + + // destructor + ~KResolverManager(); + + /* + * Register this thread in the pool + */ + void registerThread(KResolverThread* id); + + /* + * Unregister this thread from the pool + */ + void unregisterThread(KResolverThread* id); + + /* + * Requests new data to work on. + * + * This function should only be called from a worker thread. This function + * is thread-safe. + * + * If there is data to be worked on, this function will return it. If there is + * none, this function will return a null pointer. + */ + RequestData* requestData(KResolverThread* id, int maxWaitTime); + + /* + * Releases the resources and returns the resolved data. + * + * This function should only be called from a worker thread. It is + * thread-safe. It does not post the event to the manager. + */ + void releaseData(KResolverThread *id, RequestData* data); + + /* + * Registers a new worker class by way of its factory. + * + * This function is NOT thread-safe. + */ + void registerNewWorker(KNetwork::KResolverWorkerFactoryBase *factory); + + /* + * Enqueues new resolutions. + */ + void enqueue(KNetwork::KResolver *obj, RequestData* requestor); + + /* + * Dispatch a new request + */ + void dispatch(RequestData* data); + + /* + * Dequeues a resolution. + */ + void dequeue(KNetwork::KResolver *obj); + + /* + * Notifies the manager that the given resolution is about to + * be deleted. This function should only be called by the + * KResolver destructor. + */ + void aboutToBeDeleted(KNetwork::KResolver *obj); + + /* + * Notifies the manager that new events are ready. + */ + void newEvent(); + + /* + * This function is called by the manager to receive a new event. It operates + * on the @ref eventSemaphore semaphore, which means it will block till there + * is at least one event to go. + */ + void receiveEvent(); + + private: + /* + * finds a suitable worker for this request + */ + KNetwork::KResolverWorkerBase *findWorker(KNetwork::KResolverPrivate *p); + + /* + * finds data for this request + */ + RequestData* findData(KResolverThread*); + + /* + * Handle completed requests. + * + * This function is called by releaseData above + */ + void handleFinished(); + + /* + * Handle one completed request. + * + * This function is called by handleFinished above. + */ + bool handleFinishedItem(RequestData* item); + + /* + * Notifies the parent class that this request is done. + * + * This function deletes the request + */ + void doNotifying(RequestData *p); + + /* + * Dequeues and notifies an object that is in Queued state + * Returns true if the object is no longer queued; false if it could not + * be dequeued (i.e., it's running) + */ + bool dequeueNew(KNetwork::KResolver* obj); + }; + + /* + * @internal + * This class is a worker thread in the resolver system. + * This class must be thread-safe. + */ + class KResolverThread: public TQThread + { + private: + // private constructor. Only the manager can create worker threads + KResolverThread(); + RequestData* data; + + protected: + virtual void run(); // here the thread starts + + friend class KNetwork::Internal::KResolverManager; + friend class KNetwork::KResolverWorkerBase; + + public: + bool checkResolver(); // see KResolverWorkerBase::checkResolver + void acquireResolver(); // see KResolverWorkerBase::acquireResolver + void releaseResolver(); // see KResolverWorkerBase::releaseResolver + }; + + } // namespace Internal + +} // namespace KNetwork + + +#endif |