00001
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
00138
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
00209 qsort(listP->item, listP->size, sizeof(void *),
00210 (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates));
00211
00212
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
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;
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
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
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
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
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
00596
00597 if (!FileStat(z, &fs)) {
00598 ResponseStatusErrno(sessionP);
00599 return TRUE;
00600 }
00601
00602 if (fs.st_mode & S_IFDIR) {
00603
00604
00605
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
00775
00776
00777
00778
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
00913
00914
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
01102
01103
01104 TConn * const connectionP = userHandle;
01105 struct _TServer * const srvP = connectionP->server->srvP;
01106
01107 unsigned int requestCount;
01108
01109 abyss_bool connectionDone;
01110
01111
01112 requestCount = 0;
01113 connectionDone = FALSE;
01114
01115 while (!connectionDone) {
01116 abyss_bool success;
01117
01118
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
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
01184
01185
01186
01187
01188
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
01217
01218
01219
01220
01221
01222
01223
01224 typedef struct {
01225
01226 TConn * firstP;
01227 unsigned int count;
01228
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;
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
01276
01277
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
01290 *pp = connectionP->nextOutstandingP;
01291 --listP->count;
01292
01293 ConnWaitAndRelease(connectionP);
01294 } else {
01295
01296 pp = &connectionP->nextOutstandingP;
01297 }
01298 }
01299 }
01300
01301
01302
01303 static void
01304 waitForConnectionFreed(outstandingConnList * const outstandingConnListP
01305 ATTR_UNUSED) {
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
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
01340
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
01377
01378
01379
01380
01381
01382
01383
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
01427
01428
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
01464
01465
01466
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
01498
01499
01500
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
01545
01546
01547
01548
01549
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
01583
01584
01585
01586
01587
01588
01589
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
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620 struct _TServer * const srvP = serverP->srvP;
01621
01622 #ifndef _WIN32
01623
01624 switch (fork()) {
01625 case 0:
01626 break;
01627 case -1:
01628 TraceExit("Unable to become a daemon");
01629 default:
01630
01631 exit(0);
01632 }
01633
01634 setsid();
01635
01636
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
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
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796