diff options
-rw-r--r-- | segget/connection.cpp | 51 | ||||
-rw-r--r-- | segget/connection.h | 15 | ||||
-rw-r--r-- | segget/distfile.cpp | 15 | ||||
-rw-r--r-- | segget/distfile.h | 2 | ||||
-rw-r--r-- | segget/network.cpp | 10 | ||||
-rw-r--r-- | segget/requestserver.cpp | 2 | ||||
-rw-r--r-- | segget/response.h | 3 | ||||
-rw-r--r-- | segget/scripts/client.py | 7 | ||||
-rw-r--r-- | segget/scripts/functions.py | 77 | ||||
-rw-r--r-- | segget/scripts/net0.py | 15 | ||||
-rw-r--r-- | segget/scriptserver.cpp | 320 | ||||
-rw-r--r-- | segget/scriptserver.h | 73 | ||||
-rw-r--r-- | segget/segget.conf | 75 | ||||
-rw-r--r-- | segget/segget.cpp | 20 | ||||
-rw-r--r-- | segget/segget.h | 1 | ||||
-rw-r--r-- | segget/settings.cpp | 3 | ||||
-rw-r--r-- | segget/settings.h | 6 |
17 files changed, 662 insertions, 33 deletions
diff --git a/segget/connection.cpp b/segget/connection.cpp index 9380cf4..2f8399c 100644 --- a/segget/connection.cpp +++ b/segget/connection.cpp @@ -25,6 +25,7 @@ */ #include "connection.h" +long script_waiting_connection_num=-1; uint Tconnection::total_connections=0; Tconnection connection_array[MAX_CONNECTS]; time_t prev_time; @@ -35,9 +36,8 @@ void init_connections(){ }; } -void Tconnection::start(CURLM *cm, uint network_number, uint distfile_num, Tsegment *started_segment, uint best_mirror_num){ +int Tconnection::start(CURLM *cm, uint network_number, uint distfile_num, Tsegment *started_segment, uint best_mirror_num){ try{ - stats.active_connections_counter++; segment=started_segment; debug("Starting connection for distfile: "+segment->parent_distfile->name); mirror_num=best_mirror_num; @@ -55,7 +55,6 @@ void Tconnection::start(CURLM *cm, uint network_number, uint distfile_num, Tsegm } Tmirror *Pcurr_mirror; - string url; switch (network_array[network_num].network_mode){ case MODE_REMOTE:{ url=segment->parent_distfile->url_list[mirror_num]; @@ -74,16 +73,24 @@ void Tconnection::start(CURLM *cm, uint network_number, uint distfile_num, Tsegm } debug(" URL:"+url); + if (run_user_python_script(connection_num)){ + return REJECTED_BY_USER_PYTHON_SCRIPT; + } + debug("aaaaa"); Pcurr_mirror->start(); debug("bbbbb"); network_array[network_num].connect(); debug("ccccc"); + + stats.active_connections_counter++; segment->prepare_for_connection(cm, connection_num, network_num, distfile_num, url); debug("Started connection for distfile: "+segment->parent_distfile->name); + return 0; }catch(...){ error_log("Error in connection.cpp: start()"); } + return ERROR_WHILE_PREPARING_CONNECTION; } /* string explain_curl_error(int error_code){ @@ -98,6 +105,17 @@ string explain_curl_error(int error_code){ void Tconnection::stop(CURLcode connection_result){ try{ stats.active_connections_counter--; + Tmirror *Pcurr_mirror; + switch (network_array[network_num].network_mode){ + case MODE_REMOTE: + case MODE_CORAL_CDN:{ + Pcurr_mirror=find_mirror(strip_mirror_name(url)); + break; + } + default:{ + Pcurr_mirror=&network_array[network_num].benchmarked_mirror_list[mirror_num]; + } + } debug("Finished connection for distfile: "+segment->parent_distfile->name+" Segment#:"+toString(segment->segment_num)+" Network#"+toString(network_num)+" Status: "+toString(connection_result)); if (connection_result){ string error_str=curl_easy_strerror(connection_result); @@ -105,21 +123,26 @@ void Tconnection::stop(CURLcode connection_result){ error_log("Finished connection for distfile: "+segment->parent_distfile->name+" Segment#:"+toString(segment->segment_num)+" Network#"+toString(network_num)+" Status: "+toString(connection_result)); error_log(" ERROR "+toString(connection_result)+": "+error_str); } - - msg_clean_connection(connection_num); active=false; network_array[network_num].disconnect(); // network_array[network_num].benchmarked_mirror_list[mirror_num].stop(); segment->segment_file.close(); if (connection_result==0){ if (! segment->segment_verification_is_ok()){ + connection_result=CURLE_READ_ERROR; + Pcurr_mirror->stop(time_left_from(connection_array[connection_num].start_time),0); debug("curl_lies - there is a problem downloading segment"); error_log("curl_lies - there is a problem downloading segment"); - connection_result=CURLE_READ_ERROR; + }else{ + Pcurr_mirror->stop(time_left_from(connection_array[connection_num].start_time),segment->segment_size); } + }else{ + Pcurr_mirror->stop(time_left_from(connection_array[connection_num].start_time),0); } - segment->parent_distfile->active_connections_num--; + + msg_clean_connection(connection_num); + /* Tmirror *Pcurr_mirror; if (network_array[network_num].network_mode==MODE_LOCAL){ @@ -131,18 +154,6 @@ void Tconnection::stop(CURLcode connection_result){ } */ - Tmirror *Pcurr_mirror; - switch (network_array[network_num].network_mode){ - case MODE_REMOTE: - case MODE_CORAL_CDN:{ - Pcurr_mirror=find_mirror(strip_mirror_name(segment->url)); - break; - } - default:{ - Pcurr_mirror=&network_array[network_num].benchmarked_mirror_list[mirror_num]; - } - } - timeval now_time; gettimeofday(&now_time,NULL); @@ -170,7 +181,6 @@ void Tconnection::stop(CURLcode connection_result){ // error -> start downloading again // msg_status2(segment->connection_num, toString(connection_result)+"]- Failed download "+segment->file_name); debug(toString(connection_result)+"]- Failed download "+segment->url); - Pcurr_mirror->stop(time_left_from(connection_array[connection_num].start_time),0); if (segment->try_num>=settings.max_tries){ segment->status=SFAILED; segment->parent_distfile->status=DFAILED; @@ -183,7 +193,6 @@ void Tconnection::stop(CURLcode connection_result){ log("Succesfully downloaded "+segment->file_name+" on connection#"+toString(connection_num)); debug(" Successful download "+segment->url); // already done earlier in this function Pcurr_mirror=find_mirror(strip_mirror_name(segment->url)); - Pcurr_mirror->stop(time_left_from(connection_array[connection_num].start_time),segment->segment_size); segment->status=SDOWNLOADED; segment->parent_distfile->inc_dld_segments_count(segment); }; diff --git a/segget/connection.h b/segget/connection.h index bdb4a59..a758ee6 100644 --- a/segget/connection.h +++ b/segget/connection.h @@ -33,6 +33,7 @@ class Tsegment; #include "segment.h" #include "utils.h" #include "networkbroker.h" +#include "scriptserver.h" using namespace std; @@ -40,12 +41,14 @@ class Tconnection{ static uint total_connections; private: Tnetwork_distfile_broker_phases connection_start_time_network_phase_for_pf_networks; + public: uint network_num; uint mirror_num; - public: + string url; ulong total_dld_bytes; ulong bytes_per_last_interval; uint connection_num; + ulong max_speed_limit; bool active; timeval start_time; Tsegment *segment; @@ -53,18 +56,24 @@ class Tconnection{ connection_start_time_network_phase_for_pf_networks(E_USE_AS_LOCAL_MIRRORS), network_num(0), mirror_num(0), + url(""), total_dld_bytes(0), bytes_per_last_interval(0), connection_num(0), + max_speed_limit(0), active(0), start_time(), - segment(0){}; - void start(CURLM *cm, uint network_number, uint distfile_num, Tsegment *started_segment, uint best_mirror_num); + segment(0) + {}; + Tconnection(const Tconnection &L); // copy constructor + Tconnection & operator=(const Tconnection &L); + int start(CURLM *cm, uint network_number, uint distfile_num, Tsegment *started_segment, uint best_mirror_num); void stop(CURLcode connection_result); void inc_bytes_per_last_interval(ulong new_bytes_count); void show_connection_progress(ulong time_diff); }; +extern long script_waiting_connection_num; extern time_t prev_time; extern Tconnection connection_array[MAX_CONNECTS]; void init_connections(); diff --git a/segget/distfile.cpp b/segget/distfile.cpp index 11b7be7..4f56bbe 100644 --- a/segget/distfile.cpp +++ b/segget/distfile.cpp @@ -340,8 +340,12 @@ bool Tdistfile::choose_best_mirror(CURLM* cm, uint connection_num, uint network_ debug("Downloading from BEST_MIRROR:"+url_str); // Pbest_mirror->start(); // active_connections_num++; - connection_array[connection_num].start(cm, network_num, num, &dn_segments[seg_num], best_mirror_num); - return R_R_DOWNLOAD_STARTED; + int result=connection_array[connection_num].start(cm, network_num, num, &dn_segments[seg_num], best_mirror_num); + if (result){ + return result; + }else{ + return R_R_DOWNLOAD_STARTED; + } } else{ error_log("Can't choose mirror for segment:"+dn_segments[seg_num].file_name); @@ -384,7 +388,12 @@ bool Tdistfile::choose_best_local_mirror(CURLM* cm, uint connection_num, uint ne if (best_mirror_num!=-1){ debug("Downloading from BEST_LOCAL_MIRROR:"+network_array[network_num].benchmarked_mirror_list[best_mirror_num].url); // active_connections_num++; - connection_array[connection_num].start(cm, network_num, num, &dn_segments[seg_num], best_mirror_num); + int result=connection_array[connection_num].start(cm, network_num, num, &dn_segments[seg_num], best_mirror_num); + if (result){ + return result; + }else{ + return R_R_DOWNLOAD_STARTED; + } return R_R_DOWNLOAD_STARTED; } else{ diff --git a/segget/distfile.h b/segget/distfile.h index a14e137..69f20c7 100644 --- a/segget/distfile.h +++ b/segget/distfile.h @@ -91,10 +91,10 @@ long is_symlink_restricted(string distfile_name); class Tdistfile{ private: - uint dld_segments_count; bool choose_best_local_mirror(CURLM* cm, uint connection_num, uint network_num, uint seg_num); bool choose_best_mirror(CURLM* cm, uint connection_num, uint network_num, uint seg_num); public: + uint dld_segments_count; Tnetwork_distfile_broker network_distfile_brokers_array[MAX_NETWORKS]; string json_data; // bool downloaded; diff --git a/segget/network.cpp b/segget/network.cpp index ea417ce..ccde337 100644 --- a/segget/network.cpp +++ b/segget/network.cpp @@ -53,8 +53,12 @@ void Tnetwork::load_mirror_list(){ benchmarked_mirror_list.push_back(cur_mirror); debug("LOCAL_MIRROR_ADDED:"+mirror_line); } - } - catch(...){ + }catch(ifstream::failure e){ + if (!file.eof()){ + error_log("Mirror list file: "+mirror_list_file_name+" was opened, but an error occured while reading from it."); + return; + } + }catch(...){ error_log("Mirror list file: "+mirror_list_file_name+" was opened, but an error occured while reading from it."); } }catch(...){ @@ -106,7 +110,7 @@ void Tnetwork::init(uint priority_value){ { conf.set("network_mirrors","only_local_when_possible",only_local_when_possible); load_mirror_list(); - log("Settings: Network"+toString(network_num)+" local mirror_list size:"+toString(mirror_list.size())); + log("Settings in file:network"+toString(network_num)+"_mirrors.conf local mirror_list size:"+toString(benchmarked_mirror_list.size())); break; }; case MODE_PROXY_FETCHER: diff --git a/segget/requestserver.cpp b/segget/requestserver.cpp index de365d2..fd1111f 100644 --- a/segget/requestserver.cpp +++ b/segget/requestserver.cpp @@ -24,7 +24,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "proxyfetcher.h" +#include "requestserver.h" void *run_request_server(void * ){ try{ diff --git a/segget/response.h b/segget/response.h index 77ec9fe..fbeb4f5 100644 --- a/segget/response.h +++ b/segget/response.h @@ -56,6 +56,9 @@ using namespace std; #define DO_NOT_ALLOW_REMOTE_NETWORKS 204 #define ALLOW_LOWER_PRIORITY_NETWORKS 205 +#define REJECTED_BY_USER_PYTHON_SCRIPT 301 +#define ERROR_WHILE_PREPARING_CONNECTION 302 + int decode_server_response(string server_response); #endif
\ No newline at end of file diff --git a/segget/scripts/client.py b/segget/scripts/client.py new file mode 100644 index 0000000..87b97bf --- /dev/null +++ b/segget/scripts/client.py @@ -0,0 +1,7 @@ +# TCP client example +from functions import * +from net0 import * +#user_script + +schedule() +accept_segment()
\ No newline at end of file diff --git a/segget/scripts/functions.py b/segget/scripts/functions.py new file mode 100644 index 0000000..07fe90a --- /dev/null +++ b/segget/scripts/functions.py @@ -0,0 +1,77 @@ +import sys +import socket + +def get(var_name): + print("GET::"+var_name) + client_socket.send ("g<c>"+var_name) + data = client_socket.recv(512) + print "RECIEVED:" , data + #connection.num, + #connection.max_speed_limit, + #network.num, + #network.active_connections_count, + #distfile.size, + #distfile.dld_segments_count, + #distfile.segments_count, + #distfile.active_connections_count, + #segment.num, + #segment.try_num, + #segment.size, + if ((var_name=="connection.url") or (var_name=="distfile.name") or (var_name=="segment.range")): + return data + else: + return int(data) + +def set(var_name,var_value): + var_value_str=str(var_value); + print("SET::"+var_name+"="+var_value_str) + client_socket.send ("s<c>"+var_name+"<n>"+var_value_str) + data = client_socket.recv(512) + print "RECIEVED:" , data + if (data=="o<r>"): + return 0 + else: + return 1 + +def accept_segment(): + print "Accepting segment" + client_socket.send ("a<c>") + client_socket.close() + sys.exit(0) + +def reject_segment(): + print "Rejecting segment" + client_socket.send ("r<c>") + client_socket.close() + sys.exit(0) +# in case users forget to use quotes +class Tconnection: + num="connection.num" + max_speed_limit="connection.max_speed_limit" + url="connection.url" + +class Tnetwork: + num="network.num" + mode="network.mode" + active_connections_count="network.active_connections_count" + +class Tdistfile: + name="distfile.name" + size="distfile.size" + dld_segments_count="distfile.dld_segments_count" + segments_count="distfile.segments_count" + active_connections_count="distfile.active_connections_count" + +class Tsegment: + num="segment.num" + try_num="segment.try_num" + size="segment.size" + range="segment.range" + +connection=Tconnection +network=Tnetwork +distfile=Tdistfile +segment=Tsegment + +client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +client_socket.connect("/tmp/segget_script_socket")
\ No newline at end of file diff --git a/segget/scripts/net0.py b/segget/scripts/net0.py new file mode 100644 index 0000000..8d87955 --- /dev/null +++ b/segget/scripts/net0.py @@ -0,0 +1,15 @@ +from functions import * +import time; +def schedule(): + localtime = time.localtime(time.time()); + hour=localtime[3]; + # disable downloading distfiles that have size more than 5 000 000 bytes + # from 8-00 to 22-00. + if hour>8 and hour<21 and (get("distfile.size"))>5000000: + print "reject because distfile is too big" + reject_segment() + # set speed limit 50 000 cps for distfiles larger than 1 000 000 bytes + if get("distfile.size")>1000000: + print "limit connection speed" + set(connection.max_speed_limit, 50000) + accept_segment()
\ No newline at end of file diff --git a/segget/scriptserver.cpp b/segget/scriptserver.cpp new file mode 100644 index 0000000..44173d7 --- /dev/null +++ b/segget/scriptserver.cpp @@ -0,0 +1,320 @@ +/* +* 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 "scriptserver.h" + +map<std::string, Tvar_nums> variables_; + +#define RESPONSE_OK "o<r>"; +#define RESPONSE_UNKNOWN_VARIABLE "u<r>"; +#define RESPONSE_ERROR "e<r>"; + +#define ACCEPT_SEGMENT 0; +#define ERROR_HAPPEND_SO_ACCEPT_SEGMENT 0; +#define REJECT_SEGMENT 1; + +FILE * stderr_file; +FILE * stdout_file; +int script_server_sockfd, script_client_sockfd; + +string set(uint connection_num, string var_name_and_value){ + try{ + string var_name, var_value; + if (! split("<n>",var_name_and_value,var_name,var_value)){ + map<string,Tvar_nums>::const_iterator ci = variables_.find(var_name); + if (ci == variables_.end()){ + return RESPONSE_UNKNOWN_VARIABLE; + }else{ + switch (ci->second){ + case CONNECTION_MAX_SPEED_LIMIT:{ + ulong new_max_speed_limit=atol(var_value.c_str()); + if (new_max_speed_limit==0){ + error_log("Error in scriptserver.cpp: set("+var_name+"=" + +var_value+"): Can't convert "+var_value+" to integer"); + return RESPONSE_ERROR; + }else{ + connection_array[connection_num].max_speed_limit=new_max_speed_limit; + debug("set("+var_name+"="+var_value+")"); + return RESPONSE_OK; + } + } + default:{ + error_log("Error in scriptserver.cpp: set("+var_name+"=" + +var_value+"): UNKNOWN VARIABLE"); + return RESPONSE_UNKNOWN_VARIABLE; + } + } + } + } + return RESPONSE_ERROR; + }catch(...){ + error_log("Error in scriptserver.cpp: set()"); + return RESPONSE_ERROR; + } +} + +string get(uint connection_num, string var_name){ + try{ + map<string,Tvar_nums>::const_iterator ci = variables_.find(var_name); + if (ci == variables_.end()){ + return RESPONSE_UNKNOWN_VARIABLE; + }else{ + switch (ci->second){ + case DISTFILE_NAME:{ + return connection_array[connection_num].segment->parent_distfile->name; + } + case DISTFILE_SIZE:{ + return toString(connection_array[connection_num].segment->parent_distfile->size); + } + case DISTFILE_DLD_SEGMENTS_COUNT:{ + return toString(connection_array[connection_num].segment->parent_distfile->dld_segments_count); + } + case DISTFILE_SEGMENTS_COUNT:{ + return toString(connection_array[connection_num].segment->parent_distfile->segments_count); + } + case DISTFILE_ACTIVE_CONNECTIONS_COUNT:{ + return toString(connection_array[connection_num].segment->parent_distfile->active_connections_num); + } + case SEGMENT_NUM:{ + return toString(connection_array[connection_num].segment->segment_num); + } + case SEGMENT_TRY_NUM:{ + return toString(connection_array[connection_num].segment->try_num); + } + case SEGMENT_SIZE:{ + return toString(connection_array[connection_num].segment->segment_size); + } + case SEGMENT_RANGE:{ + return connection_array[connection_num].segment->range; + } + case CONNECTION_NUM:{ + return toString(connection_num); + } + case CONNECTION_URL:{ + return connection_array[connection_num].url; + } + case NETWORK_NUM:{ + return toString(connection_array[connection_num].network_num); + } + case NETWORK_MODE:{ + return toString(network_array[connection_array[connection_num].network_num].network_mode); + } + case NETWORK_ACTIVE_CONNECTIONS_COUNT:{ + return toString(network_array[connection_array[connection_num].network_num].active_connections_num); + } + default: return RESPONSE_UNKNOWN_VARIABLE; //unknown variable + } + } + return RESPONSE_ERROR; + }catch(...){ + error_log("Error in scriptserver.cpp: get()"); + return RESPONSE_ERROR; + } +} +void init_variables(){ + try{ + variables_["connection.num"]=CONNECTION_NUM; + variables_["connection.url"]=CONNECTION_URL; + variables_["connection.max_speed_limit"]=CONNECTION_MAX_SPEED_LIMIT; + variables_["network.num"]=NETWORK_NUM; + variables_["network.mode"]=NETWORK_MODE; + variables_["network.active_connections_count"]=NETWORK_ACTIVE_CONNECTIONS_COUNT; + variables_["distfile.name"]=DISTFILE_NAME; + variables_["distfile.size"]=DISTFILE_SIZE; + variables_["distfile.dld_segments_count"]=DISTFILE_DLD_SEGMENTS_COUNT; + variables_["distfile.segments_count"]=DISTFILE_SEGMENTS_COUNT; + variables_["distfile.active_connections_count"]=DISTFILE_ACTIVE_CONNECTIONS_COUNT; + variables_["segment.num"]=SEGMENT_NUM; + variables_["segment.try_num"]=SEGMENT_TRY_NUM; + variables_["segment.size"]=SEGMENT_SIZE; + variables_["segment.range"]=SEGMENT_RANGE; +// variables_[""]=; + }catch(...){ + error_log("Error in scriptserver.cpp: init_variables()"); + } +} +void send(int fd, string response){ + try{ + if (write(fd, response.c_str(), response.length())!=(int)response.length()){ + error_log("Error in scriptserver.cpp: send(): response msg size and sent data size are different."); + }; + }catch(...){ + error_log("Error in scriptserver.cpp: send()"); + } +} + +void killscript(int pID){ + try{ + debug("Before killing script"); +/* int killReturn = kill( pID, SIGKILL); // Kill child process + if( killReturn == ESRCH){ // pid does not exist + error_log("Python script does not exist!"); + }else if( killReturn == EPERM){ // No permission to send signal + error_log("No permission to kill python script"); + }else debug("Signal to kill python script sent. All Ok!"); +*/ + waitpid(pID, NULL, 0); + close(script_server_sockfd); + close(script_client_sockfd); + debug("After killing script"); + }catch(...){ + error_log("Error in scriptserver.cpp: killscript()"); + } +} + +bool run_user_python_script(uint connection_num){ + pid_t pID; + try{ + init_variables(); + socklen_t server_len, client_len; + struct sockaddr_un server_address; + struct sockaddr_un client_address; + + int result; + fd_set readfds, testfds; + + unlink("/tmp/segget_script_socket"); + // Create and name a socket for the server: + script_server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + server_address.sun_family = AF_UNIX; + strcpy(server_address.sun_path, "/tmp/segget_script_socket"); + server_len = sizeof(server_address); + bind(script_server_sockfd, (struct sockaddr *)&server_address, server_len); + //Create a connection queue and initialize readfds to handle input from server_sockfd: + listen(script_server_sockfd, 5); + FD_ZERO(&readfds); + FD_SET(script_server_sockfd, &readfds); + + pID = fork(); + if (pID == 0){ // child + alarm(2); // 2 second limit for script to execute + stderr_file = fopen((settings.logs_dir+"/net" + +toString(connection_array[connection_num].network_num) + +"_script_stderr.log").c_str(), "a+"); + if(stderr_file) { + dup2(fileno(stderr_file), 2); + fclose(stderr_file); + } + stdout_file = fopen((settings.logs_dir+"/net" + +toString(connection_array[connection_num].network_num) + +"_script_stdout.log").c_str(), "a+"); + if(stdout_file) { + dup2(fileno(stdout_file), 1); + fclose(stdout_file); + } + system((settings.python_path+" /home/mona/idfetcha/scripts/client.py").c_str()); + _exit(0); + }else{ + if (pID < 0){ // failed to fork + error_log("Error in scriptserver.cpp: failed to fork"); + return 0; + } + } + + error_log("Created pid:"+toString(pID)); + // parent + //Now wait for clients and requests. Because you have passed a null pointer as the timeout parameter, no timeout will occur. The program will exit and report an error if select returns a value less than 1: + struct timeval user_script_start_time; + gettimeofday(&user_script_start_time,NULL); + + while(1000>time_left_from(user_script_start_time)) { + int fd; + int nread; + testfds = readfds; + + debug("scriptserver is waiting for connections"); + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + result = select(FD_SETSIZE, &testfds, (fd_set *)0, (fd_set *)0, &timeout); + if(result < 1) { + error_log("Error in scriptserver.cpp: run_script_server(): error on select "); + killscript(pID); + return ERROR_HAPPEND_SO_ACCEPT_SEGMENT; + } + //Once you know you’ve got activity, you can find which descriptor it’s on by checking each in turn using FD_ISSET: + for(fd = 0; fd < FD_SETSIZE; fd++) { + if(FD_ISSET(fd,&testfds)) { + //If the activity is on server_sockfd, it must be a request for a new connection, and you add the associated client_sockfd to the descriptor set: + if (fd==script_server_sockfd){ + debug("new script client - read"); + client_len = sizeof(client_address); + script_client_sockfd = accept(script_server_sockfd, + (struct sockaddr *)&client_address, &client_len); + FD_SET(script_client_sockfd, &readfds); + debug("adding script client on fd:"+toString(script_client_sockfd)); + break; + }else{ + script_client_sockfd=fd; + ioctl(fd, FIONREAD, &nread); + if(nread == 0) { + debug("removing script client from fd:"+toString(fd)); + }else{ + char buffer[100000]=""; + if (nread!=read(fd, &buffer, nread)){ + error_log("Error in scriptserver.cpp : run_script_server(): Not all data has been read from script-client"); + } + string recv_msg=noupper(buffer); + debug("SCRIPT-SERVER RECIVED:"+recv_msg); + string command, arguments, send_response; + if (! split("<c>",recv_msg,command,arguments)){ + switch (command[0]){ + case 'g':{ + debug("getting: "+arguments); + send(fd,get(connection_num,arguments)); + break; + } + case 's':{ + debug("setting: "+arguments); + send(fd,set(connection_num,arguments)); + break; + } + case 'a':{ + debug("accepting segment: "); + killscript(pID); + return ACCEPT_SEGMENT; + } + case 'r':{ + debug("rejecting segment: "); + killscript(pID); + return REJECT_SEGMENT; + } + } + } + } + } + } + } + } + killscript(pID); + return ACCEPT_SEGMENT; + }catch(...){ + error_log("Error in scriptserver.cpp: run_script_server()"); + return ERROR_HAPPEND_SO_ACCEPT_SEGMENT; + } + killscript(pID); +}
\ No newline at end of file diff --git a/segget/scriptserver.h b/segget/scriptserver.h new file mode 100644 index 0000000..4b3c916 --- /dev/null +++ b/segget/scriptserver.h @@ -0,0 +1,73 @@ +/* +* 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 +*/ + +#ifndef __SCRIPTSERVER_H__ +#define __SCRIPTSERVER_H__ + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <stdio.h> +//#include <netinet/in.h> +//#include <arpa/inet.h> +#include <sys/un.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <string.h> +#include <json/json.h> +#include "tui.h" +#include "pkg.h" + +enum Tvar_nums{ + CONNECTION_NUM, + CONNECTION_URL, + CONNECTION_MAX_SPEED_LIMIT, + NETWORK_NUM, + NETWORK_MODE, + NETWORK_ACTIVE_CONNECTIONS_COUNT, + DISTFILE_NAME, + DISTFILE_SIZE, + DISTFILE_DLD_SEGMENTS_COUNT, + DISTFILE_SEGMENTS_COUNT, + DISTFILE_ACTIVE_CONNECTIONS_COUNT, + SEGMENT_NUM, + SEGMENT_TRY_NUM, + SEGMENT_SIZE, + SEGMENT_RANGE +}; + +extern map<std::string, Tvar_nums> variables_; + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +//void *run_script_server(void * ); +bool run_user_python_script(uint connection_num); +#endif
\ No newline at end of file diff --git a/segget/segget.conf b/segget/segget.conf index 4cac4a3..616ce1e 100644 --- a/segget/segget.conf +++ b/segget/segget.conf @@ -279,6 +279,81 @@ request_ip=127.0.0.1 # request_port=10000 request_port=10000 +[scripting_and_scheduling] +# Segget provides Python scripting functionalyty to support scheduling. +# Each time segget tries to start a new connection certain network it calls +# a python script (client.py) to accept or reject this connection and +# if necessary adjusts its settings. + +# PYTHON_PATH +# Define path to python +# Default: +# python_path=/usr/bin/python +python_path=/usr/bin/python + +# SCRIPTS_DIR +# Define path to a dir with python scripts. Before establishing connection for +# a particular segment via network# segget checks SCRIPTS_DIR. +# If SCRIPTS_DIR contains net#.py file, segget will launch schedule() function +# from this file to apply settings for connetion and accept or reject this +# segment for the moment. net#.py file is a causual python script file +# with a user-writen schedule() function. +# It's necessary to import functions before using get("variable"), +# set("variable",value), accept_segment() and reject_segment() in schedule(). +# get() function can obtain values for the following variables: +# connection.num, connection.url, connection.max_speed_limit, +# network.num, network.mode, network.active_connections_count, +# distfile.name, distfile.size, distfile.dld_segments_count, +# distfile.segments_count, distfile.active_connections_count, +# segment.num, segment.try_num, segment.size, segment.range +# set() function can change connection.max_speed_limit, see example: +# -----------------EXAMPLE STARTS----------------- +# from functions import * +# import time; +# def schedule(): +# localtime = time.localtime(time.time()); +# hour=localtime[3]; +# # disable downloading distfiles that have size more than 5 000 000 bytes +# # from 8-00 to 22-00. +# if hour>8 and hour<21 and (get("distfile.size"))>5000000: +# print "reject because distfile is too big" +# reject_segment() +# # set speed limit 50 000 cps for distfiles larger than 1 000 000 bytes +# if get("distfile.size")>1000000: +# print "limit connection speed" +# set(connection.max_speed_limit, 50000) +# accept_segment() +# -----------------EXAMPLE ENDS----------------- +# From example above localtime returns following tuple: +# Index Attributes Values +# 0 tm_year e.i.: 2008 +# 1 tm_mon 1 to 12 +# 2 tm_mday 1 to 31 +# 3 tm_hour 0 to 23 +# 4 tm_min 0 to 59 +# 5 tm_sec 0 to 61 (60 or 61 are leap-seconds) +# 6 tm_wday 0 to 6 (0 is Monday) +# 7 tm_yday 1 to 366 (Julian day) +# 8 tm_isdst -1, 0, 1, -1 means library determines DST +# Therefore localtime[3] provides hours. +# Segment will be accecpted by default if it was neither accepted nor rejected +# during the schedule() function. +# sagget saves logs of resulting stdout and stderr in the log folder +# separatly for each network. Hence, if there's an error in net3.py file python +# error message would be saved to net3_script_stderr.log. Results of print would +# be saved in net3_script_stdout.log. +# Default: +# scripts_dir=./scripts +scripts_dir=./scripts + +# script_socket_path +# Segget uses AF_UNIX domain sockets for communication with python. +# Specify path for the socket on your filesystem. +# NOTE !: Default value can NOT be changed yet (option under development). +# Default: +# script_socket_path=/tmp/segget_script_socket +script_socket_path=/tmp/segget_script_socket + [logs] # LOGS_DIR # Define a dir to store log files. diff --git a/segget/segget.cpp b/segget/segget.cpp index dd5a626..7160c60 100644 --- a/segget/segget.cpp +++ b/segget/segget.cpp @@ -336,7 +336,18 @@ void launch_request_server_thread(){ 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(); @@ -394,6 +405,13 @@ int routine(){ }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(...){ diff --git a/segget/segget.h b/segget/segget.h index 4edf30e..b74c458 100644 --- a/segget/segget.h +++ b/segget/segget.h @@ -56,6 +56,7 @@ #include "ui_server.h" #include "proxyfetcher.h" #include "requestserver.h" +#include "scriptserver.h" using namespace std; diff --git a/segget/settings.cpp b/segget/settings.cpp index e4415c8..8a4a324 100644 --- a/segget/settings.cpp +++ b/segget/settings.cpp @@ -127,6 +127,9 @@ void Tsettings::init(){ conf.set("request_server","request_ip",request_ip); conf.set("request_server","request_port",request_port,1,65535); + conf.set("scripting_and_scheduling","python_path",python_path); + conf.set("scripting_and_scheduling","scripts_dir",scripts_dir); + conf.clear(); }catch(...){ error_log_no_msg("Error in settings.cpp: init()"); diff --git a/segget/settings.h b/segget/settings.h index f7c2e95..38fb115 100644 --- a/segget/settings.h +++ b/segget/settings.h @@ -79,6 +79,9 @@ class Tsettings{ //request_server string request_ip; ulong request_port; + //scripting_and_scheduling + string python_path; + string scripts_dir; //logs string logs_dir; string general_log_file; @@ -129,6 +132,9 @@ class Tsettings{ //request_server request_ip("127.0.0.1"), request_port(10000), + //scripting_and_scheduling + python_path("/usr/bin/python"), + scripts_dir("./scripts"), //logs logs_dir("./logs"), general_log_file("segget.log"), |