Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "miProxy.h"
- #include <iostream>
- #include <string>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/time.h>
- #include <netdb.h>
- #include <array>
- #include <thread>
- #include <mutex>
- #include <cmath>
- #include <chrono>
- #include <bits/stdc++.h>
- using namespace std;
- #define MAXCLIENTS 30
- map<string, vector<int>> BITRATE_INFO;
- mutex bitrate_info_mutex;
- void reply_to_client(int client_sock, string title, string request_header, string ip);
- void VideoServer::init(int argc, char** argv) {
- if (!strcmp(argv[1], "--nodns")) {
- using_dns = false;
- listen_port = stoi(argv[2]);
- ip = argv[3];
- alpha = stod(argv[4]);
- log_path = argv[5];
- dns_port = -1;
- }
- else {
- using_dns = true;
- listen_port = stoi(argv[2]);
- ip = argv[3];
- dns_port = stoi(argv[4]);
- alpha = stod(argv[5]);
- log_path = argv[6];
- }
- logfile.open(log_path);
- }
- void VideoServer::write_to_log(string log) {
- log_mutex.lock();
- logfile << log << endl;
- log_mutex.unlock();
- }
- int VideoServer::get_master_socket(struct sockaddr_in * address){
- int yes = 1;
- int master_socket;
- master_socket = socket(AF_INET, SOCK_STREAM, 0);
- if(master_socket <= 0) {
- perror("socket failed");
- exit(EXIT_FAILURE);
- }
- int success = setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
- if(success < 0) {
- perror("setsockopt");
- exit(EXIT_FAILURE);
- }
- address->sin_family = AF_INET;
- address->sin_addr.s_addr = INADDR_ANY;
- address->sin_port = htons(listen_port);
- success = ::bind(master_socket, (struct sockaddr *)address, sizeof(*address));
- if (success < 0) {
- perror("bind failed");
- exit(EXIT_FAILURE);
- }
- printf("---Listening on port %d---\n", listen_port);
- if (listen(master_socket, 3) < 0) {
- perror("listen");
- exit(EXIT_FAILURE);
- }
- return master_socket;
- }
- string get_title(string header) {
- int tou = header.find("GET ");
- int wei = header.find(" HTTP");
- return header.substr(tou + 4, wei - tou - 4);
- }
- int VideoServer::find_max_sd(fd_set * readfds, int * client_fds, int length, int max_sd) {
- int sd = -1;
- for (int i = 0; i < length; ++i) {
- sd = client_fds[i];
- if(sd > 0)
- FD_SET(sd, readfds);
- if(sd > max_sd)
- max_sd = sd;
- }
- return max_sd;
- }
- void VideoServer::start_listening() {
- struct sockaddr_in address;
- master_socket = get_master_socket(&address);
- client_sockets.fill(0);
- addrlen = sizeof(address);
- char buffer[1024];
- bzero(buffer, 1024);
- fd_set readfds;
- while(true) {
- //clear the socket set
- FD_ZERO(&readfds);
- //add master socket to set
- FD_SET(master_socket, &readfds);
- for (const auto & client_sock: client_sockets){
- if (client_sock != 0){
- FD_SET(client_sock, &readfds);
- }
- }
- //wait for an activity on one of the sockets , timeout is NULL ,
- //so wait indefinitely
- activity = select(FD_SETSIZE, &readfds , NULL , NULL , NULL);
- if ((activity < 0) && (errno!=EINTR)) {
- perror("select error");
- }
- //If something happened on the master socket ,
- //then its an incoming connection, call accept()
- if (FD_ISSET(master_socket, &readfds)) {
- int new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen);
- if (new_socket < 0) {
- perror("accept");
- exit(EXIT_FAILURE);
- }
- //inform user of socket number - used in send and receive commands
- printf("\n---New host connection---\n");
- printf("socket fd is %d , ip is : %s , port : %d \n", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
- // add new socket to array of sockets
- // XXX: This could be re-written to just use vectors and append
- // but this can be lef-- not as an exercise for the reader
- for (auto & client_sock: client_sockets) {
- //if position is empty
- if(client_sock == 0) {
- client_sock = new_socket;
- break;
- }
- }
- }
- //else its some IO operation on some other socket
- for (auto & client_sock: client_sockets) {
- string header = "";
- // Note: sd == 0 is our default here by fd 0 is actually stdin
- if (client_sock != 0 && FD_ISSET(client_sock, &readfds)) {
- //Check if it was for closing , and also read the
- //incoming message
- getpeername(client_sock, (struct sockaddr*)&address, (socklen_t*)&addrlen);
- do_proxy_stuff(client_sock, inet_ntoa(address.sin_addr));
- }
- }
- }
- }
- void gai_host(string &header, string new_host) {
- int tou = header.find("Host:");
- int wei = header.find("User-Agent:");
- header.erase(tou, wei - tou);
- header.insert(tou, new_host);
- }
- void print_stuff(string content, string type) {
- cout << "--- " << type << " ---" << endl;
- cout << content << endl;
- cout << "--- END ---" << endl;
- }
- int initiated_connection(string server_addr) {
- int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- struct sockaddr_in server;
- server.sin_family = AF_INET;
- server.sin_port = htons((u_short) 80);
- struct hostent* sp = gethostbyname(server_addr.c_str());
- memcpy(&server.sin_addr, sp->h_addr, sp->h_length);
- if (connect(sockfd, (sockaddr*) &server, sizeof(server)) != 0) {
- std::cout << "Connetion to Apache failed" << endl;
- return -1;
- }
- else {
- return sockfd;
- }
- }
- int get_content_length(string header, int *header_length) {
- // garbage code plz fix
- string target = "Content-Length: ";
- string next = "Keep-Alive";
- size_t begin = header.find(target);
- size_t end = header.find(next);
- if (begin == string::npos || end == string::npos) {
- return 0;
- }
- size_t content_length = stoi(header.substr(begin + target.length(), end - begin - target.length()));
- size_t end_header = header.find("\r\n\r\n");
- if (end_header == string::npos) {
- cout << "no end header" << endl;
- return 0;
- } else {
- *header_length = end_header + 4;
- return content_length;
- }
- }
- void VideoServer::prepare_log(string client_ip, string chunk_name, string server_ip, double duration, int tput, int avg_tput, int bitrate) {
- std::ostringstream strs;
- strs << duration;
- string log = client_ip + " " + chunk_name + " " + server_ip + " " + strs.str() + to_string(tput) + " " + to_string(avg_tput) + " " + to_string(bitrate);
- write_to_log(log);
- }
- string get_chunkname(string path_name) {
- for (int start = path_name.length() - 1; start >= 0; start--) {
- if (path_name[start] == '/') {
- return path_name.substr(start + 1, path_name.length());
- }
- }
- return path_name;
- }
- void VideoServer::do_proxy_stuff(int client_socket, string client_ip) {
- char header_buffer[512];
- char recv_buffer[4096];
- string video_title = "jasonGggggg";
- double T_cur;
- bool client_asking_for_video;
- while(true) {
- bzero(header_buffer, 512);
- bzero(recv_buffer, 4096);
- client_asking_for_video = false;
- pair<int, int> segfrag;
- int chosen_bitrate = -1;
- // read client request
- valread = read(client_socket, header_buffer, 512);
- if (valread != 0) {
- std::chrono::time_point<std::chrono::system_clock> start, end;
- client_asking_for_video = false;
- bool is_receiving_a_manifest = false;
- header_buffer[valread] = '\0';
- string client_request(header_buffer);
- print_stuff(client_request, "Client Request");
- video_title = get_title(client_request); // about to receive manifest
- if (client_request.find("Seg") != string::npos && client_request.find("-Frag") != string::npos) { // client asking for video fragment
- client_asking_for_video = true;
- start = std::chrono::system_clock::now();
- chosen_bitrate = determining_bitrate(video_title, T_cur);
- cout << "TCUR is " << T_cur << endl;
- print_stuff(to_string(chosen_bitrate), "BITRATE");
- change_bitrate(client_request, chosen_bitrate);
- }
- gai_host(client_request, "Host: " + string(ip) + "\r\n");
- print_stuff(client_request, "Modified Request");
- // forward request to apache
- int apache_socket = initiated_connection(ip);
- send(apache_socket, client_request.c_str(), client_request.size(), 0);
- // get apache's response
- int total_bytes_received = 0;
- int content_length = 0;
- int length_of_header = 0;
- total_bytes_received += read(apache_socket, header_buffer, 512);
- content_length = get_content_length(string(header_buffer), &length_of_header);
- send(client_socket, header_buffer, total_bytes_received, 0);
- print_stuff(string(header_buffer), "Header from Apche");
- string kommunist_manifesto(header_buffer);
- if (kommunist_manifesto.find("manifest") != string::npos) { // if this is a manifest
- is_receiving_a_manifest = true;
- }
- while(total_bytes_received != content_length + length_of_header) {
- int bytes_received_this_round = 0;
- bytes_received_this_round = read(apache_socket, recv_buffer, 4096);
- total_bytes_received += bytes_received_this_round;
- send(client_socket, recv_buffer, bytes_received_this_round, 0);
- if (is_receiving_a_manifest) {
- kommunist_manifesto += string(recv_buffer);
- }
- cout << "Received: " << total_bytes_received << " | Expcting: " << content_length + length_of_header << endl;
- }
- // update throughput
- if (client_asking_for_video) {
- end = std::chrono::system_clock::now();
- std::chrono::duration<double> elapsed_seconds = end - start;
- cout << "Time elapsed " << elapsed_seconds.count() << endl;
- double t_new = total_bytes_received * 8 / 1000 / elapsed_seconds.count();
- cout << "Bandwidth = " << t_new << "Kbps" << endl;
- T_cur = alpha * t_new + (1 - alpha) * T_cur;
- prepare_log(client_ip, get_chunkname(video_title), ip, elapsed_seconds.count(), t_new, T_cur, chosen_bitrate);
- }
- // parsse birate info
- if (is_receiving_a_manifest) {
- find_indices(kommunist_manifesto, video_title);
- if (BITRATE_INFO.find(video_title) != BITRATE_INFO.end()) {
- T_cur = BITRATE_INFO[video_title][0];
- }
- }
- }
- }
- close(client_socket);
- }
- int VideoServer::determining_bitrate(string video_title, double T_cur) {
- bitrate_info_mutex.lock();
- for (auto it: BITRATE_INFO) {
- cout << it.first << endl;
- for (auto it2:it.second) {
- cout << it2;
- }
- }
- int max_bitrate = BITRATE_INFO[video_title][0];
- for (size_t i = 0; i < BITRATE_INFO[video_title].size(); i++) {
- if (BITRATE_INFO[video_title][i] * 1.5 <= T_cur) {
- max_bitrate = BITRATE_INFO[video_title][i];
- }
- else {
- break;
- }
- }
- bitrate_info_mutex.unlock();
- return max_bitrate;
- }
- void VideoServer::find_indices(string &manifest, string title) {
- // O(n^2) lan function, qiu optimize
- string target = "bitrate=\"";
- vector<int> available_bitrates;
- for (unsigned int i = 0; i < manifest.length(); i++) {
- if (manifest.substr(i, target.length()) == target) {
- unsigned int end_of_bitrate;
- for (end_of_bitrate = 0; isdigit(manifest[i + target.length() + end_of_bitrate]); end_of_bitrate++) {
- continue;
- }
- available_bitrates.push_back(stoi(manifest.substr(i + target.length(), end_of_bitrate + 1)));
- }
- }
- sort(available_bitrates.begin(), available_bitrates.end());
- bitrate_info_mutex.lock();
- BITRATE_INFO[title] = available_bitrates;
- bitrate_info_mutex.unlock();
- }
- int content_length(string header) {
- string target = "Content-Length: ";
- string next = "Keep-Alive";
- size_t begin = header.find(target);
- size_t end = header.find(next);
- string number = header.substr(begin + target.length(), end - begin - target.length());
- return stoi(number);
- }
- void VideoServer::change_bitrate(string& input, int to_sub) {
- int found = int(input.find("Seg"));
- int start = found;
- while(input[start] != '/') --start;
- input.replace(start + 1, found - start - 1, to_string(to_sub));
- }
- int main(int argc , char *argv[]){
- VideoServer vs;
- vs.init(argc, argv);
- vs.start_listening();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement