Rename openpli-streamproxy to external.
[vuplus_transtreamproxy] / src / Utils.cpp
1 /*
2  * Utils.cpp
3  *
4  *  Created on: 2014. 6. 10.
5  *      Author: oskwon
6  */
7
8 #include <errno.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <dirent.h>
12 #include <signal.h>
13 #include <sys/wait.h>
14
15 #include <arpa/inet.h>
16 #include <sys/socket.h>
17
18 #include <sstream>
19 #include <fstream>
20
21 #include "mpegts.h"
22
23 #include "Utils.h"
24 #include "Logger.h"
25 #include "UriDecoder.h"
26
27 using namespace std;
28 //----------------------------------------------------------------------
29
30 std::string ultostr(int64_t data)
31 {
32         std::stringstream ss;
33         ss << data;
34         return ss.str();
35 }
36 //----------------------------------------------------------------------
37
38 int strtollu(std::string data)
39 {
40         long long retval;
41         std::stringstream ss;
42         try {
43                 ss.str(data);
44                 ss >> retval;
45         }
46         catch(...) {
47                 return -1;
48         }
49         return retval;
50 }
51 //----------------------------------------------------------------------
52
53 std::string trim(std::string& s, const std::string& drop)
54 {
55         std::string r = s.erase(s.find_last_not_of(drop) + 1);
56         return r.erase(0, r.find_first_not_of(drop));
57 }
58 //----------------------------------------------------------------------
59
60 int split(std::string data, const char delimiter, std::vector<string>& tokens)
61 {
62         std::stringstream data_stream(data);
63         for(std::string token; std::getline(data_stream, token, delimiter); tokens.push_back(trim(token)));
64         return tokens.size();
65 }
66 //----------------------------------------------------------------------
67
68 bool split_key_value(std::string data, std::string delimiter, std::string &key, std::string &value)
69 {
70         int idx = data.find(delimiter);
71         if (idx == string::npos) {
72                 WARNING("split key & value (data : %s, delimiter : %s)", data.c_str(), delimiter.c_str());
73                 return false;
74         }
75         key = data.substr(0, idx);
76         value = data.substr(idx+1, data.length()-idx);
77         return true;
78 }
79 //----------------------------------------------------------------------
80
81 std::string read_request()
82 {
83         std::string request = "";
84         while (true) {
85                 char buffer[128] = {0};
86                 fgets(buffer, 127, stdin);
87
88                 request += buffer;
89                 if(request.find("\r\n\r\n") != string::npos)
90                         break;
91         }
92         return request;
93 }
94 //----------------------------------------------------------------------
95
96 bool RequestHeader::parse_header(std::string header)
97 {
98         std::vector<string> lines;
99         split(header, '\n', lines);
100
101         DEBUG("header lines count : %d", lines.size());
102         std::vector<string>::iterator iter = lines.begin();
103         std::vector<string> infos;
104         if (split(*iter, ' ', infos) != 3) {
105                 ERROR("fail to parse info : %d", infos.size());
106                 return false;
107         }
108
109         type    = REQ_TYPE_TRANSCODING_LIVE;
110         method  = infos[0];
111         path    = infos[1];
112         version = infos[2];
113
114         if (strncmp(path.c_str(), "/file", 5) == 0) {
115                 std::vector<std::string> tokens;
116                 if (split(path.substr(6), '&', tokens) > 0) {
117                         for (int i = 0; i < tokens.size(); ++i) {
118                                 std::string data = tokens[i];
119                                 std::string key = "", value = "";
120                                 if (!split_key_value(data, "=", key, value)) {
121                                         ERROR("fail to request : %s", data.c_str());
122                                         continue;
123                                 }
124                                 if (key == "file") {
125                                         extension[key] = UriDecoder().decode(value.c_str());;
126                                         continue;
127                                 }
128                                 extension[key] = value;
129                         }
130                 }
131                 type = REQ_TYPE_TRANSCODING_FILE;
132
133 //              DEBUG(":: HEADER :: %s", extension["file"].c_str());
134 //              std::map<std::string, std::string>::iterator iter = extension.begin();
135 //              for (; iter != extension.end(); ++iter) {
136 //                      std::string key = iter->first;
137 //                      std::string value = iter->second;
138 //                      DEBUG("[%s] -> [%s]", key.c_str(), value.c_str());
139 //              }
140         }
141         DEBUG("info (%d) -> type : [%s], path : [%s], version : [%s]", infos.size(), method.c_str(), path.c_str(), version.c_str());
142
143         for (++iter; iter != lines.end(); ++iter) {
144                 std::string key = "", value = "";
145                 if (!split_key_value(*iter, ":", key, value))
146                         continue;
147                 if (key == "")
148                         continue;
149                 key = trim(key);
150                 value = trim(value);
151
152                 if (key.length() > 0) {
153                         params[key] = value;
154                         DEBUG("add params : %s -> %s", key.c_str(), value.c_str());
155                 }
156         }
157         return true;
158 }
159 //----------------------------------------------------------------------
160
161 off_t make_response(ThreadParams *params, std::string& response)
162 {
163         response = "";
164
165         LINESTAMP();
166
167         off_t byte_offset = 0;
168         RequestHeader *header = ((ThreadParams*) params)->request;
169         switch(header->type) {
170         case REQ_TYPE_TRANSCODING_FILE: {
171                         MpegTS *source = (MpegTS*)((ThreadParams*) params)->source;
172
173                         std::string range = header->params["Range"];
174                         if((range.length() > 7) && (range.substr(0, 6) == "bytes=")) {
175                                 range = range.substr(6);
176                                 if(range.find('-') == (range.length() - 1)) {
177                                         byte_offset = strtollu(range);
178                                 }
179                         }
180
181                         off_t content_length = source->stream_length - byte_offset;
182                         if (byte_offset > 0) {
183                                 content_length += 1;
184                                 response += HTTP_PARTIAL;
185                         }
186                         else {
187                                 response += HTTP_OK;
188                         }
189                         response += HTTP_PARAMS;
190                         response += "Accept-Ranges: bytes\r\n"
191                                             "Content-Length: " + ultostr(content_length) + "\r\n";
192                         response += string("Content-Range: bytes ") +
193                                         ultostr(byte_offset) + "-" +
194                                         ultostr(source->stream_length - 1) + "/" +
195                                         ultostr(source->stream_length) + "\r\n";
196                         response += HTTP_DONE;
197                 }
198                 break;
199         case REQ_TYPE_TRANSCODING_LIVE: {
200                         response += HTTP_OK;
201                         response += HTTP_PARAMS;
202                         response += HTTP_DONE;
203                 }
204                 break;
205         default: return -1;
206         }
207         return byte_offset;
208 }
209 //----------------------------------------------------------------------
210
211 void Util::vlog(const char * format, ...) throw()
212 {
213         static char vlog_buffer[MAX_PRINT_LEN];
214     memset(vlog_buffer, 0, MAX_PRINT_LEN);
215
216     va_list args;
217         va_start(args, format);
218         vsnprintf(vlog_buffer, MAX_PRINT_LEN-1, format, args);
219         va_end(args);
220
221         WARNING("%s", vlog_buffer);
222 }
223 //----------------------------------------------------------------------
224
225 std::string get_host_addr()
226 {
227         std::stringstream ss;
228     struct sockaddr_in addr;
229     socklen_t addrlen = sizeof(addr);
230
231     getpeername(0, (struct sockaddr*)&addr, &addrlen);
232     ss << inet_ntoa(addr.sin_addr);
233
234     return ss.str();
235 }
236 //-------------------------------------------------------------------------------
237
238 std::vector<int> find_process_by_name(std::string name, int mypid)
239 {
240         std::vector<int> pidlist;
241         char cmdlinepath[256] = {0};
242         DIR* d = opendir("/proc");
243         if (d != 0) {
244                 struct dirent* de;
245                 while ((de = readdir(d)) != 0) {
246                         int pid = atoi(de->d_name);
247                         if (pid > 0) {
248                                 sprintf(cmdlinepath, "/proc/%s/cmdline", de->d_name);
249
250                                 std::string cmdline;
251                                 std::ifstream cmdlinefile(cmdlinepath);
252                                 std::getline(cmdlinefile, cmdline);
253                                 if (!cmdline.empty()) {
254                                         size_t pos = cmdline.find('\0');
255                                         if (pos != string::npos)
256                                         cmdline = cmdline.substr(0, pos);
257                                         pos = cmdline.rfind('/');
258                                         if (pos != string::npos)
259                                         cmdline = cmdline.substr(pos + 1);
260                                         if ((name == cmdline) && ((mypid != pid) || (mypid == 0))) {
261                                                 pidlist.push_back(pid);
262                                         }
263                                 }
264                         }
265                 }
266                 closedir(d);
267         }
268         return pidlist;
269 }
270 //-------------------------------------------------------------------------------
271
272 void kill_process(int pid)
273 {
274         int result = kill(pid, SIGINT);
275         DEBUG("SEND SIGINT to %d, result : %d", pid, result);
276         sleep(1);
277 }
278 //----------------------------------------------------------------------