Переход на edge-triggered; устранение жора CPU
This commit is contained in:
parent
ca1662c403
commit
06f9e483c3
@ -27,6 +27,15 @@ struct Server {
|
|||||||
|
|
||||||
private shared int epfd, sock;
|
private shared int epfd, sock;
|
||||||
void start(MD...)() { // TODO: реализовать "слушальщика" хрюникс сокетов (AF_UNIX)
|
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;
|
bool ipv6;
|
||||||
for (short i; i < address.length; ++i)
|
for (short i; i < address.length; ++i)
|
||||||
if (address[i] == ':') {ipv6=true;break;}
|
if (address[i] == ':') {ipv6=true;break;}
|
||||||
@ -47,15 +56,22 @@ struct Server {
|
|||||||
err(bind(sock, cast(sockaddr*)&sockt, sockt.sizeof), "bind");
|
err(bind(sock, cast(sockaddr*)&sockt, sockt.sizeof), "bind");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hz;
|
||||||
setsockopt(sock,
|
setsockopt(sock,
|
||||||
IPPROTO_TCP, TCP_NODELAY | SO_REUSEADDR | SO_REUSEPORT,
|
IPPROTO_TCP, SO_REUSEADDR,
|
||||||
cast(void*)(new int), int.sizeof);
|
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");
|
err(listen(sock, 512), "listen");
|
||||||
serve!MD;
|
serve!MD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() @nogc {
|
||||||
epfd.close();
|
epfd.close();
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
@ -66,7 +82,7 @@ struct Server {
|
|||||||
epoll_event[MAX_EVENTS] evts;
|
epoll_event[MAX_EVENTS] evts;
|
||||||
|
|
||||||
ev.data.fd = sock;
|
ev.data.fd = sock;
|
||||||
ev.events = EPOLLIN | EPOLLEXCLUSIVE;
|
ev.events = EPOLLIN;
|
||||||
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);
|
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -77,23 +93,35 @@ struct Server {
|
|||||||
// sockaddr_in addr;
|
// sockaddr_in addr;
|
||||||
// socklen_t al = sockaddr_in.sizeof;
|
// socklen_t al = sockaddr_in.sizeof;
|
||||||
// ev.data.fd = accept4(sock, cast(sockaddr*)&addr, &al, SOCK_NONBLOCK);
|
// 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);
|
ev.data.fd = accept4(sock, null, null, SOCK_NONBLOCK);
|
||||||
epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
|
epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
|
||||||
// ip = cast(string)inet_ntoa(addr.sin_addr);
|
// 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:
|
rd:
|
||||||
ubyte[128] buf;
|
ubyte[256] buf;
|
||||||
for (;;) { // обработчик запросов
|
for (;;) { // обработчик запросов
|
||||||
auto rd = recv(fd, cast(void*)buf, buf.sizeof, 0);
|
auto rd = recv(fd, cast(void*)buf, buf.sizeof, 0);
|
||||||
if (rd < 1) break;
|
if (rd < 1) break;
|
||||||
auto rqst = parseReq(buf);
|
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 foreach (mm; __traits(allMembers, T)) {
|
||||||
static if (__traits(isStaticFunction, __traits(getMember, T, mm))) {
|
static if (__traits(isStaticFunction, __traits(getMember, T, mm))) {
|
||||||
foreach(attr; __traits(getAttributes, __traits(getMember, T, mm))) {
|
foreach(attr; __traits(getAttributes, __traits(getMember, T, mm))) {
|
||||||
static if (is(typeof(attr) == Location)) {
|
static if (is(typeof(attr) == Location)) {
|
||||||
parseAndValidateURL(rqst.path, &rqst);
|
|
||||||
if (rqst.path == attr.path) {
|
if (rqst.path == attr.path) {
|
||||||
Response rsp;
|
Response rsp;
|
||||||
__traits(getMember, T, mm)(&rsp, &rqst);
|
__traits(getMember, T, mm)(&rsp, &rqst);
|
||||||
@ -123,7 +151,8 @@ struct Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Request parseReq(ubyte[] body) { // TODO: реализовать парсинг заголовков, оформленных хер пойми как
|
// TODO: реализовать парсинг заголовков, оформленных хер пойми как
|
||||||
|
Request parseReq(ubyte[] body) {
|
||||||
int prev;
|
int prev;
|
||||||
short[] xxx;
|
short[] xxx;
|
||||||
Request req;
|
Request req;
|
||||||
|
@ -30,27 +30,10 @@ string getStatus(short status) {
|
|||||||
return "WTF";
|
return "WTF";
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: memory leak
|
short parseAndValidateURL(char[] url, Request* rqst) {
|
||||||
void append(char[]* src, char symb) @nogc {
|
if (url.length > 2048) return 1; // too long url
|
||||||
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");
|
|
||||||
rqst.path = null;
|
rqst.path = null;
|
||||||
bool notArgumentPart;
|
bool notArgumentPart;
|
||||||
scope (exit) append(&rqst.args, '&');
|
|
||||||
for (short i; i < url.length; ++i) {
|
for (short i; i < url.length; ++i) {
|
||||||
switch (url[i]) {
|
switch (url[i]) {
|
||||||
case '?':
|
case '?':
|
||||||
@ -58,22 +41,24 @@ void parseAndValidateURL(char[] url, Request* rqst) {
|
|||||||
notArgumentPart = true;
|
notArgumentPart = true;
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (url.length > i+1 && url[i+1] != '/') append(&rqst.path, '/');
|
if (url.length > i+1 && url[i+1] != '/') rqst.path ~= '/';
|
||||||
break;
|
break;
|
||||||
case '=', '&':
|
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;
|
break;
|
||||||
|
|
||||||
case 'A': .. case 'Z':
|
case 'A': .. case 'Z':
|
||||||
case 'a': .. case 'z':
|
case 'a': .. case 'z':
|
||||||
case '0': .. case '9':
|
case '0': .. case '9':
|
||||||
case '-', '_', '.', '~', '!', '$', '\'', '(', ')', '*', '+', ',', ';', '@', '[', ']', '|', '%':
|
case '-', '_', '.', '~', '!', '$', '\'', '(', ')', '*', '+', ',', ';', '@', '[', ']', '|', '%':
|
||||||
if (notArgumentPart) append(&rqst.args, url[i]);
|
if (notArgumentPart) rqst.args ~= url[i];
|
||||||
else append(&rqst.path, url[i]);
|
else rqst.path ~= url[i];
|
||||||
break;
|
break;
|
||||||
default: throw new Exception("Malformed URL");
|
default: return 1; // malformed url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rqst.args ~= '&';
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
@ -173,5 +158,9 @@ private static enum Statuses: short { // спизженно с https://github.co
|
|||||||
@("Service Unavailable") service_unavailable = 503,
|
@("Service Unavailable") service_unavailable = 503,
|
||||||
@("Gateway Timeout") gateway_timeout = 504,
|
@("Gateway Timeout") gateway_timeout = 504,
|
||||||
@("HTTP Version Not Supported") http_version_not_supported = 505,
|
@("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