4 #include <netinet/in.h>
19 Stream::Stream(const string &url, size_t backlog_size, Encoding encoding)
22 data_fd(make_tempfile("")),
23 backlog_size(backlog_size),
39 Stream::Stream(const StreamProto &serialized, int data_fd)
40 : url(serialized.url()),
41 http_header(serialized.http_header()),
42 stream_header(serialized.stream_header()),
43 encoding(Stream::STREAM_ENCODING_RAW), // Will be changed later.
45 backlog_size(serialized.backlog_size()),
46 bytes_received(serialized.bytes_received()),
53 // Split old-style headers into HTTP and video headers.
54 if (!serialized.header().empty()) {
55 string header = serialized.header();
56 size_t split = header.find("\r\n\r\n");
57 if (split == string::npos) {
61 http_header = header.substr(0, split + 2); // Split off the second \r\n.
62 stream_header = header.substr(split, string::npos);
67 StreamProto Stream::serialize()
69 StreamProto serialized;
70 serialized.set_http_header(http_header);
71 serialized.set_stream_header(stream_header);
72 serialized.add_data_fds(data_fd);
73 serialized.set_backlog_size(backlog_size);
74 serialized.set_bytes_received(bytes_received);
75 serialized.set_url(url);
80 void Stream::set_backlog_size(size_t new_size)
82 if (backlog_size == new_size) {
87 if (!read_tempfile_and_close(data_fd, &existing_data)) {
91 // Unwrap the data so it's no longer circular.
92 if (bytes_received <= backlog_size) {
93 existing_data.resize(bytes_received);
95 size_t pos = bytes_received % backlog_size;
96 existing_data = existing_data.substr(pos, string::npos) +
97 existing_data.substr(0, pos);
100 // See if we need to discard data.
101 if (new_size < existing_data.size()) {
102 size_t to_discard = existing_data.size() - new_size;
103 existing_data = existing_data.substr(to_discard, string::npos);
106 // Create a new, empty data file.
107 data_fd = make_tempfile("");
111 backlog_size = new_size;
113 // Now cheat a bit by rewinding, and adding all the old data back.
114 bytes_received -= existing_data.size();
116 iov.iov_base = const_cast<char *>(existing_data.data());
117 iov.iov_len = existing_data.size();
124 void Stream::put_client_to_sleep(Client *client)
126 sleeping_clients.push_back(client);
129 // Return a new set of iovecs that contains only the first <bytes_wanted> bytes of <data>.
130 vector<iovec> collect_iovecs(const vector<iovec> &data, size_t bytes_wanted)
133 size_t max_iovecs = std::min<size_t>(data.size(), IOV_MAX);
134 for (size_t i = 0; i < max_iovecs && bytes_wanted > 0; ++i) {
135 if (data[i].iov_len <= bytes_wanted) {
136 // Consume the entire iovec.
137 ret.push_back(data[i]);
138 bytes_wanted -= data[i].iov_len;
140 // Take only parts of this iovec.
142 iov.iov_base = data[i].iov_base;
143 iov.iov_len = bytes_wanted;
151 // Return a new set of iovecs that contains all of <data> except the first <bytes_wanted> bytes.
152 vector<iovec> remove_iovecs(const vector<iovec> &data, size_t bytes_wanted)
156 for (i = 0; i < data.size() && bytes_wanted > 0; ++i) {
157 if (data[i].iov_len <= bytes_wanted) {
158 // Consume the entire iovec.
159 bytes_wanted -= data[i].iov_len;
161 // Take only parts of this iovec.
163 iov.iov_base = reinterpret_cast<char *>(data[i].iov_base) + bytes_wanted;
164 iov.iov_len = data[i].iov_len - bytes_wanted;
170 // Add the rest of the iovecs unchanged.
171 ret.insert(ret.end(), data.begin() + i, data.end());
175 void Stream::add_data_raw(const vector<iovec> &orig_data)
177 vector<iovec> data = orig_data;
178 while (!data.empty()) {
179 size_t pos = bytes_received % backlog_size;
181 // Collect as many iovecs as we can before we hit the point
182 // where the circular buffer wraps around.
183 vector<iovec> to_write = collect_iovecs(data, backlog_size - pos);
186 ret = pwritev(data_fd, to_write.data(), to_write.size(), pos);
187 } while (ret == -1 && errno == EINTR);
190 log_perror("pwritev");
191 // Dazed and confused, but trying to continue...
194 bytes_received += ret;
196 // Remove the data that was actually written from the set of iovecs.
197 data = remove_iovecs(data, ret);
201 void Stream::add_data_deferred(const char *data, size_t bytes)
203 if (encoding == Stream::STREAM_ENCODING_METACUBE) {
204 // Add a Metacube block header before the data.
205 metacube_block_header hdr;
206 memcpy(hdr.sync, METACUBE_SYNC, sizeof(hdr.sync));
207 hdr.size = htonl(bytes);
208 hdr.flags = htonl(0);
211 iov.iov_base = new char[bytes + sizeof(hdr)];
212 iov.iov_len = bytes + sizeof(hdr);
214 memcpy(iov.iov_base, &hdr, sizeof(hdr));
215 memcpy(reinterpret_cast<char *>(iov.iov_base) + sizeof(hdr), data, bytes);
217 queued_data.push_back(iov);
218 } else if (encoding == Stream::STREAM_ENCODING_RAW) {
219 // Just add the data itself.
221 iov.iov_base = new char[bytes];
222 memcpy(iov.iov_base, data, bytes);
225 queued_data.push_back(iov);
231 void Stream::process_queued_data()
233 if (queued_data.empty()) {
237 add_data_raw(queued_data);
238 for (size_t i = 0; i < queued_data.size(); ++i) {
239 char *data = reinterpret_cast<char *>(queued_data[i].iov_base);
244 // We have more data, so wake up all clients.
245 if (to_process.empty()) {
246 swap(sleeping_clients, to_process);
248 to_process.insert(to_process.end(), sleeping_clients.begin(), sleeping_clients.end());
249 sleeping_clients.clear();