Lots of file splits

This commit is contained in:
Ian Gulliver
2019-04-28 00:17:32 +00:00
parent 731da3c769
commit 8a2a19ac37
9 changed files with 298 additions and 32 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
mirall
*.o

View File

@@ -1,5 +1,8 @@
mirall: Makefile mirall.cpp
g++ -std=gnu++2a -o mirall mirall.cpp -lgflags -lglog
mirall: Makefile mirall.o fastcgi.o fastcgi_conn.o buffer.o
g++ -std=gnu++2a -o mirall mirall.o fastcgi.o fastcgi_conn.o buffer.o -lgflags -lglog -lpthread
clean:
rm --force mirall
rm --force mirall *.o
.cpp.o: Makefile *.h
g++ -std=gnu++2a -o $@ -c $<

66
buffer.cpp Normal file
View File

@@ -0,0 +1,66 @@
#include "buffer.h"
ConstBuffer::ConstBuffer(const char *buf, size_t len)
: const_buf_(buf),
len_(len) {}
size_t ConstBuffer::ReadMaxLen() const {
return len_ - start_;
}
const char *ConstBuffer::Read(size_t len) {
CHECK_LE(len, ReadMaxLen());
const auto *ret = &const_buf_[start_];
start_ += len;
return ret;
}
bool ConstBuffer::Discard(size_t len) {
if (len > ReadMaxLen()) {
return false;
}
Read(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),
buf_(buf),
size_(size) {
len_ = len;
}
Buffer::Buffer(size_t size)
: Buffer((own_buf_.reset(new char[size]), own_buf_.get()), size, 0) {}
char *Buffer::WritePtr() {
return &buf_[len_];
}
size_t Buffer::WriteMaxLen() const {
return size_ - len_;
}
void Buffer::Wrote(size_t len) {
CHECK_LE(len, WriteMaxLen());
len_ += len;
}
void Buffer::Consume() {
if (commit_ == 0) {
return;
}
memmove(buf_, &buf_[commit_], len_ - commit_);
len_ -= commit_;
start_ -= commit_;
commit_ = 0;
}

48
buffer.h Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <glog/logging.h>
#include <memory>
class ConstBuffer {
public:
ConstBuffer(const char *buf, size_t len);
size_t ReadMaxLen() const;
const char *Read(size_t len);
template<class T> 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 {
public:
Buffer(const char *buf, size_t len) = delete;
Buffer(char *buf, size_t size, size_t len);
Buffer(size_t size);
char *WritePtr();
size_t WriteMaxLen() const;
void Wrote(size_t len);
void Consume(); // discard up to last commit
private:
std::unique_ptr<char> own_buf_;
char *buf_;
const size_t size_;
};
template<class T> const T *ConstBuffer::ReadObj() {
if (ReadMaxLen() < sizeof(T)) {
return nullptr;
}
return reinterpret_cast<const T*>(Read(sizeof(T)));
}

47
fastcgi.cpp Normal file
View File

@@ -0,0 +1,47 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <thread>
#include "fastcgi.h"
#include "fastcgi_conn.h"
FastCGIServer::FastCGIServer(int port) {
LOG(INFO) << "listening on [::1]:" << port;
listen_sock_ = socket(AF_INET6, SOCK_STREAM, 0);
PCHECK(listen_sock_ >= 0) << "socket()";
{
int optval = 1;
PCHECK(setsockopt(listen_sock_, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == 0);
}
{
sockaddr_in6 bind_addr = {
.sin6_family = AF_INET6,
.sin6_port = htons(port),
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
};
PCHECK(bind(listen_sock_, (sockaddr*) &bind_addr, sizeof(bind_addr)) == 0);
}
PCHECK(listen(listen_sock_, 128) == 0);
}
void FastCGIServer::Serve() {
while (true) {
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);
std::thread thread([conn]() { conn->Serve(); });
thread.detach();
}
}

10
fastcgi.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
class FastCGIServer {
public:
FastCGIServer(int port);
void Serve();
private:
int listen_sock_;
};

97
fastcgi_conn.cpp Normal file
View File

@@ -0,0 +1,97 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include "fastcgi_conn.h"
namespace {
struct fcgi_header {
uint8_t version;
uint8_t type;
private:
uint16_t request_id_; // network byte order
uint16_t content_length_; // network byte order
public:
uint8_t padding_length;
uint8_t reserved;
uint16_t ContentLength() const { return htons(content_length_); }
};
struct fcgi_begin_request {
uint16_t role; // network byte order
uint8_t flags;
uint8_t reserved[5];
};
constexpr auto fcgi_max_content_len = 65535;
constexpr auto fcgi_max_padding_len = 255;
constexpr auto fcgi_max_record_len = sizeof(fcgi_header) + fcgi_max_content_len + fcgi_max_padding_len;
} // namespace
FastCGIConn::FastCGIConn(int sock, const sockaddr_in6& client_addr)
: sock_(sock),
buf_(fcgi_max_record_len) {
char client_addr_str[INET6_ADDRSTRLEN];
PCHECK(inet_ntop(AF_INET6, &client_addr.sin6_addr, client_addr_str, sizeof(client_addr_str)));
LOG(INFO) << "new connection: [" << client_addr_str << "]:" << ntohs(client_addr.sin6_port);
}
FastCGIConn::~FastCGIConn() {
PCHECK(close(sock_) == 0);
LOG(INFO) << "connection closed";
}
void FastCGIConn::Serve() {
while (true) {
auto read_len = read(sock_, buf_.WritePtr(), buf_.WriteMaxLen());
PCHECK(read_len >= 0);
if (read_len == 0) {
LOG(INFO) << "peer closed connection";
}
buf_.Wrote(read_len);
ParseBuf();
buf_.Consume(); // free buffer tail space for next read
}
}
void FastCGIConn::ParseBuf() {
buf_.ResetRead();
while (true) {
const auto *header = buf_.ReadObj<fcgi_header>();
if (!header) {
return;
}
CHECK_EQ(header->version, 1);
if (buf_.ReadMaxLen() < header->ContentLength() + header->padding_length) {
return;
}
LOG(INFO) << "type: " << (int)header->type;
switch (header->type) {
case 1:
{
CHECK_EQ(header->ContentLength(), sizeof(fcgi_begin_request));
const auto *begin_request = CHECK_NOTNULL(buf_.ReadObj<fcgi_begin_request>());
CHECK_EQ(ntohs(begin_request->role), 1);
}
break;
case 4:
{
const auto *params = buf_.Read(header->ContentLength());
}
break;
}
CHECK(buf_.Discard(header->padding_length));
buf_.Commit(); // we've acted on the bytes read so far
}
}

19
fastcgi_conn.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "buffer.h"
struct sockaddr_in6;
class FastCGIConn {
public:
FastCGIConn(int sock, const sockaddr_in6& client_addr);
~FastCGIConn();
void Serve();
private:
void ParseBuf();
const int sock_;
Buffer buf_;
};

View File

@@ -1,8 +1,7 @@
#include <arpa/inet.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "fastcgi.h"
DEFINE_int32(port, 9000, "TCP port to bind");
@@ -10,30 +9,6 @@ int main(int argc, char *argv[]) {
google::InitGoogleLogging(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
auto listen_sock = socket(AF_INET6, SOCK_STREAM, 0);
PCHECK(listen_sock >= 0) << "socket()";
sockaddr_in6 bind_addr = {
.sin6_family = AF_INET6,
.sin6_port = htons(FLAGS_port),
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
};
PCHECK(bind(listen_sock, (sockaddr*) &bind_addr, sizeof(bind_addr)) == 0);
PCHECK(listen(listen_sock, 128) == 0);
while (true) {
sockaddr_in6 client_addr;
socklen_t client_addr_len = sizeof(client_addr);
auto sock = accept(listen_sock, (sockaddr*) &client_addr, &client_addr_len);
PCHECK(sock >= 0) << "accept()";
CHECK_EQ(client_addr.sin6_family, AF_INET6);
char client_addr_str[INET6_ADDRSTRLEN];
PCHECK(inet_ntop(AF_INET6, &client_addr.sin6_addr, client_addr_str, sizeof(client_addr_str)));
LOG(INFO) << "new connection: [" << client_addr_str << "]:" << ntohs(client_addr.sin6_port);
}
FastCGIServer server(FLAGS_port);
server.Serve();
}