X-Git-Url: https://git.sesse.net/?p=cubemap;a=blobdiff_plain;f=server.cpp;h=2f55589ac75773af7494417e099b0b58112814db;hp=e9bc654eb1a3cbe4d667f3bafef6119aabec01fa;hb=c687f8878c86e5895d0c4fd955695be0df2576a3;hpb=20e85bd6901355cc40a6cfb4c0deb7232d9aa63f diff --git a/server.cpp b/server.cpp index e9bc654..2f55589 100644 --- a/server.cpp +++ b/server.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -17,6 +19,7 @@ #include #include +#include "ktls.h" #include "tlse.h" #include "acceptor.h" @@ -300,7 +303,7 @@ void Server::add_client_from_serialized(const ClientProto &client, const vector< int Server::lookup_stream_by_url(const string &url) const { - map::const_iterator stream_url_it = stream_url_map.find(url); + const auto stream_url_it = stream_url_map.find(url); if (stream_url_it == stream_url_map.end()) { return -1; } @@ -909,12 +912,12 @@ int Server::parse_request(Client *client) // Parse the headers, for logging purposes. // TODO: Case-insensitivity. - multimap headers = extract_headers(lines, client->remote_addr); - multimap::const_iterator referer_it = headers.find("Referer"); + unordered_multimap headers = extract_headers(lines, client->remote_addr); + const auto referer_it = headers.find("Referer"); if (referer_it != headers.end()) { client->referer = referer_it->second; } - multimap::const_iterator user_agent_it = headers.find("User-Agent"); + const auto user_agent_it = headers.find("User-Agent"); if (user_agent_it != headers.end()) { client->user_agent = user_agent_it->second; } @@ -984,25 +987,25 @@ int Server::parse_request(Client *client) client->close_after_response = true; client->http_11 = false; } else { - multimap::const_iterator connection_it = headers.find("Connection"); + const auto connection_it = headers.find("Connection"); if (connection_it != headers.end() && connection_it->second == "close") { client->close_after_response = true; } } - map::const_iterator stream_url_map_it = stream_url_map.find(url); + const auto stream_url_map_it = stream_url_map.find(url); if (stream_url_map_it != stream_url_map.end()) { // Serve a regular stream.. client->stream = streams[stream_url_map_it->second].get(); client->serving_hls_playlist = false; } else { - map::const_iterator stream_hls_url_map_it = stream_hls_url_map.find(url); + const auto stream_hls_url_map_it = stream_hls_url_map.find(url); if (stream_hls_url_map_it != stream_hls_url_map.end()) { // Serve HLS playlist. client->stream = streams[stream_hls_url_map_it->second].get(); client->serving_hls_playlist = true; } else { - map::const_iterator ping_url_map_it = ping_url_map.find(url); + const auto ping_url_map_it = ping_url_map.find(url); if (ping_url_map_it == ping_url_map.end()) { return 404; // Not found. } else { @@ -1068,7 +1071,7 @@ void Server::construct_stream_header(Client *client) response.append(buf); } else if (client->stream_pos_end != Client::STREAM_POS_NO_END) { char buf[64]; - snprintf(buf, sizeof(buf), "Content-length: %zu\r\n", client->stream_pos_end - client->stream_pos); + snprintf(buf, sizeof(buf), "Content-length: %" PRIu64 "\r\n", client->stream_pos_end - client->stream_pos); response.append(buf); } if (client->http_11) { @@ -1165,7 +1168,7 @@ void Server::construct_hls_playlist(Client *client) void Server::construct_204(Client *client) { - map::const_iterator ping_url_map_it = ping_url_map.find(client->url); + const auto ping_url_map_it = ping_url_map.find(client->url); assert(ping_url_map_it != ping_url_map.end()); string response; @@ -1193,12 +1196,49 @@ void Server::construct_204(Client *client) change_epoll_events(client, EPOLLOUT | EPOLLET | EPOLLRDHUP); } +namespace { + template void delete_from(vector *v, T elem) { typename vector::iterator new_end = remove(v->begin(), v->end(), elem); v->erase(new_end, v->end()); } + +void send_ktls_close(int sock) +{ + uint8_t record_type = 21; // Alert. + uint8_t body[] = { + 1, // Warning level (but still fatal!). + 0, // close_notify. + }; + + int cmsg_len = sizeof(record_type); + char buf[CMSG_SPACE(cmsg_len)]; + + msghdr msg = {0}; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_TLS; + cmsg->cmsg_type = TLS_SET_RECORD_TYPE; + cmsg->cmsg_len = CMSG_LEN(cmsg_len); + *CMSG_DATA(cmsg) = record_type; + msg.msg_controllen = cmsg->cmsg_len; + + iovec msg_iov; + msg_iov.iov_base = body; + msg_iov.iov_len = sizeof(body); + msg.msg_iov = &msg_iov; + msg.msg_iovlen = 1; + + int err; + do { + err = sendmsg(sock, &msg, 0); + } while (err == -1 && errno == EINTR); // Ignore all other errors. +} + +} // namespace void Server::close_client(Client *client) { @@ -1214,6 +1254,10 @@ void Server::close_client(Client *client) } if (client->tls_context) { + if (client->in_ktls_mode) { + // Keep GnuTLS happy. + send_ktls_close(client->sock); + } tls_destroy_context(client->tls_context); } @@ -1247,6 +1291,14 @@ bool Server::more_requests(Client *client) // Log to access_log. access_log->write(client->get_stats()); + // Flush pending data; does not cancel out TCP_CORK (since that still takes priority), + // but does a one-off flush. + int one = 1; + if (setsockopt(client->sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) == -1) { + log_perror("setsockopt(TCP_NODELAY)"); + // Can still continue. + } + // Switch states and reset the parsers. We don't reset statistics. client->state = Client::READING_REQUEST; client->url.clear();