context_loop.c

00001 /*
00002  * $Id: context_loop.c 5151 2007-05-09 18:59:58Z ajc $
00003  */
00014 #include "webcit.h"
00015 #include "webserver.h"
00016 
00018 pthread_mutex_t SessionListMutex;
00019 
00020 struct wcsession *SessionList = NULL; 
00022 pthread_key_t MyConKey;         
00029 void free_attachments(struct wcsession *sess) {
00030         struct wc_attachment *att;
00031 
00032         while (sess->first_attachment != NULL) {
00033                 att = sess->first_attachment;
00034                 sess->first_attachment = sess->first_attachment->next;
00035                 free(att->data);
00036                 free(att);
00037         }
00038 }
00039 
00043 void do_housekeeping(void)
00044 {
00045         struct wcsession *sptr, *ss;
00046         struct wcsession *sessions_to_kill = NULL;
00047         int num_sessions = 0;
00048         static int num_threads = MIN_WORKER_THREADS;
00049 
00054         pthread_mutex_lock(&SessionListMutex);
00055         num_sessions = 0;
00056         for (sptr = SessionList; sptr != NULL; sptr = sptr->next) {
00057                 ++num_sessions;
00058 
00060                 if ((time(NULL) - (sptr->lastreq)) >
00061                    (time_t) WEBCIT_TIMEOUT) {
00062                         sptr->killthis = 1;
00063                 }
00064 
00066                 if (sptr->killthis) {
00067 
00069                         if (sptr == SessionList) {
00070                                 SessionList = SessionList->next;
00071                         }
00072                         else for (ss=SessionList;ss!=NULL;ss=ss->next) {
00073                                 if (ss->next == sptr) {
00074                                         ss->next = ss->next->next;
00075                                 }
00076                         }
00077 
00078                         sptr->next = sessions_to_kill;
00079                         sessions_to_kill = sptr;
00080                 }
00081         }
00082         pthread_mutex_unlock(&SessionListMutex);
00083 
00087         while (sessions_to_kill != NULL) {
00088                 lprintf(3, "Destroying session %d\n", sessions_to_kill->wc_session);
00089                 pthread_mutex_lock(&sessions_to_kill->SessionMutex);
00090                 close(sessions_to_kill->serv_sock);
00091                 close(sessions_to_kill->chat_sock);
00092                 if (sessions_to_kill->preferences != NULL) {
00093                         free(sessions_to_kill->preferences);
00094                 }
00095                 if (sessions_to_kill->cache_fold != NULL) {
00096                         free(sessions_to_kill->cache_fold);
00097                 }
00098                 free_attachments(sessions_to_kill);
00099                 free_march_list(sessions_to_kill);
00100                 pthread_mutex_unlock(&sessions_to_kill->SessionMutex);
00101                 sptr = sessions_to_kill->next;
00102                 free(sessions_to_kill);
00103                 sessions_to_kill = sptr;
00104                 --num_sessions;
00105         }
00106 
00111         while ( (num_sessions > num_threads)
00112               && (num_threads <= MAX_WORKER_THREADS) ) {
00113                 spawn_another_worker_thread();
00114                 ++num_threads;
00115                 lprintf(3, "There are %d sessions and %d threads active.\n",
00116                         num_sessions, num_threads);
00117         }
00118 }
00119 
00120 
00124 void housekeeping_loop(void)
00125 {
00126         while (1) {
00127                 sleeeeeeeeeep(HOUSEKEEPING);
00128                 do_housekeeping();
00129         }
00130 }
00131 
00132 
00141 int GenerateSessionID(void)
00142 {
00143         static int seq = (-1);
00144 
00145         if (seq < 0) {
00146                 seq = (int) time(NULL);
00147         }
00148                 
00149         return ++seq;
00150 }
00151 
00152 
00159 int req_gets(int sock, char *buf, char *hold)
00160 {
00161         int a;
00162 
00163         if (strlen(hold) == 0) {
00164                 strcpy(buf, "");
00165                 a = client_getln(sock, buf, SIZ);
00166                 if (a<1) return(-1);
00167         } else {
00168                 safestrncpy(buf, hold, SIZ);
00169         }
00170         strcpy(hold, "");
00171 
00172         if (!strncasecmp(buf, "Cookie: ", 8)) {
00173                 for (a = 0; a < strlen(buf); ++a)
00174                         if (buf[a] == ';') {
00175                                 sprintf(hold, "Cookie: %s", &buf[a + 1]);
00176                                 buf[a] = 0;
00177                                 while (isspace(hold[8]))
00178                                         strcpy(&hold[8], &hold[9]);
00179                                 return(0);
00180                         }
00181         }
00182 
00183         return(0);
00184 }
00185 
00193 int lingering_close(int fd)
00194 {
00195         char buf[SIZ];
00196         int i;
00197         fd_set set;
00198         struct timeval tv, start;
00199 
00200         gettimeofday(&start, NULL);
00201         shutdown(fd, 1);
00202         do {
00203                 do {
00204                         gettimeofday(&tv, NULL);
00205                         tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
00206                         tv.tv_usec = start.tv_usec - tv.tv_usec;
00207                         if (tv.tv_usec < 0) {
00208                                 tv.tv_sec--;
00209                                 tv.tv_usec += 1000000;
00210                         }
00211                         FD_ZERO(&set);
00212                         FD_SET(fd, &set);
00213                         i = select(fd + 1, &set, NULL, NULL, &tv);
00214                 } while (i == -1 && errno == EINTR);
00215 
00216                 if (i <= 0)
00217                         break;
00218 
00219                 i = read(fd, buf, sizeof buf);
00220         } while (i != 0 && (i != -1 || errno == EINTR));
00221 
00222         return close(fd);
00223 }
00224 
00225 
00226 
00233 int is_bogus(char *http_cmd) {
00234         char *url;
00235         int i, max;
00236 
00237         url = strstr(http_cmd, " ");
00238         if (url == NULL) return(1);
00239         ++url;
00240 
00241         char *bogus_prefixes[] = {
00242                 "/scripts/root.exe",    
00243                 "/c/winnt",
00244                 "/MSADC/",
00245                 "/_vti",                
00246                 "/MSOffice"             
00247         };
00248 
00249         max = sizeof(bogus_prefixes) / sizeof(char *);
00250 
00251         for (i=0; i<max; ++i) {
00252                 if (!strncasecmp(url, bogus_prefixes[i], strlen(bogus_prefixes[i]))) {
00253                         return(2);
00254                 }
00255         }
00256 
00257         return(0);      /* probably ok */
00258 }
00259 
00260 
00261 
00275 void context_loop(int sock)
00276 {
00277         struct httprequest *req = NULL;
00278         struct httprequest *last = NULL;
00279         struct httprequest *hptr;
00280         char buf[SIZ], hold[SIZ];
00281         int desired_session = 0;
00282         int got_cookie = 0;
00283         int gzip_ok = 0;
00284         struct wcsession *TheSession, *sptr;
00285         char httpauth_string[1024];
00286         char httpauth_user[1024];
00287         char httpauth_pass[1024];
00288         char accept_language[256];
00289         char *ptr = NULL;
00290         int session_is_new = 0;
00291 
00292         strcpy(httpauth_string, "");
00293         strcpy(httpauth_user, DEFAULT_HTTPAUTH_USER);
00294         strcpy(httpauth_pass, DEFAULT_HTTPAUTH_PASS);
00295 
00299         memset(hold, 0, sizeof(hold));
00300         do {
00301                 if (req_gets(sock, buf, hold) < 0) return;
00302 
00306                 if (!strncasecmp(buf, "Accept-encoding:", 16)) {
00307                         if (strstr(&buf[16], "gzip")) {
00308                                 gzip_ok = 1;
00309                         }
00310                 }
00311 
00315                 if (!strncasecmp(buf, "Cookie: webcit=", 15)) {
00316                         cookie_to_stuff(&buf[15], &desired_session,
00317                                 NULL, 0, NULL, 0, NULL, 0);
00318                         got_cookie = 1;
00319                 }
00320 
00324                 if (!strncasecmp(buf, "Authorization: Basic ", 21)) {
00325                         CtdlDecodeBase64(httpauth_string, &buf[21], strlen(&buf[21]));
00326                         extract_token(httpauth_user, httpauth_string, 0, ':', sizeof httpauth_user);
00327                         extract_token(httpauth_pass, httpauth_string, 1, ':', sizeof httpauth_pass);
00328                 }
00329 
00330                 if (!strncasecmp(buf, "If-Modified-Since: ", 19)) {
00331                         if_modified_since = httpdate_to_timestamp(&buf[19]);
00332                 }
00333 
00334                 if (!strncasecmp(buf, "Accept-Language: ", 17)) {
00335                         safestrncpy(accept_language, &buf[17], sizeof accept_language);
00336                 }
00337 
00341                 hptr = (struct httprequest *)
00342                         malloc(sizeof(struct httprequest));
00343                 if (req == NULL)
00344                         req = hptr;
00345                 else
00346                         last->next = hptr;
00347                 hptr->next = NULL;
00348                 last = hptr;
00349 
00350                 safestrncpy(hptr->line, buf, sizeof hptr->line);
00351 
00352         } while (strlen(buf) > 0);
00353 
00360         ptr = strstr(req->line, " /webcit ");   /*< Handle "/webcit" */
00361         if (ptr != NULL) {
00362                 strcpy(ptr+2, ptr+8);
00363         }
00364 
00365         ptr = strstr(req->line, " /webcit");    /*< Handle "/webcit/" */
00366         if (ptr != NULL) {
00367                 strcpy(ptr+1, ptr+8);
00368         }
00369 
00372         safestrncpy(buf, req->line, sizeof buf);
00373         lprintf(5, "HTTP: %s\n", buf);
00374 
00376         if (is_bogus(buf)) {
00377                 strcpy(req->line, "GET /404 HTTP/1.1");
00378                 strcpy(buf, "GET /404 HTTP/1.1");
00379         }
00380 
00384         remove_token(buf, 0, ' ');
00385         if (buf[1]==' ') buf[1]=0;
00386 
00391         if (!strncasecmp(buf, "/robots.txt", 11)) {
00392                 strcpy(req->line, "GET /static/robots.txt"
00393                                 "?force_close_session=yes HTTP/1.1");
00394         }
00395         else if (!strncasecmp(buf, "/favicon.ico", 12)) {
00396                 strcpy(req->line, "GET /static/favicon.ico");
00397         }
00398 
00405         else if ( (strcmp(buf, "/"))
00406                 && (strncasecmp(buf, "/listsub", 8))
00407                 && (strncasecmp(buf, "/freebusy", 9))
00408                 && (strncasecmp(buf, "/do_logout", 10))
00409                 && (strncasecmp(buf, "/groupdav", 9))
00410                 && (strncasecmp(buf, "/static", 7))
00411                 && (strncasecmp(buf, "/rss", 4))
00412                 && (strncasecmp(buf, "/404", 4))
00413                 && (got_cookie == 0)) {
00414                 strcpy(req->line, "GET /static/nocookies.html"
00415                                 "?force_close_session=yes HTTP/1.1");
00416         }
00417 
00421         TheSession = NULL;
00422 
00423         if (TheSession == NULL) {
00424                 pthread_mutex_lock(&SessionListMutex);
00425                 for (sptr = SessionList; sptr != NULL; sptr = sptr->next) {
00426 
00428                         if ( (strlen(httpauth_user) > 0)
00429                            &&(!strcasecmp(sptr->httpauth_user, httpauth_user))
00430                            &&(!strcasecmp(sptr->httpauth_pass, httpauth_pass)) ) {
00431                                 TheSession = sptr;
00432                         }
00433 
00435                         if ( (desired_session != 0) && (sptr->wc_session == desired_session)) {
00436                                 TheSession = sptr;
00437                         }
00438 
00439                 }
00440                 pthread_mutex_unlock(&SessionListMutex);
00441         }
00442 
00446         if (TheSession == NULL) {
00447                 lprintf(3, "Creating a new session\n");
00448                 TheSession = (struct wcsession *)
00449                         malloc(sizeof(struct wcsession));
00450                 memset(TheSession, 0, sizeof(struct wcsession));
00451                 TheSession->serv_sock = (-1);
00452                 TheSession->chat_sock = (-1);
00453         
00454                 /* If we're recreating a session that expired, it's best to give it the same
00455                  * session number that it had before.  The client browser ought to pick up
00456                  * the new session number and start using it, but in some rare situations it
00457                  * doesn't, and that's a Bad Thing because it causes lots of spurious sessions
00458                  * to get created.
00459                  */     
00460                 if (desired_session == 0) {
00461                         TheSession->wc_session = GenerateSessionID();
00462                 }
00463                 else {
00464                         TheSession->wc_session = desired_session;
00465                 }
00466 
00467                 strcpy(TheSession->httpauth_user, httpauth_user);
00468                 strcpy(TheSession->httpauth_pass, httpauth_pass);
00469                 pthread_mutex_init(&TheSession->SessionMutex, NULL);
00470                 pthread_mutex_lock(&SessionListMutex);
00471                 TheSession->next = SessionList;
00472                 SessionList = TheSession;
00473                 pthread_mutex_unlock(&SessionListMutex);
00474                 session_is_new = 1;
00475         }
00476 
00485         pthread_mutex_lock(&TheSession->SessionMutex);          /*< bind */
00486         pthread_setspecific(MyConKey, (void *)TheSession);
00487         TheSession->http_sock = sock;
00488         TheSession->lastreq = time(NULL);                       /*< log */
00489         TheSession->gzip_ok = gzip_ok;
00490 #ifdef ENABLE_NLS
00491         if (session_is_new) {
00492                 httplang_to_locale(accept_language);
00493         }
00494         go_selected_language();                         /*< set locale */
00495 #endif
00496         session_loop(req);                              /*< do transaction */
00497 #ifdef ENABLE_NLS
00498         stop_selected_language();                       /*< unset locale */
00499 #endif
00500         pthread_mutex_unlock(&TheSession->SessionMutex);        /*< unbind */
00501 
00503         while (req != NULL) {
00504                 hptr = req->next;
00505                 free(req);
00506                 req = hptr;
00507         }
00508 
00513         clear_local_substs();
00514 }

Generated on Wed Jun 20 23:13:07 2007 for webcit by  doxygen 1.5.2