]> git.sesse.net Git - cubemap/blob - httpinput.h
Fix infinite CPU usage on waitpid().
[cubemap] / httpinput.h
1 #ifndef _HTTPINPUT_H
2 #define _HTTPINPUT_H 1
3
4 #include <stddef.h>
5 #include <mutex>
6 #include <string>
7 #include <vector>
8
9 #include "input.h"
10 #include "metacube2.h"
11 #include "stream.h"
12
13 class InputProto;
14
15 // Despite the name, covers input over both HTTP and pipes, both typically
16 // wrapped in Metacube.
17 class HTTPInput : public Input {
18 public:
19         HTTPInput(const std::string &url, Input::Encoding encoding);
20
21         // Serialization/deserialization.
22         HTTPInput(const InputProto &serialized);
23         virtual InputProto serialize() const;
24         
25         virtual void close_socket();
26
27         virtual std::string get_url() const { return url; }
28
29         virtual void add_destination(int stream_index);
30
31         virtual InputStats get_stats() const;
32
33 private:
34         // Actually does the download.
35         virtual void do_work();
36         
37         // Open a socket that connects to the given host and port. Does DNS resolving.
38         int lookup_and_connect(const std::string &host, const std::string &port);
39
40         // Open a child process with the given command line (given to /bin/sh).
41         // Returns a pipe to its standard output.
42         int open_child_process(const std::string &cmdline);
43
44         // Parses a HTTP response. Returns false if it not a 200.
45         bool parse_response(const std::string &response);
46
47         // Stores the given data, looks for Metacube blocks (skipping data if needed),
48         // and calls process_block() for each one.
49         void process_data(char *ptr, size_t bytes);
50
51         // Drops <num_bytes> bytes from the head of <pending_data>,
52         // and outputs a warning.
53         void drop_pending_data(size_t num_bytes);
54
55         void process_metacube_metadata_block(const metacube2_block_header &hdr, const char *payload, uint32_t payload_size);
56
57         enum State {
58                 NOT_CONNECTED,
59                 SENDING_REQUEST,
60                 RECEIVING_HEADER,
61                 RECEIVING_DATA,
62                 CLOSING_SOCKET,  // Due to error.
63         };
64         State state;
65
66         std::vector<int> stream_indices;
67
68         // The URL and its parsed components.
69         std::string url;
70         std::string host, port, path;
71
72         // What the input stream is to be interpreted as (normally Metacube).
73         Input::Encoding encoding;
74
75         // The HTTP request, with headers and all.
76         // Only relevant for SENDING_REQUEST.
77         std::string request;
78
79         // How many bytes we've sent of the request so far.
80         // Only relevant for SENDING_REQUEST.
81         size_t request_bytes_sent;
82
83         // The HTTP response we've received so far. Only relevant for RECEIVING_HEADER.
84         std::string response;
85
86         // The HTTP response headers we want to give clients for this input.
87         std::string http_header;
88
89         // The stream heder we want to give clients for this input.
90         std::string stream_header;
91
92         // Data we have received but not fully processed yet.
93         std::vector<char> pending_data;
94
95         // If <pending_data> starts with a Metacube header,
96         // this is true.
97         bool has_metacube_header = false;
98
99         // The socket we are downloading on (or -1).
100         int sock = -1;
101
102         // Mutex protecting <stats>.
103         mutable std::mutex stats_mutex;
104
105         // The current statistics for this connection. Protected by <stats_mutex>.
106         InputStats stats;
107
108         // Number of (started) connection attempts since last data byte was successfully read.
109         unsigned num_connection_attempts = 0;
110
111         // If set, don't log anything related to connections.
112         // (Only set if we've had enough unsuccessful connection attempts.)
113         bool suppress_logging = false;
114
115         // Last time we made a connection with logging enabled.
116         // (Initially at some point before the epoch.)
117         timespec last_verbose_connection { -3600, 0 };
118
119         // If we've received a Metacube2 PTS metadata block, it belongs to the
120         // next regular block we receive, and is stored here in the meantime.
121         // If we haven't received one yet (or we've already received the
122         // corresponding data block), this is empty, ie., timebase_num == 0.
123         RationalPTS next_block_pts;
124 };
125
126 #endif  // !defined(_HTTPINPUT_H)