summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'seggetd/seggetd.cpp')
-rw-r--r--seggetd/seggetd.cpp557
1 files changed, 557 insertions, 0 deletions
diff --git a/seggetd/seggetd.cpp b/seggetd/seggetd.cpp
new file mode 100644
index 0000000..a34b2f9
--- /dev/null
+++ b/seggetd/seggetd.cpp
@@ -0,0 +1,557 @@
+/*
+* Copyright (C) 2010 Robin H.Johnson, Ovechko Kostyantyn <fastinetserver@gmail.com>.
+*
+* Project: IDFetch.
+* Developer: Ovechko Kostyantyn Olexandrovich (Kharkiv State Technical University of Construction and Architecture, Ukraine).
+* Mentor: Robin H. Johnson (Gentoo Linux: Developer, Trustee & Infrastructure Lead).
+* Mentoring organization: Gentoo Linux.
+* Sponsored by GSOC 2010.
+*
+* This file is part of Segget.
+*
+* Segget is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* Segget is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with Segget; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "segget.h"
+/*
+int load_pkgs(){
+ try{
+
+ ifstream json_pkg_list_file;
+ json_pkg_list_file.exceptions (ofstream::failbit | ofstream::badbit);
+ try{
+ json_pkg_list_file.open((settings.pkg_list_dir+"/pkg.list").c_str());
+ }catch(...){
+ error_log("Error: Can't open "+settings.pkg_list_dir+"/pkg.list"+" file");
+ return 1;
+ }
+ string buff((std::istreambuf_iterator<char>(json_pkg_list_file)), std::istreambuf_iterator<char>());
+ try{
+ json_pkg_list_file>>buff;
+ }catch(std::ifstream::failure e){
+ if (!json_pkg_list_file.eof()){
+ error_log("Error: Can't read pkg.list file: "+(string)e.what());
+ return 1;
+ }
+ }catch(...){
+ error_log("Unknown Error: Can't read pkg.list file");
+ return 1;
+ }
+ try{
+ json_pkg_list_file.close();
+ }catch(...){
+ error_log("Error: Can't close pkg.list file");
+ }
+ try{
+ // cout<< buff<<"\n";
+ json_object *json_array_pkg_list;
+ json_array_pkg_list = json_tokener_parse(buff.c_str());
+ if (is_error(json_array_pkg_list))
+ printf("error parsing json: %s\n",json_tokener_errors[-(unsigned long)json_array_pkg_list]);
+ else {
+ stats.pkg_count=json_object_array_length(json_array_pkg_list);
+ Ppkg_array= new Tpkg* [stats.pkg_count];
+ // create 0 pkg for distfiles to provide proxy-fetcher
+ for(uint array_item_num=0;array_item_num<stats.pkg_count;array_item_num++){
+ Ppkg_array[array_item_num]=new Tpkg;
+ Ppkg_array[array_item_num]->load_pkg_from_json(json_object_array_get_idx(json_array_pkg_list,array_item_num));
+ }
+ }
+ return 0;
+ }catch(...){
+ error_log("Error: Can't parse json data from pkg.list file");
+ return 1;
+ }
+ }catch(...){
+ error_log("Error in segget.cpp: load_pkgs()");
+ return 1;
+ }
+}
+*/
+/*
+void show_pkgs(){
+ try{
+ for (uint array_item_num=0;array_item_num<stats.pkg_count;array_item_num++){
+ cout <<"PKG:"<<array_item_num<<") cat:"<< Ppkg_array[array_item_num]->category <<" name:"<< Ppkg_array[array_item_num]->name <<"\n";
+ for(uint distfile_array_item_num=0;distfile_array_item_num<Ppkg_array[array_item_num]->distfile_count;distfile_array_item_num++){
+ cout << " "<< distfile_array_item_num<<") distfile_name:"<< Ppkg_array[array_item_num]->Pdistfile_list[distfile_array_item_num]->name<<"\n";
+ for(uint urllist_array_item_num=0;urllist_array_item_num<Ppkg_array[array_item_num]->Pdistfile_list[distfile_array_item_num]->url_count;urllist_array_item_num++){
+ cout <<" "<<Ppkg_array[array_item_num]->Pdistfile_list[distfile_array_item_num]->url_list[urllist_array_item_num]<<"\n";
+ }
+ }
+ }
+ }catch(...){
+ error_log("Error in segget.cpp: show_pkgs()");
+ }
+}
+*/
+int pkg_choose_segment(Tpkg * cur_pkg, uint connection_num){
+ try{
+ uint distfile_num(0);
+ uint segment_num(0);
+ debug("Entered pkg_choose_segment()");
+ while(distfile_num<cur_pkg->distfile_count){
+// if (Ppkg_array[pkg_num]->distfile_vector[distfile_num].allows_new_actions()){
+ debug("considering distfile:"+toString(distfile_num));
+ if (cur_pkg->Pdistfile_list[distfile_num]->allows_new_actions()){
+ debug("segment_num:"+toString(segment_num));
+ debug("segment_count:"+toString(cur_pkg->Pdistfile_list[distfile_num]->segments_count));
+ while (segment_num<cur_pkg->Pdistfile_list[distfile_num]->segments_count){
+ debug("segment_num:"+toString(segment_num));
+// debug(" segment_num:"+toString(segment_num));
+ // segments_in_progress[connection_num]=
+ // if not(Ppkg_array[pkg_num]->Pdistfile_list[distfile_num]->get_segment_downloaded_status(segment_num);
+ debug("Let's get segment status: "+statusToString(cur_pkg->Pdistfile_list[distfile_num]->dn_segments[segment_num].status));
+ if (cur_pkg->Pdistfile_list[distfile_num]->dn_segments[segment_num].status==SWAITING){
+ if (0==cur_pkg->Pdistfile_list[distfile_num]->provide_segment(cm, connection_num, segment_num)){
+ return 0; // download started
+ };
+ // no success with this segment though it's waiting
+ // probably there will be a problem downloading next segment
+ // so let's go for the next distfile
+ // and return to this distfile later - next time pkg_choose_segment is called
+ break;
+ }else{
+ debug("status is not SWAITING - go for the next segment");
+ // haven't managed to provide this segment, go for the next one
+ segment_num++;
+ }
+ }
+ }
+ distfile_num++;
+ segment_num=0;
+ }
+ distfile_num=0;
+ return 1;
+ }catch(...){
+ error_log("Error: segget.cpp : pkg_choose_segment()");
+ return 1;
+ }
+}
+
+int choose_segment(uint connection_num){
+ try{
+ debug("Entered choose_segment()");
+// for (uint pkg_num=0; pkg_num<stats.pkg_count; pkg_num++){
+// debug("pkg_num:"+toString(pkg_num));
+// if (0==pkg_choose_segment(Ppkg_array[pkg_num], connection_num)){
+// return 0;
+// }
+// }
+
+ if (0==pkg_choose_segment(&request_server_pkg, connection_num)){
+ return 0;
+ }
+ debug("choose_segment() goes for proxy-fetcher distfiles");
+ // download distfiles as a proxy-fetcher
+ if (0==pkg_choose_segment(&proxy_fetcher_pkg, connection_num)){
+ return 0;
+ }
+ // for (uint array_item_num=0;array_item_num<pkg_count;array_item_num++){
+ //for(int distfile_array_item_num=0;distfile_array_item_num<Ppkg_array[array_item_num]->distfile_count;distfile_array_item_num++){
+ // if (Ppkg_array[array_item_num]->Pdistfile_list[distfile_array_item_num]->url_count)
+ // Ppkg_array[array_item_num]->Pdistfile_list[distfile_array_item_num]->dosegments();
+ //}
+ //}
+ return 1;
+ }catch(...){
+ error_log("Error: segget.cpp : choose_segment()");
+ return 1;
+ }
+}
+int download_pkgs(){
+ try{
+ // cout << "Need to download: " << segments_count << " segments\n";
+ CURLMsg *msg;
+ long L;
+ int M, Q, U = -1;
+ fd_set R, W, E;
+ struct timeval T;
+
+ try{
+ cm = curl_multi_init();
+ // we can optionally limit the total amount of connections this multi handle uses
+ curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX_CONNECTS);
+ }catch(...){
+ error_log("Error in segget.cpp: download_pkgs() : while calling curl_global_init() and curl_multi_init()");
+ return EXIT_FAILURE;
+ }
+
+// for (uint connection_num = 0; connection_num < settings.max_connections; ++connection_num) {
+// if ( ! connection_array[connection_num].active){
+// if (choose_segment(connection_num))
+// break;
+// }
+// };
+ bool keep_running_flag=true;
+ struct timeval prev_connection_activation_cycle_time;
+ while (keep_running_flag) {
+ // Use free connections to download segments connections
+ if (1000>time_left_since(prev_connection_activation_cycle_time)){
+ debug("Not enough time left to start connection activation cycle");
+ sleep(1);
+ }else{
+ debug("Entering connection activation cycle");
+ gettimeofday(&prev_connection_activation_cycle_time,NULL);
+ for (uint connection_num = 0; connection_num < settings.max_connections; ++connection_num) {
+ debug("connection_num:"+toString(connection_num));
+ if ( ! connection_array[connection_num].active){
+ debug("connection is not active - choosing segment");
+ if (choose_segment(connection_num)){
+ // if no success don't try the same for other connections
+ debug("No segment found for connection:"+toString(connection_num)+" => no reason to look for a segment for other connections");
+ break;
+ }else{
+// U++;
+ }
+ }
+ else{
+ debug("connection is active");
+ }
+ };
+ debug("Exit connection activation sycle");
+ }
+ debug("After attempt to start connection activation cycle");
+ U=stats.active_connections_counter;
+ debug("before multi_perform");
+// while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(cm, &U)){};
+ if (CURLM_CALL_MULTI_PERFORM != curl_multi_perform(cm, &U)){
+ debug("after multi_perform");
+// if (U) {
+ FD_ZERO(&R);
+ FD_ZERO(&W);
+ FD_ZERO(&E);
+ if (curl_multi_fdset(cm, &R, &W, &E, &M)) {
+ error_log("Error: curl_multi_fdset");
+// fprintf(stderr, "E: curl_multi_fdset\n");
+ return EXIT_FAILURE;
+ }
+ if (curl_multi_timeout(cm, &L)) {
+ error_log("Error: curl_multi_timeout");
+// fprintf(stderr, "E: curl_multi_timeout\n");
+ return EXIT_FAILURE;
+ }
+ if (L == -1)
+ L = 100;
+ if (M == -1) {
+ #ifdef WIN32
+ Sleep(L);
+ #else
+ sleep(L / 1000);
+ #endif
+ } else {
+ T.tv_sec = L/1000;
+ T.tv_usec = (L%1000)*1000;
+ if (0 > select(M+1, &R, &W, &E, &T)) {
+// fprintf(stderr, "E: select(%i,,,,%li): %i: %s\n",
+ error_log("Error: select ("+toString(M+1)+","+toString(L)+"):"+toString(errno)+": "+strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+// }
+ debug("before multi_info_read");
+ while ((msg = curl_multi_info_read(cm, &Q))) {
+ debug("inside multi_info_read");
+ if (msg->msg == CURLMSG_DONE) {
+ Tsegment *current_segment;
+ CURL *e = msg->easy_handle;
+ curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &current_segment);
+// CURLcode connection_result=msg->data.result;
+// string result_msg_text="RESULT:"+toString(connection_result)+" "+curl_easy_strerror(msg->data.result)+" while downloading segment";
+// msg_status1(current_segment->connection_num,current_segment->segment_num,result_msg_text);
+ curl_multi_remove_handle(cm, e);
+
+ connection_array[current_segment->connection_num].stop(msg->data.result);
+
+// if (not choose_segment(current_segment->connection_num)) {
+// U++; // just to prevent it from remaining at 0 if there are more URLs to get
+// };
+ stats.show_totals();
+ curl_easy_cleanup(e);
+ }else {
+ error_log("ERROR: CURLMsg: "+msg->msg);
+ }
+ }
+ }
+ }
+ curl_multi_cleanup(cm);
+ curl_global_cleanup();
+ log("Nothing to download - Exiting... (Press any key to exit) ");
+ return EXIT_SUCCESS;
+ }catch(...){
+ error_log("Error in segget.cpp: download_pkgs()");
+ return EXIT_FAILURE;
+ }
+}
+void *refresh_tui_screen(void * ){
+ while (true){
+ ulong time_diff_msecs=time_left_since(stats.previous_time);
+ if (time_diff_msecs >= settings.current_speed_time_interval_msecs){
+ show_progress(time_diff_msecs);
+ };
+ stats.show_totals();
+ sleep(1);
+ }
+ return 0;
+}
+
+void launch_tui_thread(){
+ pthread_t tui_thread;
+ int iret1;
+ iret1 = pthread_create( &tui_thread, NULL, refresh_tui_screen, (void*) NULL);
+}
+
+void launch_ui_server_thread(){
+ pthread_t ui_server_thread;
+ int iret1;
+ debug_no_msg("Creating ui_server_thread.");
+ ui_server.init();
+ iret1 = pthread_create( &ui_server_thread, NULL, run_ui_server, (void*) NULL);
+ debug_no_msg("ui_server_thread launched");
+}
+
+void launch_proxy_fetcher_server_thread(){
+ if (settings.provide_proxy_fetcher_ip!="none"){
+ pthread_t proxy_fetcher_server_thread;
+ int iret1;
+ debug_no_msg("Creating ui_server_thread.");
+// proxy_fetcher_server_thread.init();
+ iret1 = pthread_create( &proxy_fetcher_server_thread, NULL, run_proxy_fetcher_server, (void*) NULL);
+ debug_no_msg("proxy_fetcher_server_thread launched");
+ }
+}
+
+void launch_request_server_thread(){
+ if (settings.request_ip!="none"){
+ pthread_t request_server_thread;
+ int iret1;
+ debug_no_msg("Creating request_server_thread.");
+// proxy_fetcher_server_thread.init();
+ iret1 = pthread_create( &request_server_thread, NULL, run_request_server, (void*) NULL);
+ debug_no_msg("request_server_thread launched");
+ }
+}
+/*
+void launch_script_server_thread(){
+// if (settings.request_ip!="none"){
+ pthread_t script_server_thread;
+ int iret1;
+ debug_no_msg("Creating script_server_thread.");
+// proxy_fetcher_server_thread.init();
+ iret1 = pthread_create( &script_server_thread, NULL, run_script_server, (void*) NULL);
+ debug_no_msg("script_server_thread launched");
+// }
+}
+*/
+void segget_exit(int sig){
+ try{
+ endwin();
+ }
+ catch(...)
+ {
+ //error while ending curses
+ }
+ try{
+ for(uint fd = 0; fd <= ui_server.max_fd_num; fd++) {
+ close(fd);
+ }
+ }
+ catch(...)
+ {
+ //error while clossing server_sockfd
+ }
+ error_log_no_msg("Segget exits because cought signal:"+toString(sig));
+ cout<<"Bye!\n\n";
+ exit(0);
+}
+
+int routine(){
+ try{
+ signal(SIGABRT,segget_exit);//If program aborts go to assigned function "segget_exit".
+ signal(SIGTERM,segget_exit);//If program terminates go to assigned function "segget_exit".
+ signal(SIGINT,segget_exit);//If program terminates go to assigned function "segget_exit".
+ try{
+ gettimeofday(&stats.segget_start_time,NULL);
+// stats.prev_time=time((time_t *)NULL);
+ }catch(...){
+ error_log("Error in stats.cpp: reset_previous_time()");
+ }
+ try{
+ //load settings
+ settings.init();
+ }
+ catch(...)
+ {
+ //error while loading settings
+ }
+ try{
+ init_connections();
+ }catch(...){
+ error_log("error while init_connections");
+ }
+ try{
+ // This function is NOT thread-safe => call it before any other thread is launched
+ curl_global_init(CURL_GLOBAL_ALL);
+ }catch(...){
+ error_log_no_msg("Error in segget.cpp: routine: while calling curl_global_init()");
+ }
+ try{
+ launch_ui_server_thread();
+ }catch(...){
+ error_log_no_msg("Error in segget.cpp launch_ui_server() failed");
+ }
+ try{
+ launch_request_server_thread();
+ }catch(...){
+ error_log_no_msg("Error in segget.cpp launch_proxy_fetcher_server_thread failed");
+ }
+/*
+ try{
+ launch_script_server_thread();
+ }catch(...){
+ error_log_no_msg("Error in segget.cpp launch_script_server_thread failed");
+ }
+*/
+ try{
+ launch_proxy_fetcher_server_thread();
+ }catch(...){
+ error_log_no_msg("Error in segget.cpp launch_proxy_fetcher_server_thread failed");
+ }
+ try{
+ launch_tui_thread();
+ }catch(...){
+ error_log_no_msg("Error in segget.cpp launch_tui_theread() failed");
+ }
+// try{
+// load_pkgs();
+// }catch(...){
+ //error while loading pkgs
+// }
+ try{
+ //show_pkgs();
+ stats.show_totals();
+ }catch(...){
+ //error while showing stats
+ }
+ try{
+ download_pkgs();
+ }catch(...){
+ //error while downloading_pkgs
+ }
+ try{
+ close(ui_server.server_sockfd);
+ }catch(...){
+ //error while clossing server_sockfd
+ }
+ return 0;
+ }catch(...)
+ {
+ perror("Error in segget.cpp: routine()");
+ }
+ return 1;
+}
+
+void start_daemon_mode(){
+ try{
+ debug("start_daemon_mode()");
+ switch (fork())
+ {
+ case 0: break; //child
+ case -1: error_log("Error in segget.cpp: start_daemon_mode() during first fork()"); //fork error
+ default: exit(0); //parent
+ }
+ struct rlimit _ResourceLimit;
+ if (getrlimit(RLIMIT_NOFILE, &_ResourceLimit)!=0) error_log("Error in segget.cpp: start_daemon_mode() during getrlimit()");
+ if (_ResourceLimit.rlim_max==0) throw("Error in segget.cpp: start_daemon_mode() - no open file descriptors");
+ for (uint i=0;i<_ResourceLimit.rlim_max;i++) close(i);
+ if (setsid()==-1) error_log_no_msg("Error in segget.cpp: start_daemon_mode() during setsid()");
+ switch (fork()){
+ case 0: break; // child
+ case -1: error_log_no_msg("Error in segget.cpp: start_daemon_mode() during second fork()");
+ default: exit(0); // parent
+ }
+ umask(0);
+ // prevent unmount problems - switch to root
+// chdir("/");
+ // create descriptors in case someone will use them
+ int fileDesc = open("/dev/null", O_RDWR); //stdin
+ //stdout
+ if (dup(fileDesc)){
+ log_no_msg("Error in segget.cpp: start_daemon_mode: during dup(fileDesc) - stdout");
+// exit(1);
+ }
+ //stderr
+ if (dup(fileDesc)){
+ log_no_msg("Error in segget.cpp: start_daemon_mode: during dup(fileDesc) - stderr");
+// exit(1);
+ }
+ log_no_msg("Starting daemon routine");
+ routine();
+ log_no_msg("Exited daemon routine");
+ }catch (...){
+ error_log_no_msg("Error in segget.cpp: start_daemon_mode()");
+ exit(1);
+ }
+}
+
+int init_curses(){
+ try{
+ initscr();
+ curs_set(0);
+ refresh();
+ return 0;
+ }catch(...){
+ perror("Error in segget.cpp: init_curses()");
+ }
+ return 1;
+}
+int parse_cli_arguments(int argc, char* argv[]){
+ try{
+ string option,name,value;
+ cout << "argc = " << argc << endl;
+ int posEqual;
+ for(int i = 0; i < argc; i++){
+ cout << "argv[" << i << "] = " << argv[i] << endl;
+ option=argv[i];
+ posEqual=option.find('=');
+ name = trim(option.substr(0,posEqual));
+ value = trim(option.substr(posEqual+1));
+ if (name=="--conf-dir") {settings.conf_dir=value; continue;};
+ if (name=="--no-daemon"){settings.no_daemon_flag=true; continue;}
+ }
+ return 0;
+ }catch(...){
+ perror("Error in segget.cpp: init_curses()");
+ }
+ return 1;
+}
+
+int main(int argc, char* argv[])
+{
+ try{
+ parse_cli_arguments(argc, argv);
+ if (settings.no_daemon_flag){
+ init_curses();
+ routine();
+ endwin(); // exit curses
+ }else{
+ start_daemon_mode();
+ }
+ exit (0);
+ }catch(...){
+ perror("Error in segget.cpp main()");
+ }
+ exit(1);
+} \ No newline at end of file