abyss_server.c

Go to the documentation of this file.
00001 /* Copyright information is at end of file */
00002 #include <assert.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <string.h>
00006 #include <time.h>
00007 #include <errno.h>
00008 #ifdef WIN32
00009   #include <io.h>
00010 #else
00011   #include <unistd.h>
00012   #include <grp.h>
00013 #endif
00014 #include <fcntl.h>
00015 
00016 #include <xmlrpc-c/config.h>
00017 #include "abyss_mallocvar.h"
00018 #include "abyss_xmlrpc_int.h"
00019 
00020 #include <xmlrpc-c/abyss.h>
00021 #include "abyss_trace.h"
00022 #include "abyss_session.h"
00023 #include "abyss_conn.h"
00024 #include "abyss_socket.h"
00025 #ifdef WIN32
00026   #include "socket_win.h"
00027 #else
00028   #include "abyss_socket_unix.h"
00029 #endif
00030 #include "abyss_http.h"
00031 #include "abyss_date.h"
00032 #include "abyss_info.h"
00033 
00034 #include "abyss_server.h"
00035 
00036 
00037 void
00038 ServerTerminate(TServer * const serverP) {
00039 
00040     struct _TServer * const srvP = serverP->srvP;
00041 
00042     srvP->terminationRequested = true;
00043 }
00044 
00045 
00046 
00047 void
00048 ServerResetTerminate(TServer * const serverP) {
00049 
00050     struct _TServer * const srvP = serverP->srvP;
00051 
00052     srvP->terminationRequested = false;
00053 }
00054 
00055 
00056 
00057 typedef int (*TQSortProc)(const void *, const void *);
00058 
00059 static int
00060 cmpfilenames(const TFileInfo **f1,const TFileInfo **f2) {
00061     if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR))
00062         return (-1);
00063     if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR))
00064         return 1;
00065 
00066     return strcmp((*f1)->name,(*f2)->name);
00067 }
00068 
00069 static int
00070 cmpfiledates(const TFileInfo **f1,const TFileInfo **f2) {
00071     if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR))
00072         return (-1);
00073     if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR))
00074         return 1;
00075 
00076     return ((*f1)->time_write-(*f2)->time_write);
00077 }
00078 
00079 
00080 
00081 static void
00082 determineSortType(const char *  const query,
00083                   abyss_bool *  const ascendingP,
00084                   uint16_t *    const sortP,
00085                   abyss_bool *  const textP,
00086                   const char ** const errorP) {
00087 
00088     *ascendingP = TRUE;
00089     *sortP = 1;
00090     *textP = FALSE;
00091     *errorP = NULL;
00092     
00093     if (query) {
00094         if (xmlrpc_streq(query, "plain"))
00095             *textP = TRUE;
00096         else if (xmlrpc_streq(query, "name-up")) {
00097             *sortP = 1;
00098             *ascendingP = TRUE;
00099         } else if (xmlrpc_streq(query, "name-down")) {
00100             *sortP = 1;
00101             *ascendingP = FALSE;
00102         } else if (xmlrpc_streq(query, "date-up")) {
00103             *sortP = 2;
00104             *ascendingP = TRUE;
00105         } else if (xmlrpc_streq(query, "date-down")) {
00106             *sortP = 2;
00107             *ascendingP = FALSE;
00108         } else  {
00109             xmlrpc_asprintf(errorP, "invalid query value '%s'", query);
00110         }
00111     }
00112 }
00113 
00114 
00115 
00116 static void
00117 generateListing(TList *       const listP,
00118                 char *        const z,
00119                 const char *  const uri,
00120                 TPool *       const poolP,
00121                 const char ** const errorP,
00122                 uint16_t *    const responseStatusP) {
00123     
00124     TFileInfo fileinfo;
00125     TFileFind findhandle;
00126 
00127     *errorP = NULL;
00128 
00129     if (!FileFindFirst(&findhandle, z, &fileinfo)) {
00130         *responseStatusP = ResponseStatusFromErrno(errno);
00131         xmlrpc_asprintf(errorP, "Can't read first entry in directory");
00132     } else {
00133         ListInit(listP);
00134 
00135         do {
00136             TFileInfo * fi;
00137             /* Files whose names start with a dot are ignored */
00138             /* This includes implicitly the ./ and ../ */
00139             if (*fileinfo.name == '.') {
00140                 if (xmlrpc_streq(fileinfo.name, "..")) {
00141                     if (xmlrpc_streq(uri, "/"))
00142                         continue;
00143                 } else
00144                     continue;
00145             }
00146             fi = (TFileInfo *)PoolAlloc(poolP, sizeof(fileinfo));
00147             if (fi) {
00148                 abyss_bool success;
00149                 memcpy(fi, &fileinfo, sizeof(fileinfo));
00150                 success =  ListAdd(listP, fi);
00151                 if (!success)
00152                     xmlrpc_asprintf(errorP, "ListAdd() failed");
00153             } else
00154                 xmlrpc_asprintf(errorP, "PoolAlloc() failed.");
00155         } while (!*errorP && FileFindNext(&findhandle, &fileinfo));
00156 
00157         if (*errorP) {
00158             *responseStatusP = 500;
00159             ListFree(listP);
00160         }            
00161         FileFindClose(&findhandle);
00162     }
00163 }
00164 
00165 
00166 
00167 static void
00168 sendDirectoryDocument(TList *      const listP,
00169                       abyss_bool   const ascending,
00170                       uint16_t     const sort,
00171                       abyss_bool   const text,
00172                       const char * const uri,
00173                       MIMEType *   const mimeTypeP,
00174                       TSession *   const sessionP,
00175                       char *       const z) {
00176 
00177     char *p,z1[26],z2[20],z3[9],u;
00178     const char * z4;
00179     int16_t i;
00180     uint32_t k;
00181 
00182     if (text) {
00183         sprintf(z, "Index of %s" CRLF, uri);
00184         i = strlen(z)-2;
00185         p = z + i + 2;
00186 
00187         while (i > 0) {
00188             *(p++) = '-';
00189             --i;
00190         }
00191 
00192         *p = '\0';
00193         strcat(z, CRLF CRLF
00194                "Name                      Size      "
00195                "Date-Time             Type" CRLF
00196                "------------------------------------"
00197                "--------------------------------------------"CRLF);
00198     } else {
00199         sprintf(z, "<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>"
00200                 "<H1>Index of %s</H1><PRE>",
00201                 uri, uri);
00202         strcat(z, "Name                      Size      "
00203                "Date-Time             Type<HR WIDTH=100%>"CRLF);
00204     }
00205 
00206     HTTPWriteBodyChunk(sessionP, z, strlen(z));
00207 
00208     /* Sort the files */
00209     qsort(listP->item, listP->size, sizeof(void *),
00210           (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates));
00211     
00212     /* Write the listing */
00213     if (ascending)
00214         i = 0;
00215     else
00216         i = listP->size - 1;
00217 
00218     while ((i < listP->size) && (i >= 0)) {
00219         TFileInfo * fi;
00220         struct tm ftm;
00221 
00222         fi = listP->item[i];
00223 
00224         if (ascending)
00225             ++i;
00226         else
00227             --i;
00228             
00229         strcpy(z, fi->name);
00230 
00231         k = strlen(z);
00232 
00233         if (fi->attrib & A_SUBDIR) {
00234             z[k++] = '/';
00235             z[k] = '\0';
00236         }
00237 
00238         if (k > 24) {
00239             z[10] = '\0';
00240             strcpy(z1, z);
00241             strcat(z1, "...");
00242             strcat(z1, z + k - 11);
00243             k = 24;
00244             p = z1 + 24;
00245         } else {
00246             strcpy(z1, z);
00247             
00248             ++k;
00249             p = z1 + k;
00250             while (k < 25)
00251                 z1[k++] = ' ';
00252             
00253             z1[25] = '\0';
00254         }
00255 
00256         ftm = *gmtime(&fi->time_write);
00257         sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1,
00258                 ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec);
00259 
00260         if (fi->attrib & A_SUBDIR) {
00261             strcpy(z3, "   --  ");
00262             z4 = "Directory";
00263         } else {
00264             if (fi->size < 9999)
00265                 u = 'b';
00266             else {
00267                 fi->size /= 1024;
00268                 if (fi->size < 9999)
00269                     u = 'K';
00270                 else {
00271                     fi->size /= 1024;
00272                     if (fi->size < 9999)
00273                         u = 'M';
00274                     else
00275                         u = 'G';
00276                 }
00277             }
00278                 
00279             sprintf(z3, "%5llu %c", (long long unsigned int)fi->size, u);
00280             
00281             if (xmlrpc_streq(fi->name, ".."))
00282                 z4 = "";
00283             else
00284                 z4 = MIMETypeFromFileName2(mimeTypeP, fi->name);
00285 
00286             if (!z4)
00287                 z4 = "Unknown";
00288         }
00289 
00290         if (text)
00291             sprintf(z, "%s%s %s    %s   %s"CRLF, z1, p, z3, z2, z4);
00292         else
00293             sprintf(z, "<A HREF=\"%s%s\">%s</A>%s %s    %s   %s"CRLF,
00294                     fi->name, fi->attrib & A_SUBDIR ? "/" : "",
00295                     z1, p, z3, z2, z4);
00296 
00297         HTTPWriteBodyChunk(sessionP, z, strlen(z));
00298     }
00299         
00300     /* Write the tail of the file */
00301     if (text)
00302         strcpy(z, SERVER_PLAIN_INFO);
00303     else
00304         strcpy(z, "</PRE>" SERVER_HTML_INFO "</BODY></HTML>" CRLF CRLF);
00305     
00306     HTTPWriteBodyChunk(sessionP, z, strlen(z));
00307 }
00308 
00309 
00310 
00311 static void
00312 fileDate(TSession * const sessionP,
00313          time_t     const statFilemodTime,
00314          TDate *    const fileDateP) {
00315 
00316     abyss_bool haveDate;
00317     TDate filemodDate;
00318 
00319     haveDate = DateFromLocal(&filemodDate, statFilemodTime);
00320 
00321     if (haveDate) {
00322         if (DateCompare(&sessionP->date, &filemodDate) < 0)
00323             *fileDateP = sessionP->date;
00324         else
00325             *fileDateP = filemodDate;
00326     } else
00327         *fileDateP = sessionP->date;
00328 }
00329 
00330 
00331 
00332 static abyss_bool
00333 ServerDirectoryHandler(TSession * const r,
00334                        char *     const z,
00335                        time_t     const fileModTime,
00336                        MIMEType * const mimeTypeP) {
00337 
00338     TList list;
00339     abyss_bool text;
00340     abyss_bool ascending;
00341     uint16_t sort;    /* 1=by name, 2=by date */
00342     TPool pool;
00343     TDate date;
00344     const char * error;
00345     uint16_t responseStatus=0;
00346     TDate dirdate;
00347     const char * imsHdr;
00348     
00349     determineSortType(r->request_info.query, &ascending, &sort, &text, &error);
00350 
00351     if (error) {
00352         ResponseStatus(r,400);
00353         xmlrpc_strfree(error);
00354         return TRUE;
00355     }
00356 
00357     fileDate(r, fileModTime, &dirdate);
00358 
00359     imsHdr = RequestHeaderValue(r, "If-Modified-Since");
00360     if (imsHdr) {
00361         if (DateDecode(imsHdr, &date)) {
00362             if (DateCompare(&dirdate, &date) <= 0) {
00363                 ResponseStatus(r, 304);
00364                 ResponseWrite(r);
00365                 return TRUE;
00366             }
00367         }
00368     }
00369 
00370     if (!PoolCreate(&pool, 1024)) {
00371         ResponseStatus(r, 500);
00372         return TRUE;
00373     }
00374 
00375     generateListing(&list, z, r->request_info.uri,
00376                     &pool, &error, &responseStatus);
00377     if (error) {
00378         ResponseStatus(r, responseStatus);
00379         xmlrpc_strfree(error);
00380         PoolFree(&pool);
00381         return TRUE;
00382     }
00383 
00384     /* Send something to the user to show that we are still alive */
00385     ResponseStatus(r, 200);
00386     ResponseContentType(r, (text ? "text/plain" : "text/html"));
00387 
00388     if (DateToString(&dirdate, z))
00389         ResponseAddField(r, "Last-Modified", z);
00390     
00391     ResponseChunked(r);
00392     ResponseWrite(r);
00393 
00394     if (r->request_info.method!=m_head)
00395         sendDirectoryDocument(&list, ascending, sort, text,
00396                               r->request_info.uri, mimeTypeP, r, z);
00397 
00398     HTTPWriteEndChunk(r);
00399 
00400     /* Free memory and exit */
00401     ListFree(&list);
00402     PoolFree(&pool);
00403 
00404     return TRUE;
00405 }
00406 
00407 
00408 
00409 #define BOUNDARY    "##123456789###BOUNDARY"
00410 
00411 static void
00412 sendBody(TSession *   const sessionP,
00413          TFile *      const fileP,
00414          uint64_t     const filesize,
00415          const char * const mediatype,
00416          uint64_t     const start0,
00417          uint64_t     const end0,
00418          char *       const z) {
00419 
00420     if (sessionP->ranges.size == 0)
00421         ConnWriteFromFile(sessionP->conn, fileP, 0, filesize - 1, z, 4096, 0);
00422     else if (sessionP->ranges.size == 1)
00423         ConnWriteFromFile(sessionP->conn, fileP, start0, end0, z, 4096, 0);
00424     else {
00425         uint64_t i;
00426         for (i = 0; i <= sessionP->ranges.size; ++i) {
00427             ConnWrite(sessionP->conn,"--", 2);
00428             ConnWrite(sessionP->conn, BOUNDARY, strlen(BOUNDARY));
00429             ConnWrite(sessionP->conn, CRLF, 2);
00430 
00431             if (i < sessionP->ranges.size) {
00432                 uint64_t start;
00433                 uint64_t end;
00434                 abyss_bool decoded;
00435                     
00436                 decoded = RangeDecode((char *)(sessionP->ranges.item[i]),
00437                                       filesize,
00438                                       &start, &end);
00439                 if (decoded) {
00440                     /* Entity header, not response header */
00441                     sprintf(z, "Content-type: %s" CRLF
00442                             "Content-range: bytes %llu-%llu/%llu" CRLF
00443                             "Content-length: %llu" CRLF
00444                             CRLF, mediatype, (long long unsigned int)start,
00445                      (long long unsigned int)end,
00446                             (long long unsigned int)filesize,
00447                      (long long unsigned int)(end-start+1));
00448 
00449                     ConnWrite(sessionP->conn, z, strlen(z));
00450 
00451                     ConnWriteFromFile(sessionP->conn, fileP, start, end, z,
00452                                       4096, 0);
00453                 }
00454             }
00455         }
00456     }
00457 }
00458 
00459 
00460 
00461 static abyss_bool
00462 ServerFileHandler(TSession * const r,
00463                   char *     const z,
00464                   time_t     const fileModTime,
00465                   MIMEType * const mimeTypeP) {
00466 
00467     const char * mediatype;
00468     TFile file;
00469     uint64_t filesize;
00470     uint64_t start;
00471     uint64_t end;
00472     TDate date;
00473     char * p;
00474     TDate filedate;
00475     
00476     mediatype = MIMETypeGuessFromFile2(mimeTypeP, z);
00477 
00478     if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) {
00479         ResponseStatusErrno(r);
00480         return TRUE;
00481     }
00482 
00483     fileDate(r, fileModTime, &filedate);
00484 
00485     p = RequestHeaderValue(r, "if-modified-since");
00486     if (p) {
00487         if (DateDecode(p,&date)) {
00488             if (DateCompare(&filedate, &date) <= 0) {
00489                 ResponseStatus(r, 304);
00490                 ResponseWrite(r);
00491                 return TRUE;
00492             } else
00493                 r->ranges.size = 0;
00494         }
00495     }
00496     filesize = FileSize(&file);
00497 
00498     switch (r->ranges.size) {
00499     case 0:
00500         ResponseStatus(r, 200);
00501         break;
00502 
00503     case 1: {
00504         abyss_bool decoded;
00505         decoded = RangeDecode((char *)(r->ranges.item[0]), filesize,
00506                               &start, &end);
00507         if (!decoded) {
00508             ListFree(&(r->ranges));
00509             ResponseStatus(r, 200);
00510             break;
00511         }
00512         
00513         sprintf(z, "bytes %llu-%llu/%llu", (long long unsigned int)start,
00514          (long long unsigned int)end, (long long unsigned int)filesize);
00515 
00516         ResponseAddField(r, "Content-range", z);
00517         ResponseContentLength(r, end - start + 1);
00518         ResponseStatus(r, 206);
00519     } break;
00520 
00521     default:
00522         ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY);
00523         ResponseStatus(r, 206);
00524         break;
00525     }
00526     
00527     if (r->ranges.size == 0) {
00528         ResponseContentLength(r, filesize);
00529         ResponseContentType(r, mediatype);
00530     }
00531     
00532     if (DateToString(&filedate, z))
00533         ResponseAddField(r, "Last-Modified", z);
00534 
00535     ResponseWrite(r);
00536 
00537     if (r->request_info.method != m_head)
00538         sendBody(r, &file, filesize, mediatype, start, end, z);
00539 
00540     FileClose(&file);
00541 
00542     return TRUE;
00543 }
00544 
00545 
00546 
00547 static abyss_bool
00548 ServerDefaultHandlerFunc(TSession * const sessionP) {
00549 
00550     struct _TServer * const srvP = ConnServer(sessionP->conn)->srvP;
00551 
00552     char *p;
00553     char z[4096];
00554     TFileStat fs;
00555     unsigned int i;
00556     abyss_bool endingslash=FALSE;
00557 
00558     if (!RequestValidURIPath(sessionP)) {
00559         ResponseStatus(sessionP, 400);
00560         return TRUE;
00561     }
00562 
00563     /* Must check for * (asterisk uri) in the future */
00564     if (sessionP->request_info.method == m_options) {
00565         ResponseAddField(sessionP, "Allow", "GET, HEAD");
00566         ResponseContentLength(sessionP, 0);
00567         ResponseStatus(sessionP, 200);
00568         return TRUE;
00569     }
00570 
00571     if ((sessionP->request_info.method != m_get) &&
00572         (sessionP->request_info.method != m_head)) {
00573         ResponseAddField(sessionP, "Allow", "GET, HEAD");
00574         ResponseStatus(sessionP, 405);
00575         return TRUE;
00576     }
00577 
00578     strcpy(z, srvP->filespath);
00579     strcat(z, sessionP->request_info.uri);
00580 
00581     p = z + strlen(z) - 1;
00582     if (*p == '/') {
00583         endingslash = TRUE;
00584         *p = '\0';
00585     }
00586 
00587 #ifdef WIN32
00588     p = z;
00589     while (*p) {
00590         if ((*p) == '/')
00591             *p= '\\';
00592 
00593         ++p;
00594     }
00595 #endif  /* WIN32 */
00596 
00597     if (!FileStat(z, &fs)) {
00598         ResponseStatusErrno(sessionP);
00599         return TRUE;
00600     }
00601 
00602     if (fs.st_mode & S_IFDIR) {
00603         /* Redirect to the same directory but with the ending slash
00604         ** to avoid problems with some browsers (IE for examples) when
00605         ** they generate relative urls */
00606         if (!endingslash) {
00607             strcpy(z, sessionP->request_info.uri);
00608             p = z+strlen(z);
00609             *p = '/';
00610             *(p+1) = '\0';
00611             ResponseAddField(sessionP, "Location", z);
00612             ResponseStatus(sessionP, 302);
00613             ResponseWrite(sessionP);
00614             return TRUE;
00615         }
00616 
00617         *p = DIRECTORY_SEPARATOR[0];
00618         ++p;
00619 
00620         i = srvP->defaultfilenames.size;
00621         while (i-- > 0) {
00622             *p = '\0';        
00623             strcat(z, (srvP->defaultfilenames.item[i]));
00624             if (FileStat(z, &fs)) {
00625                 if (!(fs.st_mode & S_IFDIR))
00626                     return ServerFileHandler(sessionP, z, fs.st_mtime,
00627                                              srvP->mimeTypeP);
00628             }
00629         }
00630 
00631         *(p-1) = '\0';
00632         
00633         if (!FileStat(z, &fs)) {
00634             ResponseStatusErrno(sessionP);
00635             return TRUE;
00636         }
00637         return ServerDirectoryHandler(sessionP, z, fs.st_mtime,
00638                                       srvP->mimeTypeP);
00639     } else
00640         return ServerFileHandler(sessionP, z, fs.st_mtime,
00641                                  srvP->mimeTypeP);
00642 }
00643 
00644 
00645 
00646 static void
00647 initUnixStuff(struct _TServer * const srvP) {
00648 #ifndef WIN32
00649     srvP->pidfile = srvP->uid = srvP->gid = -1;
00650 #endif
00651 }
00652 
00653 
00654 
00655 static abyss_bool
00656 logOpen(struct _TServer * const srvP) {
00657 
00658     abyss_bool success;
00659 
00660     success = FileOpenCreate(&srvP->logfile, srvP->logfilename,
00661                              O_WRONLY | O_APPEND);
00662     if (success) {
00663         abyss_bool success;
00664         success = MutexCreate(&srvP->logmutex);
00665         if (success)
00666             srvP->logfileisopen = TRUE;
00667         else
00668             TraceMsg("Can't create mutex for log file");
00669 
00670         if (!success)
00671             FileClose(&srvP->logfile);
00672     } else
00673         TraceMsg("Can't open log file '%s'", srvP->logfilename);
00674 
00675     return success;
00676 }
00677 
00678 
00679 
00680 static void
00681 logClose(struct _TServer * const srvP) {
00682 
00683     if (srvP->logfileisopen) {
00684         FileClose(&srvP->logfile);
00685         MutexFree(&srvP->logmutex);
00686         srvP->logfileisopen = FALSE;
00687     }
00688 }
00689 
00690 
00691 
00692 static void
00693 initSocketStuff(struct _TServer * const srvP,
00694                 abyss_bool        const noAccept,
00695                 TSocket *         const userSocketP,
00696                 uint16_t          const port,
00697                 const char **     const errorP) {
00698 
00699     if (userSocketP) {
00700         *errorP = NULL;
00701         srvP->serverAcceptsConnections = TRUE;
00702         srvP->socketBound = TRUE;
00703         srvP->listenSocketP = userSocketP;
00704     } else if (noAccept) {
00705         *errorP = NULL;
00706         srvP->serverAcceptsConnections = FALSE;
00707         srvP->socketBound = FALSE;
00708     } else {
00709         *errorP = NULL;
00710         srvP->serverAcceptsConnections = TRUE;
00711         srvP->socketBound = FALSE;
00712         srvP->port = port;
00713     }
00714     srvP->weCreatedListenSocket = FALSE;
00715 }
00716 
00717 
00718 
00719 static void
00720 createServer(struct _TServer ** const srvPP,
00721              abyss_bool         const noAccept,
00722              TSocket *          const userSocketP,
00723              uint16_t           const portNumber,             
00724              const char **      const errorP) {
00725 
00726     struct _TServer * srvP;
00727 
00728     MALLOCVAR(srvP);
00729 
00730     if (srvP == NULL) {
00731         xmlrpc_asprintf(errorP,
00732                         "Unable to allocate space for server descriptor");
00733     } else {
00734         srvP->terminationRequested = false;
00735 
00736         initSocketStuff(srvP, noAccept, userSocketP, portNumber, errorP);
00737 
00738         if (!*errorP) {
00739             srvP->defaulthandler = ServerDefaultHandlerFunc;
00740 
00741             srvP->name             = strdup("unnamed");
00742             srvP->filespath        = strdup(DEFAULT_DOCS);
00743             srvP->logfilename      = NULL;
00744             srvP->keepalivetimeout = 15;
00745             srvP->keepalivemaxconn = 30;
00746             srvP->timeout          = 15;
00747             srvP->advertise        = TRUE;
00748             srvP->mimeTypeP        = NULL;
00749             srvP->useSigchld       = FALSE;
00750             
00751             initUnixStuff(srvP);
00752 
00753             ListInitAutoFree(&srvP->handlers);
00754             ListInitAutoFree(&srvP->defaultfilenames);
00755 
00756             srvP->logfileisopen = FALSE;
00757 
00758             *errorP = NULL;
00759         }        
00760         if (*errorP)
00761             free(srvP);
00762     }
00763     *srvPP = srvP;
00764 }
00765 
00766 
00767 
00768 static void
00769 setNamePathLog(TServer *    const serverP,
00770                const char * const name,
00771                const char * const filesPath,
00772                const char * const logFileName) {
00773 /*----------------------------------------------------------------------------
00774    This odd function exists to help with backward compatibility.
00775    Today, we have the expandable model where you create a server with
00776    default parameters, then use ServerSet... functions to choose
00777    non-default parameters.  But before, you specified these three
00778    parameters right in the arguments of various create functions.
00779 -----------------------------------------------------------------------------*/
00780     if (name)
00781         ServerSetName(serverP, name);
00782     if (filesPath)
00783         ServerSetFilesPath(serverP, filesPath);
00784     if (logFileName)
00785         ServerSetLogFileName(serverP, logFileName);
00786 }
00787 
00788 
00789 
00790 abyss_bool
00791 ServerCreate(TServer *    const serverP,
00792              const char * const name,
00793              uint16_t     const portNumber,
00794              const char * const filesPath,
00795              const char * const logFileName) {
00796 
00797     abyss_bool const noAcceptFalse = FALSE;
00798 
00799     abyss_bool success;
00800     const char * error;
00801 
00802     createServer(&serverP->srvP, noAcceptFalse, NULL, portNumber, &error);
00803 
00804     if (error) {
00805         TraceMsg(error);
00806         xmlrpc_strfree(error);
00807         success = FALSE;
00808     } else {
00809         success = TRUE;
00810     
00811         setNamePathLog(serverP, name, filesPath, logFileName);
00812     }
00813 
00814     return success;
00815 }
00816 
00817 
00818 
00819 static void
00820 createSocketFromOsSocket(TOsSocket    const osSocket,
00821                          TSocket **   const socketPP) {
00822 
00823 #ifdef WIN32
00824     SocketWinCreateWinsock(osSocket, socketPP);
00825 #else
00826     SocketUnixCreateFd(osSocket, socketPP);
00827 #endif
00828 }
00829 
00830 
00831 
00832 abyss_bool
00833 ServerCreateSocket(TServer *    const serverP,
00834                    const char * const name,
00835                    TOsSocket    const socketFd,
00836                    const char * const filesPath,
00837                    const char * const logFileName) {
00838 
00839     abyss_bool success;
00840     TSocket * socketP;
00841 
00842     createSocketFromOsSocket(socketFd, &socketP);
00843 
00844     if (socketP) {
00845         abyss_bool const noAcceptFalse = FALSE;
00846 
00847         const char * error;
00848 
00849         createServer(&serverP->srvP, noAcceptFalse, socketP, 0, &error);
00850 
00851         if (error) {
00852             TraceMsg(error);
00853             success = FALSE;
00854             xmlrpc_strfree(error);
00855         } else {
00856             success = TRUE;
00857             
00858             setNamePathLog(serverP, name, filesPath, logFileName);
00859         }
00860     } else
00861         success = FALSE;
00862 
00863     return success;
00864 }
00865 
00866 
00867 
00868 abyss_bool
00869 ServerCreateNoAccept(TServer *    const serverP,
00870                      const char * const name,
00871                      const char * const filesPath,
00872                      const char * const logFileName) {
00873 
00874     abyss_bool const noAcceptTrue = TRUE;
00875 
00876     abyss_bool success;
00877     const char * error;
00878 
00879     createServer(&serverP->srvP, noAcceptTrue, NULL, 0, &error);
00880 
00881     if (error) {
00882         TraceMsg(error);
00883         success = FALSE;
00884         xmlrpc_strfree(error);
00885     } else {
00886         success = TRUE;
00887         
00888         setNamePathLog(serverP, name, filesPath, logFileName);
00889     }
00890     return success;
00891 }
00892 
00893 
00894 
00895 void
00896 ServerCreateSocket2(TServer *     const serverP,
00897                     TSocket *     const socketP,
00898                     const char ** const errorP) {
00899     
00900     abyss_bool const noAcceptFalse = FALSE;
00901 
00902     assert(socketP);
00903 
00904     createServer(&serverP->srvP, noAcceptFalse, socketP, 0, errorP);
00905 }
00906 
00907 
00908 
00909 static void
00910 terminateHandlers(TList * const handlersP) {
00911 /*----------------------------------------------------------------------------
00912    Terminate all handlers in the list '*handlersP'.
00913 
00914    I.e. call each handler's terminate function.
00915 -----------------------------------------------------------------------------*/
00916     if (handlersP->item) {
00917         unsigned int i;
00918         for (i = handlersP->size; i > 0; --i) {
00919             URIHandler2 * const handlerP = handlersP->item[i-1];
00920             if (handlerP->term)
00921                 handlerP->term(handlerP->userdata);
00922         }
00923     }
00924 }
00925 
00926 
00927 
00928 void
00929 ServerFree(TServer * const serverP) {
00930 
00931     struct _TServer * const srvP = serverP->srvP;
00932 
00933     if (srvP->weCreatedListenSocket)
00934         SocketDestroy(srvP->listenSocketP);
00935 
00936     xmlrpc_strfree(srvP->name);
00937 
00938     xmlrpc_strfree(srvP->filespath);
00939     
00940     ListFree(&srvP->defaultfilenames);
00941 
00942     terminateHandlers(&srvP->handlers);
00943 
00944     ListFree(&srvP->handlers);
00945 
00946     logClose(srvP);
00947 
00948     if (srvP->logfilename)
00949         xmlrpc_strfree(srvP->logfilename);
00950 
00951     free(srvP);
00952 }
00953 
00954 
00955 
00956 void
00957 ServerSetName(TServer *    const serverP,
00958               const char * const name) {
00959 
00960     xmlrpc_strfree(serverP->srvP->name);
00961     
00962     serverP->srvP->name = strdup(name);
00963 }
00964 
00965 
00966 
00967 void
00968 ServerSetFilesPath(TServer *    const serverP,
00969                    const char * const filesPath) {
00970 
00971     xmlrpc_strfree(serverP->srvP->filespath);
00972     
00973     serverP->srvP->filespath = strdup(filesPath);
00974 }
00975 
00976 
00977 
00978 void
00979 ServerSetLogFileName(TServer *    const serverP,
00980                      const char * const logFileName) {
00981     
00982     struct _TServer * const srvP = serverP->srvP;
00983 
00984     if (srvP->logfilename)
00985         xmlrpc_strfree(srvP->logfilename);
00986     
00987     srvP->logfilename = strdup(logFileName);
00988 }
00989 
00990 
00991 
00992 void
00993 ServerSetKeepaliveTimeout(TServer * const serverP,
00994                           uint32_t  const keepaliveTimeout) {
00995 
00996     serverP->srvP->keepalivetimeout = keepaliveTimeout;
00997 }
00998 
00999 
01000 
01001 void
01002 ServerSetKeepaliveMaxConn(TServer * const serverP,
01003                           uint32_t  const keepaliveMaxConn) {
01004 
01005     serverP->srvP->keepalivemaxconn = keepaliveMaxConn;
01006 }
01007 
01008 
01009 
01010 void
01011 ServerSetTimeout(TServer * const serverP,
01012                  uint32_t  const timeout) {
01013 
01014     serverP->srvP->timeout = timeout;
01015 }
01016 
01017 
01018 
01019 void
01020 ServerSetAdvertise(TServer *  const serverP,
01021                    abyss_bool const advertise) {
01022 
01023     serverP->srvP->advertise = advertise;
01024 }
01025 
01026 
01027 
01028 void
01029 ServerSetMimeType(TServer *  const serverP,
01030                   MIMEType * const MIMETypeP) {
01031 
01032     serverP->srvP->mimeTypeP = MIMETypeP;
01033 }
01034 
01035 
01036 
01037 static void
01038 runUserHandler(TSession *        const sessionP,
01039                struct _TServer * const srvP) {
01040 
01041     abyss_bool handled;
01042     int i;
01043     
01044     for (i = srvP->handlers.size-1, handled = FALSE;
01045          i >= 0 && !handled;
01046          --i) {
01047         URIHandler2 * const handlerP = srvP->handlers.item[i];
01048         
01049         if (handlerP->handleReq2)
01050             handlerP->handleReq2(handlerP, sessionP, &handled);
01051         else if (handlerP->handleReq1)
01052             handled = handlerP->handleReq1(sessionP);
01053     }
01054     
01055     if (!handled)
01056         ((URIHandler)(srvP->defaulthandler))(sessionP);
01057 }
01058 
01059 
01060 
01061 static void
01062 processDataFromClient(TConn *      const connectionP,
01063                       abyss_bool   const lastReqOnConn,
01064                       abyss_bool * const keepAliveP) {
01065 
01066     TSession session;
01067 
01068     RequestInit(&session, connectionP);
01069 
01070     session.serverDeniesKeepalive = lastReqOnConn;
01071         
01072     RequestRead(&session);
01073     if (session.status == 0) {
01074         if (session.version.major >= 2)
01075             ResponseStatus(&session, 505);
01076         else if (!RequestValidURI(&session))
01077             ResponseStatus(&session, 400);
01078         else
01079             runUserHandler(&session, connectionP->server->srvP);
01080     }
01081     assert(session.status != 0);
01082     
01083     if (session.responseStarted)
01084         HTTPWriteEndChunk(&session);
01085     else
01086         ResponseError(&session);
01087 
01088     *keepAliveP = HTTPKeepalive(&session);
01089     
01090     SessionLog(&session);
01091 
01092     RequestFree(&session);
01093 }
01094 
01095 
01096 static TThreadProc serverFunc;
01097 
01098 static void
01099 serverFunc(void * const userHandle) {
01100 /*----------------------------------------------------------------------------
01101    Do server stuff on one connection.  At its simplest, this means do
01102    one HTTP request.  But with keepalive, it can be many requests.
01103 -----------------------------------------------------------------------------*/
01104     TConn *           const connectionP = userHandle;
01105     struct _TServer * const srvP = connectionP->server->srvP;
01106 
01107     unsigned int requestCount;
01108         /* Number of requests we've handled so far on this connection */
01109     abyss_bool connectionDone;
01110         /* No more need for this HTTP connection */
01111 
01112     requestCount = 0;
01113     connectionDone = FALSE;
01114 
01115     while (!connectionDone) {
01116         abyss_bool success;
01117         
01118         /* Wait to read until timeout */
01119         success = ConnRead(connectionP, srvP->keepalivetimeout);
01120 
01121         if (!success)
01122             connectionDone = TRUE;
01123         else {
01124             abyss_bool const lastReqOnConn =
01125                 requestCount + 1 >= srvP->keepalivemaxconn;
01126 
01127             abyss_bool keepalive;
01128             
01129             processDataFromClient(connectionP, lastReqOnConn, &keepalive);
01130             
01131             ++requestCount;
01132 
01133             if (!keepalive)
01134                 connectionDone = TRUE;
01135             
01136             /**************** Must adjust the read buffer *****************/
01137             ConnReadInit(connectionP);
01138         }
01139     }
01140 }
01141 
01142 
01143 
01144 static void
01145 createAndBindSocket(struct _TServer * const srvP) {
01146 
01147     abyss_bool success;
01148 
01149     success = SocketInit();
01150     if (!success)
01151         TraceMsg("Can't initialize TCP sockets");
01152     else {
01153         TSocket * socketP;
01154         
01155         SocketUnixCreate(&socketP);
01156         
01157         if (!socketP)
01158             TraceMsg("Can't create a socket");
01159         else {
01160             abyss_bool success;
01161             
01162             success = SocketBind(socketP, NULL, srvP->port);
01163             
01164             if (!success)
01165                 TraceMsg("Failed to bind listening socket to port number %u",
01166                          srvP->port);
01167             else {
01168                 srvP->weCreatedListenSocket = TRUE;
01169                 srvP->socketBound = TRUE;
01170                 srvP->listenSocketP = socketP;
01171             }
01172             if (!success)
01173                 SocketDestroy(socketP);
01174         }
01175     }
01176 }
01177 
01178 
01179 
01180 void
01181 ServerInit(TServer * const serverP) {
01182 /*----------------------------------------------------------------------------
01183    Initialize a server to accept connections.
01184 
01185    Do not confuse this with creating the server -- ServerCreate().
01186 
01187    Not necessary or valid with a server that doesn't accept connections (i.e.
01188    user supplies the TCP connections).
01189 -----------------------------------------------------------------------------*/
01190     struct _TServer * const srvP = serverP->srvP;
01191     abyss_bool success;
01192     
01193     if (!srvP->serverAcceptsConnections) {
01194         TraceMsg("ServerInit() is not valid on a server that doesn't "
01195                  "accept connections "
01196                  "(i.e. created with ServerCreateNoAccept)");
01197         success = FALSE;
01198     } else {
01199         if (!srvP->socketBound)
01200             createAndBindSocket(srvP);
01201 
01202         if (srvP->socketBound) {
01203             success = SocketListen(srvP->listenSocketP, MAX_CONN);
01204 
01205             if (!success)
01206                 TraceMsg("Failed to listen on bound socket.");
01207         } else
01208             success = FALSE;
01209     }
01210     if (!success)
01211         exit(1);
01212 }
01213 
01214 
01215 
01216 /* We don't do any locking on the outstanding connections list, so 
01217    we must make sure that only the master thread (the one that listens
01218    for connections) ever accesses it.
01219 
01220    That's why when a thread completes, it places the connection in
01221    "finished" status, but doesn't destroy the connection.
01222 */
01223 
01224 typedef struct {
01225 
01226     TConn * firstP;
01227     unsigned int count;
01228         /* Redundant with 'firstP', for quick access */
01229 } outstandingConnList;
01230 
01231 
01232 
01233 static void
01234 createOutstandingConnList(outstandingConnList ** const listPP) {
01235 
01236     outstandingConnList * listP;
01237 
01238     MALLOCVAR_NOFAIL(listP);
01239 
01240     listP->firstP = NULL;  /* empty list */
01241     listP->count = 0;
01242 
01243     *listPP = listP;
01244 }
01245 
01246 
01247 
01248 static void
01249 destroyOutstandingConnList(outstandingConnList * const listP) {
01250 
01251     assert(listP->firstP == NULL);
01252     assert(listP->count == 0);
01253 
01254     free(listP);
01255 }
01256 
01257 
01258 
01259 static void
01260 addToOutstandingConnList(outstandingConnList * const listP,
01261                          TConn *               const connectionP) {
01262 
01263     connectionP->nextOutstandingP = listP->firstP;
01264 
01265     listP->firstP = connectionP;
01266 
01267     ++listP->count;
01268 }
01269 
01270 
01271 
01272 static void
01273 freeFinishedConns(outstandingConnList * const listP) {
01274 /*----------------------------------------------------------------------------
01275    Garbage-collect the resources associated with connections that are
01276    finished with their jobs.  Thread resources, connection pool
01277    descriptor, etc.
01278 -----------------------------------------------------------------------------*/
01279     TConn ** pp;
01280 
01281     pp = &listP->firstP;
01282 
01283     while (*pp) {
01284         TConn * const connectionP = (*pp);
01285 
01286         ThreadUpdateStatus(connectionP->threadP);
01287         
01288         if (connectionP->finished) {
01289             /* Take it out of the list */
01290             *pp = connectionP->nextOutstandingP;
01291             --listP->count;
01292             
01293             ConnWaitAndRelease(connectionP);
01294         } else {
01295             /* Move to next connection in list */
01296             pp = &connectionP->nextOutstandingP;
01297         }
01298     }
01299 }
01300 
01301 
01302 
01303 static void
01304 waitForConnectionFreed(outstandingConnList * const outstandingConnListP
01305                        ATTR_UNUSED) {
01306 /*----------------------------------------------------------------------------
01307   Wait for a connection descriptor in 'connectionPool' to be probably
01308   freed.
01309 -----------------------------------------------------------------------------*/
01310 
01311     /* TODO: We should do something more sophisticated here.  For pthreads,
01312        we can have a thread signal us by semaphore when it terminates.
01313        For fork, we might be able to use the "done" handler argument
01314        to ConnCreate() to get interrupted when the death of a child
01315        signal happens.
01316     */
01317 
01318     xmlrpc_millisecond_sleep(2000);
01319 }
01320 
01321 
01322 
01323 static void
01324 waitForNoConnections(outstandingConnList * const outstandingConnListP) {
01325 
01326     while (outstandingConnListP->firstP) {
01327         freeFinishedConns(outstandingConnListP);
01328     
01329         if (outstandingConnListP->firstP)
01330             waitForConnectionFreed(outstandingConnListP);
01331     }
01332 }
01333 
01334 
01335 
01336 static void
01337 waitForConnectionCapacity(outstandingConnList * const outstandingConnListP) {
01338 /*----------------------------------------------------------------------------
01339    Wait until there are fewer than the maximum allowed connections in
01340    progress.
01341 -----------------------------------------------------------------------------*/
01342     while (outstandingConnListP->count >= MAX_CONN) {
01343         freeFinishedConns(outstandingConnListP);
01344         if (outstandingConnListP->firstP)
01345             waitForConnectionFreed(outstandingConnListP);
01346     }
01347 }
01348 
01349 
01350 
01351 #ifndef WIN32
01352 void
01353 ServerHandleSigchld(pid_t const pid) {
01354 
01355     ThreadHandleSigchld(pid);
01356 }
01357 #endif
01358 
01359 
01360 
01361 void
01362 ServerUseSigchld(TServer * const serverP) {
01363 
01364     struct _TServer * const srvP = serverP->srvP;
01365     
01366     srvP->useSigchld = TRUE;
01367 }
01368 
01369 
01370 
01371 TThreadDoneFn destroySocket;
01372 
01373 static void
01374 destroyConnSocket(void * const userHandle) {
01375 /*----------------------------------------------------------------------------
01376    This is a "connection done" function for the connection the server
01377    serves.  It gets called some time after the connection has done its
01378    thing.  Its job is to clean up stuff the server created for use by
01379    the connection, but the server can't clean up because the
01380    connection might be processed asynchronously in a background
01381    thread.
01382 
01383    To wit, we destroy the connection's socket.
01384 -----------------------------------------------------------------------------*/
01385     TConn * const connectionP = userHandle;
01386 
01387     SocketDestroy(connectionP->socketP);
01388 }
01389 
01390 
01391 #include "../../dprint.h"
01392 static void 
01393 serverRun2(TServer * const serverP) {
01394 
01395     struct _TServer * const srvP = serverP->srvP;
01396     outstandingConnList * outstandingConnListP;
01397 
01398     createOutstandingConnList(&outstandingConnListP);
01399 
01400     while (!srvP->terminationRequested) {
01401         TConn * connectionP;
01402 
01403         abyss_bool connected;
01404         abyss_bool failed;
01405         TSocket * connectedSocketP;
01406         TIPAddr peerIpAddr;
01407 
01408         SocketAccept(srvP->listenSocketP,
01409                      &connected, &failed,
01410                      &connectedSocketP, &peerIpAddr);
01411         
01412         if (connected) {
01413             const char * error;
01414 
01415             freeFinishedConns(outstandingConnListP);
01416 
01417             waitForConnectionCapacity(outstandingConnListP);
01418 
01419             ConnCreate(&connectionP, serverP, connectedSocketP,
01420                        &serverFunc, &destroyConnSocket, ABYSS_BACKGROUND,
01421                        srvP->useSigchld,
01422                        &error);
01423             if (!error) {
01424                 addToOutstandingConnList(outstandingConnListP, connectionP);
01425                 ConnProcess(connectionP);
01426                 /* When connection is done (which could be later, courtesy
01427                    of a background thread), destroyConnSocket() will
01428                    destroy *connectedSocketP.
01429                 */
01430             } else {
01431                 xmlrpc_strfree(error);
01432                 SocketDestroy(connectedSocketP);
01433             }
01434         } else if (failed)
01435             TraceMsg("Socket Error=%d", SocketError(srvP->listenSocketP));
01436     }
01437     waitForNoConnections(outstandingConnListP);
01438 
01439     destroyOutstandingConnList(outstandingConnListP);
01440 }
01441 
01442 
01443 
01444 void 
01445 ServerRun(TServer * const serverP) {
01446 
01447     struct _TServer * const srvP = serverP->srvP;
01448 
01449     if (!srvP->socketBound)
01450         TraceMsg("This server is not set up to accept connections "
01451                  "on its own, so you can't use ServerRun().  "
01452                  "Try ServerRunConn() or ServerInit()");
01453     else
01454         serverRun2(serverP);
01455 }
01456 
01457 
01458 
01459 static void
01460 serverRunConn(TServer * const serverP,
01461               TSocket * const connectedSocketP) {
01462 /*----------------------------------------------------------------------------
01463    Do the HTTP transaction on the TCP connection on the socket
01464    'connectedSocketP'.
01465    (socket must be in connected state, with nothing having been read or
01466    written on the connection yet).
01467 -----------------------------------------------------------------------------*/
01468     struct _TServer * const srvP = serverP->srvP;
01469 
01470     TConn * connectionP;
01471     const char * error;
01472 
01473     srvP->keepalivemaxconn = 1;
01474 
01475     ConnCreate(&connectionP, 
01476                serverP, connectedSocketP,
01477                &serverFunc, NULL, ABYSS_FOREGROUND, srvP->useSigchld,
01478                &error);
01479     if (error) {
01480         TraceMsg("Couldn't create HTTP connection out of "
01481                  "connected socket.  %s", error);
01482         xmlrpc_strfree(error);
01483     } else {
01484         ConnProcess(connectionP);
01485 
01486         ConnWaitAndRelease(connectionP);
01487     }
01488 }
01489 
01490 
01491 
01492 void
01493 ServerRunConn2(TServer *     const serverP,
01494                TSocket *     const connectedSocketP,
01495                const char ** const errorP) {
01496 /*----------------------------------------------------------------------------
01497    Do the HTTP transaction on the TCP connection on the socket
01498    'connectedOsSocket'.
01499    (socket must be connected state, with nothing having been read or
01500    written on the connection yet).
01501 -----------------------------------------------------------------------------*/
01502     struct _TServer * const srvP = serverP->srvP;
01503 
01504     if (srvP->serverAcceptsConnections)
01505         xmlrpc_asprintf(errorP,
01506                         "This server is configured to accept connections on "
01507                         "its own socket.  "
01508                         "Try ServerRun() or ServerCreateNoAccept().");
01509     else {
01510         serverRunConn(serverP, connectedSocketP);
01511         *errorP = NULL;
01512     }
01513 }
01514 
01515 
01516 
01517 void
01518 ServerRunConn(TServer * const serverP,
01519               TOsSocket const connectedOsSocket) {
01520 
01521     TSocket * socketP;
01522     createSocketFromOsSocket(connectedOsSocket, &socketP);
01523     if (!socketP)
01524         TraceExit("Unable to use supplied socket");
01525     else {
01526         const char * error;
01527 
01528         ServerRunConn2(serverP, socketP, &error);
01529 
01530         if (error) {
01531             TraceExit("Failed to run server on connection on file "
01532                       "descriptor %d.  %s", connectedOsSocket, error);
01533             xmlrpc_strfree(error);
01534         }
01535         SocketDestroy(socketP);
01536     }
01537 }
01538 
01539 
01540 
01541 void
01542 ServerRunOnce(TServer * const serverP) {
01543 /*----------------------------------------------------------------------------
01544    Accept a connection from the listening socket and do the HTTP
01545    transaction that comes over it.
01546 
01547    If no connection is presently waiting on the listening socket, wait
01548    for one.  But return immediately if we receive a signal during the
01549    wait.
01550 -----------------------------------------------------------------------------*/
01551     struct _TServer * const srvP = serverP->srvP;
01552 
01553     if (!srvP->socketBound)
01554         TraceMsg("This server is not set up to accept connections "
01555                  "on its own, so you can't use ServerRunOnce().  "
01556                  "Try ServerRunConn() or ServerInit()");
01557     else {
01558         abyss_bool connected;
01559         abyss_bool failed;
01560         TSocket *  connectedSocketP;
01561         TIPAddr    remoteAddr;
01562     
01563         srvP->keepalivemaxconn = 1;
01564 
01565         SocketAccept(srvP->listenSocketP,
01566                      &connected, &failed,
01567                      &connectedSocketP, &remoteAddr);
01568         if (connected) {
01569             serverRunConn(serverP, connectedSocketP);
01570             SocketDestroy(connectedSocketP);
01571         } else if (failed)
01572             TraceMsg("Socket Error=%d", SocketError(srvP->listenSocketP));
01573     }
01574 }
01575 
01576 
01577 
01578 void
01579 ServerRunOnce2(TServer *           const serverP,
01580                enum abyss_foreback const foregroundBackground ATTR_UNUSED) {
01581 /*----------------------------------------------------------------------------
01582    This is a backward compatibility interface to ServerRunOnce().
01583 
01584    'foregroundBackground' is meaningless.  We always process the
01585    connection in the foreground.  The parameter exists because we once
01586    thought we could do them in the background, but we really can't do
01587    that in any clean way.  If Caller wants background execution, he can
01588    spin his own thread or process to call us.  It makes much more sense
01589    in Caller's context.
01590 -----------------------------------------------------------------------------*/
01591     ServerRunOnce(serverP);
01592 }
01593 
01594 
01595 
01596 static void
01597 setGroups(void) {
01598 
01599 #ifdef HAVE_SETGROUPS   
01600     if (setgroups(0, NULL) == (-1))
01601         TraceExit("Failed to setup the group.");
01602 #endif
01603 }
01604 
01605 
01606 
01607 void
01608 ServerDaemonize(TServer * const serverP) {
01609 /*----------------------------------------------------------------------------
01610    Turn Caller into a daemon (i.e. fork a child, then exit; the child
01611    returns to Caller).
01612 
01613    NOTE: It's ridiculous, but conventional, for us to do this.  It's
01614    ridiculous because the task of daemonizing is not something
01615    particular to Abyss.  It ought to be done by a higher level.  In
01616    fact, it should be done before the Abyss server program is even
01617    execed.  The user should run a "daemonize" program that creates a
01618    daemon which execs the Abyss server program.
01619 -----------------------------------------------------------------------------*/
01620     struct _TServer * const srvP = serverP->srvP;
01621 
01622 #ifndef _WIN32
01623     /* Become a daemon */
01624     switch (fork()) {
01625     case 0:
01626         break;
01627     case -1:
01628         TraceExit("Unable to become a daemon");
01629     default:
01630         /* We are the parent */
01631         exit(0);
01632     }
01633     
01634     setsid();
01635 
01636     /* Change the current user if we are root */
01637     if (getuid()==0) {
01638         if (srvP->uid == (uid_t)-1)
01639             TraceExit("Can't run under root privileges.  "
01640                       "Please add a User option in your "
01641                       "Abyss configuration file.");
01642 
01643         setGroups();
01644 
01645         if (srvP->gid != (gid_t)-1)
01646             if (setgid(srvP->gid)==(-1))
01647                 TraceExit("Failed to change the group.");
01648         
01649         if (setuid(srvP->uid) == -1)
01650             TraceExit("Failed to change the user.");
01651     }
01652     
01653     if (srvP->pidfile != -1) {
01654         char z[16];
01655     
01656         sprintf(z, "%d", getpid());
01657         FileWrite(&srvP->pidfile, z, strlen(z));
01658         FileClose(&srvP->pidfile);
01659     }
01660 #endif  /* _WIN32 */
01661 }
01662 
01663 
01664 
01665 void
01666 ServerAddHandler2(TServer *     const serverP,
01667                   URIHandler2 * const handlerArgP,
01668                   abyss_bool *  const successP) {
01669 
01670     URIHandler2 * handlerP;
01671 
01672     MALLOCVAR(handlerP);
01673     if (handlerP == NULL)
01674         *successP = FALSE;
01675     else {
01676         *handlerP = *handlerArgP;
01677 
01678         if (handlerP->init == NULL)
01679             *successP = TRUE;
01680         else
01681             handlerP->init(handlerP, successP);
01682 
01683         if (*successP)
01684             *successP = ListAdd(&serverP->srvP->handlers, handlerP);
01685 
01686         if (!*successP)
01687             free(handlerP);
01688     }
01689 }
01690 
01691 
01692 
01693 static URIHandler2 *
01694 createHandler(URIHandler const function) {
01695 
01696     URIHandler2 * handlerP;
01697 
01698     MALLOCVAR(handlerP);
01699     if (handlerP != NULL) {
01700         handlerP->init       = NULL;
01701         handlerP->term       = NULL;
01702         handlerP->userdata   = NULL;
01703         handlerP->handleReq2 = NULL;
01704         handlerP->handleReq1 = function;
01705     }
01706     return handlerP;
01707 }
01708 
01709 
01710 
01711 abyss_bool
01712 ServerAddHandler(TServer *  const serverP,
01713                  URIHandler const function) {
01714 
01715     URIHandler2 * handlerP;
01716     abyss_bool success;
01717 
01718     handlerP = createHandler(function);
01719 
01720     if (handlerP == NULL)
01721         success = FALSE;
01722     else {
01723         success = ListAdd(&serverP->srvP->handlers, handlerP);
01724 
01725         if (!success)
01726             free(handlerP);
01727     }
01728     return success;
01729 }
01730 
01731 
01732 
01733 void
01734 ServerDefaultHandler(TServer *  const serverP,
01735                      URIHandler const handler) {
01736 
01737     serverP->srvP->defaulthandler =
01738         handler ? handler : ServerDefaultHandlerFunc;
01739 }
01740 
01741 
01742 
01743 void
01744 LogWrite(TServer *    const serverP,
01745          const char * const msg) {
01746 
01747     struct _TServer * const srvP = serverP->srvP;
01748 
01749     if (!srvP->logfileisopen && srvP->logfilename)
01750         logOpen(srvP);
01751 
01752     if (srvP->logfileisopen) {
01753         abyss_bool success;
01754         success = MutexLock(&srvP->logmutex);
01755         if (success) {
01756             const char * const lbr = "\n";
01757             FileWrite(&srvP->logfile, msg, strlen(msg));
01758             FileWrite(&srvP->logfile, lbr, strlen(lbr));
01759         
01760             MutexUnlock(&srvP->logmutex);
01761         }
01762     }
01763 }
01764 /*******************************************************************************
01765 **
01766 ** server.c
01767 **
01768 ** This file is part of the ABYSS Web server project.
01769 **
01770 ** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
01771 ** All rights reserved.
01772 **
01773 ** Redistribution and use in source and binary forms, with or without
01774 ** modification, are permitted provided that the following conditions
01775 ** are met:
01776 ** 1. Redistributions of source code must retain the above copyright
01777 **    notice, this list of conditions and the following disclaimer.
01778 ** 2. Redistributions in binary form must reproduce the above copyright
01779 **    notice, this list of conditions and the following disclaimer in the
01780 **    documentation and/or other materials provided with the distribution.
01781 ** 3. The name of the author may not be used to endorse or promote products
01782 **    derived from this software without specific prior written permission.
01783 ** 
01784 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
01785 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
01786 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
01787 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
01788 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
01789 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
01790 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
01791 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
01792 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
01793 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
01794 ** SUCH DAMAGE.
01795 **
01796 ******************************************************************************/

Generated on Thu May 17 10:00:23 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6