#include "protocol.hfa" #define _GNU_SOURCE extern "C" { #include } #include #include // #include // Don't use stdio.h, too slow to compile extern "C" { int snprintf ( char * s, size_t n, const char * format, ... ); #include } #include #include #include "options.hfa" const char * volatile date = 0p; const char * http_msgs[] = { "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: %zu \n\n", "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", }; _Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0]))); const int http_codes[] = { 200, 400, 404, 413, 414, }; _Static_assert( KNOWN_CODES == (sizeof(http_codes) / sizeof(http_codes[0]))); int code_val(HttpCode code) { return http_codes[code]; } static inline int answer( int fd, const char * it, int len) { while(len > 0) { // Call write int ret = write(fd, it, len); if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) abort( "'answer error' error: (%d) %s\n", (int)errno, strerror(errno) ); } // update it/len it += ret; len -= ret; } return 0; } int answer_error( int fd, HttpCode code ) { /* paranoid */ assert( code < KNOWN_CODES && code != OK200 ); int idx = (int)code; return answer( fd, http_msgs[idx], strlen( http_msgs[idx] ) ); } int answer_header( int fd, size_t size ) { const char * fmt = http_msgs[OK200]; int len = 200; char buffer[len]; len = snprintf(buffer, len, fmt, date, size); return answer( fd, buffer, len ); } [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) { char * it = buffer; size_t count = len - 1; int rlen = 0; READ: for() { int ret = cfa_read(fd, (void*)it, count, 0, -1`s, 0p, 0p); // int ret = read(fd, (void*)it, count); if(ret == 0 ) return [OK200, true, 0, 0]; if(ret < 0 ) { if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ; // if( errno == EINVAL ) return [E400, true, 0, 0]; abort( "read error: (%d) %s\n", (int)errno, strerror(errno) ); } it[ret + 1] = '\0'; rlen += ret; if( strstr( it, "\r\n\r\n" ) ) break; it += ret; count -= ret; if( count < 1 ) return [E414, false, 0, 0]; } printf("%.*s\n", rlen, buffer); it = buffer; int ret = memcmp(it, "GET /", 5); if( ret != 0 ) return [E400, false, 0, 0]; it += 5; char * end = strstr( it, " " ); return [OK200, false, it, end - it]; } void sendfile( int pipe[2], int fd, int ans_fd, size_t count ) { off_t offset = 0; ssize_t ret; SPLICE1: while(count > 0) { ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, SPLICE_F_MOVE | SPLICE_F_MORE, 0, -1`s, 0p, 0p); if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1; abort( "splice [0] error: (%d) %s\n", (int)errno, strerror(errno) ); } count -= ret; offset += ret; size_t in_pipe = ret; SPLICE2: while(in_pipe > 0) { ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, SPLICE_F_MOVE | SPLICE_F_MORE, 0, -1`s, 0p, 0p); if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2; abort( "splice [1] error: (%d) %s\n", (int)errno, strerror(errno) ); } in_pipe -= ret; } } } //============================================================================================= #include #include #include struct date_buffer { char buff[100]; }; thread DateFormater { int idx; date_buffer buffers[2]; }; void ?{}( DateFormater & this ) { ((thread&)this){ *options.clopts.instance }; this.idx = 0; memset( this.buffers[0].buff, 0, sizeof(this.buffers[0]) ); memset( this.buffers[1].buff, 0, sizeof(this.buffers[1]) ); } void main(DateFormater & this) { LOOP: for() { waitfor( ^?{} : this) { break LOOP; } or else {} Time now = getTimeNsec(); // Date: Wed, 17 Apr 2013 12:00:00 GMT strftime( this.buffers[this.idx].buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now ); printf("Changing date to %s\n", this.buffers[this.idx].buff); char * next = this.buffers[this.idx].buff; __atomic_exchange_n((char * volatile *)&date, next, __ATOMIC_SEQ_CST); this.idx = (this.idx + 1) % 2; sleep(1`s); } } //============================================================================================= DateFormater * the_date_formatter; void init_protocol(void) { the_date_formatter = alloc(); (*the_date_formatter){}; } void deinit_protocol(void) { ^(*the_date_formatter){}; free( the_date_formatter ); }