sws.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id: sws.c,v 1.44 2004/03/09 08:38:25 bagder Exp $
  22. ***************************************************************************/
  23. /* sws.c: simple (silly?) web server
  24. This code was originally graciously donated to the project by Juergen
  25. Wilke. Thanks a bunch!
  26. */
  27. #include "setup.h" /* portability help from the lib directory */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <stdarg.h>
  32. #include <unistd.h>
  33. #include <signal.h>
  34. #include <time.h>
  35. #include <sys/time.h>
  36. #include <sys/types.h>
  37. #ifdef HAVE_SYS_SOCKET_H
  38. #include <sys/socket.h>
  39. #endif
  40. #ifdef HAVE_NETINET_IN_H
  41. #include <netinet/in.h>
  42. #endif
  43. #ifdef _XOPEN_SOURCE_EXTENDED
  44. /* This define is "almost" required to build on HPUX 11 */
  45. #include <arpa/inet.h>
  46. #endif
  47. #ifdef HAVE_NETDB_H
  48. #include <netdb.h>
  49. #endif
  50. #include "getpart.h"
  51. #ifndef FALSE
  52. #define FALSE 0
  53. #endif
  54. #ifndef TRUE
  55. #define TRUE 1
  56. #endif
  57. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  58. #include <windows.h>
  59. #include <winsock2.h>
  60. #define EINPROGRESS WSAEINPROGRESS
  61. #define EWOULDBLOCK WSAEWOULDBLOCK
  62. #define EISCONN WSAEISCONN
  63. #define ENOTSOCK WSAENOTSOCK
  64. #define ECONNREFUSED WSAECONNREFUSED
  65. #endif
  66. #define REQBUFSIZ 150000
  67. #define REQBUFSIZ_TXT "149999"
  68. struct httprequest {
  69. char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */
  70. int offset; /* size of the incoming request */
  71. int testno; /* test number found in the request */
  72. int partno; /* part number found in the request */
  73. int open; /* keep connection open info, as found in the request */
  74. bool auth_req; /* authentication required, don't wait for body unless
  75. there's an Authorization header */
  76. bool auth; /* Authorization header present in the incoming request */
  77. size_t cl; /* Content-Length of the incoming request */
  78. bool digest; /* Authorization digest header found */
  79. bool ntlm; /* Authorization ntlm header found */
  80. };
  81. int ProcessRequest(struct httprequest *req);
  82. void storerequest(char *reqbuf);
  83. #define DEFAULT_PORT 8999
  84. #ifndef DEFAULT_LOGFILE
  85. #define DEFAULT_LOGFILE "log/sws.log"
  86. #endif
  87. #define SWSVERSION "cURL test suite HTTP server/0.1"
  88. #define REQUEST_DUMP "log/server.input"
  89. #define RESPONSE_DUMP "log/server.response"
  90. #define TEST_DATA_PATH "%s/data/test%d"
  91. /* very-big-path support */
  92. #define MAXDOCNAMELEN 140000
  93. #define MAXDOCNAMELEN_TXT "139999"
  94. #define REQUEST_KEYWORD_SIZE 256
  95. #define CMD_AUTH_REQUIRED "auth_required"
  96. /* global variable, where to find the 'data' dir */
  97. const char *path=".";
  98. enum {
  99. DOCNUMBER_NOTHING = -7,
  100. DOCNUMBER_QUIT = -6,
  101. DOCNUMBER_BADCONNECT = -5,
  102. DOCNUMBER_INTERNAL= -4,
  103. DOCNUMBER_CONNECT = -3,
  104. DOCNUMBER_WERULEZ = -2,
  105. DOCNUMBER_404 = -1
  106. };
  107. /* sent as reply to a QUIT */
  108. static const char *docquit =
  109. "HTTP/1.1 200 Goodbye\r\n"
  110. "\r\n";
  111. /* sent as reply to a CONNECT */
  112. static const char *docconnect =
  113. "HTTP/1.1 200 Mighty fine indeed\r\n"
  114. "\r\n";
  115. /* sent as reply to a "bad" CONNECT */
  116. static const char *docbadconnect =
  117. "HTTP/1.1 501 Forbidden you fool\r\n"
  118. "\r\n";
  119. /* send back this on 404 file not found */
  120. static const char *doc404 = "HTTP/1.1 404 Not Found\n"
  121. "Server: " SWSVERSION "\n"
  122. "Connection: close\n"
  123. "Content-Type: text/html\n"
  124. "\n"
  125. "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
  126. "<HTML><HEAD>\n"
  127. "<TITLE>404 Not Found</TITLE>\n"
  128. "</HEAD><BODY>\n"
  129. "<H1>Not Found</H1>\n"
  130. "The requested URL was not found on this server.\n"
  131. "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
  132. #ifdef SIGPIPE
  133. static volatile int sigpipe;
  134. #endif
  135. static FILE *logfp;
  136. static void logmsg(const char *msg, ...)
  137. {
  138. time_t t = time(NULL);
  139. va_list ap;
  140. struct tm *curr_time = localtime(&t);
  141. char buffer[256]; /* possible overflow if you pass in a huge string */
  142. va_start(ap, msg);
  143. vsprintf(buffer, msg, ap);
  144. va_end(ap);
  145. fprintf(logfp, "%02d:%02d:%02d (%d) %s\n",
  146. curr_time->tm_hour,
  147. curr_time->tm_min,
  148. curr_time->tm_sec, (int)getpid(), buffer);
  149. fflush(logfp);
  150. }
  151. #ifdef SIGPIPE
  152. static void sigpipe_handler(int sig)
  153. {
  154. (void)sig; /* prevent warning */
  155. sigpipe = 1;
  156. }
  157. #endif
  158. #define END_OF_HEADERS "\r\n\r\n"
  159. static char *test2file(int testno)
  160. {
  161. static char filename[256];
  162. sprintf(filename, TEST_DATA_PATH, path, testno);
  163. return filename;
  164. }
  165. int ProcessRequest(struct httprequest *req)
  166. {
  167. char *line=req->reqbuf;
  168. char chunked=FALSE;
  169. static char request[REQUEST_KEYWORD_SIZE];
  170. static char doc[MAXDOCNAMELEN];
  171. char logbuf[256];
  172. int prot_major, prot_minor;
  173. char *end;
  174. end = strstr(req->reqbuf, END_OF_HEADERS);
  175. /* try to figure out the request characteristics as soon as possible, but
  176. only once! */
  177. if((req->testno == DOCNUMBER_NOTHING) &&
  178. sscanf(line, "%" REQBUFSIZ_TXT"s %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
  179. request,
  180. doc,
  181. &prot_major,
  182. &prot_minor) == 4) {
  183. char *ptr;
  184. /* find the last slash */
  185. ptr = strrchr(doc, '/');
  186. /* get the number after it */
  187. if(ptr) {
  188. FILE *stream;
  189. char *filename;
  190. char *cmd = NULL;
  191. int cmdsize = 0;
  192. if((strlen(doc) + strlen(request)) < 200)
  193. sprintf(logbuf, "Got request: %s %s HTTP/%d.%d",
  194. request, doc, prot_major, prot_minor);
  195. else
  196. sprintf(logbuf, "Got a *HUGE* request HTTP/%d.%d",
  197. prot_major, prot_minor);
  198. logmsg(logbuf);
  199. if(!strncmp("/verifiedserver", ptr, 15)) {
  200. logmsg("Are-we-friendly question received");
  201. req->testno = DOCNUMBER_WERULEZ;
  202. return 1; /* done */
  203. }
  204. if(!strncmp("/quit", ptr, 15)) {
  205. logmsg("Request-to-quit received");
  206. req->testno = DOCNUMBER_QUIT;
  207. return 1; /* done */
  208. }
  209. ptr++; /* skip the slash */
  210. req->testno = strtol(ptr, &ptr, 10);
  211. if(req->testno > 10000) {
  212. req->partno = req->testno % 10000;
  213. req->testno /= 10000;
  214. }
  215. else
  216. req->partno = 0;
  217. sprintf(logbuf, "Reqested test number %d part %d",
  218. req->testno, req->partno);
  219. logmsg(logbuf);
  220. filename = test2file(req->testno);
  221. stream=fopen(filename, "rb");
  222. if(!stream) {
  223. logmsg("Couldn't open test file %d", req->testno);
  224. return 0;
  225. }
  226. else {
  227. /* get the custom server control "commands" */
  228. cmd = (char *)spitout(stream, "reply", "servercmd", &cmdsize);
  229. fclose(stream);
  230. if(cmdsize) {
  231. logmsg("Found a reply-servercmd section!");
  232. if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) {
  233. logmsg("instructed to require authorization header");
  234. req->auth_req = TRUE;
  235. }
  236. }
  237. }
  238. }
  239. else {
  240. if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
  241. doc, &prot_major, &prot_minor) == 3) {
  242. sprintf(logbuf, "Receiced a CONNECT %s HTTP/%d.%d request",
  243. doc, prot_major, prot_minor);
  244. logmsg(logbuf);
  245. if(prot_major*10+prot_minor == 10)
  246. req->open = FALSE; /* HTTP 1.0 closes connection by default */
  247. if(!strncmp(doc, "bad", 3))
  248. /* if the host name starts with bad, we fake an error here */
  249. req->testno = DOCNUMBER_BADCONNECT;
  250. else if(!strncmp(doc, "test", 4)) {
  251. char *ptr = strchr(doc, ':');
  252. if(ptr)
  253. req->testno = atoi(ptr+1);
  254. else
  255. req->testno = DOCNUMBER_CONNECT;
  256. }
  257. else
  258. req->testno = DOCNUMBER_CONNECT;
  259. }
  260. else {
  261. logmsg("Did not find test number in PATH");
  262. req->testno = DOCNUMBER_404;
  263. }
  264. }
  265. }
  266. if(!end)
  267. /* we don't have a complete request yet! */
  268. return 0;
  269. /* **** Persistancy ****
  270. *
  271. * If the request is a HTTP/1.0 one, we close the connection unconditionally
  272. * when we're done.
  273. *
  274. * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
  275. * header that might say "close". If it does, we close a connection when
  276. * this request is processed. Otherwise, we keep the connection alive for X
  277. * seconds.
  278. */
  279. do {
  280. if(!req->cl && !strncasecmp("Content-Length:", line, 15)) {
  281. /* If we don't ignore content-length, we read it and we read the whole
  282. request including the body before we return. If we've been told to
  283. ignore the content-length, we will return as soon as all headers
  284. have been received */
  285. req->cl = strtol(line+15, &line, 10);
  286. logmsg("Found Content-Legth: %d in the request", req->cl);
  287. break;
  288. }
  289. else if(!strncasecmp("Transfer-Encoding: chunked", line,
  290. strlen("Transfer-Encoding: chunked"))) {
  291. /* chunked data coming in */
  292. chunked = TRUE;
  293. }
  294. if(chunked) {
  295. if(strstr(req->reqbuf, "\r\n0\r\n"))
  296. /* end of chunks reached */
  297. return 1; /* done */
  298. else
  299. return 0; /* not done */
  300. }
  301. line = strchr(line, '\n');
  302. if(line)
  303. line++;
  304. } while(line);
  305. if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
  306. req->auth = TRUE; /* Authorization: header present! */
  307. if(req->auth_req)
  308. logmsg("Authorization header found, as required");
  309. }
  310. if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
  311. /* If the client is passing this Digest-header, we set the part number
  312. to 1000. Not only to spice up the complexity of this, but to make
  313. Digest stuff to work in the test suite. */
  314. req->partno += 1000;
  315. req->digest = TRUE; /* header found */
  316. logmsg("Received Digest request, sending back data %d", req->partno);
  317. }
  318. else if(!req->ntlm &&
  319. strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
  320. /* If the client is passing this type-3 NTLM header */
  321. req->partno += 1002;
  322. req->ntlm = TRUE; /* NTLM found */
  323. logmsg("Received NTLM type-3, sending back data %d", req->partno);
  324. }
  325. else if(!req->ntlm &&
  326. strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
  327. /* If the client is passing this type-1 NTLM header */
  328. req->partno += 1001;
  329. req->ntlm = TRUE; /* NTLM found */
  330. logmsg("Received NTLM type-1, sending back data %d", req->partno);
  331. }
  332. if(strstr(req->reqbuf, "Connection: close"))
  333. req->open = FALSE; /* close connection after this request */
  334. if(req->cl && (req->auth || !req->auth_req)) {
  335. if(req->cl <= strlen(end+strlen(END_OF_HEADERS)))
  336. return 1; /* done */
  337. else
  338. return 0; /* not complete yet */
  339. }
  340. return 1; /* done */
  341. }
  342. /* store the entire request in a file */
  343. void storerequest(char *reqbuf)
  344. {
  345. FILE *dump;
  346. dump = fopen(REQUEST_DUMP, "ab"); /* b is for windows-preparing */
  347. if(dump) {
  348. fwrite(reqbuf, 1, strlen(reqbuf), dump);
  349. fclose(dump);
  350. logmsg("Wrote request input to " REQUEST_DUMP);
  351. }
  352. else {
  353. logmsg("Failed to write request input to " REQUEST_DUMP);
  354. }
  355. }
  356. /* return 0 on success, non-zero on failure */
  357. static int get_request(int sock, struct httprequest *req)
  358. {
  359. int fail= FALSE;
  360. char *reqbuf = req->reqbuf;
  361. /*** Init the httpreqest structure properly for the upcoming request ***/
  362. memset(req, 0, sizeof(struct httprequest));
  363. /* here's what should not be 0 from the start */
  364. req->testno = DOCNUMBER_NOTHING; /* safe default */
  365. req->open = TRUE; /* connection should remain open and wait for more
  366. commands */
  367. /*** end of httprequest init ***/
  368. while (req->offset < REQBUFSIZ) {
  369. int got = sread(sock, reqbuf + req->offset, REQBUFSIZ - req->offset);
  370. if (got <= 0) {
  371. if (got < 0) {
  372. perror("recv");
  373. logmsg("recv() returned error");
  374. return DOCNUMBER_INTERNAL;
  375. }
  376. logmsg("Connection closed by client");
  377. return DOCNUMBER_INTERNAL;
  378. }
  379. req->offset += got;
  380. reqbuf[req->offset] = 0;
  381. if(ProcessRequest(req))
  382. break;
  383. }
  384. if (req->offset >= REQBUFSIZ) {
  385. logmsg("Request buffer overflow, closing connection");
  386. reqbuf[REQBUFSIZ-1]=0;
  387. fail = TRUE;
  388. /* dump the request to an external file anyway */
  389. }
  390. else
  391. reqbuf[req->offset]=0;
  392. /* dump the request to an external file */
  393. storerequest(reqbuf);
  394. return fail; /* success */
  395. }
  396. /* returns -1 on failure */
  397. static int send_doc(int sock, struct httprequest *req)
  398. {
  399. int written;
  400. int count;
  401. const char *buffer;
  402. char *ptr;
  403. FILE *stream;
  404. char *cmd=NULL;
  405. int cmdsize=0;
  406. FILE *dump;
  407. int persistant = TRUE;
  408. static char weare[256];
  409. char partbuf[80]="data";
  410. req->open = FALSE;
  411. logmsg("Send response number %d part %d", req->testno, req->partno);
  412. if(req->testno < 0) {
  413. switch(req->testno) {
  414. case DOCNUMBER_QUIT:
  415. logmsg("Replying to QUIT");
  416. buffer = docquit;
  417. break;
  418. case DOCNUMBER_WERULEZ:
  419. /* we got a "friends?" question, reply back that we sure are */
  420. logmsg("Identifying ourselves as friends");
  421. sprintf(weare, "HTTP/1.1 200 OK\r\n\r\nWE ROOLZ: %d\r\n",
  422. (int)getpid());
  423. buffer = weare;
  424. break;
  425. case DOCNUMBER_INTERNAL:
  426. logmsg("Bailing out due to internal error");
  427. return -1;
  428. case DOCNUMBER_CONNECT:
  429. logmsg("Replying to CONNECT");
  430. buffer = docconnect;
  431. break;
  432. case DOCNUMBER_BADCONNECT:
  433. logmsg("Replying to a bad CONNECT");
  434. buffer = docbadconnect;
  435. break;
  436. case DOCNUMBER_404:
  437. default:
  438. logmsg("Replying to with a 404");
  439. buffer = doc404;
  440. break;
  441. }
  442. ptr = NULL;
  443. stream=NULL;
  444. count = strlen(buffer);
  445. }
  446. else {
  447. char *filename = test2file(req->testno);
  448. if(0 != req->partno)
  449. sprintf(partbuf, "data%d", req->partno);
  450. stream=fopen(filename, "rb");
  451. if(!stream) {
  452. logmsg("Couldn't open test file");
  453. return 0;
  454. }
  455. else {
  456. buffer = spitout(stream, "reply", partbuf, &count);
  457. ptr = (char *)buffer;
  458. fclose(stream);
  459. }
  460. /* re-open the same file again */
  461. stream=fopen(filename, "rb");
  462. if(!stream) {
  463. logmsg("Couldn't open test file");
  464. return 0;
  465. }
  466. else {
  467. /* get the custom server control "commands" */
  468. cmd = (char *)spitout(stream, "reply", "postcmd", &cmdsize);
  469. fclose(stream);
  470. }
  471. }
  472. dump = fopen(RESPONSE_DUMP, "ab"); /* b is for windows-preparing */
  473. if(!dump) {
  474. logmsg("couldn't create logfile: " RESPONSE_DUMP);
  475. return -1;
  476. }
  477. /* If the word 'swsclose' is present anywhere in the reply chunk, the
  478. connection will be closed after the data has been sent to the requesting
  479. client... */
  480. if(strstr(buffer, "swsclose") || !count) {
  481. persistant = FALSE;
  482. logmsg("connection close instruction swsclose found in response");
  483. }
  484. do {
  485. written = swrite(sock, buffer, count);
  486. if (written < 0) {
  487. logmsg("Sending response failed and we bailed out!");
  488. return -1;
  489. }
  490. /* write to file as well */
  491. fwrite(buffer, 1, written, dump);
  492. count -= written;
  493. buffer += written;
  494. } while(count>0);
  495. fclose(dump);
  496. logmsg("Response sent!");
  497. if(ptr)
  498. free(ptr);
  499. if(cmdsize > 0 ) {
  500. char command[32];
  501. int num;
  502. char *ptr=cmd;
  503. do {
  504. if(2 == sscanf(ptr, "%31s %d", command, &num)) {
  505. if(!strcmp("wait", command))
  506. sleep(num); /* wait this many seconds */
  507. else
  508. logmsg("Unknown command in reply command section");
  509. }
  510. ptr = strchr(ptr, '\n');
  511. if(ptr)
  512. ptr++;
  513. else
  514. ptr = NULL;
  515. } while(ptr && *ptr);
  516. }
  517. if(cmd)
  518. free(cmd);
  519. req->open = persistant;
  520. return 0;
  521. }
  522. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  523. static void win32_init(void)
  524. {
  525. WORD wVersionRequested;
  526. WSADATA wsaData;
  527. int err;
  528. wVersionRequested = MAKEWORD(2, 0);
  529. err = WSAStartup(wVersionRequested, &wsaData);
  530. if (err != 0) {
  531. perror("Winsock init failed");
  532. fprintf(logfp, "Error initializing winsock -- aborting\n");
  533. fclose(logfp);
  534. exit(1);
  535. }
  536. if ( LOBYTE( wsaData.wVersion ) != 2 ||
  537. HIBYTE( wsaData.wVersion ) != 0 ) {
  538. WSACleanup();
  539. perror("Winsock init failed");
  540. fprintf(logfp, "No suitable winsock.dll found -- aborting\n");
  541. fclose(logfp);
  542. exit(1);
  543. }
  544. }
  545. static void win32_cleanup(void)
  546. {
  547. WSACleanup();
  548. }
  549. #endif
  550. int main(int argc, char *argv[])
  551. {
  552. struct sockaddr_in me;
  553. int sock, msgsock, flag;
  554. unsigned short port = DEFAULT_PORT;
  555. const char *logfile = DEFAULT_LOGFILE;
  556. FILE *pidfile;
  557. struct httprequest req;
  558. if(argc>1) {
  559. port = atoi(argv[1]);
  560. if(argc>2) {
  561. path = argv[2];
  562. }
  563. }
  564. logfp = fopen(logfile, "a");
  565. if (!logfp) {
  566. perror(logfile);
  567. exit(1);
  568. }
  569. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  570. win32_init();
  571. #endif
  572. #ifdef SIGPIPE
  573. #ifdef HAVE_SIGNAL
  574. signal(SIGPIPE, sigpipe_handler);
  575. #endif
  576. #ifdef HAVE_SIGINTERRUPT
  577. siginterrupt(SIGPIPE, 1);
  578. #endif
  579. #endif
  580. sock = socket(AF_INET, SOCK_STREAM, 0);
  581. if (sock < 0) {
  582. perror("opening stream socket");
  583. fprintf(logfp, "Error opening socket -- aborting\n");
  584. fclose(logfp);
  585. exit(1);
  586. }
  587. flag = 1;
  588. if (setsockopt
  589. (sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag,
  590. sizeof(int)) < 0) {
  591. perror("setsockopt(SO_REUSEADDR)");
  592. }
  593. me.sin_family = AF_INET;
  594. me.sin_addr.s_addr = INADDR_ANY;
  595. me.sin_port = htons(port);
  596. if (bind(sock, (struct sockaddr *) &me, sizeof me) < 0) {
  597. perror("binding stream socket");
  598. fprintf(logfp, "Error binding socket -- aborting\n");
  599. fclose(logfp);
  600. exit(1);
  601. }
  602. pidfile = fopen(".http.pid", "w");
  603. if(pidfile) {
  604. fprintf(pidfile, "%d\n", (int)getpid());
  605. fclose(pidfile);
  606. }
  607. else
  608. fprintf(stderr, "Couldn't write pid file\n");
  609. /* start accepting connections */
  610. listen(sock, 5);
  611. while (1) {
  612. msgsock = accept(sock, NULL, NULL);
  613. if (msgsock == -1)
  614. continue;
  615. logmsg("** New client connected");
  616. do {
  617. if(get_request(msgsock, &req))
  618. /* non-zero means error, break out of loop */
  619. break;
  620. send_doc(msgsock, &req);
  621. if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) {
  622. logmsg("special request received, no persistancy");
  623. break;
  624. }
  625. if(!req.open) {
  626. logmsg("instructed to close connection after server-reply");
  627. break;
  628. }
  629. if(req.open)
  630. logmsg("persistant connection, awaits new request");
  631. /* if we got a CONNECT, loop and get another request as well! */
  632. } while(req.open || (req.testno == DOCNUMBER_CONNECT));
  633. logmsg("** Closing client connection");
  634. sclose(msgsock);
  635. if (req.testno == DOCNUMBER_QUIT)
  636. break;
  637. }
  638. sclose(sock);
  639. fclose(logfp);
  640. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  641. win32_cleanup();
  642. #endif
  643. return 0;
  644. }