diff --git a/buffer.cc b/buffer.cc index e7507d6..ee9b413 100644 --- a/buffer.cc +++ b/buffer.cc @@ -23,6 +23,14 @@ bool ConstBuffer::Discard(size_t len) { return true; } +void ConstBuffer::ResetRead() { + start_ = commit_; +} + +void ConstBuffer::Commit() { + commit_ = start_; +} + Buffer::Buffer(char *buf, size_t size, size_t len) : ConstBuffer(buf, size), @@ -58,11 +66,12 @@ void Buffer::Wrote(size_t len) { len_ += len; } -void Buffer::Commit() { - if (start_ == 0) { +void Buffer::Consume() { + if (commit_ == 0) { return; } - memmove(buf_, &buf_[start_], len_ - start_); - len_ -= start_; - start_ = 0; + memmove(buf_, &buf_[commit_], len_ - commit_); + len_ -= commit_; + start_ -= commit_; + commit_ = 0; } diff --git a/buffer.h b/buffer.h index 2bd3cc1..024cbbf 100644 --- a/buffer.h +++ b/buffer.h @@ -12,11 +12,14 @@ class ConstBuffer { template [[nodiscard]] const T *ReadObj(); bool Discard(size_t len); // like Read() but don't use the result + void ResetRead(); // next read from last commit + void Commit(); // commit read position protected: const char *const_buf_; size_t len_; size_t start_ = 0; + size_t commit_ = 0; }; class Buffer : public ConstBuffer { @@ -29,7 +32,7 @@ class Buffer : public ConstBuffer { bool Write(const std::string_view& str); void Wrote(size_t len); - void Commit(); // commit read position + void Consume(); // discard up to last commit protected: std::unique_ptr own_buf_; diff --git a/fastcgi.cc b/fastcgi.cc index e008a85..c2a57b5 100644 --- a/fastcgi.cc +++ b/fastcgi.cc @@ -1,8 +1,8 @@ #include #include #include +#include #include -#include #include "fastcgi.h" #include "fastcgi_conn.h" @@ -14,6 +14,9 @@ FastCGIServer::FastCGIServer(int port, const std::function= 0) << "epoll_create()"; + listen_sock_ = socket(AF_INET6, SOCK_STREAM, 0); PCHECK(listen_sock_ >= 0) << "socket()"; @@ -32,20 +35,58 @@ FastCGIServer::FastCGIServer(int port, const std::function 0) << "epoll_wait()"; - auto client_sock = accept(listen_sock_, (sockaddr*) &client_addr, &client_addr_len); - PCHECK(client_sock >= 0) << "accept()"; - CHECK_EQ(client_addr.sin6_family, AF_INET6); + for (auto i = 0; i < num_fd; ++i) { + if (events[i].data.ptr == nullptr) { + NewConn(); + } else { + auto conn = static_cast(events[i].data.ptr); + if (!conn->Read()) { + PCHECK(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, conn->Sock(), nullptr) == 0); + delete conn; + } + } + } + } +} +void FastCGIServer::NewConn() { + sockaddr_in6 client_addr; + socklen_t client_addr_len = sizeof(client_addr); + + auto client_sock = accept(listen_sock_, (sockaddr*) &client_addr, &client_addr_len); + PCHECK(client_sock >= 0) << "accept()"; + CHECK_EQ(client_addr.sin6_family, AF_INET6); + + { auto *conn = new FastCGIConn(client_sock, client_addr, callback_, headers_); - std::thread thread([conn]() { conn->Serve(); }); - thread.detach(); + struct epoll_event ev{ + .events = EPOLLIN, + .data = { + .ptr = conn, + }, + }; + PCHECK(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, client_sock, &ev) == 0); } } diff --git a/fastcgi.h b/fastcgi.h index 47388bc..88df29f 100644 --- a/fastcgi.h +++ b/fastcgi.h @@ -12,7 +12,10 @@ class FastCGIServer { void Serve(); private: - int listen_sock_; + void NewConn(); + const std::function)> callback_; const std::unordered_set headers_; + int epoll_fd_; + int listen_sock_; }; diff --git a/fastcgi_conn.cc b/fastcgi_conn.cc index b8b1f91..3bb8b11 100644 --- a/fastcgi_conn.cc +++ b/fastcgi_conn.cc @@ -31,16 +31,22 @@ bool FastCGIConn::Write(const std::vector& vecs) { return writev(sock_, vecs.data(), vecs.size()) == total_size; } -void FastCGIConn::Serve() { +bool FastCGIConn::Read() { + if (!buf_.Refill()) { + return false; + } + while (true) { + buf_.ResetRead(); + const auto *header = buf_.ReadObj(); if (!header) { break; } CHECK_EQ(header->version, 1); - if (!buf_.BufferAtLeast(header->ContentLength())) { - return; + if (buf_.ReadMaxLen() < header->ContentLength()) { + break; } switch (header->type) { @@ -95,5 +101,10 @@ void FastCGIConn::Serve() { buf_.Commit(); // we've acted on the bytes read so far } - delete this; + buf_.Consume(); + return true; +} + +int FastCGIConn::Sock() { + return sock_; } diff --git a/fastcgi_conn.h b/fastcgi_conn.h index 8be573b..1db0c47 100644 --- a/fastcgi_conn.h +++ b/fastcgi_conn.h @@ -14,10 +14,11 @@ class FastCGIConn { FastCGIConn(int sock, const sockaddr_in6& client_addr, const std::function)>& callback, const std::unordered_set& headers); ~FastCGIConn(); - void Serve(); - + [[nodiscard]] bool Read(); [[nodiscard]] bool Write(const std::vector& vecs); + [[nodiscard]] int Sock(); + private: const int sock_; const std::function)>& callback_; diff --git a/stream_buffer.cc b/stream_buffer.cc index fbdf645..e02a4cb 100644 --- a/stream_buffer.cc +++ b/stream_buffer.cc @@ -4,23 +4,11 @@ StreamBuffer::StreamBuffer(int sock, size_t size) : Buffer(size), sock_(sock) {} -bool StreamBuffer::BufferAtLeast(size_t len) { - CHECK_LE(start_ + len, size_); - - while (ReadMaxLen() < len) { - auto read_len = read(sock_, WritePtr(), WriteMaxLen()); - PCHECK(read_len >= 0); - if (read_len == 0) { - return false; - } - Wrote(read_len); +bool StreamBuffer::Refill() { + auto read_len = read(sock_, WritePtr(), WriteMaxLen()); + if (read_len == 0) { + return false; } + Wrote(read_len); return true; } - -const char *StreamBuffer::Read(size_t len) { - if (!BufferAtLeast(len)) { - return nullptr; - } - return Buffer::Read(len); -} diff --git a/stream_buffer.h b/stream_buffer.h index 4537a6d..bcfc629 100644 --- a/stream_buffer.h +++ b/stream_buffer.h @@ -6,14 +6,8 @@ class StreamBuffer : public Buffer { public: StreamBuffer(int sock, size_t size); - [[nodiscard]] bool BufferAtLeast(size_t len); - [[nodiscard]] const char *Read(size_t len) override; - template [[nodiscard]] const T *ReadObj(); + [[nodiscard]] bool Refill(); private: int sock_; }; - -template const T *StreamBuffer::ReadObj() { - return reinterpret_cast(Read(sizeof(T))); -}