web_client.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <time.h>
00021 #include <sys/time.h>
00022 #include <sys/types.h>
00023 #include <unistd.h>
00024 
00025 #include <string.h>
00026 #include <string>
00027 
00028 #include <wwwsys.h>
00029 #include <WWWUtil.h>
00030 #include <WWWCore.h>
00031 #include <WWWInit.h>
00032 #include <HTReqMan.h>
00033 #include <HTTimer.h>
00034 #include <HTEvent.h>
00035 #include <HTEvtLst.h>
00036 #include <HTDialog.h>
00037 
00038 #include <archon/util/logger.H>
00039 #include <archon/util/text.H>
00040 #include <archon/util/uri.H>
00041 #include <archon/util/pipe.H>
00042 #include <archon/util/web_client.H>
00043 
00044 namespace Archon
00045 {
00046   namespace Utilities
00047   {
00048     namespace Web
00049     {
00050       using namespace std;
00051 
00052       namespace
00053       {
00054         struct SockEvents
00055         {
00056           SOCKET s;                           // Our socket
00057           HTEvent *events[HTEvent_TYPES];   // Event parameters for read, write, oob
00058           HTTimer *timeouts[HTEvent_TYPES];
00059         };
00060 
00061         struct EventOrder
00062         {
00063           HTEvent *event;
00064           SOCKET s;
00065           HTEventType type;
00066           HTPriority skipped;
00067         };
00068 
00069         enum SockEvents_action
00070         {
00071           SockEvents_mayCreate,
00072           SockEvents_find
00073         };
00074 
00075         fd_set FdArray[HTEvent_TYPES];
00076         SOCKET maxSocket = 0;               // Max socket file descriptor in use
00077         const int eventsToExecute = 10;     // How many to execute in one select loop
00078         HTList *hashTable[HT_M_HASH_SIZE];
00079         HTList *eventOrderList = 0;
00080 
00081 
00082         SockEvents *getSockEvents(SOCKET s, SockEvents_action action)
00083         {
00084           long v = s % HT_M_HASH_SIZE;
00085           HTList *cur;
00086           SockEvents *pres;
00087 
00088           /* if the socket doesn't exists, don't do anything */
00089           if(s == INVSOC) return 0;
00090 
00091           if(hashTable[v] == 0) hashTable[v] = HTList_new();
00092           cur = hashTable[v];
00093           while((pres = static_cast<SockEvents *>(HTList_nextObject(cur))))
00094             if(pres->s == s) return pres;
00095 
00096           if(action == SockEvents_mayCreate)
00097           {
00098             if((pres = static_cast<SockEvents *>(HT_CALLOC(1, sizeof(SockEvents)))) == 0)
00099               HT_OUTOFMEM("HTEventList_register");
00100             pres->s = s;
00101             HTList_addObject(hashTable[v], static_cast<void *>(pres));
00102             return pres;
00103           }
00104           return 0;
00105         }
00106 
00107         int remainingEventTypes(SockEvents *pres)
00108         {
00109           int ret = 0;
00110           for(int i = 0; i < HTEvent_TYPES; ++i)
00111             if(pres->events[i] != 0) ret |= 1<<i;
00112           return ret;
00113         }
00114 
00115         /*
00116          * Event timeout handler
00117          * If an event didn't occur before the timeout then call it explicitly
00118          * indicating that it timed out.
00119          */
00120         int eventTimeoutHandler(HTTimer *timer, void *param, HTEventType type)
00121         {
00122           SockEvents *sockp = static_cast<SockEvents *>(param);
00123           HTEvent *event = 0;
00124 
00125           // Check for read timeout
00126           if(sockp->timeouts[HTEvent_INDEX(HTEvent_READ)] == timer)
00127           {
00128             event = sockp->events[HTEvent_INDEX(HTEvent_READ)];
00129             HTTRACE(THD_TRACE, "Event....... READ timed out on %d.\n" _ sockp->s);
00130             return (*event->cbf) (sockp->s, event->param, HTEvent_TIMEOUT);
00131           }
00132 
00133           // Check for write timeout
00134           if(sockp->timeouts[HTEvent_INDEX(HTEvent_WRITE)] == timer)
00135           {
00136             event = sockp->events[HTEvent_INDEX(HTEvent_WRITE)];
00137             HTTRACE(THD_TRACE, "Event....... WRITE timed out on %d.\n" _ sockp->s);
00138             return (*event->cbf) (sockp->s, event->param, HTEvent_TIMEOUT);
00139           }
00140 
00141           // Check for out-of-band data timeout
00142           if(sockp->timeouts[HTEvent_INDEX(HTEvent_OOB)] == timer)
00143           {
00144             event = sockp->events[HTEvent_INDEX(HTEvent_OOB)];
00145             HTTRACE(THD_TRACE, "Event....... OOB timed out on %d.\n" _ sockp->s);
00146             return (*event->cbf) (sockp->s, event->param, HTEvent_TIMEOUT);
00147           }
00148           HTTRACE(THD_TRACE, "Event....... No event for timer %p with context %p\n" _ timer _ param);
00149           return HT_ERROR;
00150         }
00151 
00152         /*
00153          * This function is called by the libwww to handle registration of new 
00154          *
00155          * For a given socket, reqister a request structure, a set of operations, 
00156          * a HTEventCallback function, and a priority. For this implementation, 
00157          * we allow only a single HTEventCallback function for all operations.
00158          * and the priority field is ignored.
00159          */
00160         int registerEvent(SOCKET s, HTEventType type, HTEvent *event)
00161         {
00162           int newset = 0;
00163           SockEvents *sockp;
00164           HTTRACE(THD_TRACE, "Event....... Register socket %d, request %p handler %p type %s at priority %d\n" _ 
00165                   s _ reinterpret_cast<unsigned>(event->request) _ 
00166                   reinterpret_cast<unsigned>(event->cbf) _ HTEvent_type2str(type) _ 
00167                   static_cast<unsigned>(event->priority));
00168           if(s==INVSOC || HTEvent_INDEX(type) >= HTEvent_TYPES) return 0;
00169 
00170           /*
00171            * Insert socket into appropriate file descriptor set. We also make sure
00172            * that it is registered in the global set.
00173            */
00174           HTTRACE(THD_TRACE, "Event....... Registering socket for %s\n" _ HTEvent_type2str(type));
00175           sockp = getSockEvents(s, SockEvents_mayCreate);
00176           sockp->s = s;
00177           sockp->events[HTEvent_INDEX(type)] = event;
00178           newset = remainingEventTypes(sockp);
00179           FD_SET(s, FdArray+HTEvent_INDEX(type));
00180 
00181           HTTRACEDATA(reinterpret_cast<char *>(FdArray)+HTEvent_INDEX(type), 8, "HTEventList_register: (s:%d)" _ s);
00182 
00183           if(s > maxSocket)
00184           {
00185             maxSocket = s ;
00186             HTTRACE(THD_TRACE, "Event....... New value for maxSocket is %d\n" _ maxSocket);
00187           }
00188 
00189           /*
00190           **  If the timeout has been set (relative in millis) then we register 
00191           **  a new timeout for this event unless we already have a timer.
00192           */
00193           if(event->millis >= 0)
00194           {
00195             sockp->timeouts[HTEvent_INDEX(type)] =
00196               HTTimer_new(sockp->timeouts[HTEvent_INDEX(type)],
00197                           eventTimeoutHandler, sockp, event->millis, YES, YES);
00198           }
00199 
00200           return HT_OK;
00201         }
00202 
00203         /*
00204          * Remove the registered information for the specified socket for the actions 
00205          * specified in ops. if no actions remain after the unregister, the registered
00206          * info is deleted, and, if the socket has been registered for notification, 
00207          * the HTEventCallback will be invoked.
00208          */
00209         int unregisterEvent(SOCKET s, HTEventType type)
00210         {
00211           long v = s % HT_M_HASH_SIZE;
00212           HTList *cur = hashTable[v];
00213           HTList *last = cur;
00214           SockEvents *pres;
00215           int ret = HT_ERROR;
00216 
00217           /* if the socket doesn't exists, don't do anything */
00218           if(s == INVSOC) return HT_OK;
00219 
00220           while(cur && (pres = static_cast<SockEvents *>(HTList_nextObject(cur))))
00221           {
00222             if(pres->s == s)
00223             {
00224               int remaining = 0;
00225 
00226               /*
00227                * Unregister the event from this action
00228                */
00229               pres->events[HTEvent_INDEX(type)] = 0;
00230               remaining = remainingEventTypes(pres);
00231 
00232               /*
00233                * Check to see of there was a timeout connected with the event.
00234                * If so then delete the timeout as well.
00235                */
00236               {
00237                 HTTimer *timer = pres->timeouts[HTEvent_INDEX(type)];
00238                 if(timer) HTTimer_delete(timer);
00239                 pres->timeouts[HTEvent_INDEX(type)] = 0;
00240               }
00241 
00242               FD_CLR(s, FdArray+HTEvent_INDEX(type));
00243 
00244               HTTRACEDATA(reinterpret_cast<char *>(FdArray)+HTEvent_INDEX(type), 8, "HTEventList_unregister: (s:%d)" _ s);
00245 
00246               /*
00247               **  Check to see if we can delete the action completely. We do this
00248               **  if there are no more events registered.
00249               */
00250               if(remaining == 0)
00251               {
00252                 HTList *doomed = cur;
00253                 HTTRACE(THD_TRACE, "Event....... No more events registered for socket %d\n" _ s);
00254                 HT_FREE(pres);
00255                 pres = static_cast<SockEvents *>(HTList_nextObject(cur));
00256                 HTList_quickRemoveElement(doomed, last);
00257               }
00258               ret = HT_OK;
00259 
00260               HTTRACE(THD_TRACE, "Event....... Socket %d unregistered for %s\n" _ s _ 
00261                       HTEvent_type2str(type));
00262 
00263               /* We found the socket and can break */
00264               break;
00265             }
00266             last = cur;
00267           }
00268           if(THD_TRACE)
00269           {
00270             if(ret == HT_ERROR)
00271               HTTRACE(THD_TRACE, "Event....... Couldn't find socket %d. Can't unregister type %s\n" _
00272                       s _ HTEvent_type2str(type));
00273           }
00274           return ret;
00275         }
00276 
00277 
00278         int addEvent(SOCKET s, HTEventType type, ms_t now)
00279         {
00280           EventOrder *pres;
00281           HTList *cur = eventOrderList;
00282           HTList *insertAfter = cur;
00283           SockEvents *sockp = getSockEvents(s, SockEvents_find);
00284           HTEvent *event;
00285 
00286           if(sockp == 0 || (event = sockp->events[HTEvent_INDEX(type)]) == 0)
00287           {
00288             HTTRACE(THD_TRACE, "EventOrder.. no event found for socket %d, type %s.\n" _
00289                     s _ HTEvent_type2str(type));
00290             return HT_ERROR;
00291           }
00292 
00293           /* Fixup the timeout */
00294           if(sockp->timeouts[HTEvent_INDEX(type)])
00295             HTTimer_refresh(sockp->timeouts[HTEvent_INDEX(type)], now);
00296 
00297           /* Look to see if it's already here from before */
00298           while((pres = static_cast<EventOrder *>(HTList_nextObject(cur))))
00299           {
00300             if(pres->s == s && pres->event == event && pres->type == type)
00301             {
00302               ++*(reinterpret_cast<int *>(&(pres->skipped)));
00303               return HT_OK;
00304             }
00305             if(pres->event->priority+pres->skipped > event->priority)
00306               insertAfter = cur;
00307           }
00308 
00309           /* Create a new element */
00310           if((pres = static_cast<EventOrder *>(HT_CALLOC(1, sizeof(EventOrder)))) == 0)
00311             HT_OUTOFMEM("EventOrder_add");
00312           pres->event = event;
00313           pres->s = s;
00314           pres->type = type;
00315           HTList_addObject(insertAfter, static_cast<void *>(pres));
00316           return HT_OK;
00317         }
00318 
00319         int executeAndDeleteEvents()
00320         {
00321           HTList *cur = eventOrderList;
00322           EventOrder *pres;
00323           int i = 0;
00324           HTTRACE(THD_TRACE, "EventOrder.. execute ordered events\n");
00325           if(cur == 0) return NO;
00326           while((pres = static_cast<EventOrder *>(HTList_removeLastObject(cur))) && i<eventsToExecute)
00327           {
00328             HTEvent *event = pres->event;
00329             int ret;
00330             HTTRACE(THD_TRACE, "EventList... calling socket %d, request %p handler %p type %s\n" _ 
00331                     pres->s _ reinterpret_cast<unsigned>(event->request) _ 
00332                     reinterpret_cast<unsigned>(event->cbf) _ HTEvent_type2str(pres->type));
00333             ret = (*pres->event->cbf)(pres->s, pres->event->param, pres->type);
00334             HT_FREE(pres);
00335             if(ret != HT_OK) return ret;
00336             i++;
00337           }
00338           return HT_OK;
00339         }
00340 
00341         bool clearAllEvents()
00342         {
00343           HTList *cur = eventOrderList;
00344           EventOrder *pres;
00345           HTTRACE(THD_TRACE, "EventOrder.. Clearing all ordered events\n");
00346           if(cur)
00347           {
00348             while((pres = static_cast<EventOrder *>(HTList_nextObject(cur))))
00349               HT_FREE(pres);
00350             return true;
00351           }
00352           return false;
00353         }
00354 
00355         int printer(const char *fmt, va_list pArgs) throw()
00356         {
00357           return HT_OK; // vfprintf(stdout, fmt, pArgs);
00358         }
00359 
00360         int tracer(const char *fmt, va_list pArgs) throw()
00361         {
00362           return HT_OK; // vfprintf(stderr, fmt, pArgs);
00363         }
00364       }
00365 
00366       Mutex clientExistsMutex;
00367       bool clientExists = false;
00368 
00369       struct DefaultClient: Client
00370       {
00371         string applicationName;
00372         string applicationVersion;
00373         string cacheRootPath;
00374         long cacheSize;
00375         int maxSockets;
00376         Time eventHandlerMaxIdle;
00377 
00378         Mutex mutex;
00379         bool libwwwInitialized;
00380 
00381         bool eventHandlerActive;
00382         unsigned numberOfRequests;
00383         bool terminate;
00384 
00385         Condition requestChange;
00386         Condition eventHandlerQuit;
00387 
00388         DefaultClient(string applicationName, string applicationVersion,
00389                       string cacheRootPath, long cacheSize,
00390                       int maxSockets) throw(UnexpectedException):
00391           applicationName(applicationName),
00392           applicationVersion(applicationVersion),
00393           cacheRootPath(cacheRootPath),
00394           cacheSize(cacheSize),
00395           maxSockets(maxSockets),
00396           eventHandlerMaxIdle(10.0),
00397           libwwwInitialized(false),
00398           eventHandlerActive(false),
00399           numberOfRequests(0),
00400           terminate(false),
00401           requestChange(mutex),
00402           eventHandlerQuit(mutex)
00403         {
00404           Mutex::Lock l(clientExistsMutex);
00405           if(clientExists)
00406             ARCHON_THROW1(ResourceException,
00407                           "Only one client may exist at a time");
00408           clientExists = true;
00409         }
00410 
00411         ~DefaultClient()
00412         {
00413           {
00414             Mutex::Lock l(mutex);
00415             if(libwwwInitialized)
00416             {
00417               // Kill all active requests
00418               HTNet_killAll();
00419 
00420               // Kill event loop
00421               terminate = true;
00422               requestChange.notifyAll();
00423               while(eventHandlerActive) eventHandlerQuit.wait();
00424 
00425               clearAllEvents();
00426 
00427               // Clean up the persistent cache (if any)
00428               HTCacheTerminate();
00429 
00430               // Clean up all the global preferences
00431               HTFormat_deleteAll();
00432 
00433               // Remove bindings between suffixes, media types
00434               HTBind_deleteAll();
00435 
00436               // Terminate libwww
00437               HTLibTerminate();
00438 
00439               libwwwInitialized = false;
00440             }
00441           }
00442           {
00443             Mutex::Lock l(clientExistsMutex);
00444             clientExists = false;
00445           }
00446         }
00447 
00448         Ref<Response> request(Ref<Request>) throw(RequestException);
00449       };
00450 
00451       Ref<Client> Client::get(string applicationName,
00452                               string applicationVersion, int maxSockets)
00453         throw(UnexpectedException)
00454       {
00455         return new DefaultClient(applicationName, applicationVersion,
00456                                  "", -1, maxSockets);
00457       }
00458 
00459       Ref<Client> Client::get(string applicationName,
00460                               string applicationVersion,
00461                               string cacheRootPath, long cacheSize,
00462                               int maxSockets)
00463         throw(UnexpectedException)
00464       {
00465         return new DefaultClient(applicationName, applicationVersion,
00466                                  cacheRootPath, cacheSize, maxSockets);
00467       }
00468 
00469       struct DefaultRequest: Client::Request
00470       {
00471         DefaultRequest(const Uri &uri): Client::Request(uri) {}
00472       };
00473 
00474       Ref<Client::Request> Client::Request::get(const Uri &uri)
00475       {
00476         return new DefaultRequest(uri);
00477       }
00478 
00479       HTErrorMessage libwwwErrors[HTERR_ELEMENTS] = {HTERR_ENGLISH_INITIALIZER};
00480 
00481       struct DefaultResponse: Client::Response, Stream::Pipe
00482       {
00483         DefaultResponse(DefaultClient *client):
00484           Stream::Pipe(4096, true), client(client),
00485           setupDone(false), setup(*this) {}
00486 
00487         string getContentType()
00488         {
00489           return contentType;
00490         }
00491 
00495         void doSetup(HTRequest *request)
00496         {
00497           HTParentAnchor *anchor = HTRequest_anchor(request);
00498           HTFormat format = HTAnchor_format(anchor);
00499           {
00500             Mutex::Lock l(*this);
00501             contentType = HTAtom_name(format);
00502             setupDone = true;
00503           }
00504           setup.notifyAll();
00505         }
00506 
00510         void setError(HTRequest *request, int status)
00511         {
00512           string m;
00513           if(HTList *l = HTRequest_error(request))
00514             while(HTError *e = (HTError *)HTList_nextObject(l))
00515             {
00516               if(m.size()) m += ", ";
00517               HTErrorMessage &n = libwwwErrors[HTError_index(e)];
00518               if(n.code) m += Text::toString(n.code) + " - ";
00519               m += n.msg;
00520               break; // We want only the last error for now
00521             }
00522           if(!m.size()) m += Text::toString(status);
00523           {
00524             Mutex::Lock l(*this);
00525             error = m;
00526             setupDone = true;
00527           }
00528           setup.notifyAll();
00529         }
00530 
00531         void waitForSetup()
00532         {
00533           Mutex::Lock l(*this);
00534           while(!setupDone) setup.wait();
00535         }
00536 
00537         DefaultClient *client;
00538 
00539         string error;
00540         string contentType;
00541 
00542         bool setupDone;
00543         Condition setup;
00544 
00545         void refDispose(Mutex::Lock &l)
00546         {
00547           Stream::Pipe::refDispose(l);
00548         }
00549       };
00550 
00551 
00552 
00553       namespace
00554       {
00555         struct LibwwwStream;
00556 
00557         struct LibwwwStreamClass
00558         {
00559           char *name;
00560           int (*flush)(LibwwwStream *);
00561           int (*_free)(LibwwwStream *);
00562           int (*abort)(LibwwwStream *, HTList *errorlist);
00563           int (*put_character)(LibwwwStream *, char);
00564           int (*put_string)(LibwwwStream *, const char *);
00565           int (*put_block)(LibwwwStream *, const char *, int);
00566         };
00567 
00568         struct LibwwwStream
00569         {
00570           const LibwwwStreamClass *isa;
00571           HTRequest *request;
00572           Ref<Stream::Writer> writer;
00573           DefaultResponse *response;
00574           bool setupDone;
00575 
00576           LibwwwStream(HTRequest *request,
00577                        Ref<Stream::Writer> writer,
00578                        DefaultResponse *response);
00579         };
00580 
00581         int libwwwFlush(LibwwwStream *) throw() { return HT_OK; }
00582         int libwwwFree(LibwwwStream *) throw()  { return HT_OK; }
00583 
00587         int libwwwAbort(LibwwwStream *, HTList *errorlist) throw()
00588         {
00589           cerr << "Libwww::Stream::ABORT\n"; return HT_ERROR;
00590         }
00591 
00595         void doSetup(LibwwwStream *stream)
00596         {
00597           stream->response->doSetup(stream->request);
00598           stream->setupDone = true;
00599         }
00600 
00604         int libwwwPutCharacter(LibwwwStream *stream, char c) throw()
00605         {
00606           if(!stream->setupDone) doSetup(stream);
00607           try
00608           {
00609             stream->response->write(&c, 1);
00610           }
00611           catch(Stream::WriteException &) { return HT_ERROR; }
00612           catch(ThreadTerminatedException &) { return HT_ERROR; }
00613           return HT_OK;
00614         }
00615 
00619         int libwwwPutString(LibwwwStream *stream, const char *s) throw()
00620         {
00621           if(!stream->setupDone) doSetup(stream);
00622           try
00623           {
00624             stream->response->writeAll(s, strlen(s));
00625           }
00626           catch(Stream::WriteException &) { return HT_ERROR; }
00627           catch(ThreadTerminatedException &) { return HT_ERROR; }
00628           return HT_OK;
00629         }
00630 
00636         int libwwwPutBlock(LibwwwStream *stream, const char *b, int l) throw()
00637         {
00638           if(!stream->setupDone) doSetup(stream);
00639           try
00640           {
00641             stream->response->writeAll(b, l);
00642           }
00643           catch(Stream::WriteException &) { return HT_ERROR; }
00644           catch(ThreadTerminatedException &) { return HT_ERROR; }
00645           return HT_OK;
00646         }
00647 
00648         const LibwwwStreamClass libwwwRequestContextClass =
00649         {
00650           "libwwwStream",
00651           libwwwFlush,
00652           libwwwFree,
00653           libwwwAbort,
00654           libwwwPutCharacter,
00655           libwwwPutString,
00656           libwwwPutBlock
00657         };
00658 
00659         LibwwwStream::LibwwwStream(HTRequest *request,
00660                                    Ref<Stream::Writer> writer,
00661                                    DefaultResponse *response):
00662           isa(&libwwwRequestContextClass),
00663           request(request), writer(writer), response(response),
00664           setupDone(false) {}
00665 
00666 
00667 
00668         int terminateConnection(HTRequest *request, HTResponse *response,
00669                                 void *param, int status) throw()
00670         {
00671           LibwwwStream *stream =
00672             static_cast<LibwwwStream *>(HTRequest_context(request));
00673 
00674           if(!stream->setupDone)
00675           {
00676             if(status == 200) stream->response->doSetup(request);
00677             else stream->response->setError(request, status);
00678           }
00679 
00680           --stream->response->client->numberOfRequests;
00681 
00682           delete stream;
00683           //HTRequest_delete(request);
00684 
00685           return HT_OK;
00686         }
00687 
00688 
00689         void libwwwEventHandler(DefaultClient *client)
00690         {
00691           //Logger::get()->log("LibwwwEventHandler: started");
00692 
00693           Mutex::Lock l(client->mutex);
00694 
00695           for(;;)
00696           {
00697             ms_t timeout;
00698             fd_set treadset;
00699             fd_set twriteset;
00700             fd_set texceptset;
00701             int maxfds;
00702 
00703             Time wakeup = Time::now();
00704             wakeup += client->eventHandlerMaxIdle;
00705 
00706             // Wait if there are no requests. Quit if we timed out or
00707             // are terminated.
00708             for(;;)
00709             {
00710               if(!client->terminate)
00711               {
00712                 if(client->numberOfRequests) break;
00713                 if(!client->requestChange.timedWait(wakeup)) continue;
00714               }
00715 
00716               // Timed out or was terminated
00717               client->eventHandlerActive = false;
00718               //Logger::get()->log("LibwwwEventHandler: stopped");
00719               client->eventHandlerQuit.notifyAll();
00720               l.release();
00721               return;
00722             }
00723 
00724             /*
00725              * Inspect all registered timers. Every expired timer will
00726              * get its handler called, and the time to the next
00727              * expiration is returned in the argument. This scheme has
00728              * a flaw since if we add a new event that expires before
00729              * the timeout determined below then its timeout handler
00730              * might not get called as soon as it should.
00731              */
00732             if(HTTimer_next(&timeout))
00733               ARCHON_THROW1(InternalException,
00734                             "HTTimer_next failed");
00735 
00736             /*
00737              *  Now we copy the current active file descriptors to pass them to select.
00738              */
00739             treadset   = FdArray[HTEvent_INDEX(HTEvent_READ)];
00740             twriteset  = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
00741             texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
00742 
00743             /* And also get the max socket value */
00744             maxfds = maxSocket;
00745 
00746             wakeup = Time::now();
00747             wakeup.addMilliSeconds(timeout);
00748             int activeSockets = client->requestChange.select(maxfds+1, &treadset, &twriteset, &texceptset, wakeup);
00749             if(activeSockets <= 0) continue;
00750 
00751             unsigned long now = HTGetTimeInMillis();
00752 
00753             /* There were active sockets. Determine which fd sets they were in */
00754             for(SOCKET s = 0; s <= maxfds; ++s)
00755             {
00756               if(FD_ISSET(s, &texceptset) && addEvent(s, HTEvent_OOB, now) != HT_OK)
00757                 ARCHON_THROW1(InternalException,
00758                               "addEvent failed");
00759               if(FD_ISSET(s, &twriteset) && addEvent(s, HTEvent_WRITE, now) != HT_OK)
00760                 ARCHON_THROW1(InternalException,
00761                               "addEvent failed");
00762               if(FD_ISSET(s, &treadset) && addEvent(s, HTEvent_READ, now) != HT_OK)
00763                 ARCHON_THROW1(InternalException,
00764                               "addEvent failed");
00765             }
00766             if(executeAndDeleteEvents() != HT_OK)
00767               ARCHON_THROW1(InternalException,
00768                             "executeAndDeleteEvents failed");
00769           }
00770         }
00771       }
00772 
00773 
00783       Ref<Client::Response> DefaultClient::request(Ref<Request> request) throw(RequestException)
00784       {
00785         bool startEventHandler = false;
00786 
00787         Mutex::Lock l(mutex);
00788 
00789         if(!libwwwInitialized)
00790         {
00791           // If the Library is not already initialized then do it
00792           HTLibInit(applicationName.c_str(), applicationVersion.c_str());
00793 
00794           // Register the default set of messages and dialog functions 
00795           HTAlertInit();
00796           HTAlert_setInteractive(YES);
00797 
00798           // Register the default set of transport protocols
00799           HTTransportInit();
00800 
00801           // Register the default set of application protocol modules
00802           //HTProtocolPreemptiveInit();
00803           HTProtocolInit();
00804 
00805           // Initialize suffix bindings for local files
00806           HTBind_init();
00807 
00808           // Set max number of sockets we want open simultanously
00809           HTNet_setMaxSocket(maxSockets);
00810 
00811           // The persistent cache does not work in preemptive mode
00812           if(cacheSize > 0) HTCacheInit(cacheRootPath.c_str(), cacheSize);
00813 
00814           // Register the default set of BEFORE and AFTER filters
00815           HTNetInit();
00816 
00817           // Set up the default set of Authentication schemes
00818           HTAAInit();
00819 
00820           // Get any proxy or gateway environment variables
00821           HTProxy_getEnvVar();
00822 
00823           HTList *converters = HTList_new();
00824 
00825           // Register the default set of converters
00826           HTConverterInit(converters);
00827 
00828           // Register the default libwww HTML parser
00829           //HTMLInit(converters);
00830 
00831           // Set the convertes as global converters for all requests
00832           HTFormat_setConversion(converters);
00833 
00834           // Register the default set of transfer encoders and
00835           // decoders
00836           HTList *transferEncodings = HTList_new();
00837           HTTransferEncoderInit(transferEncodings);
00838           HTFormat_setTransferCoding(transferEncodings);
00839 
00840           // Register the default set of content encoders and decoders
00841           HTList *contentEncodings = HTList_new();
00842           HTContentEncoderInit(contentEncodings);
00843           if(HTList_count(contentEncodings) > 0)
00844             HTFormat_setContentCoding(contentEncodings);
00845           else
00846           {
00847             HTList_delete(contentEncodings);
00848             contentEncodings = 0;
00849           }
00850 
00851           // Register the default set of MIME header parsers
00852           HTMIMEInit();
00853 
00854           // Register the default set of file suffix bindings
00855           HTFileInit();
00856 
00857           // Register the default set of Icons for directory listings
00858           HTIconInit(0);
00859 
00860           // Register our own event manager
00861           HTEvent_setRegisterCallback(registerEvent);
00862           HTEvent_setUnregisterCallback(unregisterEvent);
00863 
00864           // Gotta set up our own traces
00865           HTPrint_setCallback(printer);
00866           HTTrace_setCallback(tracer);
00867 
00868           HTSetTraceMessageMask(""); // See http://www.w3.org/Library/src/HTHome.html#Trace
00869     
00870           // Add our own filter to handle termination
00871           HTNet_addAfter(terminateConnection, 0, 0, HT_ALL, HT_FILTER_LAST);
00872 
00873           eventOrderList = HTList_new();
00874 
00875           libwwwInitialized = true;
00876         }
00877 
00878         // Create a pipe with expanding buffers
00879         DefaultResponse *defaultResponse = new DefaultResponse(this);
00880         Ref<Response> response(defaultResponse);
00881         Ref<Stream::Writer> writer(defaultResponse);
00882 
00883         HTRequest *htRequest = HTRequest_new();
00884 
00885         LibwwwStream *stream = new LibwwwStream(htRequest, writer, defaultResponse);
00886 
00887         // The stream object is not deallocated by Libwww.
00888         HTRequest_setOutputStream(htRequest, reinterpret_cast<HTStream *>(stream));
00889         HTRequest_setOutputFormat(htRequest, WWW_SOURCE);
00890 
00891         // The context object is not deallocated by Libwww.
00892         HTRequest_setContext(htRequest, stream);
00893 
00894         //HTRequest_setFlush(request, YES);
00895         HTRequest_setPreemptive(htRequest, NO);
00896 
00897         HTAnchor *anchor = HTAnchor_findAddress(request->getUri().toString().c_str());
00898 
00899         ++numberOfRequests;
00900 
00901         if(!eventHandlerActive) eventHandlerActive = startEventHandler = true;
00902 
00903         HTLoadAnchor(anchor, htRequest);
00904 
00905         l.release();
00906 
00907         if(startEventHandler) Thread::run(libwwwEventHandler, this);
00908         else requestChange.notifyAll();
00909 
00910         defaultResponse->waitForSetup();
00911         if(defaultResponse->error.size())
00912           ARCHON_THROW1(RequestException, defaultResponse->error);
00913 
00914         return response;
00915       }
00916     }
00917   }
00918 }

Generated on Sun Jul 30 22:55:44 2006 for Archon by  doxygen 1.4.4