Advertisement
Guest User

Untitled

a guest
Oct 23rd, 2019
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.50 KB | None | 0 0
  1. #include "miProxy.h"
  2. #include <iostream>
  3. #include <string>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <errno.h>
  7. #include <unistd.h>
  8. #include <arpa/inet.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <sys/time.h>
  13. #include <netdb.h>
  14. #include <array>
  15. #include <thread>
  16. #include <mutex>
  17. #include <cmath>
  18. #include <chrono>
  19. #include <bits/stdc++.h>
  20. using namespace std;
  21.  
  22. #define MAXCLIENTS 30
  23.  
  24. map<string, vector<int>> BITRATE_INFO;
  25. mutex bitrate_info_mutex;
  26.  
  27. void reply_to_client(int client_sock, string title, string request_header, string ip);
  28.  
  29. void VideoServer::init(int argc, char** argv) {
  30. if (!strcmp(argv[1], "--nodns")) {
  31. using_dns = false;
  32. listen_port = stoi(argv[2]);
  33. ip = argv[3];
  34. alpha = stod(argv[4]);
  35. log_path = argv[5];
  36. dns_port = -1;
  37. }
  38. else {
  39. using_dns = true;
  40. listen_port = stoi(argv[2]);
  41. ip = argv[3];
  42. dns_port = stoi(argv[4]);
  43. alpha = stod(argv[5]);
  44. log_path = argv[6];
  45. }
  46. logfile.open(log_path);
  47. }
  48.  
  49. void VideoServer::write_to_log(string log) {
  50. log_mutex.lock();
  51. logfile << log << endl;
  52. log_mutex.unlock();
  53. }
  54.  
  55. int VideoServer::get_master_socket(struct sockaddr_in * address){
  56. int yes = 1;
  57. int master_socket;
  58. master_socket = socket(AF_INET, SOCK_STREAM, 0);
  59. if(master_socket <= 0) {
  60. perror("socket failed");
  61. exit(EXIT_FAILURE);
  62. }
  63. int success = setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
  64. if(success < 0) {
  65. perror("setsockopt");
  66. exit(EXIT_FAILURE);
  67. }
  68. address->sin_family = AF_INET;
  69. address->sin_addr.s_addr = INADDR_ANY;
  70. address->sin_port = htons(listen_port);
  71. success = ::bind(master_socket, (struct sockaddr *)address, sizeof(*address));
  72. if (success < 0) {
  73. perror("bind failed");
  74. exit(EXIT_FAILURE);
  75. }
  76. printf("---Listening on port %d---\n", listen_port);
  77. if (listen(master_socket, 3) < 0) {
  78. perror("listen");
  79. exit(EXIT_FAILURE);
  80. }
  81. return master_socket;
  82. }
  83.  
  84. string get_title(string header) {
  85. int tou = header.find("GET ");
  86. int wei = header.find(" HTTP");
  87. return header.substr(tou + 4, wei - tou - 4);
  88. }
  89.  
  90. int VideoServer::find_max_sd(fd_set * readfds, int * client_fds, int length, int max_sd) {
  91. int sd = -1;
  92. for (int i = 0; i < length; ++i) {
  93. sd = client_fds[i];
  94. if(sd > 0)
  95. FD_SET(sd, readfds);
  96. if(sd > max_sd)
  97. max_sd = sd;
  98. }
  99. return max_sd;
  100. }
  101.  
  102. void VideoServer::start_listening() {
  103. struct sockaddr_in address;
  104. master_socket = get_master_socket(&address);
  105. client_sockets.fill(0);
  106. addrlen = sizeof(address);
  107. char buffer[1024];
  108. bzero(buffer, 1024);
  109.  
  110. fd_set readfds;
  111. while(true) {
  112. //clear the socket set
  113. FD_ZERO(&readfds);
  114.  
  115. //add master socket to set
  116. FD_SET(master_socket, &readfds);
  117. for (const auto & client_sock: client_sockets){
  118. if (client_sock != 0){
  119. FD_SET(client_sock, &readfds);
  120. }
  121. }
  122. //wait for an activity on one of the sockets , timeout is NULL ,
  123. //so wait indefinitely
  124. activity = select(FD_SETSIZE, &readfds , NULL , NULL , NULL);
  125. if ((activity < 0) && (errno!=EINTR)) {
  126. perror("select error");
  127. }
  128.  
  129. //If something happened on the master socket ,
  130. //then its an incoming connection, call accept()
  131. if (FD_ISSET(master_socket, &readfds)) {
  132. int new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen);
  133. if (new_socket < 0) {
  134. perror("accept");
  135. exit(EXIT_FAILURE);
  136. }
  137.  
  138. //inform user of socket number - used in send and receive commands
  139. printf("\n---New host connection---\n");
  140. printf("socket fd is %d , ip is : %s , port : %d \n", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
  141.  
  142.  
  143. // add new socket to array of sockets
  144. // XXX: This could be re-written to just use vectors and append
  145. // but this can be lef-- not as an exercise for the reader
  146. for (auto & client_sock: client_sockets) {
  147. //if position is empty
  148. if(client_sock == 0) {
  149. client_sock = new_socket;
  150. break;
  151. }
  152. }
  153. }
  154. //else its some IO operation on some other socket
  155. for (auto & client_sock: client_sockets) {
  156. string header = "";
  157. // Note: sd == 0 is our default here by fd 0 is actually stdin
  158. if (client_sock != 0 && FD_ISSET(client_sock, &readfds)) {
  159. //Check if it was for closing , and also read the
  160. //incoming message
  161. getpeername(client_sock, (struct sockaddr*)&address, (socklen_t*)&addrlen);
  162. do_proxy_stuff(client_sock, inet_ntoa(address.sin_addr));
  163. }
  164. }
  165. }
  166.  
  167. }
  168.  
  169. void gai_host(string &header, string new_host) {
  170. int tou = header.find("Host:");
  171. int wei = header.find("User-Agent:");
  172. header.erase(tou, wei - tou);
  173. header.insert(tou, new_host);
  174. }
  175.  
  176.  
  177. void print_stuff(string content, string type) {
  178. cout << "--- " << type << " ---" << endl;
  179. cout << content << endl;
  180. cout << "--- END ---" << endl;
  181. }
  182.  
  183.  
  184. int initiated_connection(string server_addr) {
  185. int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  186. struct sockaddr_in server;
  187. server.sin_family = AF_INET;
  188. server.sin_port = htons((u_short) 80);
  189. struct hostent* sp = gethostbyname(server_addr.c_str());
  190. memcpy(&server.sin_addr, sp->h_addr, sp->h_length);
  191. if (connect(sockfd, (sockaddr*) &server, sizeof(server)) != 0) {
  192. std::cout << "Connetion to Apache failed" << endl;
  193. return -1;
  194. }
  195. else {
  196. return sockfd;
  197. }
  198.  
  199. }
  200.  
  201. int get_content_length(string header, int *header_length) {
  202. // garbage code plz fix
  203. string target = "Content-Length: ";
  204. string next = "Keep-Alive";
  205. size_t begin = header.find(target);
  206. size_t end = header.find(next);
  207. if (begin == string::npos || end == string::npos) {
  208. return 0;
  209. }
  210. size_t content_length = stoi(header.substr(begin + target.length(), end - begin - target.length()));
  211. size_t end_header = header.find("\r\n\r\n");
  212. if (end_header == string::npos) {
  213. cout << "no end header" << endl;
  214. return 0;
  215. } else {
  216. *header_length = end_header + 4;
  217. return content_length;
  218. }
  219. }
  220.  
  221. void VideoServer::prepare_log(string client_ip, string chunk_name, string server_ip, double duration, int tput, int avg_tput, int bitrate) {
  222. std::ostringstream strs;
  223. strs << duration;
  224. string log = client_ip + " " + chunk_name + " " + server_ip + " " + strs.str() + to_string(tput) + " " + to_string(avg_tput) + " " + to_string(bitrate);
  225. write_to_log(log);
  226. }
  227.  
  228. string get_chunkname(string path_name) {
  229. for (int start = path_name.length() - 1; start >= 0; start--) {
  230. if (path_name[start] == '/') {
  231. return path_name.substr(start + 1, path_name.length());
  232. }
  233. }
  234. return path_name;
  235. }
  236.  
  237.  
  238. void VideoServer::do_proxy_stuff(int client_socket, string client_ip) {
  239. char header_buffer[512];
  240. char recv_buffer[4096];
  241. string video_title = "jasonGggggg";
  242. double T_cur;
  243. bool client_asking_for_video;
  244.  
  245.  
  246. while(true) {
  247. bzero(header_buffer, 512);
  248. bzero(recv_buffer, 4096);
  249. client_asking_for_video = false;
  250. pair<int, int> segfrag;
  251. int chosen_bitrate = -1;
  252.  
  253. // read client request
  254. valread = read(client_socket, header_buffer, 512);
  255. if (valread != 0) {
  256. std::chrono::time_point<std::chrono::system_clock> start, end;
  257. client_asking_for_video = false;
  258. bool is_receiving_a_manifest = false;
  259. header_buffer[valread] = '\0';
  260. string client_request(header_buffer);
  261. print_stuff(client_request, "Client Request");
  262.  
  263. video_title = get_title(client_request); // about to receive manifest
  264. if (client_request.find("Seg") != string::npos && client_request.find("-Frag") != string::npos) { // client asking for video fragment
  265. client_asking_for_video = true;
  266. start = std::chrono::system_clock::now();
  267. chosen_bitrate = determining_bitrate(video_title, T_cur);
  268.  
  269. cout << "TCUR is " << T_cur << endl;
  270. print_stuff(to_string(chosen_bitrate), "BITRATE");
  271. change_bitrate(client_request, chosen_bitrate);
  272. }
  273.  
  274. gai_host(client_request, "Host: " + string(ip) + "\r\n");
  275. print_stuff(client_request, "Modified Request");
  276.  
  277. // forward request to apache
  278. int apache_socket = initiated_connection(ip);
  279. send(apache_socket, client_request.c_str(), client_request.size(), 0);
  280.  
  281. // get apache's response
  282. int total_bytes_received = 0;
  283. int content_length = 0;
  284. int length_of_header = 0;
  285. total_bytes_received += read(apache_socket, header_buffer, 512);
  286. content_length = get_content_length(string(header_buffer), &length_of_header);
  287. send(client_socket, header_buffer, total_bytes_received, 0);
  288. print_stuff(string(header_buffer), "Header from Apche");
  289.  
  290. string kommunist_manifesto(header_buffer);
  291. if (kommunist_manifesto.find("manifest") != string::npos) { // if this is a manifest
  292. is_receiving_a_manifest = true;
  293. }
  294.  
  295. while(total_bytes_received != content_length + length_of_header) {
  296. int bytes_received_this_round = 0;
  297. bytes_received_this_round = read(apache_socket, recv_buffer, 4096);
  298. total_bytes_received += bytes_received_this_round;
  299. send(client_socket, recv_buffer, bytes_received_this_round, 0);
  300. if (is_receiving_a_manifest) {
  301. kommunist_manifesto += string(recv_buffer);
  302. }
  303. cout << "Received: " << total_bytes_received << " | Expcting: " << content_length + length_of_header << endl;
  304. }
  305.  
  306. // update throughput
  307. if (client_asking_for_video) {
  308. end = std::chrono::system_clock::now();
  309. std::chrono::duration<double> elapsed_seconds = end - start;
  310. cout << "Time elapsed " << elapsed_seconds.count() << endl;
  311. double t_new = total_bytes_received * 8 / 1000 / elapsed_seconds.count();
  312. cout << "Bandwidth = " << t_new << "Kbps" << endl;
  313. T_cur = alpha * t_new + (1 - alpha) * T_cur;
  314. prepare_log(client_ip, get_chunkname(video_title), ip, elapsed_seconds.count(), t_new, T_cur, chosen_bitrate);
  315. }
  316.  
  317. // parsse birate info
  318. if (is_receiving_a_manifest) {
  319. find_indices(kommunist_manifesto, video_title);
  320. if (BITRATE_INFO.find(video_title) != BITRATE_INFO.end()) {
  321. T_cur = BITRATE_INFO[video_title][0];
  322. }
  323. }
  324. }
  325. }
  326.  
  327. close(client_socket);
  328. }
  329.  
  330. int VideoServer::determining_bitrate(string video_title, double T_cur) {
  331. bitrate_info_mutex.lock();
  332. for (auto it: BITRATE_INFO) {
  333. cout << it.first << endl;
  334. for (auto it2:it.second) {
  335. cout << it2;
  336. }
  337. }
  338. int max_bitrate = BITRATE_INFO[video_title][0];
  339. for (size_t i = 0; i < BITRATE_INFO[video_title].size(); i++) {
  340. if (BITRATE_INFO[video_title][i] * 1.5 <= T_cur) {
  341. max_bitrate = BITRATE_INFO[video_title][i];
  342. }
  343. else {
  344. break;
  345. }
  346. }
  347. bitrate_info_mutex.unlock();
  348. return max_bitrate;
  349. }
  350.  
  351.  
  352. void VideoServer::find_indices(string &manifest, string title) {
  353. // O(n^2) lan function, qiu optimize
  354. string target = "bitrate=\"";
  355. vector<int> available_bitrates;
  356. for (unsigned int i = 0; i < manifest.length(); i++) {
  357. if (manifest.substr(i, target.length()) == target) {
  358. unsigned int end_of_bitrate;
  359. for (end_of_bitrate = 0; isdigit(manifest[i + target.length() + end_of_bitrate]); end_of_bitrate++) {
  360. continue;
  361. }
  362. available_bitrates.push_back(stoi(manifest.substr(i + target.length(), end_of_bitrate + 1)));
  363. }
  364. }
  365. sort(available_bitrates.begin(), available_bitrates.end());
  366. bitrate_info_mutex.lock();
  367. BITRATE_INFO[title] = available_bitrates;
  368. bitrate_info_mutex.unlock();
  369. }
  370.  
  371.  
  372.  
  373. int content_length(string header) {
  374. string target = "Content-Length: ";
  375. string next = "Keep-Alive";
  376. size_t begin = header.find(target);
  377. size_t end = header.find(next);
  378. string number = header.substr(begin + target.length(), end - begin - target.length());
  379. return stoi(number);
  380. }
  381.  
  382.  
  383. void VideoServer::change_bitrate(string& input, int to_sub) {
  384. int found = int(input.find("Seg"));
  385. int start = found;
  386. while(input[start] != '/') --start;
  387. input.replace(start + 1, found - start - 1, to_string(to_sub));
  388. }
  389.  
  390. int main(int argc , char *argv[]){
  391. VideoServer vs;
  392. vs.init(argc, argv);
  393. vs.start_listening();
  394. return 0;
  395. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement