File indexing completed on 2024-03-24 15:27:07

0001 /*  -*- C++ -*-
0002  *  Copyright (C) 2003-2005 Thiago Macieira <thiago@kde.org>
0003  *
0004  *
0005  *  Permission is hereby granted, free of charge, to any person obtaining
0006  *  a copy of this software and associated documentation files (the
0007  *  "Software"), to deal in the Software without restriction, including
0008  *  without limitation the rights to use, copy, modify, merge, publish,
0009  *  distribute, sublicense, and/or sell copies of the Software, and to
0010  *  permit persons to whom the Software is furnished to do so, subject to
0011  *  the following conditions:
0012  *
0013  *  The above copyright notice and this permission notice shall be included
0014  *  in all copies or substantial portions of the Software.
0015  *
0016  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0017  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0019  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0020  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0021  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0022  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023  */
0024 
0025 #ifndef KRESOLVER_P_H
0026 #define KRESOLVER_P_H
0027 
0028 #include <config-network.h>
0029 #include <sys/types.h>
0030 
0031 #include <QByteArray>
0032 #include <QList>
0033 #include <QThread>
0034 #include <QMutex>
0035 #include <QWaitCondition>
0036 #include <QSemaphore>
0037 #include <QEvent>
0038 
0039 #include "k3resolver.h"
0040 
0041 /* decide whether we need a mutex */
0042 #if !HAVE_GETPROTOBYNAME_R || !HAVE_GETSERVBYNAME_R || !HAVE_GETHOSTBYNAME_R || !HAVE_GETSERVBYPORT_R
0043 # define NEED_MUTEX
0044 extern QMutex getXXbyYYmutex;
0045 #endif
0046 
0047 /* some systems have the functions, but don't declare them */
0048 #if HAVE_GETSERVBYNAME_R && !HAVE_GETSERVBYNAME_R_PROTO
0049 extern "C" {
0050     struct servent;
0051     extern int getservbyname_r(const char *serv, const char *proto,
0052                                struct servent *servbuf,
0053                                char *buf, size_t buflen,
0054                                struct servent **result);
0055     extern int getservbyport_r(int port, const char *proto,
0056                                struct servent *servbuf,
0057                                char *buf, size_t buflen,
0058                                struct servent **result);
0059 
0060     struct protoent;
0061     extern int getprotobyname_r(const char *proto, struct protoent *protobuf,
0062                                 char *buf, size_t buflen,
0063                                 struct protoent **result);
0064     extern int getprotobynumber_r(int proto, struct protoent *protobuf,
0065                                   char *buf, size_t buflen,
0066                                   struct protoent **result);
0067 }
0068 #endif
0069 
0070 /* decide whether res_init is thread-safe or not */
0071 #if defined(__GLIBC__)
0072 # undef RES_INIT_THREADSAFE
0073 #endif
0074 
0075 namespace KNetwork
0076 {
0077 // defined in network/qresolverworkerbase.h
0078 class KResolverWorkerBase;
0079 class KResolverWorkerFactoryBase;
0080 class KResolverPrivate;
0081 
0082 namespace Internal
0083 {
0084 class KResolverManager;
0085 class KResolverThread;
0086 struct RequestData;
0087 
0088 struct InputData {
0089     QString node, service;
0090     QByteArray protocolName;
0091     int flags;
0092     int familyMask;
0093     int socktype;
0094     int protocol;
0095 };
0096 }
0097 
0098 class KResolverPrivate
0099 {
0100 public:
0101     // parent class. Should never be changed!
0102     KResolver *parent;
0103     bool deleteWhenDone : 1;
0104     bool waiting : 1;
0105 
0106     // class status. Should not be changed by worker threads!
0107     volatile int status;
0108     volatile int errorcode, syserror;
0109 
0110     // input data. Should not be changed by worker threads!
0111     Internal::InputData input;
0112 
0113     // mutex
0114     QMutex mutex;
0115 
0116     // output data
0117     KResolverResults results;
0118 
0119     KDELIBS4SUPPORT_DEPRECATED explicit KResolverPrivate(KResolver *_parent,
0120                               const QString &_node = QString(),
0121                               const QString &_service = QString())
0122         : parent(_parent), deleteWhenDone(false), waiting(false),
0123           status(0), errorcode(0), syserror(0)
0124     {
0125         input.node = _node;
0126         input.service = _service;
0127         input.flags = 0;
0128         input.familyMask = KResolver::AnyFamily;
0129         input.socktype = 0;
0130         input.protocol = 0;
0131 
0132         results.setAddress(_node, _service);
0133     }
0134 };
0135 
0136 namespace Internal
0137 {
0138 struct RequestData {
0139     // worker threads should not change values in the input data
0140     KNetwork::KResolverPrivate *obj;
0141     const KNetwork::Internal::InputData *input;
0142     KNetwork::KResolverWorkerBase *worker; // worker class
0143     RequestData *requestor; // class that requested us
0144 
0145     volatile int nRequests; // how many requests that we made we still have left
0146 };
0147 
0148 /*
0149  * @internal
0150  * This class is the resolver manager
0151  */
0152 class KResolverManager
0153 {
0154 public:
0155     enum EventTypes
0156     { ResolutionCompleted = 1576 }; // arbitrary value;
0157 
0158     /*
0159      * This wait condition is used to notify wait states (KResolver::wait) that
0160      * the resolver manager has finished processing one or more objects. All
0161      * objects in wait state will be woken up and will check if they are done.
0162      * If they aren't, they will go back to sleeping.
0163      */
0164     QWaitCondition notifyWaiters;
0165 
0166 private:
0167     /*
0168      * This variable is used to count the number of threads that are running
0169      */
0170     volatile unsigned short runningThreads;
0171 
0172     /*
0173      * This variable is used to count the number of threads that are currently
0174      * waiting for data.
0175      */
0176     unsigned short availableThreads;
0177 
0178     /*
0179      * This wait condition is used to notify worker threads that there is new
0180      * data available that has to be processed. All worker threads wait on this
0181      * waitcond for a limited amount of time.
0182      */
0183     QWaitCondition feedWorkers;
0184 
0185     // this mutex protects the data in this object
0186     QMutex mutex;
0187 
0188     // hold a list of all the current threads we have
0189     QList<KResolverThread *> workers;
0190 
0191     // hold a list of all the new requests we have
0192     QList<RequestData *> newRequests;
0193 
0194     // hold a list of all the requests in progress we have
0195     QList<RequestData *> currentRequests;
0196 
0197     // hold a list of all the workers we have
0198     QList<KNetwork::KResolverWorkerFactoryBase *> workerFactories;
0199 
0200     // private constructor
0201     KResolverManager();
0202 
0203 public:
0204     static KResolverManager *manager();  // creates and returns the global manager
0205 
0206     // destructor
0207     ~KResolverManager();
0208 
0209     /*
0210      * Register this thread in the pool
0211      */
0212     void registerThread(KResolverThread *id);
0213 
0214     /*
0215      * Unregister this thread from the pool
0216      */
0217     void unregisterThread(KResolverThread *id);
0218 
0219     /*
0220      * Requests new data to work on.
0221      *
0222      * This function should only be called from a worker thread. This function
0223      * is thread-safe.
0224      *
0225      * If there is data to be worked on, this function will return it. If there is
0226      * none, this function will return a null pointer.
0227      */
0228     RequestData *requestData(KResolverThread *id, int maxWaitTime);
0229 
0230     /*
0231      * Releases the resources and returns the resolved data.
0232      *
0233      * This function should only be called from a worker thread. It is
0234      * thread-safe. It does not post the event to the manager.
0235      */
0236     void releaseData(KResolverThread *id, RequestData *data);
0237 
0238     /*
0239      * Registers a new worker class by way of its factory.
0240      *
0241      * This function is NOT thread-safe.
0242      */
0243     void registerNewWorker(KNetwork::KResolverWorkerFactoryBase *factory);
0244 
0245     /*
0246      * Enqueues new resolutions.
0247      */
0248     void enqueue(KNetwork::KResolver *obj, RequestData *requestor);
0249 
0250     /*
0251      * Dispatch a new request
0252      */
0253     void dispatch(RequestData *data);
0254 
0255     /*
0256      * Dequeues a resolution.
0257      */
0258     void dequeue(KNetwork::KResolver *obj);
0259 
0260     /*
0261      * Notifies the manager that the given resolution is about to
0262      * be deleted. This function should only be called by the
0263      * KResolver destructor.
0264      */
0265     void aboutToBeDeleted(KNetwork::KResolver *obj);
0266 
0267     /*
0268      * Notifies the manager that new events are ready.
0269      */
0270     void newEvent();
0271 
0272     /*
0273      * This function is called by the manager to receive a new event. It operates
0274      * on the eventSemaphore() semaphore, which means it will block till there
0275      * is at least one event to go.
0276      */
0277     void receiveEvent();
0278 
0279 private:
0280     /*
0281      * finds a suitable worker for this request
0282      */
0283     KNetwork::KResolverWorkerBase *findWorker(KNetwork::KResolverPrivate *p);
0284 
0285     /*
0286      * finds data for this request
0287      */
0288     RequestData *findData(KResolverThread *);
0289 
0290     /*
0291      * Handle completed requests.
0292      *
0293      * This function is called by releaseData above
0294      */
0295     void handleFinished();
0296 
0297     /*
0298      * Handle one completed request.
0299      *
0300      * This function is called by handleFinished above.
0301      */
0302     bool handleFinishedItem(RequestData *item);
0303 
0304     /*
0305      * Notifies the parent class that this request is done.
0306      *
0307      * This function deletes the request
0308      */
0309     void doNotifying(RequestData *p);
0310 
0311     /*
0312      * Dequeues and notifies an object that is in Queued state
0313      * Returns true if the object is no longer queued; false if it could not
0314      * be dequeued (i.e., it's running)
0315      */
0316     bool dequeueNew(KNetwork::KResolver *obj);
0317 };
0318 
0319 /*
0320  * @internal
0321  * This class is a worker thread in the resolver system.
0322  * This class must be thread-safe.
0323  */
0324 class KResolverThread: public QThread
0325 {
0326 private:
0327     // private constructor. Only the manager can create worker threads
0328     KResolverThread();
0329     RequestData *data;
0330 
0331 protected:
0332     void run() override;       // here the thread starts
0333 
0334     friend class KNetwork::Internal::KResolverManager;
0335     friend class KNetwork::KResolverWorkerBase;
0336 
0337 public:
0338     bool checkResolver(); // see KResolverWorkerBase::checkResolver
0339     void acquireResolver();   // see KResolverWorkerBase::acquireResolver
0340     void releaseResolver();   // see KResolverWorkerBase::releaseResolver
0341 };
0342 
0343 } // namespace Internal
0344 
0345 } // namespace KNetwork
0346 
0347 #endif