adding a transfer cap to the daemon

Feature requests for the GTK+ version of Transmission
Post Reply
JohnQPublic
Posts: 6
Joined: Mon May 31, 2010 2:54 am

adding a transfer cap to the daemon

Post by JohnQPublic »

So i would really like to see a feature added to the daemon that would allow you to set a monthly maximum on how much bandwidth transmission uses. I have the daemon running on my server that is on 24/7 and would like transmission to automatically clamp its bandwidth down once it has hit 200GB transfered in rolling 30 day period and then reset itself after it has fallen below 200GB. uTorrent has this feature and it is very nice but obviously since it doesn't run natively on nix it is not an option.

I can write a bit of code in python, never done c, which it looks like the daemon is written in, but i am willing to attempt if someone will point me in the right dirrection.

Here is my general idea of what the code might look like in non-c, i would also add two lines to the settings.json file, period and transferCap:

Code: Select all

# write out to a log file atleast once a day with the current date and the total bytes up and down in one line
def usage(date, totalUsageBytes):
    usageLog = open(usage.log)
    usageLog.write(%2D %2M %4Y; %20d\n  %(date, totalUsageBytes) )
    usageLog.close()

# check the log file created above atleast once a day, go through looking for the first line where the date is less than the value of the period setting in the setings.json file, check if the usage listed on that line plus the transferCap setting is greater than or equal to the current total usage, and if it is, set upload and download speed to .1 kbps, then undo it when it falls below.
def transfer_cap():
    currentDate = getDate()
    usageLog = open(usage.log)
    for line in usageLog.lines():
         parts = line.split(';')
         date = parts[0]
         if date + period >= currentDate
             usage = parts[1]
             break
    if usage >= transferCap
        maxUp = 0.1
        maxDown = 0.1 
     else:
         maxUp = default
         maxDown = default         
Anyone think this is doable and willing to point me in the right dirrection to implement it?

Thanks,

JQP
JohnQPublic
Posts: 6
Joined: Mon May 31, 2010 2:54 am

Re: adding a transfer cap to the daemon

Post by JohnQPublic »

So i have taken some time to learn some C and have looked through the source a bit more. I propose adding a function call to the while loop on line 462 of the daemon.c file that calls a new function added to the end of the utils.c file. My function is missing a few things that i don't quite know how to do so any help will be appreciated.

Added line in daemon.c:

Code: Select all

int counter = checkTransferCap( counter );
New function in utils.c:

Code: Select all

#include <iostream.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <string>
int checkTransferCap( counter )
{
    counter++;

do {
    counter = 0;
    char configDir = FIX ME; /* get the config dirrectory */
    int GB = FIX ME; /* get the cap from the config file */
    int days = FIX ME; /* get the rolling window from the config file */
    int wait = 3600; /* Number of seconds between checks, 3600 = 1 hour */
    int period = days * 86400; /* Number of seconds in a day multiplied by the 
                                * number of days in the rolling cap */
    int limit = GB * ( 8^10 ); /* set the limit in bytes to the number of 
                                * gigabytes specified */
    int currentUseage = FIX ME; /* Get current total bytes up and
                                 * down, then add together */
    int currentDate = FIX ME; /* get seconds from epoch */
    
    /* update usage log with current stats */
    FILE *usageLog;
    usageLog = fopen(configDir"/usage.log", "r+");
    fprint (usageLog, "/d;/d\n", currentDate, currentUsage);
    fclose(usageLog);
    
    /* read usage log and check if cap has been exceeded */
    using namespace std;

    ifstream data(configDir"/usage.log", ios::in);
    string line, temp;
    istringstream oss;
    int count = 0;
    vector< vector<string> > DataFromFile;

    while(getline(data, line)){
        DataFromFile.push_back( vector<string>() );
        oss.clear();
        oss.str(line);
        while(oss >> temp)
            DataFromFile[count].push_back(temp);
        count++;
    }

    for(int i = 0; i < DataFromFile.size(); i++){
        int entryDate = DataFromFile[i][0];
        if ( (entryDate + period) < currentDate ){
            int previousUsage = DataFromFile[i][1];
            if ( (previousUsage + limit) < currentUsage){
                FIX ME; /* Call the update bandwidth function and set speed 
                         * limit to 0.1 Kb/s */
                break;
            }
            else{
                FIX ME; /* set bandwidth back to previous setting*/
                break;
            };
           
        }
    }
} while (counter >= wait);
    

    return counter;

} 
Thank you, any help is most appreciated.
JohnQPublic
Posts: 6
Joined: Mon May 31, 2010 2:54 am

Re: adding a transfer cap to the daemon

Post by JohnQPublic »

So i have written code that works in a simulation but am having a little bit of difficulty integrating it with the actual source. Specifically lines 49 and 50 are giving me a segmentation fault. this is most likely because i am calling the tr_sessionSetSpeedLimit() function incorrectly. If someone familiar with the source would kindly tell me what I'm doing wrong, it would be most appreciated. also any general pointers are welcome.

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <stddef.h>
#include <string.h>
#include <../libtransmission/transmission.h>
#include <math.h>




void update_cap_monitor(int norm_up, int norm_down);


int write_out(int time, int usage);

int check_usage(int time, int usage);

void update_cap_monitor(int norm_up, int norm_down)
{
    printf("declaring my vars\n");
    int limit_down;
    int limit_up;
    uint64_t total_bandwidth;
    int current_time = time(NULL);
    printf("setting mySession and setme\n");
    tr_session * mySession = NULL;
    struct tr_session_stats setme;


    printf("getting cumulative stats\n");
    tr_sessionGetCumulativeStats(mySession, &setme);

    printf("loading bandwidth from stats\n");
    total_bandwidth = abs(setme.downloadedBytes) + abs(setme.uploadedBytes);
    printf("total bandwidth is %ld\n", (long int)total_bandwidth);
    if (write_out(current_time, total_bandwidth)) {
        printf("log updated\n");
        if (check_usage(current_time, total_bandwidth)) {
            limit_down = 1;
            limit_up = 1;
        }
        else {
            limit_down = norm_down;
            limit_up = norm_up;
        }
        printf("setting bandwidth limit up and down.\n");
        tr_sessionSetSpeedLimit( mySession, TR_UP, limit_up );
        tr_sessionSetSpeedLimit( mySession, TR_DOWN, limit_down );
    }
    printf("retuning to deamon.c.\n");
}

int write_out(int time, int usage)
{
    FILE *cap_log;
    int cp_test, i;

    cp_test = system("cat /var/lib/transmission-daemon/info/log.txt > /var/lib/transmission-daemon/info/log.bkup");
    if (cp_test == 0) {
        cap_log = fopen("/var/lib/transmission-daemon/info/log.txt", "w");
        fprintf(cap_log, "%d %d\n", time, usage);
        fclose(cap_log);
        i = system("cat /var/lib/transmission-daemon/info/log.bkup >> /var/lib/transmission-daemon/info/log.txt");
        return 1;
    }
    return 0;
}

int check_usage(int time, int usage)
{
    printf("declaring vars for usage test.\n");
    FILE *cap_log;
    int i, c, l, historic_time, historic_usage;
    char line[1000];
    char *line_copy, *string_time, *string_usage;
    int cap = 1000;
    int period = 60;
    int time_diff;
    int usage_diff;

    printf("opening log file.\n");
    cap_log = fopen("/var/lib/transmission-daemon/info/log.txt", "r");
    for (i=1000; i>0; --i) {

        l = fgets(line, 1000, cap_log);

        if ( (c = strlen(line)) > 1 ) {

            line_copy = strdup(line);
            string_time = strtok (line_copy, " ");
            string_usage = strtok(NULL, " ");


            historic_time = atoi(string_time);
            historic_usage = atoi(string_usage);

            time_diff = time - historic_time;
            usage_diff = usage - historic_usage;
            printf("starting comparison.\n");
            if ( time_diff<period && usage_diff>cap) {
                printf("returning 1.\n");
                fclose(cap_log);
                return 1;
            }
            else if (time_diff>period && usage_diff<cap) {
                printf("returning 0.\n");
                fclose(cap_log);
                return 0;
            }
        }
        else {
            printf("error reading log file for comparison.\n");
            break;
        }
    }
    fclose(cap_log);
    return 0;
}
Thanks!
frankeh
Posts: 2
Joined: Wed Jan 12, 2011 12:41 pm

Re: adding a transfer cap to the daemon

Post by frankeh »

Bumping this as it's a feature that I would greatly appreciate.
Did you ever get that edit working?
ijuxda

Re: adding a transfer cap to the daemon

Post by ijuxda »

I have the daemon running on my server that is on 24/7 and would like transmission to automatically clamp its bandwidth down once it has hit 200GB transfered in rolling 30 day period and then reset itself after it has fallen below 200GB.
One way you could do this right now is with a cron script and transmission-remote (arguments --session-stats and --downlimit).
Last edited by ijuxda on Mon Feb 14, 2011 3:59 am, edited 1 time in total.
frankeh
Posts: 2
Joined: Wed Jan 12, 2011 12:41 pm

Re: adding a transfer cap to the daemon

Post by frankeh »

--session-stats isn't on the man page, and --downloadlimit adjusts the per second bandwidth, not the overall.

If --session-stats is a real argument, what does it output?

Edit: Wait, could you monitor stats.json? Can anyone show me the example of the stats.json file? I don't have a machine I can install transmission on yet.
gunzip
Posts: 272
Joined: Wed May 05, 2010 2:12 am

Re: adding a transfer cap to the daemon

Post by gunzip »

frankeh wrote:If --session-stats is a real argument, what does it output?

Code: Select all

$ transmission-remote --session-stats
CURRENT SESSION
  Uploaded:   255.0 MiB
  Downloaded: 756.0 MiB
  Ratio:      0.33
  Duration:   13 hours

TOTAL
  Started 483 times
  Uploaded:   333.5 GiB
  Downloaded: 157.7 GiB
  Ratio:      2.11
  Duration:   79 days
frankeh wrote:Can anyone show me the example of the stats.json file?

Code: Select all

$ cat ~/.config/transmissioncli/stats.json
{
    "downloaded-bytes": 169277890125, 
    "files-added": 82204, 
    "seconds-active": 6869488, 
    "session-count": 483, 
    "uploaded-bytes": 358106446461
}
ijuxda

Re: adding a transfer cap to the daemon

Post by ijuxda »

Can you please clarify what is meant by "bandwidth".
Post Reply