KDECore
kresolvermanager.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026
00027 #include <sys/types.h>
00028 #include <netinet/in.h>
00029 #include <limits.h>
00030 #include <unistd.h>
00031
00032 #ifdef HAVE_RES_INIT
00033 # include <sys/stat.h>
00034 extern "C" {
00035 # include <arpa/nameser.h>
00036 }
00037 # include <time.h>
00038 # include <resolv.h>
00039 #endif
00040
00041 #include <qapplication.h>
00042 #include <qstring.h>
00043 #include <qcstring.h>
00044 #include <qptrlist.h>
00045 #include <qtimer.h>
00046 #include <qmutex.h>
00047 #include <qthread.h>
00048 #include <qwaitcondition.h>
00049 #include <qsemaphore.h>
00050
00051 #include <kde_file.h>
00052 #include <kdebug.h>
00053 #include "kresolver.h"
00054 #include "kresolver_p.h"
00055 #include "kresolverworkerbase.h"
00056
00057 namespace KNetwork
00058 {
00059 namespace Internal
00060 {
00061 void initSrvWorker();
00062 void initStandardWorkers();
00063 }
00064 }
00065
00066 using namespace KNetwork;
00067 using namespace KNetwork::Internal;
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 namespace
00116 {
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 class ResInitUsage
00129 {
00130 public:
00131
00132 #ifdef HAVE_RES_INIT
00133 time_t mTime;
00134 int useCount;
00135
00136 # ifndef RES_INIT_THREADSAFE
00137 QWaitCondition cond;
00138 QMutex mutex;
00139 # endif
00140
00141 bool shouldResInit()
00142 {
00143
00144 KDE_struct_stat st;
00145 if (KDE_stat("/etc/resolv.conf", &st) != 0)
00146 return false;
00147
00148 if (mTime != st.st_mtime)
00149 {
00150 kdDebug(179) << "shouldResInit: /etc/resolv.conf updated" << endl;
00151 return true;
00152 }
00153 return false;
00154 }
00155
00156 void callResInit()
00157 {
00158 if (mTime != 0)
00159 {
00160
00161
00162 kdDebug(179) << "callResInit: calling res_init()" << endl;
00163 res_init();
00164 }
00165
00166 KDE_struct_stat st;
00167 if (KDE_stat("/etc/resolv.conf", &st) == 0)
00168 mTime = st.st_mtime;
00169 }
00170
00171 ResInitUsage()
00172 : mTime(0), useCount(0)
00173 { }
00174
00175
00176
00177
00178 void release()
00179 {
00180 # ifndef RES_INIT_THREADSAFE
00181 QMutexLocker locker(&mutex);
00182 if (--useCount == 0)
00183 {
00184 if (shouldResInit())
00185 callResInit();
00186
00187
00188 cond.wakeAll();
00189 }
00190 # else
00191
00192 # endif
00193 }
00194
00195
00196
00197
00198 void acquire()
00199 {
00200 # ifndef RES_INIT_THREADSAFE
00201 mutex.lock();
00202
00203 if (shouldResInit())
00204 {
00205 if (useCount)
00206 {
00207
00208
00209
00210
00211 cond.wait(&mutex);
00212 }
00213 else
00214
00215 callResInit();
00216 }
00217 useCount++;
00218 mutex.unlock();
00219
00220 # else
00221 if (shouldResInit())
00222 callResInit();
00223
00224 # endif
00225 }
00226
00227 #else
00228 ResInitUsage()
00229 { }
00230
00231 bool shouldResInit()
00232 { return false; }
00233
00234 void acquire()
00235 { }
00236
00237 void release()
00238 { }
00239 #endif
00240
00241 } resInit;
00242
00243 }
00244
00245
00246
00247
00248
00249
00250
00251 static const int maxThreadWaitTime = 2000;
00252 static const int maxThreads = 5;
00253
00254 static pid_t pid;
00255
00256 KResolverThread::KResolverThread()
00257 : data(0L)
00258 {
00259 }
00260
00261
00262 void KResolverThread::run()
00263 {
00264
00265
00266
00267
00268 KResolverManager::manager()->registerThread(this);
00269 while (true)
00270 {
00271 data = KResolverManager::manager()->requestData(this, ::maxThreadWaitTime);
00272
00273
00274 if (data)
00275 {
00276
00277
00278
00279
00280 ;
00281
00282
00283 data->worker->run();
00284
00285
00286 KResolverManager::manager()->releaseData(this, data);
00287
00288
00289 }
00290 else
00291 break;
00292 }
00293
00294 KResolverManager::manager()->unregisterThread(this);
00295
00296 }
00297
00298 bool KResolverThread::checkResolver()
00299 {
00300 return resInit.shouldResInit();
00301 }
00302
00303 void KResolverThread::acquireResolver()
00304 {
00305 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
00306 getXXbyYYmutex.lock();
00307 #endif
00308
00309 resInit.acquire();
00310 }
00311
00312 void KResolverThread::releaseResolver()
00313 {
00314 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
00315 getXXbyYYmutex.unlock();
00316 #endif
00317
00318 resInit.release();
00319 }
00320
00321 static KResolverManager *globalManager;
00322
00323 KResolverManager* KResolverManager::manager()
00324 {
00325 if (globalManager == 0L)
00326 new KResolverManager();
00327 return globalManager;
00328 }
00329
00330 KResolverManager::KResolverManager()
00331 : runningThreads(0), availableThreads(0)
00332 {
00333 globalManager = this;
00334 workers.setAutoDelete(true);
00335 currentRequests.setAutoDelete(true);
00336 initSrvWorker();
00337 initStandardWorkers();
00338
00339 pid = getpid();
00340 }
00341
00342 KResolverManager::~KResolverManager()
00343 {
00344
00345
00346
00347 for (workers.first(); workers.current(); workers.next())
00348 workers.current()->terminate();
00349 }
00350
00351 void KResolverManager::registerThread(KResolverThread* )
00352 {
00353 }
00354
00355 void KResolverManager::unregisterThread(KResolverThread*)
00356 {
00357 runningThreads--;
00358 }
00359
00360
00361 RequestData* KResolverManager::requestData(KResolverThread *th, int maxWaitTime)
00362 {
00364
00366
00367
00368
00369 QMutexLocker locker(&mutex);
00370 RequestData *data = findData(th);
00371
00372 if (data)
00373
00374 return data;
00375
00376
00377 availableThreads++;
00378 feedWorkers.wait(&mutex, maxWaitTime);
00379 availableThreads--;
00380
00381 data = findData(th);
00382 return data;
00383 }
00384
00385 RequestData* KResolverManager::findData(KResolverThread* th)
00386 {
00388
00389
00391
00392
00393 for (RequestData *curr = newRequests.first(); curr; curr = newRequests.next())
00394 if (!curr->worker->m_finished)
00395 {
00396
00397 if (curr->obj)
00398 curr->obj->status = KResolver::InProgress;
00399 curr->worker->th = th;
00400
00401
00402 currentRequests.append(newRequests.take());
00403
00404 return curr;
00405 }
00406
00407
00408 return 0L;
00409 }
00410
00411
00412 void KResolverManager::releaseData(KResolverThread *, RequestData* data)
00413 {
00415
00417
00418
00419
00420
00421 if (data->obj)
00422 {
00423 data->obj->status = KResolver::PostProcessing;
00424 }
00425
00426 data->worker->m_finished = true;
00427 data->worker->th = 0L;
00428
00429
00430 handleFinished();
00431 }
00432
00433
00434 void KResolverManager::handleFinished()
00435 {
00436 bool redo = false;
00437 QPtrQueue<RequestData> doneRequests;
00438
00439 mutex.lock();
00440
00441
00442
00443
00444 RequestData *curr = currentRequests.last();
00445 while (curr)
00446 {
00447 if (curr->worker->th == 0L)
00448 {
00449 if (handleFinishedItem(curr))
00450 {
00451 doneRequests.enqueue(currentRequests.take());
00452 if (curr->requestor &&
00453 curr->requestor->nRequests == 0 &&
00454 curr->requestor->worker->m_finished)
00455
00456 redo = true;
00457 }
00458 }
00459
00460 curr = currentRequests.prev();
00461 }
00462
00463
00464 while (RequestData *d = doneRequests.dequeue())
00465 doNotifying(d);
00466
00467 mutex.unlock();
00468
00469 if (redo)
00470 {
00471
00472
00473 handleFinished();
00474 }
00475 }
00476
00477
00478 bool KResolverManager::handleFinishedItem(RequestData* curr)
00479
00480 {
00481
00482
00483
00484 if (curr->worker->m_finished && curr->nRequests == 0)
00485 {
00486
00487 if (curr->obj)
00488 curr->obj->status = KResolver::PostProcessing;
00489
00490 if (curr->requestor)
00491 --curr->requestor->nRequests;
00492
00493
00494
00495 return true;
00496 }
00497 return false;
00498 }
00499
00500
00501
00502 void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory)
00503 {
00504 workerFactories.append(factory);
00505 }
00506
00507 KResolverWorkerBase* KResolverManager::findWorker(KResolverPrivate* p)
00508 {
00510
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522 KResolverWorkerBase *worker;
00523 for (KResolverWorkerFactoryBase *factory = workerFactories.first(); factory;
00524 factory = workerFactories.next())
00525 {
00526 worker = factory->create();
00527
00528
00529 worker->input = &p->input;
00530
00531 if (worker->preprocess())
00532 {
00533
00534 if (worker->m_finished)
00535 p->status = KResolver::PostProcessing;
00536 else
00537 p->status = KResolver::Queued;
00538 return worker;
00539 }
00540
00541
00542 delete worker;
00543 }
00544
00545
00546 return 0L;
00547 }
00548
00549 void KResolverManager::doNotifying(RequestData *p)
00550 {
00552
00553
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 if (p->obj)
00578 {
00579
00580 p->obj->mutex.lock();
00581 KResolver* parent = p->obj->parent;
00582 KResolverResults& r = p->obj->results;
00583
00584 if (p->obj->status == KResolver::Canceled)
00585 {
00586 p->obj->status = KResolver::Canceled;
00587 p->obj->errorcode = KResolver::Canceled;
00588 p->obj->syserror = 0;
00589 r.setError(KResolver::Canceled, 0);
00590 }
00591 else if (p->worker)
00592 {
00593
00594 p->worker->postprocess();
00595
00596
00597
00598 r = p->worker->results;
00599
00600
00601 r.setAddress(p->input->node, p->input->service);
00602
00603
00604
00605
00606 p->obj->errorcode = r.error();
00607 p->obj->syserror = r.systemError();
00608 p->obj->status = !r.isEmpty() ?
00609 KResolver::Success : KResolver::Failed;
00610 }
00611 else
00612 {
00613 r.empty();
00614 r.setError(p->obj->errorcode, p->obj->syserror);
00615 }
00616
00617
00618 if (!p->obj->waiting && parent)
00619
00620
00621
00622 QApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted)));
00623
00624
00625 p->obj->mutex.unlock();
00626 }
00627 else
00628 {
00629
00630 if (p->worker)
00631 p->worker->postprocess();
00632 }
00633
00634 delete p->worker;
00635
00636
00637
00638
00639 delete p;
00640
00641
00642 notifyWaiters.wakeAll();
00643 }
00644
00645
00646
00647
00648 void KResolverManager::enqueue(KResolver *obj, RequestData *requestor)
00649 {
00650 RequestData *newrequest = new RequestData;
00651 newrequest->nRequests = 0;
00652 newrequest->obj = obj->d;
00653 newrequest->input = &obj->d->input;
00654 newrequest->requestor = requestor;
00655
00656
00657
00658 if ((newrequest->worker = findWorker(obj->d)) == 0L)
00659 {
00660
00661
00662 obj->d->status = KResolver::Failed;
00663 obj->d->errorcode = KResolver::UnsupportedFamily;
00664 obj->d->syserror = 0;
00665
00666 doNotifying(newrequest);
00667 return;
00668 }
00669
00670
00671
00672 if (requestor)
00673 requestor->nRequests++;
00674
00675 if (!newrequest->worker->m_finished)
00676 dispatch(newrequest);
00677 else if (newrequest->nRequests > 0)
00678 {
00679 mutex.lock();
00680 currentRequests.append(newrequest);
00681 mutex.unlock();
00682 }
00683 else
00684
00685 doNotifying(newrequest);
00686 }
00687
00688
00689
00690 void KResolverManager::dispatch(RequestData *data)
00691 {
00692
00693
00694
00695
00696 QMutexLocker locker(&mutex);
00697
00698
00699 newRequests.append(data);
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 if (availableThreads == 0 && runningThreads < maxThreads)
00728 {
00729
00730
00731
00732 KResolverThread *th = workers.first();
00733 while (th && th->running())
00734 th = workers.next();
00735
00736 if (th == 0L)
00737
00738 th = new KResolverThread;
00739 else
00740 workers.take();
00741
00742 th->start();
00743 workers.append(th);
00744 runningThreads++;
00745 }
00746
00747 feedWorkers.wakeAll();
00748
00749
00750 workers.first();
00751 while (workers.current())
00752 {
00753 if (!workers.current()->running())
00754 workers.remove();
00755 else
00756 workers.next();
00757 }
00758 }
00759
00760
00761 bool KResolverManager::dequeueNew(KResolver* obj)
00762 {
00763
00764
00765
00766
00767 KResolverPrivate *d = obj->d;
00768
00769
00770 RequestData *curr = newRequests.first();
00771 while (curr)
00772 if (curr->obj == d)
00773 {
00774
00775
00776 d->status = KResolver::Canceled;
00777 d->errorcode = KResolver::Canceled;
00778 d->syserror = 0;
00779 newRequests.take();
00780
00781 delete curr->worker;
00782 delete curr;
00783
00784 return true;
00785 }
00786 else
00787 curr = newRequests.next();
00788
00789
00790 curr = currentRequests.first();
00791 while (curr)
00792 if (curr->obj == d)
00793 {
00794
00795
00796 d->mutex.lock();
00797
00798 d->status = KResolver::Canceled;
00799 d->errorcode = KResolver::Canceled;
00800 d->syserror = 0;
00801
00802
00803 curr->obj = 0L;
00804 curr->input = 0L;
00805 if (curr->worker)
00806 curr->worker->input = 0L;
00807
00808 d->mutex.unlock();
00809 }
00810 else
00811 curr = currentRequests.next();
00812
00813 return false;
00814 }
00815
00816
00817
00818 void KResolverManager::dequeue(KResolver *obj)
00819 {
00820 QMutexLocker locker(&mutex);
00821 dequeueNew(obj);
00822 }