Переход на edge-triggered; устранение жора CPU
This commit is contained in:
parent
ca1662c403
commit
06f9e483c3
@ -27,6 +27,15 @@ struct Server {
|
||||
|
||||
private shared int epfd, sock;
|
||||
void start(MD...)() { // TODO: реализовать "слушальщика" хрюникс сокетов (AF_UNIX)
|
||||
// import core.stdc.signal;
|
||||
// extern(C) void z (int s) nothrow @nogc @system {
|
||||
// signal(s, SIG_IGN);
|
||||
// this.epfd.close();
|
||||
// this.sock.close();
|
||||
// raise(0);
|
||||
// }
|
||||
// signal(SIGINT, &z);
|
||||
|
||||
bool ipv6;
|
||||
for (short i; i < address.length; ++i)
|
||||
if (address[i] == ':') {ipv6=true;break;}
|
||||
@ -47,15 +56,22 @@ struct Server {
|
||||
err(bind(sock, cast(sockaddr*)&sockt, sockt.sizeof), "bind");
|
||||
}
|
||||
|
||||
int hz;
|
||||
setsockopt(sock,
|
||||
IPPROTO_TCP, TCP_NODELAY | SO_REUSEADDR | SO_REUSEPORT,
|
||||
cast(void*)(new int), int.sizeof);
|
||||
IPPROTO_TCP, SO_REUSEADDR,
|
||||
cast(void*)hz, int.sizeof);
|
||||
setsockopt(sock,
|
||||
IPPROTO_TCP, TCP_NODELAY,
|
||||
cast(void*)hz, int.sizeof);
|
||||
// setsockopt(sock,
|
||||
// IPPROTO_TCP, SO_REUSEPORT,
|
||||
// cast(void*)hz, int.sizeof);
|
||||
|
||||
err(listen(sock, 512), "listen");
|
||||
serve!MD;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
void stop() @nogc {
|
||||
epfd.close();
|
||||
sock.close();
|
||||
}
|
||||
@ -66,7 +82,7 @@ struct Server {
|
||||
epoll_event[MAX_EVENTS] evts;
|
||||
|
||||
ev.data.fd = sock;
|
||||
ev.events = EPOLLIN | EPOLLEXCLUSIVE;
|
||||
ev.events = EPOLLIN;
|
||||
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);
|
||||
|
||||
for (;;) {
|
||||
@ -77,23 +93,35 @@ struct Server {
|
||||
// sockaddr_in addr;
|
||||
// socklen_t al = sockaddr_in.sizeof;
|
||||
// ev.data.fd = accept4(sock, cast(sockaddr*)&addr, &al, SOCK_NONBLOCK);
|
||||
ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
|
||||
ev.data.fd = accept4(sock, null, null, SOCK_NONBLOCK);
|
||||
epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
|
||||
// ip = cast(string)inet_ntoa(addr.sin_addr);
|
||||
}
|
||||
|
||||
// if (ev.data.fd == -1) {
|
||||
if (evts[i].events & EPOLLRDHUP) {
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, null);
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
|
||||
rd:
|
||||
ubyte[128] buf;
|
||||
ubyte[256] buf;
|
||||
for (;;) { // обработчик запросов
|
||||
auto rd = recv(fd, cast(void*)buf, buf.sizeof, 0);
|
||||
if (rd < 1) break;
|
||||
auto rqst = parseReq(buf);
|
||||
|
||||
if (parseAndValidateURL(rqst.path, &rqst)) {
|
||||
static auto resp = "HTTP/1.1 400 Bad Request\r\nContent-length: 15\r\n\r\n400 Bad Request";
|
||||
write(fd, cast(void*)resp, resp.length);
|
||||
continue;
|
||||
}
|
||||
|
||||
static foreach (mm; __traits(allMembers, T)) {
|
||||
static if (__traits(isStaticFunction, __traits(getMember, T, mm))) {
|
||||
foreach(attr; __traits(getAttributes, __traits(getMember, T, mm))) {
|
||||
static if (is(typeof(attr) == Location)) {
|
||||
parseAndValidateURL(rqst.path, &rqst);
|
||||
if (rqst.path == attr.path) {
|
||||
Response rsp;
|
||||
__traits(getMember, T, mm)(&rsp, &rqst);
|
||||
@ -123,7 +151,8 @@ struct Server {
|
||||
}
|
||||
}
|
||||
|
||||
Request parseReq(ubyte[] body) { // TODO: реализовать парсинг заголовков, оформленных хер пойми как
|
||||
// TODO: реализовать парсинг заголовков, оформленных хер пойми как
|
||||
Request parseReq(ubyte[] body) {
|
||||
int prev;
|
||||
short[] xxx;
|
||||
Request req;
|
||||
|
@ -30,27 +30,10 @@ string getStatus(short status) {
|
||||
return "WTF";
|
||||
}
|
||||
|
||||
// FIXME: memory leak
|
||||
void append(char[]* src, char symb) @nogc {
|
||||
import core.memory: pureMalloc, pureFree;
|
||||
auto arr =
|
||||
cast (char[])
|
||||
pureMalloc(src.length + 1)
|
||||
[0..src.length + 1];
|
||||
|
||||
arr[$-1..$] = symb;
|
||||
arr[0..$-1] = *src;
|
||||
*src = arr;
|
||||
|
||||
arr = null;
|
||||
pureFree(arr.ptr);
|
||||
}
|
||||
|
||||
void parseAndValidateURL(char[] url, Request* rqst) {
|
||||
if (url.length > 2048) throw new Exception("Too long URL");
|
||||
short parseAndValidateURL(char[] url, Request* rqst) {
|
||||
if (url.length > 2048) return 1; // too long url
|
||||
rqst.path = null;
|
||||
bool notArgumentPart;
|
||||
scope (exit) append(&rqst.args, '&');
|
||||
for (short i; i < url.length; ++i) {
|
||||
switch (url[i]) {
|
||||
case '?':
|
||||
@ -58,22 +41,24 @@ void parseAndValidateURL(char[] url, Request* rqst) {
|
||||
notArgumentPart = true;
|
||||
break;
|
||||
case '/':
|
||||
if (url.length > i+1 && url[i+1] != '/') append(&rqst.path, '/');
|
||||
if (url.length > i+1 && url[i+1] != '/') rqst.path ~= '/';
|
||||
break;
|
||||
case '=', '&':
|
||||
if (notArgumentPart && url[i-1] != url[i]) append(&rqst.args, url[i]);
|
||||
if (notArgumentPart && url[i-1] != url[i]) rqst.args ~= url[i];
|
||||
break;
|
||||
|
||||
case 'A': .. case 'Z':
|
||||
case 'a': .. case 'z':
|
||||
case '0': .. case '9':
|
||||
case '-', '_', '.', '~', '!', '$', '\'', '(', ')', '*', '+', ',', ';', '@', '[', ']', '|', '%':
|
||||
if (notArgumentPart) append(&rqst.args, url[i]);
|
||||
else append(&rqst.path, url[i]);
|
||||
if (notArgumentPart) rqst.args ~= url[i];
|
||||
else rqst.path ~= url[i];
|
||||
break;
|
||||
default: throw new Exception("Malformed URL");
|
||||
default: return 1; // malformed url
|
||||
}
|
||||
}
|
||||
rqst.args ~= '&';
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Request {
|
||||
@ -173,5 +158,9 @@ private static enum Statuses: short { // спизженно с https://github.co
|
||||
@("Service Unavailable") service_unavailable = 503,
|
||||
@("Gateway Timeout") gateway_timeout = 504,
|
||||
@("HTTP Version Not Supported") http_version_not_supported = 505,
|
||||
@("Variant Also Negotiates") variant_also_negotiates = 506
|
||||
@("Variant Also Negotiates") variant_also_negotiates = 506,
|
||||
@("Insufficient Storage") insufficient_storage = 507, // (WebDAV)
|
||||
@("Loop Detected") loop_detected = 508, // (WebDAV)
|
||||
@("Not Extended") not_extended = 510,
|
||||
@("Network Authentication Required") network_authentication_required = 511
|
||||
}
|
Loading…
Reference in New Issue
Block a user