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