Server::Server()
{
- epoll_fd = epoll_create(1024); // Size argument is ignored.
+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
log_perror("epoll_fd");
exit(1);
{
lock_guard<mutex> lock(mu);
assert(stream_index >= 0 && stream_index < ssize_t(streams.size()));
- assert(hls_backlog_margin >= 0);
assert(hls_backlog_margin < streams[stream_index]->backlog_size);
streams[stream_index]->hls_backlog_margin = hls_backlog_margin;
}
{
lock_guard<mutex> lock(mu);
assert(stream_index >= 0 && stream_index < ssize_t(streams.size()));
- Stream *stream = streams[stream_index].get();
- stream->http_header = http_header;
-
- if (stream_header != stream->stream_header) {
- // We cannot start at any of the older starting points anymore,
- // since they'd get the wrong header for the stream (not to mention
- // that a changed header probably means the stream restarted,
- // which means any client starting on the old one would probably
- // stop playing properly at the change point). Next block
- // should be a suitable starting point (if not, something is
- // pretty strange), so it will fill up again soon enough.
- stream->suitable_starting_points.clear();
-
- if (!stream->fragments.empty()) {
- stream->fragments.clear();
- ++stream->discontinuity_counter;
- stream->clear_hls_playlist_cache();
- }
- }
- stream->stream_header = stream_header;
+ streams[stream_index]->set_header(http_header, stream_header);
+}
+
+void Server::set_unavailable(int stream_index)
+{
+ lock_guard<mutex> lock(mu);
+ assert(stream_index >= 0 && stream_index < ssize_t(streams.size()));
+ streams[stream_index]->set_unavailable();
}
void Server::set_pacing_rate(int stream_index, uint32_t pacing_rate)
{
switch (client->state) {
case Client::READING_REQUEST: {
- if (client->tls_context != nullptr) {
+ if (client->tls_context != nullptr && !client->in_ktls_mode) {
if (send_pending_tls_data(client)) {
// send_pending_tls_data() hit postconditions #1 or #4.
return;
// Try to read more of the request.
char buf[1024];
int ret;
- if (client->tls_context == nullptr) {
- ret = read_nontls_data(client, buf, sizeof(buf));
+ if (client->tls_context == nullptr || client->in_ktls_mode) {
+ ret = read_plain_data(client, buf, sizeof(buf));
if (ret == -1) {
- // read_nontls_data() hit postconditions #1 or #2.
+ // read_plain_data() hit postconditions #1 or #2.
return;
}
} else {
assert(status == RP_FINISHED);
- if (client->tls_context && !client->in_ktls_mode && tls_established(client->tls_context)) {
- // We're ready to enter kTLS mode, unless we still have some
- // handshake data to send (which then must be sent as non-kTLS).
- if (send_pending_tls_data(client)) {
- // send_pending_tls_data() hit postconditions #1 or #4.
- return;
- }
- ret = tls_make_ktls(client->tls_context, client->sock);
- if (ret < 0) {
- log_tls_error("tls_make_ktls", ret);
- close_client(client);
- return;
- }
- client->in_ktls_mode = true;
- }
-
int error_code = parse_request(client);
if (error_code == 200) {
if (client->serving_hls_playlist) {
} else if (client->stream_pos_end != Client::STREAM_POS_NO_END) {
// We're sending a fragment, and should have all of it,
// so start sending right away.
- assert(client->stream_pos >= 0);
+ assert(ssize_t(client->stream_pos) >= 0);
client->state = Client::SENDING_DATA;
goto sending_data;
} else if (stream->prebuffering_bytes == 0) {
// 100 kB prebuffer but end up sending a 10 MB GOP.
assert(client->stream_pos == Client::STREAM_POS_AT_END);
assert(client->stream_pos_end == Client::STREAM_POS_NO_END);
- deque<size_t>::const_iterator starting_point_it =
+ deque<uint64_t>::const_iterator starting_point_it =
lower_bound(stream->suitable_starting_points.begin(),
stream->suitable_starting_points.end(),
stream->bytes_received - stream->prebuffering_bytes);
goto send_data_again;
}
-int Server::read_nontls_data(Client *client, char *buf, size_t max_size)
+int Server::read_plain_data(Client *client, char *buf, size_t max_size)
{
int ret;
do {
int Server::read_tls_data(Client *client, char *buf, size_t max_size)
{
read_again:
+ assert(!client->in_ktls_mode);
+
int ret;
do {
ret = read(client->sock, buf, max_size);
return -1;
}
+ if (tls_established(client->tls_context)) {
+ // We're ready to enter kTLS mode, unless we still have some
+ // handshake data to send (which then must be sent as non-kTLS).
+ if (send_pending_tls_data(client)) {
+ // send_pending_tls_data() hit postconditions #1 or #4.
+ return -1;
+ }
+ int err = tls_make_ktls(client->tls_context, client->sock); // Don't overwrite ret.
+ if (err < 0) {
+ log_tls_error("tls_make_ktls", ret);
+ close_client(client);
+ return -1;
+ }
+ client->in_ktls_mode = true;
+ }
+
assert(ret > 0);
return ret;
}
}
Stream *stream = client->stream;
- if (stream->http_header.empty()) {
- return 503; // Service unavailable.
- }
if (client->serving_hls_playlist) {
if (stream->encoding == Stream::STREAM_ENCODING_METACUBE) {
}
if (client->stream_pos_end == Client::STREAM_POS_NO_END) {
+ if (stream->unavailable) {
+ return 503; // Service unavailable.
+ }
+
// This stream won't end, so we don't have a content-length,
// and can just as well tell the client it's Connection: close
// (otherwise, we'd have to implement chunking TE for no good reason).