source: benchmark/io/http/protocol.cfa@ baad96e

Last change on this file since baad96e was 17c6edeb, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

  • Property mode set to 100644
File size: 19.1 KB
RevLine 
[0aec496]1#include "protocol.hfa"
2
[c82af9f]3#define _GNU_SOURCE
4extern "C" {
5 #include <fcntl.h>
6}
[8c43d05]7
[857a1c6]8#define xstr(s) str(s)
9#define str(s) #s
10
[8c43d05]11#include <fstream.hfa>
[0aec496]12#include <iofwd.hfa>
[3f39009]13#include <io/types.hfa>
14#include <mutex_stmt.hfa>
[0aec496]15
16#include <assert.h>
17// #include <stdio.h> // Don't use stdio.h, too slow to compile
18extern "C" {
19 int snprintf ( char * s, size_t n, const char * format, ... );
[32d1383]20 ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
[8c43d05]21 // #include <linux/io_uring.h>
[0aec496]22}
23#include <string.h>
24#include <errno.h>
25
[d11d6eb]26#include "options.hfa"
[ef3c383]27#include "worker.hfa"
[0aec496]28
[ed2cb3c]29#define PLAINTEXT_1WRITE
[857a1c6]30#define PLAINTEXT_MEMCPY
[ed2cb3c]31#define PLAINTEXT_NOCOPY
[3f95dab]32// #define LINKED_IO
[32d1383]33#define TRUE_SENDFILE
[ed2cb3c]34
[7f0ac12]35static inline __s32 wait_res( io_future_t & this ) {
36 wait( this );
37 if( this.result < 0 ) {{
38 errno = -this.result;
39 return -1;
40 }}
41 return this.result;
42}
43
[2caed18]44struct https_msg_str {
45 char msg[512];
46 size_t len;
[0aec496]47};
48
[2caed18]49const https_msg_str * volatile http_msgs[KNOWN_CODES] = { 0 };
50
[2ecbd7b]51_Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0])));
52
[2caed18]53const int http_codes[KNOWN_CODES] = {
[ed2cb3c]54 200,
[2ecbd7b]55 200,
56 400,
57 404,
[b57db73]58 405,
[ee59ede]59 408,
[2ecbd7b]60 413,
61 414,
62};
63
64_Static_assert( KNOWN_CODES == (sizeof(http_codes) / sizeof(http_codes[0])));
65
66int code_val(HttpCode code) {
67 return http_codes[code];
68}
[0aec496]69
[3f39009]70static inline int answer( int fd, const char * it, int len ) {
[0aec496]71 while(len > 0) {
72 // Call write
[2cd784a]73 int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY);
[ee59ede]74 if( ret < 0 ) {
[32d1383]75 if( errno == ECONNRESET || errno == EPIPE || errno == EBADF ) {
76 ret = close(fd);
77 if( ret != 0 ) abort( "close in 'answer' error: (%d) %s\n", (int)errno, strerror(errno) );
78 return -ECONNRESET;
79 }
[ee59ede]80
81 abort( "'answer error' error: (%d) %s\n", (int)errno, strerror(errno) );
82 }
[0aec496]83
84 // update it/len
85 it += ret;
86 len -= ret;
87 }
88 return 0;
89}
90
[32d1383]91// int answer_error( int fd, HttpCode code ) {
92// /* paranoid */ assert( code < KNOWN_CODES && code != OK200 );
93// int idx = (int)code;
94// return answer( fd, http_msgs[idx]->msg, http_msgs[idx]->len );
95// }
[0aec496]96
[3f39009]97static int fill_header(char * it, size_t size) {
[2caed18]98 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
99 it += http_msgs[OK200]->len;
100 int len = http_msgs[OK200]->len;
101 len += snprintf(it, 512 - len, "%d \n\n", size);
[3f39009]102 return len;
103}
104
105static int answer_header( int fd, size_t size ) {
106 char buffer[512];
107 int len = fill_header(buffer, size);
[0aec496]108 return answer( fd, buffer, len );
109}
110
[32d1383]111// #if defined(PLAINTEXT_NOCOPY)
112// int answer_plaintext( int fd ) {
113// return answer(fd, http_msgs[OK200_PlainText]->msg, http_msgs[OK200_PlainText]->len); // +1 cause snprintf doesn't count nullterminator
114// }
115// #elif defined(PLAINTEXT_MEMCPY)
116// #define TEXTSIZE 15
117// int answer_plaintext( int fd ) {
118// char text[] = "Hello, World!\n\n";
119// char ts[] = xstr(TEXTSIZE) " \n\n";
120// _Static_assert(sizeof(text) - 1 == TEXTSIZE);
121// char buffer[512 + TEXTSIZE];
122// char * it = buffer;
123// memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
124// it += http_msgs[OK200]->len;
125// int len = http_msgs[OK200]->len;
126// memcpy(it, ts, sizeof(ts) - 1);
127// it += sizeof(ts) - 1;
128// len += sizeof(ts) - 1;
129// memcpy(it, text, TEXTSIZE);
130// return answer(fd, buffer, len + TEXTSIZE);
131// }
132// #elif defined(PLAINTEXT_1WRITE)
133// int answer_plaintext( int fd ) {
134// char text[] = "Hello, World!\n\n";
135// char buffer[512 + sizeof(text)];
136// char * it = buffer;
137// memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
138// it += http_msgs[OK200]->len;
139// int len = http_msgs[OK200]->len;
140// int r = snprintf(it, 512 - len, "%d \n\n", sizeof(text));
141// it += r;
142// len += r;
143// memcpy(it, text, sizeof(text));
144// return answer(fd, buffer, len + sizeof(text));
145// }
146// #else
147// int answer_plaintext( int fd ) {
148// char text[] = "Hello, World!\n\n";
149// int ret = answer_header(fd, sizeof(text));
150// if( ret < 0 ) return ret;
151// return answer(fd, text, sizeof(text));
152// }
153// #endif
154
155// int answer_empty( int fd ) {
156// return answer_header(fd, 0);
157// }
[7270432]158
[3f95dab]159static int sendfile( int pipe[2], int fd, int ans_fd, size_t count, sendfile_stats_t & stats ) {
160 int zipf_idx = -1;
161 STATS: for(i; zipf_cnts) {
162 if(count <= zipf_sizes[i]) {
163 zipf_idx = i;
164 break STATS;
165 }
166 }
167 if(zipf_idx < 0) mutex(serr) serr | "SENDFILE" | count | " greated than biggest zipf file";
168
[32d1383]169 #if defined(TRUE_SENDFILE)
170 off_t offset = 0;
171 ssize_t ret;
172 int flags = fcntl(fd, F_GETFL);
173 if(flags < 0) abort("getfl in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
174 ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
175 if(ret < 0) abort("setfl in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
[3f95dab]176
[32d1383]177 while(count) {
178 ret = sendfile(fd, ans_fd, &offset, count);
[3f95dab]179 if( ret <= 0 ) {
[32d1383]180 if( errno == EAGAIN || errno == EWOULDBLOCK ) {
181 stats.eagain++;
182 yield();
183 continue;
184 }
185 if( errno == ECONNRESET || errno == EPIPE ) {
186 ret = close(fd);
187 if( ret != 0 ) abort( "close in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
188 return -ECONNRESET;
189 }
190 abort( "sendfile error: %d (%d) %s\n", ret, (int)errno, strerror(errno) );
[3f39009]191 }
[32d1383]192 count -= ret;
193 stats.splcin++;
194 if(count > 0) stats.avgrd[zipf_idx].calls++;
195 stats.avgrd[zipf_idx].bytes += ret;
[3f39009]196 }
197
[32d1383]198 ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
199 if(ret < 0) abort("resetfl in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
200 #else
201 #error not implemented
202 // unsigned sflags = SPLICE_F_MOVE; // | SPLICE_F_MORE;
203 // off_t offset = 0;
204 // ssize_t ret;
205 // SPLICE1: while(count > 0) {
206 // stats.tries++;
207 // // ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, CFA_IO_LAZY);
208 // ret = splice(ans_fd, &offset, pipe[1], 0p, count, sflags);
209 // if( ret <= 0 ) {
210 // if( errno == ECONNRESET || errno == EPIPE ) {
211 // ret = close(fd);
212 // if( ret != 0 ) abort( "close in 'sendfile splice in' error: (%d) %s\n", (int)errno, strerror(errno) );
213 // return -ECONNRESET;
214 // }
215 // abort( "splice [0] error: %d (%d) %s\n", ret, (int)errno, strerror(errno) );
216 // }
217 // count -= ret;
218 // stats.splcin++;
219 // if(count > 0) stats.avgrd[zipf_idx].calls++;
220 // stats.avgrd[zipf_idx].bytes += ret;
221
222 // size_t in_pipe = ret;
223 // SPLICE2: while(in_pipe > 0) {
224 // ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, CFA_IO_LAZY);
225 // // ret = splice(pipe[0], 0p, fd, 0p, in_pipe, sflags);
226 // if( ret <= 0 ) {
227 // if( errno == ECONNRESET || errno == EPIPE ) {
228 // ret = close(fd);
229 // if( ret != 0 ) abort( "close in 'sendfile splice out' error: (%d) %s\n", (int)errno, strerror(errno) );
230 // return -ECONNRESET;
231 // }
232 // abort( "splice [1] error: %d (%d) %s\n", ret, (int)errno, strerror(errno) );
233 // }
234 // stats.splcot++;
235 // in_pipe -= ret;
236 // }
237
238 // }
239 #endif
[3f39009]240
[32d1383]241 return count;
[3f39009]242}
243
[32d1383]244// enum FSM_STATE {
245// Initial,
246// Retry,
247// Error,
248// Done,
249// };
250
251// struct FSM_Result {
252// FSM_STATE state;
253// int error;
254// };
255
256// static inline void ?{}(FSM_Result & this) { this.state = Initial; this.error = 0; }
257// static inline bool is_error(FSM_Result & this) { return Error == this.state; }
258// static inline bool is_done(FSM_Result & this) { return Done == this.state; }
259
260// static inline int error(FSM_Result & this, int error) {
261// this.error = error;
262// this.state = Error;
263// return error;
264// }
265
266// static inline int done(FSM_Result & this) {
267// this.state = Done;
268// return 0;
269// }
270
271// static inline int retry(FSM_Result & this) {
272// this.state = Retry;
273// return 0;
274// }
275
276// static inline int need(FSM_Result & this) {
277// switch(this.state) {
278// case Initial:
279// case Retry:
280// return 1;
281// case Error:
282// if(this.error == 0) mutex(serr) serr | "State marked error but code is 0";
283// case Done:
284// return 0;
285// }
286// }
287
288// // Generator that handles sending the header
289// generator header_g {
290// io_future_t f;
291// const char * next;
292// int fd; size_t len;
293// FSM_Result res;
294// };
295
296// static inline void ?{}(header_g & this, int fd, const char * it, size_t len ) {
297// this.next = it;
298// this.fd = fd;
299// this.len = len;
300// }
301
302// static inline void fill(header_g & this, struct io_uring_sqe * sqe) {
303// zero_sqe(sqe);
304// sqe->opcode = IORING_OP_SEND;
305// sqe->user_data = (uintptr_t)&this.f;
306// sqe->flags = IOSQE_IO_LINK;
307// sqe->fd = this.fd;
308// sqe->addr = (uintptr_t)this.next;
309// sqe->len = this.len;
310// }
311
312// static inline int error(header_g & this, int error) {
313// int ret = close(this.fd);
314// if( ret != 0 ) {
315// mutex(serr) serr | "Failed to close fd" | errno;
316// }
317// return error(this.res, error);
318// }
319
320// static inline int wait_and_process(header_g & this, sendfile_stats_t & stats) {
321// wait(this.f);
322
323// // Did something crazy happen?
324// if(this.f.result > this.len) {
325// mutex(serr) serr | "HEADER sent too much!";
326// return error(this, -ERANGE);
327// }
328
329// // Something failed?
330// if(this.f.result < 0) {
331// int error = -this.f.result;
332// if( error == ECONNRESET ) return error(this, -ECONNRESET);
333// if( error == EPIPE ) return error(this, -EPIPE);
334// if( error == ECANCELED ) {
335// mutex(serr) serr | "HEADER was cancelled, WTF!";
336// return error(this, -ECONNRESET);
337// }
338// if( error == EAGAIN || error == EWOULDBLOCK) {
339// mutex(serr) serr | "HEADER got eagain, WTF!";
340// return error(this, -ECONNRESET);
341// }
342// }
343
344// // Done?
345// if(this.f.result == this.len) {
346// return done(this.res);
347// }
348
349// stats.header++;
350
351// // It must be a Short read
352// this.len -= this.f.result;
353// this.next += this.f.result;
354// reset(this.f);
355// return retry(this.res);
356// }
357
358// // Generator that handles splicing in a file
359// struct splice_in_t {
360// io_future_t f;
361// int fd; int pipe; size_t len; off_t off;
362// short zipf_idx;
363// FSM_Result res;
364// };
365
366// static inline void ?{}(splice_in_t & this, int fd, int pipe, size_t len) {
367// this.fd = fd;
368// this.pipe = pipe;
369// this.len = len;
370// this.off = 0;
371// this.zipf_idx = -1;
372// STATS: for(i; zipf_cnts) {
373// if(len <= zipf_sizes[i]) {
374// this.zipf_idx = i;
375// break STATS;
376// }
377// }
378// if(this.zipf_idx < 0) mutex(serr) serr | "SPLICE IN" | len | " greated than biggest zipf file";
379// }
380
381// static inline void fill(splice_in_t & this, struct io_uring_sqe * sqe) {
382// zero_sqe(sqe);
383// sqe->opcode = IORING_OP_SPLICE;
384// sqe->user_data = (uintptr_t)&this.f;
385// sqe->flags = 0;
386// sqe->splice_fd_in = this.fd;
387// sqe->splice_off_in = this.off;
388// sqe->fd = this.pipe;
389// sqe->off = (__u64)-1;
390// sqe->len = this.len;
391// sqe->splice_flags = SPLICE_F_MOVE;
392// }
393
394// static inline int wait_and_process(splice_in_t & this, sendfile_stats_t & stats ) {
395// wait(this.f);
396
397// // Something failed?
398// if(this.f.result < 0) {
399// int error = -this.f.result;
400// if( error == ECONNRESET ) return error(this.res, -ECONNRESET);
401// if( error == EPIPE ) return error(this.res, -EPIPE);
402// if( error == ECANCELED ) {
403// mutex(serr) serr | "SPLICE IN was cancelled, WTF!";
404// return error(this.res, -ECONNRESET);
405// }
406// if( error == EAGAIN || error == EWOULDBLOCK) {
407// mutex(serr) serr | "SPLICE IN got eagain, WTF!";
408// return error(this.res, -ECONNRESET);
409// }
410// mutex(serr) serr | "SPLICE IN got" | error | ", WTF!";
411// return error(this.res, -ECONNRESET);
412// }
413
414// // Did something crazy happen?
415// if(this.f.result > this.len) {
416// mutex(serr) serr | "SPLICE IN spliced too much!";
417// return error(this.res, -ERANGE);
418// }
419
420// // Done?
421// if(this.f.result == this.len) {
422// return done(this.res);
423// }
424
425// stats.splcin++;
426// stats.avgrd[this.zipf_idx].calls++;
427// stats.avgrd[this.zipf_idx].bytes += this.f.result;
428
429// // It must be a Short read
430// this.len -= this.f.result;
431// this.off += this.f.result;
432// reset(this.f);
433// return retry(this.res);
434// }
435
436// generator splice_out_g {
437// io_future_t f;
438// int pipe; int fd; size_t len;
439// FSM_Result res;
440// };
441
442// static inline void ?{}(splice_out_g & this, int pipe, int fd, size_t len) {
443// this.pipe = pipe;
444// this.fd = fd;
445// this.len = len;
446// }
447
448// static inline void fill(splice_out_g & this, struct io_uring_sqe * sqe) {
449// zero_sqe(sqe);
450// sqe->opcode = IORING_OP_SPLICE;
451// sqe->user_data = (uintptr_t)&this.f;
452// sqe->flags = 0;
453// sqe->splice_fd_in = this.pipe;
454// sqe->splice_off_in = (__u64)-1;
455// sqe->fd = this.fd;
456// sqe->off = (__u64)-1;
457// sqe->len = this.len;
458// sqe->splice_flags = SPLICE_F_MOVE;
459// }
460
461// static inline int error(splice_out_g & this, int error) {
462// int ret = close(this.fd);
463// if( ret != 0 ) {
464// mutex(serr) serr | "Failed to close fd" | errno;
465// }
466// return error(this.res, error);
467// }
468
469// static inline void wait_and_process(splice_out_g & this, sendfile_stats_t & stats ) {
470// wait(this.f);
471
472// // Something failed?
473// if(this.f.result < 0) {
474// int error = -this.f.result;
475// if( error == ECONNRESET ) return error(this, -ECONNRESET);
476// if( error == EPIPE ) return error(this, -EPIPE);
477// if( error == ECANCELED ) {
478// this.f.result = 0;
479// goto SHORT_WRITE;
480// }
481// if( error == EAGAIN || error == EWOULDBLOCK) {
482// mutex(serr) serr | "SPLICE OUT got eagain, WTF!";
483// return error(this, -ECONNRESET);
484// }
485// mutex(serr) serr | "SPLICE OUT got" | error | ", WTF!";
486// return error(this, -ECONNRESET);
487// }
488
489// // Did something crazy happen?
490// if(this.f.result > this.len) {
491// mutex(serr) serr | "SPLICE OUT spliced too much!" | this.f.result | ">" | this.len;
492// return error(this.res, -ERANGE);
493// }
494
495// // Done?
496// if(this.f.result == this.len) {
497// return done(this.res);
498// }
499
500// SHORT_WRITE:
501// stats.splcot++;
502
503// // It must be a Short Write
504// this.len -= this.f.result;
505// reset(this.f);
506// return retry(this.res);
507// }
[3f39009]508
[ef3c383]509int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t fsize, sendfile_stats_t & stats ) {
510 stats.calls++;
[3f39009]511 #if defined(LINKED_IO)
[32d1383]512 // char buffer[512];
513 // int len = fill_header(buffer, fsize);
514 // header_g header = { fd, buffer, len };
515 // splice_in_t splice_in = { ans_fd, pipe[1], fsize };
516 // splice_out_g splice_out = { pipe[0], fd, fsize };
517
518 // RETRY_LOOP: for() {
519 // stats.tries++;
520 // int have = need(header.res) + need(splice_in.res) + 1;
521 // int idx = 0;
522 // struct io_uring_sqe * sqes[3];
523 // __u32 idxs[3];
[17c6edeb]524 // struct io_context$ * ctx = cfa_io_allocate(sqes, idxs, have);
[32d1383]525
526 // if(need(splice_in.res)) { fill(splice_in, sqes[idx++]); }
527 // if(need( header.res)) { fill(header , sqes[idx++]); }
528 // fill(splice_out, sqes[idx]);
529
530 // // Submit everything
531 // asm volatile("": : :"memory");
532 // cfa_io_submit( ctx, idxs, have, false );
533
534 // // wait for the results
535 // // Always wait for splice-in to complete as
536 // // we may need to kill the connection if it fails
537 // // If it already completed, this is a no-op
538 // wait_and_process(splice_in, stats);
539
540 // if(is_error(splice_in.res)) {
541 // if(splice_in.res.error == -EPIPE) return -ECONNRESET;
542 // mutex(serr) serr | "SPLICE IN failed with" | splice_in.res.error;
543 // int ret = close(fd);
544 // if( ret != 0 ) abort( "close in 'answer sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
545 // }
546
547 // // Process the other 2
548 // wait_and_process(header, stats);
549 // wait_and_process(splice_out, stats);
550
551 // if(is_done(splice_out.res)) {
552 // break RETRY_LOOP;
553 // }
554
555 // // We need to wait for the completion if
556 // // - both completed
557 // // - the header failed
558 // // -
559
560 // if( is_error(header.res)
561 // || is_error(splice_in.res)
562 // || is_error(splice_out.res)) {
563 // return -ECONNRESET;
564 // }
565 // }
566
567 // return len + fsize;
[3f39009]568 #else
569 int ret = answer_header(fd, fsize);
[32d1383]570 if( ret < 0 ) { return ret; }
[3f95dab]571 return sendfile(pipe, fd, ans_fd, fsize, stats);
[3f39009]572 #endif
573}
[ba77750]574
[7f0ac12]575[HttpCode code, bool closed, * const char file, size_t len] http_read(volatile int & fd, []char buffer, size_t len, io_future_t * f) {
[0aec496]576 char * it = buffer;
577 size_t count = len - 1;
578 int rlen = 0;
579 READ:
580 for() {
[7f0ac12]581 int ret;
582 if( f ) {
583 ret = wait_res(*f);
584 reset(*f);
585 f = 0p;
586 } else {
587 ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY);
588 }
[c3ee5f3]589 // int ret = read(fd, (void*)it, count);
[32d1383]590 if(ret == 0 ) {
591 ret = close(fd);
592 if( ret != 0 ) abort( "close in 'http read good' error: (%d) %s\n", (int)errno, strerror(errno) );
593 return [OK200, true, 0, 0];
594 }
[0aec496]595 if(ret < 0 ) {
[32d1383]596 if( errno == ECONNRESET || errno == EPIPE ) {
597 ret = close(fd);
598 if( ret != 0 ) abort( "close in 'http read bad' error: (%d) %s\n", (int)errno, strerror(errno) );
599 return [E408, true, 0, 0];
600 }
[0aec496]601 abort( "read error: (%d) %s\n", (int)errno, strerror(errno) );
602 }
603 it[ret + 1] = '\0';
604 rlen += ret;
605
606 if( strstr( it, "\r\n\r\n" ) ) break;
607
608 it += ret;
609 count -= ret;
610
[d11d6eb]611 if( count < 1 ) return [E414, false, 0, 0];
[0aec496]612 }
613
[8c43d05]614 if( options.log ) {
615 write(sout, buffer, rlen);
616 sout | nl;
617 }
[0aec496]618
619 it = buffer;
620 int ret = memcmp(it, "GET /", 5);
[d11d6eb]621 if( ret != 0 ) return [E400, false, 0, 0];
[0aec496]622 it += 5;
623
624 char * end = strstr( it, " " );
625 return [OK200, false, it, end - it];
[c82af9f]626}
627
[c3ee5f3]628//=============================================================================================
629
630#include <clock.hfa>
631#include <time.hfa>
632#include <thread.hfa>
633
[2caed18]634const char * original_http_msgs[] = {
[1db1454]635 "HTTP/1.1 200 OK\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",
[52d2545]636 "HTTP/1.1 200 OK\r\nServer: HttpForall\r\nConnection: keep-alive\r\nContent-Length: 15\r\nContent-Type: text/html\r\nDate: %s \r\n\r\nHello, World!\r\n",
[1db1454]637 "HTTP/1.1 400 Bad Request\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
638 "HTTP/1.1 404 Not Found\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
639 "HTTP/1.1 405 Method Not Allowed\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
640 "HTTP/1.1 408 Request Timeout\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
641 "HTTP/1.1 413 Payload Too Large\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
642 "HTTP/1.1 414 URI Too Long\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
[2caed18]643};
644
[c3ee5f3]645struct date_buffer {
[2caed18]646 https_msg_str strs[KNOWN_CODES];
[c3ee5f3]647};
648
649thread DateFormater {
650 int idx;
651 date_buffer buffers[2];
652};
653
654void ?{}( DateFormater & this ) {
[bf7c7ea]655 ((thread&)this){ "Server Date Thread" };
[c3ee5f3]656 this.idx = 0;
[2caed18]657 memset( &this.buffers[0], 0, sizeof(this.buffers[0]) );
658 memset( &this.buffers[1], 0, sizeof(this.buffers[1]) );
[c3ee5f3]659}
660
661void main(DateFormater & this) {
662 LOOP: for() {
663 waitfor( ^?{} : this) {
664 break LOOP;
665 }
666 or else {}
667
[2caed18]668
669 char buff[100];
[e54d0c3]670 Time now = timeHiRes();
[2caed18]671 strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
[3f39009]672 // if( options.log ) sout | "Updated date to '" | buff | "'";
[ece0e80]673
[2caed18]674 for(i; KNOWN_CODES) {
675 size_t len = snprintf( this.buffers[this.idx].strs[i].msg, 512, original_http_msgs[i], buff );
676 this.buffers[this.idx].strs[i].len = len;
677 }
[c3ee5f3]678
[2caed18]679 for(i; KNOWN_CODES) {
680 https_msg_str * next = &this.buffers[this.idx].strs[i];
681 __atomic_exchange_n((https_msg_str * volatile *)&http_msgs[i], next, __ATOMIC_SEQ_CST);
682 }
[c3ee5f3]683 this.idx = (this.idx + 1) % 2;
684
[3f39009]685 // if( options.log ) sout | "Date thread sleeping";
[2cd784a]686
[c3ee5f3]687 sleep(1`s);
688 }
689}
690
691//=============================================================================================
692DateFormater * the_date_formatter;
693
694void init_protocol(void) {
695 the_date_formatter = alloc();
696 (*the_date_formatter){};
697}
698
699void deinit_protocol(void) {
700 ^(*the_date_formatter){};
701 free( the_date_formatter );
[e54d0c3]702}
Note: See TracBrowser for help on using the repository browser.