You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/tdecore/network/kresolver_p.h

356 lines
10 KiB

/* -*- 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 */
#ifndef __OpenBSD__
#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
#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