From eb33692c9edee93e0883cd9f980d48dc7e17d801 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 6 Apr 2013 17:47:44 +0200 Subject: [PATCH 1/1] Implement header sending. --- server.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++---------- server.h | 15 ++++++++++--- 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/server.cpp b/server.cpp index 25da16c..0b399e4 100644 --- a/server.cpp +++ b/server.cpp @@ -94,13 +94,15 @@ void Server::add_client(int sock) void Server::add_stream(const string &stream_id) { - // TODO + MutexLock lock(&mutex); + streams.insert(make_pair(stream_id, Stream())); } void Server::set_header(const string &stream_id, const string &header) { - // TODO - printf("got header! %lu bytes\n", header.size()); + MutexLock lock(&mutex); + assert(streams.count(stream_id) != 0); + streams[stream_id].header = header; } void Server::add_data(const string &stream_id, const char *data, size_t bytes) @@ -155,23 +157,62 @@ void Server::process_client(Client *client) return; } - client->state = Client::SENDING_HEADER; - - epoll_event ev; - ev.events = EPOLLOUT | EPOLLRDHUP; - ev.data.fd = client->sock; + parse_request(client); + break; + } + case Client::SENDING_HEADER: { + int ret = write(client->sock, + client->header.data() + client->header_bytes_sent, + client->header.size() - client->header_bytes_sent); + if (ret == -1) { + perror("write"); + close_client(client); + return; + } + + client->header_bytes_sent += ret; + assert(client->header_bytes_sent <= client->header.size()); - if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, client->sock, &ev) == -1) { - perror("epoll_ctl(EPOLL_CTL_MOD)"); - exit(1); + if (client->header_bytes_sent < client->header.size()) { + // We haven't sent all yet. Fine; we'll do that later. + return; } - break; + + // We're done sending the header! Clear the entire header to release some memory. + client->header.clear(); + + // Start sending from the end. In other words, we won't send any of the backlog, + // but we'll start sending immediately as we get data. + client->state = Client::SENDING_DATA; + client->bytes_sent = streams[client->stream_id].data_size; } default: // TODO assert(false); } } + +void Server::parse_request(Client *client) +{ + // TODO: Actually parse the request. :-) + client->stream_id = "stream"; + + // Construct the header. + client->header = "HTTP/1.0 200 OK\r\nContent-type: todo/fixme\r\n\r\n" + + streams[client->stream_id].header; + + // Switch states. + client->state = Client::SENDING_HEADER; + + epoll_event ev; + ev.events = EPOLLOUT | EPOLLRDHUP; + ev.data.fd = client->sock; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, client->sock, &ev) == -1) { + perror("epoll_ctl(EPOLL_CTL_MOD)"); + exit(1); + } +} void Server::close_client(Client *client) { diff --git a/server.h b/server.h index c44b81e..f1cc7a0 100644 --- a/server.h +++ b/server.h @@ -23,11 +23,14 @@ struct Client { // this might not be finished. std::string client_request; -#if 0 // What stream we're connecting to; parsed from client_request. // Not relevant for READING_REQUEST. - string stream_id; -#endif + std::string stream_id; + + // The header we want to send. This is nominally a copy of Stream::header, + // but since that might change on reconnects etc., we keep a local copy here. + // Only relevant for SENDING_HEADER; blank otherwise. + std::string header; // Number of bytes we've sent of the header. Only relevant for SENDING_HEADER. size_t header_bytes_sent; @@ -61,8 +64,14 @@ public: private: void process_client(Client *client); + + // Close a given client socket, and clean up after it. void close_client(Client *client); + // Parse the HTTP request, construct the header, and set the client into + // the SENDING_HEADER state. + void parse_request(Client *client); + pthread_mutex_t mutex; // Map from stream ID to stream. -- 2.39.2