#!/usr/local/bin/python
# Copyright (c) 2003
# International Computer Science Institute
# All rights reserved.
#
# This file may contain software code developed for the
# TBIT project. The TBIT software carries the following copyright:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgment:
#      This product includes software developed by ACIRI, the AT&T
#      Center for Internet Research at ICSI (the International Computer
#      Science Institute). This product may also include software developed
#      by Stefan Savage at the University of Washington.
# 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
#    may not be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

import sys, string, fileinput, commands, os, os.path;
import urlparse, urllib;
from types import *;
import pprint, time;

# Base directory for running tests
TEST_DIR = "/home/cougar/u0/medina/RESEARCH/MEASUREMENTS/TBIT-TESTS/Alberto-Scripts";

# Specific test directories
RENOTEST_DIR = TEST_DIR + "/reno-test";
ECNTEST_DIR = TEST_DIR + "/ecn-test";
SACKSNDR3PTEST_DIR = TEST_DIR + "/sacksndr3p-test";
INITWINTEST_DIR = TEST_DIR + "/initwin-test";
ISSACKTEST_DIR = TEST_DIR + "/sack-test";
WINHALFTEST_DIR = TEST_DIR + "/winhalf-test";
TIMESTAMPTEST_DIR = TEST_DIR + "/timestamp-test";
TAHOENOFRTEST_DIR = TEST_DIR + "/tahoenofr-test";
SACKRCVRTEST_DIR = TEST_DIR + "/sackrcvr-test";
TIMEWAITTEST_DIR = TEST_DIR + "/timewait-test";
DELACKTEST_DIR = TEST_DIR + "/delack-test";
MINMSSTEST_DIR = TEST_DIR + "/minmss-test";
REORDERINGTEST_DIR = TEST_DIR + "/reordering-test";
NEWECNTEST_DIR = TEST_DIR + "/newecn-test";
REDIRECTIONTEST_DIR = TEST_DIR + "/redirection-test";
TOTDATATEST_DIR = TEST_DIR + "/totdata-test";

# Directory for URL lists
URLLISTS_DIR = TEST_DIR + "/URL-LISTS";

# TBIT return status codes
status_code = {
  -1: "FAIL",
  0: "SUCCESS",
  1: "NO_TARGET_CANON_INFO",
  2: "NO_LOCAL_HOSTNAME",
  3: "NO_SRC_CANON_INFO",
  4: "NO_SESSION_ESTABLISH",
  5: "MSS_TOO_SMALL",
  6: "BAD_ARGS",
  7: "FIREWALL_ERR", 
  8: "ERR_SOCKET_OPEN",
  9: "ERR_SOCKOPT",
  10: "ERR_MEM_ALLOC",
  11: "NO_CONNECTION",
  12: "MSS_ERR",      
  13: "BUFFER_OVERFLOW",
  14: "UNWANTED_PKT_DROP",
  15: "EARLY_RST",        
  16: "UNEXPECTED_PKT",   
  17: "DIFF_FLOW",        
  18: "ERR_CHECKSUM",     
  19: "NOT_ENOUGH_PKTS",  
  20: "BAD_OPT_LEN",      
  21: "TOO_MANY_PKTS",    
  22: "NO_DATA_RCVD",     
  23: "NO_TRGET_SPECIFIED",
  24: "BAD_OPTIONS",       
  25: "TOO_MANY_TIMEOUTS", 
  26: "TOO_MANY_RXMTS",    
  27: "NO_SACK",           
  28: "ERR_IN_SB_CALC",    
  39: "TOO_MANY_HOLES",    
  30: "TOO_MANY_DROPS",    
  31: "UNWANTED_PKT_REORDER",
};

MAX_HOST_LENGTH = 30;
MAX_IP_LENGTH = 20;

class MyFancyURLopener(urllib.FancyURLopener):

    def prompt_user_passwd(self, username, passwd):
        return;
    
def usage():
    print """Run
    run_tbit_test.py <input-file> <test-name> <m> <repeat> <output-file> <process-res-only>
    where:
    \t\t <input-file>: list of URLs to be tested
    \t\t <test-name>: Reno | ECN | Timestamp |...
    \t\t <m>: MSS parameter
    \t\t <repeat>: number of times to perform test on each server
    \t\t <output-file>: file containing the processed results
    \t\t <process-res-only>: 1 - only process results of previous experiment,
    \t\t                     0 - do both experiment and processing
    """;
    return;


def GetURLIPAddr(url):

    """ Determine IP Address of requested URL"""

    scheme, hostname, path, params, query, frag = urlparse.urlparse(url);
    if not hostname:
        l = string.split(path, "/");
        hostname = l[0];

    cmd = "host " + hostname;
    
    s,o = commands.getstatusoutput(cmd);
    ipaddrs = [];

    if not s:
        l = string.split(o, "\n");
        for l_el in l:
            if string.find(l_el, "address") > 0:
                l_el_fields = string.split(l_el);
                ipaddrs.append(l_el_fields[-1]);

    return ipaddrs;

# #########################################################
#
#    RESULTS Processing
#
###########################################################

def PadStringField(f, l):

    if len(f) < l:
        pad = l - len(f) + 1;
        while pad:
            f = f + " ";
            pad = pad - 1;
    return f;

    
def ProcessNewRenoResults(output_file):

    print "Processing Reno-test results...";

    version = {};
    version["Uncategorized"] = {};
    version["Uncategorized"]["rel"] = 0;    
    version["Uncategorized"]["unrel"] = 0;
    version["Tahoe"] = {};
    version["Tahoe"]["rel"] = 0;
    version["Tahoe"]["unrel"] = 0;    
    version["TahoeNoFR"] = {};
    version["TahoeNoFR"]["rel"] = 0;
    version["TahoeNoFR"]["unrel"] = 0;    
    version["Reno"] = {};
    version["Reno"]["rel"] = 0;
    version["Reno"]["unrel"] = 0;    
    version["NewReno"] = {};
    version["NewReno"]["rel"] = 0;
    version["NewReno"]["unrel"] = 0;    
    version["AggresiveReno"] = {};
    version["AggresiveReno"]["rel"] = 0;
    version["AggresiveReno"]["unrel"] = 0;    
    version["AggresiveTahoeNoFR"] = {};
    version["AggresiveTahoeNoFR"]["rel"] = 0;
    version["AggresiveTahoeNoFR"]["unrel"] = 0;    
    version["RenoPlus"] = {};
    version["RenoPlus"]["rel"] = 0;
    version["RenoPlus"]["unrel"] = 0;    
    version["RenoNS"] = {};
    version["RenoNS"]["rel"] = 0;
    version["RenoNS"]["unrel"] = 0;    

    c = 0;
    e = 0;
    correct = [];
    errors = []

    num_no_connection_errors = 0;
    num_not_enough_pkts_errors = 0;
    num_no_data_rcvd_errors = 0;
    num_unexpected_pkt_errors = 0;
    num_mss_errors = 0;
    num_early_rst_errors = 0;
    
    no_connection_errors = [];
    not_enough_pkts_errors = [];
    no_data_rcvd_errors = [];
    unexpected_pkt_errors = [];
    mss_errors = [];
    early_rst_errors = [];
    
    for line in fileinput.input("MASTERLOG"):

        if string.find(line, "version") > 0:

            date, runid, srv, ip, rx, to, v, rtt, reord, count, d = string.split(line);

            try:
                if string.atoi(string.split(d,"=")[1]) == 0:
                    version[string.split(v, "=")[1]]["rel"] += 1;
                else:
                    version[string.split(v, "=")[1]]["unrel"] += 1;
                    
            except:
                print "Unrecognized line: " + line;
                continue;

            l = PadStringField(srv, MAX_HOST_LENGTH) +\
                PadStringField(ip, MAX_IP_LENGTH) +\
                rx + " " + to + " " + string.split(v,"=")[1] +\
                " " + rtt + " " + reord + " " + count + " " + d;

            c += 1;
            correct.append(l);

        else:
            error_fields = string.split(line);            
            l = PadStringField(error_fields[2], MAX_HOST_LENGTH) +\
                PadStringField(error_fields[3], MAX_IP_LENGTH) +\
                str(error_fields[4:]);

            if string.find(line, "NO_CONNECTION") >= 0:
                num_no_connection_errors += 1;
                no_connection_errors.append(l);
                
            elif string.find(line, "NOT_ENOUGH_PKTS") >= 0:
                num_not_enough_pkts_errors += 1;
                not_enough_pkts_errors.append(l);
                
            elif string.find(line, "NO_DATA_RCVD") >= 0:
                num_no_data_rcvd_errors += 1;
                no_data_rcvd_errors.append(l);
                
            elif string.find(line, "UNEXPECTED_PKT") >= 0:
                num_unexpected_pkt_errors += 1;
                unexpected_pkt_errors.append(l);
                
            elif string.find(line, "MSS_ERR") >= 0:
                num_mss_errors += 1;
                mss_errors.append(l);

            elif string.find(line, "EARLY_RST") >= 0:
                num_early_rst_errors += 1;
                early_rst_errors.append(l);

            else:
                e += 1;
                errors.append(l);


    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    o_fd.write("========================================\n");

    o_fd.write(PadStringField("NewReno", 20) + " - rel:" + str(version["NewReno"]["rel"]) + \
               " unrel: " + str(version["NewReno"]["unrel"]) + "\n");
    o_fd.write(PadStringField("Reno", 20)  + " - rel:" + str(version["Reno"]["rel"]) + \
               " unrel: " + str(version["Reno"]["unrel"]) + "\n");    
    o_fd.write(PadStringField("RenoPlus", 20) + " - rel:" + str(version["RenoPlus"]["rel"]) + \
               " unrel: " + str(version["RenoPlus"]["unrel"]) + "\n");
    o_fd.write(PadStringField("AggresiveReno", 20)  + " - rel:" + str(version["AggresiveReno"]["rel"]) + \
               " unrel: " + str(version["AggresiveReno"]["unrel"]) + "\n");
    o_fd.write(PadStringField("RenoNS", 20) + " - rel:"+ str(version["RenoNS"]["rel"]) + \
               " unrel: " + str(version["RenoNS"]["unrel"]) + "\n");
    o_fd.write(PadStringField("Tahoe", 20)  + " - rel:" + str(version["Tahoe"]["rel"]) + \
               " unrel: " + str(version["Tahoe"]["unrel"]) + "\n");
    o_fd.write(PadStringField("TahoeNoFR", 20)  + " - rel:" + str(version["TahoeNoFR"]["rel"]) + \
               " unrel: " + str(version["TahoeNoFR"]["unrel"]) + "\n");
    o_fd.write(PadStringField("AggresiveTahoeNoFR", 20) + " - rel:" + str(version["AggresiveTahoeNoFR"]["rel"]) + \
               " unrel: " + str(version["AggresiveTahoeNoFR"]["unrel"]) + "\n");
    o_fd.write(PadStringField("Uncategorized", 20) + " - rel:" + str(version["Uncategorized"]["rel"]) + \
               " unrel: " + str(version["Uncategorized"]["unrel"]) + "\n");    
    o_fd.write(PadStringField("ERROR:NO_CONNECTION", 25) + str(num_no_connection_errors) + "\n");
    o_fd.write(PadStringField("ERROR:NOT_ENOUGH_PKTS", 25) + str(num_not_enough_pkts_errors) + "\n");
    o_fd.write(PadStringField("ERROR:NO_DATA_RCVD", 25) + str(num_no_data_rcvd_errors) + "\n");
    o_fd.write(PadStringField("ERROR:UNEXPECTED_PKT", 25) + str(num_unexpected_pkt_errors) + "\n");
    o_fd.write(PadStringField("ERROR:MSS_ERR", 25) + str(num_mss_errors) + "\n");
    o_fd.write(PadStringField("ERROR:EARLY_RST", 25) + str(num_early_rst_errors) + "\n");
    o_fd.write(PadStringField("ERROR:OTHERS", 25) + str(e) + "\n");    

    e = e + num_no_connection_errors + num_not_enough_pkts_errors +\
        num_no_data_rcvd_errors + num_unexpected_pkt_errors +\
        num_unexpected_pkt_errors + num_mss_errors + num_early_rst_errors;
    
    o_fd.write("---------------------------------------\n");
    o_fd.write("Errors: " + str(e) + "\n");
    o_fd.write("Total: " + str(c + e) + "\n");
    o_fd.write("========================================\n");
    

    for line in correct:
        o_fd.write(line + "\n");

    for line in no_connection_errors:
        o_fd.write(line + "\n");

    for line in not_enough_pkts_errors:
        o_fd.write(line + "\n");

    for line in no_data_rcvd_errors:
        o_fd.write(line + "\n");                

    for line in unexpected_pkt_errors:
        o_fd.write(line + "\n");

    for line in mss_errors:
        o_fd.write(line + "\n");

    for line in early_rst_errors:
        o_fd.write(line + "\n");
        
    for line in errors:
        o_fd.write(line + "\n");        
        
        

def ProcessECNResults(output_file):

    print "Processing ECN-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    ecn_sr1_se0_ar1_ae0 = 0;
    ecn_sr1_se0_ar1_ae0_vals = [];
    
    ecn_sr1_se1_ar1_ae0 = 0;
    ecn_sr1_se1_ar1_ae0_vals = [];
    
    ecn_sr1_se0_ar0_ae0 = 0;
    ecn_sr1_se0_ar0_ae0_vals = [];
    
    ecn_sr1_se1_ar1_ae1 = 0;
    ecn_sr1_se1_ar1_ae1_vals = [];
    
    ecn_sr1_se1_ar0_ae0 = 0;
    ecn_sr1_se1_ar0_ae0_vals = [];

    ecn_sr1_se0_ar1_ae1 = 0;
    ecn_sr1_se0_ar1_ae1_vals = [];
    
    ecn_sr1_se1_ar1_ae1 = 0;
    ecn_sr1_se1_ar1_ae1_vals = [];    

    ecn_unknown_results = [];

    ecn_total_errors = 0;
    ecn_no_conn_err = 0;
    ecn_no_conn_timestamp_err = 0;
    ecn_unexpected_packet_err = 0;
    ecn_early_rst_err = 0;
    ecn_other_errors = 0;

    ecn_no_conn_err_vals = [];
    ecn_no_conn_timestamp_err_vals = [];
    ecn_unexpected_packet_err_vals = [];
    ecn_early_rst_err_vals = [];
    ecn_other_errors_vals = [];        
    
    ecn_errors_vals = [];
    
    for line in fileinput.input("MASTERLOG"):

        if string.find(line, "sr=") >= 0 and \
           string.find(line, "se=") >= 0 and \
           string.find(line, "ar=") >= 0 and \
           string.find(line, "ae=") >= 0:

            # process result line
            date, runid, srv, ip, result = string.split(line);

            if string.find(line, "sr=1:se=0:ar=1:ae=0") >= 0:
                ecn_sr1_se0_ar1_ae0 += 1;
                srv = PadStringField(srv, MAX_HOST_LENGTH);
                ip = PadStringField(ip, MAX_IP_LENGTH);
                r = srv + " " + ip + result;
                ecn_sr1_se0_ar1_ae0_vals.append(r);

            elif string.find(line, "sr=1:se=1:ar=1:ae=0") >= 0:
                ecn_sr1_se1_ar1_ae0 += 1;
                srv = PadStringField(srv, MAX_HOST_LENGTH);
                ip = PadStringField(ip, MAX_IP_LENGTH);
                r = srv + " " + ip + result;
                ecn_sr1_se1_ar1_ae0_vals.append(r);                

            elif string.find(line, "sr=1:se=0:ar=0:ae=0") >= 0:
                ecn_sr1_se0_ar0_ae0 += 1;
                srv = PadStringField(srv, MAX_HOST_LENGTH);
                ip = PadStringField(ip, MAX_IP_LENGTH);
                r = srv + " " + ip + result;
                ecn_sr1_se0_ar0_ae0_vals.append(r);                            

            elif string.find(line, "sr=1:se=1:ar=0:ae=0") >= 0:
                ecn_sr1_se1_ar0_ae0 += 1;
                srv = PadStringField(srv, MAX_HOST_LENGTH);
                ip = PadStringField(ip, MAX_IP_LENGTH);
                r = srv + " " + ip + result;
                ecn_sr1_se1_ar0_ae0_vals.append(r);

            elif string.find(line, "sr=1:se=0:ar=1:ae=1") >= 0:
                ecn_sr1_se0_ar1_ae1 += 1;
                srv = PadStringField(srv, MAX_HOST_LENGTH);
                ip = PadStringField(ip, MAX_IP_LENGTH);
                r = srv + " " + ip + result;
                ecn_sr1_se0_ar1_ae1_vals.append(r);
                
            elif string.find(line, "sr=1:se=1:ar=1:ae=1") >= 0:
                ecn_sr1_se1_ar1_ae1 += 1;
                srv = PadStringField(srv, MAX_HOST_LENGTH);
                ip = PadStringField(ip, MAX_IP_LENGTH);
                r = srv + " " + ip + result;
                ecn_sr1_se1_ar1_ae1_vals.append(r);

            else:
                r = line;
                ecn_unknown_results.append(r);
    
        else:
            
            # process error line
            line_fields = string.split(line);
            ecn_total_errors += 1;

            srv = PadStringField(line_fields[2], MAX_HOST_LENGTH);
            ip = PadStringField(line_fields[3], MAX_IP_LENGTH);
            result = string.join(line_fields[4:]);

            r = srv + " " + ip + result;

            if string.find(line, "NO_CONNECTION_TIMESTAMP") >= 0:
                ecn_no_conn_timestamp_err += 1;                
                ecn_no_conn_timestamp_err_vals.append(r);
                
            elif string.find(line, "NO_CONN") >= 0:
                ecn_no_conn_err += 1;                
                ecn_no_conn_err_vals.append(r);
                
            elif string.find(line, "Unexpected") >= 0:
                ecn_unexpected_packet_err += 1;                
                ecn_unexpected_packet_err_vals.append(r);
                
            elif string.find(line, "EARLY_RST") >= 0:
                ecn_early_rst_err += 1;                
                ecn_early_rst_err_vals.append(r);
                
            else:
                ecn_other_errors += 1;                
                ecn_other_errors_vals.append(r);
            

    o_fd.write("========================================\n");
    o_fd.write("Summary:\n");
    o_fd.write("========================================\n");
    o_fd.write("sr=1:se=0:ar=1:ae=0:\t" + str(ecn_sr1_se0_ar1_ae0) + "\n");
    o_fd.write("sr=1:se=1:ar=1:ae=0:\t" + str(ecn_sr1_se1_ar1_ae0) + "\n");
    o_fd.write("sr=1:se=0:ar=0:ae=0:\t" + str(ecn_sr1_se0_ar0_ae0) + "\n");
    o_fd.write("sr=1:se=1:ar=0:ae=0:\t" + str(ecn_sr1_se1_ar0_ae0) + "\n");
    o_fd.write("sr=1:se=0:ar=1:ae=1:\t" + str(ecn_sr1_se0_ar1_ae1) + "\n");        
    o_fd.write("sr=1:se=1:ar=1:ae=1:\t" + str(ecn_sr1_se1_ar1_ae1) + "\n");    
    o_fd.write(PadStringField("ERROR: NO_CONN:", 30) + str(ecn_no_conn_timestamp_err) + "\n");    
    o_fd.write(PadStringField("ERROR: NO_CONN_TIMESTAMP:", 30) + str(ecn_no_conn_err) + "\n");
    o_fd.write(PadStringField("ERROR: UNEXPECTED_PACKET:", 30) + str(ecn_unexpected_packet_err) + "\n");
    o_fd.write(PadStringField("ERROR: EARLY_RST:", 30) + str(ecn_early_rst_err) + "\n");
    o_fd.write(PadStringField("ERROR: OTHER:", 30) + str(ecn_other_errors) + "\n");    

    o_fd.write("\n========================================\n");
    o_fd.write("Explanation of Results:\n");
    o_fd.write("========================================\n");

    o_fd.write("sr=1:                - SYN/ACK received\n");
    o_fd.write("se=1/0:              - ECN_ECHO set/not set in the SYN/ACK\n");
    o_fd.write("ar=1/0:              - Ack for the data packet (ECT and CE bits set) rcvd/not-rcvd\n");
    o_fd.write("ae=1/0:              - ack had ECN_ECHO bit set/not set.\n");

    o_fd.write("sr=1:se=0:ar=1:ae=0: - Server ECN-capable, but didn't report CE bit set\n");
    o_fd.write("sr=1:se=1:ar=1:ae=0: - Server not ECN-capable, and no ACK for data pkt\n");
    o_fd.write("sr=1:se=0:ar=0:ae=0: - Server ECN-capable, reports CE bit set\n");
    o_fd.write("sr=1:se=1:ar=0:ae=0: - Server ECN-capable. but no ACK for data pkt\n");
    o_fd.write("sr=1:se=0:ar=1:ae=1: - Server ECN-capable. but...\n");    
    o_fd.write("sr=1:se=1:ar=1:ae=1: - Server ECN-capable and properly implemented.\n");    

    o_fd.write("\n========================================\n");
    o_fd.write("Results:\n");
    o_fd.write("========================================\n");

    # Succesful cases
    for line in ecn_sr1_se0_ar1_ae0_vals:
        o_fd.write(line + "\n");

    for line in ecn_sr1_se1_ar1_ae0_vals:
        o_fd.write(line + "\n");

    for line in ecn_sr1_se0_ar0_ae0_vals:
        o_fd.write(line + "\n");

    for line in ecn_sr1_se1_ar0_ae0_vals:
        o_fd.write(line + "\n");

    for line in ecn_sr1_se0_ar1_ae1_vals:
        o_fd.write(line + "\n");
        
    for line in ecn_sr1_se1_ar1_ae1_vals:
        o_fd.write(line + "\n");

    # "Unknown" results
    for line in ecn_unknown_results:
        o_fd.write(line + "\n");                

    # Error cases
    for line in ecn_no_conn_timestamp_err_vals:
        o_fd.write(line + "\n");

    for line in ecn_no_conn_err_vals:
        o_fd.write(line + "\n");

    for line in ecn_unexpected_packet_err_vals:
        o_fd.write(line + "\n");

    for line in ecn_early_rst_err_vals:
        o_fd.write(line + "\n");

    for line in ecn_other_errors_vals:
        o_fd.write(line + "\n");        
        

def ProcessSackResults(output_file):

    print "Processing Sack-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    c = 0; e = 0;
    correct_sack = [];
    errors = [];
    sack_0 = 0;
    sack_1 = 0;

    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);
        if string.find(line, "sack") > 0:

            c += 1;
            date, runid, srv, ip, s = string.split(line);
            
            l = [PadStringField(srv, MAX_HOST_LENGTH),\
                 PadStringField(ip, MAX_IP_LENGTH), s];

            s,n = string.split(s,"=");
            if string.atoi(n) == 0:
                sack_0 += 1;
            else:
                sack_1 += 1;
                
            correct_sack.append(string.join(l));                    

        else:
            e += 1;
            line_fields = string.split(line);
            date = line_fields[0];
            runid = line_fields[1];
            srv = line_fields[2];
            ip = line_fields[3];
            error = string.join(line_fields[4:]);
            l = [PadStringField(srv, MAX_HOST_LENGTH),\
                 PadStringField(ip, MAX_IP_LENGTH),\
                 error];
            errors.append(string.join(l));

    o_fd.write("========================================\n");
    o_fd.write("sack = 0: " + str(sack_0) + "\n");
    o_fd.write("sack = 1: " + str(sack_1) + "\n");
    o_fd.write("Errors:   " + str(e)      + "\n");
    o_fd.write("Total:    " + str(c + e)  + "\n");
    o_fd.write("========================================\n");

    for url in correct_sack:
        o_fd.write(url + "\n");
 
    for url in errors:        
        o_fd.write(url + "\n");


    o_fd.close();

    return 0;            


def ProcessSackSndr3PResults(output_file):

    print "Processing SackSndr3P-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;
    
    c = 0; e = 0;
    correct_sack = [];
    correct_no_sack = [];    
    errors = [];
    sack_0 = 0; sack_1 = 0; sack_2 = 0; sack_3 = 0; sack_4 = 0;
    sack_10 = 0; sack_11 = 0; sack_12 = 0; sack_13 = 0; sack_14 = 0;    
    no_sack = 0;

    for line in fileinput.input("MASTERLOG"):

        if string.find(line, "sack") > 0:

            c += 1;
            date, runid, srv, ip, s, es, n, d, es, nd = string.split(line);
            l = [PadStringField(srv, MAX_HOST_LENGTH),\
                 PadStringField(ip, MAX_IP_LENGTH),\
                 s, es, n];

            sack_val = string.atoi(n);
            num_drops = string.atoi(nd);
            
            if sack_val == 0:
                if num_drops > 0:
                    sack_10 += 1;
                else:
                    sack_0 += 1;
            elif sack_val == 1:
                if num_drops > 0:
                    sack_11 += 1;
                else:
                    sack_1 += 1;                
            elif sack_val == 2:
                if num_drops > 0:
                    sack_12 += 1;
                else:
                    sack_2 += 1;
            elif sack_val == 3:
                if num_drops > 0:
                    sack_13 += 1;
                else:
                    sack_3 += 1;
            else:
                if num_drops > 0:
                    sack_14 += 1;
                else:
                    sack_4 += 1;

            if num_drops == 0:
                correct_sack.append(string.join(l));            

        elif string.find(line, "NO_SACK") > 0:
            c += 1;
            no_sack += 1;
            
        else:
            e += 1;
            line_fields = string.split(line);
            date = line_fields[0];
            runid = line_fields[1];
            srv = line_fields[2];
            ip = line_fields[3];
            error = string.join(line_fields[4:]);
            l = [PadStringField(srv, MAX_HOST_LENGTH),\
                 PadStringField(ip, MAX_IP_LENGTH),\
                 error];
            errors.append(string.join(l));

    o_fd.write("========================================\n");
    o_fd.write("Summary:");
    o_fd.write("========================================\n");
    o_fd.write("sack = 0: " + "rel: " + str(sack_0) + " unrel:" + str(sack_10) + "\n");
    o_fd.write("sack = 1: " + "rel: " + str(sack_1) + " unrel:" + str(sack_11) + " -- proper SACK \n");
    o_fd.write("sack = 2: " + "rel: " + str(sack_2) + " unrel:" + str(sack_12) + " -- NewReno \n");
    o_fd.write("sack = 3: " + "rel: " + str(sack_3) + " unrel:" + str(sack_13) + " -- Semi-SACK\n");
    o_fd.write("sack = 4: " + "rel: " + str(sack_4) + " unrel:" + str(sack_14) + " -- TahoeNoFR\n");
    o_fd.write("no sack:  " + str(no_sack) + "\n");    
    o_fd.write("Errors:   " + str(e) + "\n");
    o_fd.write("Total:    " + str(c + e) + "\n");
    o_fd.write("========================================\n");
    
    for url in correct_sack:
        o_fd.write(url + "\n");
 
    for url in errors:        
        o_fd.write(url + "\n");

    o_fd.close();

    return 0;
    


def ProcessWinHalfResults(output_file):

    print "Processing WinHalf-test results...";
    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    c = 0;
    e = 0;
    correct = [];
    errors = [];
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);

        l = PadStringField(line_fields[2], MAX_HOST_LENGTH) \
            + PadStringField(line_fields[3], MAX_IP_LENGTH) \
            + string.join(line_fields[4:]);
        
        if "Window" in line_fields:
            correct.append(l);
            c += 1;

        else:
            errors.append(l);
            e += 1;

    o_fd.write("========================================\n");
    o_fd.write("Summary:\n");
    o_fd.write("Errors: " +  str(e) + "\n");
    o_fd.write("Total:  " +  str(c + e) + "\n");
    o_fd.write("========================================\n");
    for url in correct:
        o_fd.write(url + "\n");

    for url in errors:        
        o_fd.write(url + "\n");    
    o_fd.close();

    return 0;


def ProcessTimestampResults(output_file):
    print "Processing Timestamp-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    ts = 0;
    n_ts = 0;
    e = 0;
    correct = [];
    errors = [];
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);
        if string.find(line, "timestamp") >= 0:
            t = string.atoi(string.split(line_fields[4], "=")[1]);
            ts += t;
            n_ts += 1 - t;
            l = PadStringField(line_fields[2], MAX_HOST_LENGTH)\
                + PadStringField(line_fields[3], MAX_IP_LENGTH) \
                + "Timestamp =" + str(t);
            
            correct.append(l);
            
        elif string.find(line, "ERROR") >= 0:
            l = PadStringField(line_fields[2], MAX_HOST_LEN) \
                + PadStringField(line_fields[3], MAX_IP_LENGTH) \
                + string.join(line_fields[4:]);
            errors.append(l);
            e += 1;
                
    total = ts + e
    o_fd.write("========================\n");
    o_fd.write("Summary:\n");
    o_fd.write("TS 0:   " +  str(n_ts) + "\n");
    o_fd.write("TS 1:   " +  str(ts) + "\n");
    o_fd.write("Errors: " + str(e) + "\n");
    o_fd.write("Total:  " + str(e + ts + n_ts) + "\n");
    o_fd.write("========================\n");

    for line in correct:
        o_fd.write(line + "\n");
    for line in errors:
        o_fd.write(line + "\n");
        
    o_fd.close();

    return 0;    


def ProcessTahoeNoFRResults(output_file):
    print "Processing TahoeNoFR-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    correct = [];
    errors = [];
    c = 0;
    e = 0;
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);
        l = PadStringField(line_fields[2], MAX_HOST_LENGTH) + \
            PadStringField(line_fields[3], MAX_IP_LENGTH) +\
            string.join(line_fields[4:]);

        if string.find(line, "ERROR") >= 0:
            errors.append(l);
            e += 1;
        else:
            correct.append(l);
            c += 1;


    o_fd.write("========================\n");
    o_fd.write("Summary:\n");
    o_fd.write("Correct: " + str(c) + "\n");
    o_fd.write("Errors:  " + str(e) + "\n");
    o_fd.write("Total:   " + str(c + e) + "\n");
    o_fd.write("========================\n");

    for line in correct:
        o_fd.write(line + "\n");
    for line in errors:
        o_fd.write(line + "\n");
    
    o_fd.close();

    return 0;

        

def ProcessSackRcvrResults(output_file):

    print "Processing SackRcvr-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    no_sack = 0;
    sack = 0;
    sack_prob = 0;
    e = 0;
    correct = [];
    sack_problems = [];
    errors = [];
    
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);

        l = PadStringField(line_fields[2], MAX_HOST_LENGTH) +\
            PadStringField(line_fields[3], MAX_IP_LENGTH) +\
            string.join(line_fields[4:]);
        
        if string.find(line, "NO_SACK") >= 0:
            no_sack += 1;

        elif string.find(line, "okay") >= 0:
            sack += 1;
            correct.append(l);

        elif string.find(line, "No sack block") >= 0 or\
                 string.find(line, "Error in sack block") >= 0 :
            sack_prob += 1;
            sack_problems.append(l);            
            
        else:
            errors.append(l);
            e += 1;
    
    o_fd.write("========================================\n");
    o_fd.write("Summary:\n");
    o_fd.write("sack OK:        " +  str(sack) + "\n");
    o_fd.write("sack problems:  " +  str(sack_prob) + "\n");    
    o_fd.write("no sack:        " +  str(no_sack) + "\n");        
    o_fd.write("Errors:         " +  str(e) + "\n");
    o_fd.write("Total:          " +  str(e + sack + sack_prob + no_sack) + "\n");
    o_fd.write("========================================\n");

    for l in correct:
        o_fd.write(l + "\n");

    for l in sack_problems:
        o_fd.write(l + "\n");        

    for l in errors:
        o_fd.write(l + "\n");        

    o_fd.close();

    return 0;

def ProcessDelACKResults(output_file):
    print "Processing DelACK-test results...";

    e = 0;
    c = 0;
    correct = [];
    errors = [];
    
    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;
    
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);

        l = PadStringField(line_fields[2], MAX_HOST_LENGTH) +\
            PadStringField(line_fields[3], MAX_IP_LENGTH) +\
            string.join(line_fields[4:]);
        
        if string.find(line, "delack") >= 0:
            c += 1;
            correct.append(l);
        else:
            e += 1;
            errors.append(l);
            
    o_fd.write("========================================\n");
    o_fd.write("Summary:\n");
    o_fd.write("Correct: " + str(c) + "\n");
    o_fd.write("Errors:  " +  str(e) + "\n");
    o_fd.write("Total:   " +  str(e + c) + "\n");
    o_fd.write("========================================\n");

    for l in correct:
        o_fd.write(l + "\n");
    for l in errors:
        o_fd.write(l + "\n");        
        
    o_fd.close();

    return;


def ProcessInitWinResults(output_file, args):

    print "Processing InitWin-test results...";

    errors = [];
    correct = [];
    e = 0;
    c = 0;
    seen_iwin = {};
    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);

        for field in line_fields:

            if string.find(field, "initWin") >= 0:

                c += 1;
                try:
                    init_win = string.atoi(string.split(line_fields[4], "=")[1]);
                except:
                    init_win = string.atoi(string.split(line_fields[4], ">")[1]);
                    
                if seen_iwin.has_key(init_win):
                    seen_iwin[init_win] += 1;
                else:
                    seen_iwin[init_win] = 1;
                correct.append(string.join(line_fields[2:]));
                break;

        else:
            e += 1;
            errors.append(string.join(line_fields[1:]));


    m = args["m"];
    o_fd.write("=================================================\n");    
    o_fd.write("Initial window in packets, with '" + str(m) + "'-byte packets\n");
    o_fd.write("=================================================\n");
    iw_sorted = seen_iwin.keys();
    iw_sorted.sort();
    o_fd.write("Initial window \t Count\n");
    for iw in iw_sorted:
        o_fd.write("\t" + str(iw) + "\t  " + str(seen_iwin[iw]) + "\n");
    o_fd.write("-----------------------------------------\n");        
    o_fd.write("Errors: " +  str(e) + "\n");
    o_fd.write("Total:  " +  str(e + c) + "\n");
    o_fd.write("-----------------------------------------\n");

    for url in correct:
        line_fields = string.split(url);
        srv = line_fields[0];
        ip = line_fields[1];
        try:
            iw = string.split(line_fields[2],"=")[1];
        except:
            iw = string.split(line_fields[2],">")[1];            
            
        l = [PadStringField(srv, MAX_HOST_LENGTH),\
             PadStringField(ip, MAX_IP_LENGTH), iw];

        o_fd.write(string.join(l) + "\n");    

    o_fd.write("========================================\n");

    o_fd.close();


def ProcessMinMSSResults(output_file):

    print "Processing MinMSS-test results...";

    errors = [];
    correct = [];
    e = 0;
    c = 0;
    seen_mss = {};
    
    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    last_server = "";
    grab_next_line = 0;
    
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);
        
        if grab_next_line:

            c += 1;
            correct.append(string.join(line_fields[1:]));
            grab_next_line = 0;

            try:
                print "Previous MSS:", line_fields[4];
            except:
                print line_fields;
                sys.exit();
            
        server = line_fields[2];

        if server != last_server: # first line for this server

            last_server = server;

            l = PadStringField(line_fields[2], MAX_HOST_LENGTH)\
                + PadStringField(line_fields[3], MAX_IP_LENGTH)\
                + string.join(line_fields[4:]);
            
            if "accepted" in line_fields:
                c += 1;
                mss = string.atoi(line_fields[6]);
                if seen_mss.has_key(mss):
                    seen_mss[mss] += 1;
                else:
                    seen_mss[mss] = 1;

                correct.append(l);

            else:
                e += 1;
                errors.append(l);

    msss = seen_mss.keys();
    msss.sort();
    o_fd.write("========================================\n");
    for m in msss:
        o_fd.write("MSS " + PadStringField(str(m) + ":", 5) + PadStringField(str(seen_mss[m]), 5) + "\n");
        
    o_fd.write("Errors:   " +  str(e) + "\n");
    o_fd.write("Total:    " +  str(e + c) + "\n");
    o_fd.write("========================================\n");
    for url in correct:
        o_fd.write(url + "\n");
    for url in errors:
        o_fd.write(url + "\n");            

    o_fd.close();            
    

def ProcessReorderingResults(output_file, args):

    print "Processing Reordering-test results...";

    errors = [];
    correct = [];
    e = 0;
    c_r = 0;
    total = 0;
    m = args["m"];

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;
    
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);
        if string.find(line, "reordering") > 0:

            l = PadStringField(line_fields[2], MAX_HOST_LENGTH) + PadStringField(line_fields[3], MAX_IP_LENGTH) + \
                "r = " + line_fields[6];

            if string.atoi(line_fields[6]) == 1:
                c_r += 1;

            correct.append(l);

        else:
            e += 1;

            l = PadStringField(line_fields[2], MAX_HOST_LENGTH) \
                + PadStringField(line_fields[3], MAX_IP_LENGTH) + string.join(line_fields[4:]);            
            errors.append(l);

        total += 1;
        
    o_fd.write("=====================\n");
    o_fd.write("Summary:\n");
    o_fd.write("  mss:        " + str(m) + "\n");
    o_fd.write("  Reordering: " + str(c_r) + "\n");
    o_fd.write("  Total:      " + str(total) + "\n");    
    o_fd.write("=====================\n");    
              
    for url in correct:
        o_fd.write(url + "\n");
    for url in errors:
        o_fd.write(url + "\n");
        
    o_fd.close();

def ProcessNewECNResults(output_file):

    print "Processing NewECN-test results...";
    
    correct = [];
    not_ecn = 0;
    ecn = 0;
    e = 0;

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    for line in fileinput.input("MASTERLOG"):
        if string.find(line, "NOT_ECN_CAPABLE") >= 0:
            not_ecn += 1;
            continue;
        elif string.find(line, "ECN_CAPABLE") >= 0:
            ecn += 1;
            correct.append(string.split(line)[2:]);
        else:
            e += 1;
                
    o_fd.write("====================================\n");
    o_fd.write("ECN-Capable: " + str(ecn) + "\n");
    o_fd.write("Not ECN-Capable: " + str(not_ecn) + "\n");
    o_fd.write("Errors: " + str(e) + "\n");
    o_fd.write("====================================\n");
    
    for line in correct:

        #pprint.pprint(line);
        #print line[0], line[1], len(string.split(string.join(line)));

        print line;
        srv, ip, ec, cs, ss, cx, sx, cnect, snect, cect1, sect1, cect0, sect0, cce, sce = string.split(string.join(line));

        l = [srv, ip, "\n",
             PadStringField(cs, 10), PadStringField(ss, 10), "\n",
             PadStringField(cx, 10), PadStringField(sx, 10), "\n",
             PadStringField(cnect, 10), PadStringField(snect, 10), "\n",
             PadStringField(cect1, 10), PadStringField(sect1, 10), "\n",
             PadStringField(cect0, 10), PadStringField(sect0, 10), "\n",             
             PadStringField(cce, 10), PadStringField(sce, 10)];

        o_fd.write(string.join(l) + "\n");

    o_fd.close();

    
def ProcessTimeWaitResults(output_file):
    print "Processing TimeWait-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    c = 0;
    e = 0;
    correct = [];
    errors = [];

    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);    

        l = PadStringField(line_fields[2], MAX_HOST_LENGTH) +\
            PadStringField(line_fields[3], MAX_IP_LENGTH) +\
            string.join(line_fields[4:]);
        
        if string.find(line, "time wait") >= 0:
            c += 1;
            correct.append(l);
        else:
            e += 1;
            errors.append(l);
            
    o_fd.write("========================================\n");
    o_fd.write("Summary:\n");
    o_fd.write("correct: " +  str(c) + "\n");
    o_fd.write("errors:  " +  str(e) + "\n");        
    o_fd.write("Total:   " +  str(c + e) + "\n");
    o_fd.write("========================================\n");

    for l in correct:
        o_fd.write(l + "\n");

    for l in errors:
        o_fd.write(l + "\n");
        
    o_fd.close();        


def CheckRedirectionType(redirection):
    """Approximate classification of redirection type"""

    print "Redirection:", redirection;

    return "";
    

def ProcessRedirectionResults(output_file):
    print "Processing Reordering-test results...";    

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    for line in fileinput.input("MASTERLOG"):
        line_fields = string.split(line);

    pos = [];
    r = 0;
    e = 0;
    total = 0;
    for line in fileinput.input("MASTERLOG"):

        line_fields = string.split(line);

        try:
            redirection = string.atoi(line_fields[4]);
            r += redirection;

        except:
            e += 1;

        total += 1;
        
        if redirection:
            # Approximate classification of redirection type
            redirect = CheckRedirectionType(line_fields[6]);
            
            pos.append(line_fields[2] + " " +
                       line_fields[3]  + "\n  Original:" + line_fields[5]  + "\n  Redirect:" + line_fields[6]);

    o_fd.write("=============================\n");
    o_fd.write("Redirections: " + str(r) + "\n");
    o_fd.write("Errors: " + str(e) + "\n");    
    o_fd.write("Total:        " + str(total) + "\n");
    o_fd.write("=============================\n");

    for line in pos:
        o_fd.write(line + "\n");
        o_fd.write("----------------------\n");


def ProcessTotDataResults(output_file):
    print "Processing TotData-test results...";

    try:
        o_fd = open(output_file, 'w');

    except:
        print "Cannot open output file...";
        return 1;

    for line in fileinput.input("MASTERLOG"):
        line_fields = string.split(line);

    c = 0;
    total_errors = 0;
    correct = [];
    no_conn_err = 0;
    no_conn_err_vals = [];
    no_data_rcvd_err = 0;
    no_data_rcvd_err_vals = [];
    not_enough_pkts_err = 0;
    not_enough_pkts_err_vals = [];
    unexpected_pkt_err = 0;
    unexpected_pkt_err_vals = []
    unknown_address_err = 0;
    unknown_address_err_vals = [];
    early_rst_err = 0;
    early_rst_err_vals = [];    
    mss_err = 0;
    mss_err_vals = [];
    other_errors = 0;
    other_errors_vals = [];
    
    for line in fileinput.input("MASTERLOG"):

        if string.find(line, "Totdata") >= 0:
            date, runid, srv, ip, td, es, val = string.split(line);
            l = PadStringField(srv, MAX_HOST_LENGTH) + " " + \
                PadStringField(ip, MAX_IP_LENGTH) + \
                "File size: " + str(val);
            c += 1;
            correct.append(l);

        else:

            total_errors += 1;
            line_fields = string.split(line);
            l = PadStringField(line_fields[2], MAX_HOST_LENGTH) + " " + \
                PadStringField(line_fields[3], MAX_IP_LENGTH) + \
                string.join(line_fields[4:]);            
            
            if string.find(line, "NO_CONNECTION") >= 0:
                no_conn_err += 1;
                no_conn_err_vals.append(l);

            elif string.find(line, "NO_DATA_RCVD") >= 0:
                no_data_rcvd_err += 1;
                no_data_rcvd_err_vals.append(l);

            elif string.find(line, "NO_ENOUGH_PKTS") >= 0:
                not_enough_pkts_err += 1;
                not_enough_pkts_vals.append(l);

            elif string.find(line, "UNEXPECTED_PKT") >= 0:
                unexpected_pkt_err += 1;
                unexpected_pkt_err_vals.append(l);

            elif string.find(line, "mss") >= 0:
                mss_err += 1;
                mss_err_vals.append(l);

            elif string.find(line, "EARLY_RST") >= 0:
                early_rst_err += 1;
                early_rst_err_vals.append(l);                                

            else:
                other_errors += 1;
                other_errors_vals.append(l);

    
    o_fd.write("========================================\n");
    o_fd.write("Summary:\n");
    o_fd.write("----------------------------------------\n");
    o_fd.write("CORRECT: " +  str(c) + "\n");
    if no_conn_err > 0:    
        o_fd.write("ERROR: NO_CONNECTION " + str(no_conn_err) + "\n");
    if no_data_rcvd_err > 0:        
        o_fd.write("ERROR: NO_DATA_RCVD " + str(no_data_rcvd_err) + "\n");
    if not_enough_pkts_err > 0:        
        o_fd.write("ERROR: NOT_ENOUGH_PKTS " + str(not_enough_pkts_err) + "\n");
    if unexpected_pkt_err > 0:        
        o_fd.write("ERROR: UNEXPECTED_PKT " + str(unexpected_pkt_err) + "\n");
    if mss_err > 0:
        o_fd.write("ERROR: MSS_ERR " + str(mss_err) + "\n");
    if early_rst_err > 0:
        o_fd.write("ERROR: ERLY_RST " + str(early_rst_err) + "\n");                
    if other_errors > 0:        
        o_fd.write("ERROR: OTHER " + str(other_errors) + "\n");    
    o_fd.write("========================================\n");
            

    for line in correct:
        o_fd.write(line + "\n");

    if no_conn_err > 0:
        for line in no_conn_err_vals:
            o_fd.write(line + "\n");

    if no_data_rcvd_err > 0:
        for line in no_data_rcvd_err_vals:
            o_fd.write(line + "\n");

    if not_enough_pkts_err > 0:
        for line in not_enough_pkts_err_vals:
            o_fd.write(line + "\n");

    if unexpected_pkt_err > 0:
        for line in unexpected_pkt_err_vals:
            o_fd.write(line + "\n");

    if mss_err > 0:
        for line in mss_err_vals:
            o_fd.write(line + "\n");

    if early_rst_err > 0:
        for line in early_rst_err_vals:
            o_fd.write(line + "\n");                    
        
    if other_errors > 0:
        for line in other_errors_vals:
            o_fd.write(line + "\n");        

        
    
# #########################################################
#
#    TEST Executions
#
###########################################################

def ExecuteRenoTest(m, srv, ipaddr, path, runid):

    data_file = "./data/" + srv + "." + ipaddr + "." + str(runid) + ".dat";
    d_fd = open(data_file, 'w');

    t_file = "t_" + srv + "_" + ipaddr + "_" + str(runid) + ".txt";
    cmd = "sudo tbit -v -m " + str(m) + " -t Reno -h " + path + " " + ipaddr + " > " + t_file;

    #cmd = "sudo tbit -v -m " + str(m) + " -t Reno -h " + path + " " + ipaddr;

    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);
    cmd = "cat " + t_file;

    print "CMD:", cmd;    
    s2, o = commands.getstatusoutput(cmd);    

    d_fd.write(o + "\n");
    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "version") >= 0:
                results = string.replace(field, "#", "");
    else:

        results  = "";
        for field in o_fields:
            if string.find(field, "RETURN CODE") >= 0:
                results = status_code[string.atoi(string.split(field, ":")[1])];
                break;

        if results == "":
            try:            
                results = status_code[string.atoi(string.split(o_fields[-1], ":")[1])];
            except:
                results = o_fields[-1];        

    return s, results;
        

def ExecuteECNTest(m, srv, ipaddr, path, type, runid):

    if type == "IP":
        cmd = "sudo tbit -v -m " + str(m) + " -t ECN_IPOnly -h " + path +" " + ipaddr;
    if type == "TCP":
        cmd = "sudo tbit -v -m " + str(m) + " -t ECN -h " + path +" " + ipaddr;

    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);
        
    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "sr=") >= 0:
                results = string.join(string.split(field), ":");
    else:
        results = "ERROR:" + str(s);
        try:
            results = status_code[string.atoi(string.split(o_fields[-1], ":")[1])];

        except:
            for field in o_fields:
                if string.find(field, "ERROR:") >= 0:
                    results = field;
                    
    return s, results;


def ExecuteNewECNTest(m, srv, ipaddr, path, runid):

    ########## 1. Check server is ECN-capable #######################################
    cmd = "sudo tbit -v -m " + str(m) + " -t ECN -h " + path +" " + ipaddr;
    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);

    code = "UNKNOWN";
    o_fields = string.split(o, "\n");

    if not s:

        for field in o_fields:
            if string.find(field, "sr=") >= 0:
                if not (string.find(field, "sr=1") >= 0 and string.find(field, "se=1") >= 0):
                    results = "NOT_ECN_CAPABLE";
                    return 0, results;
                
                else:
                    results = "ECN_CAPABLE";
                    break; 
    else:
        results = "ERROR:" + str(s);        
        try:
            results = status_code[string.atoi(string.split(o_fields[-1], ":")[1])];
    
        except:
            for field in o_fields:
                if string.find(field, "ERROR:") >= 0:
                    results = field;            
    
        return s, results;

    #results = "ECN_NOT_CHECKED"; # OJO: Remove this!

    tcpdump_outputfile = "tcpdump_tmp_" + srv + "_" + ipaddr;
    
    pid = os.fork();
    if not pid: # child process

        ########### 2. Start tcpdump as a background process ######################
        cmd = "sudo ";
        arg = "tcpdump -w " + tcpdump_outputfile + " ip src or dst " + ipaddr;

        print "CMD:", cmd + arg;
        s, o = commands.getstatusoutput(cmd +  arg);
        # Note: Using execl() here is a hack. Sorry. There seems to be
        # a misbehavior of the forked process with respect to the opened file
        # file descriptors. In this way it works fine. I will change it shortly with
        # a proper solution.
        os.execl("/bin/hostname", "");
        sys.exit(0);
        
    else: # parent

        # wait for tcpdump to get started
        time.sleep(1);
            
        ########### 3. Download URL ###############################################
        cmd = "sudo tbit -v -m " + str(m) + " -t NewECN -h " + path +" " + ipaddr;
        #cmd = "sudo tbit -v -m " + str(m) + " -t TotData -n " + srv + " -h " + path +" " + ipaddr;        
        print "CMD:", cmd;    
        s, o = commands.getstatusoutput(cmd);

        # wait for tcpdump to finish
        time.sleep(1);
        
        ########### 4. Close tcpdump ##############################################
        s, o = commands.getstatusoutput("ps -aux | grep tcpdump");
        o_fields = string.split(o,"\n");
        for field in o_fields:
            line_fields = string.split(field);
            s, o = commands.getstatusoutput("sudo kill -15 " + line_fields[1]);

    ########### 5. Compute losses and loss rate  ###################################
    # Count:
    #  - Number of retransmissions for sender
    #  - number of retransmissions for receiver
    ################################################################################    

    cmd = "tcptrace -l " + tcpdump_outputfile;
    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);
    o_fields = string.split(o, "\n");
    results_a = "";
    results_b = "";
        
    for field in o_fields:

        if string.find(field, "total packets:") >= 0 and len(string.split(field)) > 3:
            sent_fields = string.split(field);
            results_a = "  csnt:" + sent_fields[2] + " ssnt:" + sent_fields[5];
            
        if string.find(field, "rexmt data pkts") >= 0:
            rxmt_fields = string.split(field);
            results_b = "  cxmt:" + rxmt_fields[3] + " sxmt:" + rxmt_fields[7];

    results = results + results_a + results_b;

        
    ###############################################################################
    # Count number of:
    #  - ECT bit marked packets
    #  - CE bit marked packets
    ################################################################################
            
    cmd = "./new_ecn_capture " + tcpdump_outputfile + " " + ipaddr;
    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);

    results = results + " " + o;
    
    return 0, results;

def ExecuteSackTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t Sack -h " + path +" " + ipaddr;
    print "CMD:", cmd;

    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "sack=") >= 0:
                results = string.replace(field, "#", "");
    else:
        results = "ERROR:" + str(s);        
        try:
            results = status_code[string.atoi(string.split(o_fields[-1], ":")[1])];
        except:
            for field in o_fields:
                if string.find(field,"ERROR:") >= 0:
                    results = field;
        
    return s, results;


def ExecuteSackSndr3pTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit2 -m " + str(m) + " -t SackSndr3P -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);
    
    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "sack") >= 0:
                results = string.replace(field, "#", "");        
    else:
        try:
            results = "";
            for field in o_fields:
                if string.find(field, "RETURN") >= 0:
                    results = status_code[string.atoi(string.split(field)[2])];
                    
            if results == "":
                raise;

        except:
            results = "ERROR: " + str(s);                        
            for field in o_fields:
                if string.find(field, "ERROR") >= 0:
                    results = field;


    return s, results;
    
    


def ExecuteWinHalfTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t WinHalf -h " + path +" " + ipaddr;
    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "Window") >= 0:
                results = string.replace(field, "#", "");

    else:
        results = "ERROR:" + str(s);                
        for field in o_fields:
            if string.find(field,"ERROR:") >= 0:
                results = string.replace(field, "#", "");            

    return s, results;


def ExecuteTimestampTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t Timestamp -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "timestamp") >= 0:
                results = string.replace(field, "#", "");

    else:
        results = "ERROR:" + str(s);                
        for field in o_fields:
            if string.find(field,"ERROR:") >= 0:
                results = string.replace(field, "#", "");                    
        
    return s, results;


def ExecuteTahoeNoFRTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t TahoeNoFR -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");
    
    if not s:
        for field in o_fields:
            if string.find(field, "rx=") >= 0:
                results = string.replace(field, "#", "");
    else:

        results = "ERROR:" + str(s);                
        for field in o_fields:
            if string.find(field,"ERROR:") >= 0:
                results = string.replace(field, "#", "");                                    

    return s, results;


def ExecuteSackRcvrTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t SackRcvr -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "sack") >= 0:
                results = field;
    else:
        results = "ERROR:" + str(s);                
        for field in o_fields:
            if string.find(field,"RETURN") >= 0:
                results = status_code[string.atoi(string.split(field)[2])];                
                
    return s, results;
    

def ExecuteTimeWaitTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t TimeWait -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "time wait") >= 0:
                results = field;
    else:
        results = "ERROR:" + str(s);                
        for field in o_fields:
            if string.find(field,"RETURN") >= 0:
                results = status_code[string.atoi(string.split(field)[2])];                        
                
    return s, results;


def ExecuteDelACKTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t DelAck -h " + path +" " + ipaddr;
    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "delack") >= 0:
                results = field;        
    else:
        results = "ERROR:" + str(s);
        for field in o_fields:
            if string.find(field,"RETURN") >= 0:
                results = status_code[string.atoi(string.split(field)[2])];                                
            
    return s, results;


def ExecuteInitWinTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t InitWin -h " + path +" " + ipaddr;
    print "CMD:", cmd;    
    s, o = commands.getstatusoutput(cmd);

    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "initWin") >= 0:
                results = string.replace(field, "#", "");        
    else:
        try:
            results = "";
            for field in o_fields:
                if string.find(field, "RETURN") >= 0:
                    results = status_code[string.atoi(field[2])];
                    break;

            if not results:
                results = "ERROR: " + str(s);
                for field in o_fields:
                    if string.find(field, "ERROR") >= 0:
                        results = field;                
                    
        except:
            results = "ERROR: " + str(s);
            for field in o_fields:
                if string.find(field, "ERROR") >= 0:
                    results = field;

    return s, results;


def ExecuteMinMSSTest(m, srv, ipaddr, path, runid):
 
    cmd = "sudo tbit -m " + str(m) + " -t Reno -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);
    
    o_fields = string.split(o, "\n");

    results = "";

    if not s:
        results = "MSS = " + str(m) + " accepted by server";

    else:

        try:

            for field in o_fields:
                if string.find(field, "RETURN") >= 0:
                    code = status_code[string.atoi(string.split(field)[2])];
                    
            if code == "MSS_ERR":
                ns, results = ExecuteMinMSSTest( m * 2, srv, ipaddr, path, runid);
                
            elif code == "NOT_ENOUGH_PKTS" \
                     or code == "UNWANTED_PKT_DROP"\
                     or code == "BUFFER_OVERFLOW"\
                     or code == "UNEXPECTED_PKT"\
                     or code == "UNWANTED_PKT_REORDER":

                results = "MSS = " + str(m) + " accepted by server";
                
            else:
                results = "ERROR: " + str(s);
                for field in o_fields:
                    if string.find(field, "ERROR:") >= 0:
                        results = field;                    

        except:
            results = "ERROR: " + o_fields[-1];
            for field in o_fields:
                if string.find(field, "ERROR:") >= 0:
                    results = field;                                

            
    return 0, results;


def ExecuteReorderingVsMSSTest(m, srv, ipaddr, path, runid):
    
    cmd = "sudo tbit -m " + str(m) + " -t Reno -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);
    
    o_fields = string.split(o, "\n");

    results = "";

    if not s:
        for field in o_fields:
            if string.find(field, "RETURN") >= 0:
                code = status_code[string.atoi(string.split(field)[2])];
                if code == "UNWANTED_PKT_REORDER":
                    return s,1;

        return s, 0;

    else:
        
        try:
            code = status_code[string.atoi(string.split(o_fields[-1], ":")[1])];
            return s, code;
        except:
            return s, o_fields[-1];

    
def ExecuteRedirectionTest(m, srv, ipaddr, path, runid):

    url_opener = MyFancyURLopener({});
    
    path = string.replace(path, "\"","");
    srv = "http://" + srv;
    requested_url = urlparse.urljoin(srv, path);

    try:
        # Grab URL and open it
        url = string.strip(requested_url);
        u = url_opener.open(url);
    
        # Account for HTTP redirections
        actual_url = u.geturl();

        if url == actual_url:
            results = "0";
        else:
            ipaddrs = GetURLIPAddr(actual_url);
            results = "1 " +  path + " " + actual_url + " " + ipaddrs;            

        s = 0;
        
    except:
        s = 1;
        results = "Cannot process URL: " +  requested_url;
        
    return s, results;


def ExecuteTotDataTest(m, srv, ipaddr, path, runid):

    cmd = "sudo tbit -m " + str(m) + " -t TotData -h " + path +" " + ipaddr;
    print "CMD:", cmd;
    s, o = commands.getstatusoutput(cmd);
    
    o_fields = string.split(o, "\n");

    if not s:
        for field in o_fields:
            if string.find(field, "Totdata") >= 0:
                results = string.replace(field, "#", "");
    else:

        results  = "";
        for field in o_fields:
            if string.find(field, "RETURN CODE") >= 0:
                results = status_code[string.atoi(string.split(field, ":")[1])];
                break;

        if results == "":
            try:            
                results = status_code[string.atoi(string.split(o_fields[-1], ":")[1])];
            except:
                results = o_fields[-1];        

    return s, results;
            
    

def proc_results(test, output_file, args):

    status = 1;

    if test == "Reno":
        status = ProcessNewRenoResults(output_file);
        
    if test == "ECN" or test == "ECN_IPOnly":
        status = ProcessECNResults(output_file);

    if test == "SackSndr3P":
        status = ProcessSackSndr3PResults(output_file);
        
    if test == "InitWin":
        status = ProcessInitWinResults(output_file, args);
            
    if test == "Sack":
        status = ProcessSackResults(output_file);

    if test == "WinHalf":
        status = ProcessWinHalfResults(output_file);

    if test == "Timestamp":
        status = ProcessTimestampResults(output_file);

    if test == "TahoeNoFR":
        status = ProcessTahoeNoFRResults(output_file);

    if test == "SackRcvr":
        status = ProcessSackRcvrResults(output_file);

    if test == "TimeWait":
        status = ProcessTimeWaitResults(output_file);

    if test == "DelAck":
        status = ProcessDelACKResults(output_file);

    if test == "MinMSS":
        status = ProcessMinMSSResults(output_file);

    if test == "Reordering":
        status = ProcessReorderingResults(output_file, args);

    if test == "NewECN":
        status = ProcessNewECNResults(output_file);

    if test == "Redirection":
        status = ProcessRedirectionResults(output_file);

    if test == "TotData":
        status = ProcessTotDataResults(output_file);                                        

    if status:
        print "Error processing results for test:", test, "(", status, ")";


def run_test(input_file, test, m, repeat):

    print "Executing ", test, "test...";

    global MASTERLOG;
    try:
        MASTERLOG = open("MASTERLOG", 'w');
        
    except:
        print "Cannot open MASTERLOG file";    

    # Read URL list from file
    url_list = [];
    curr_dir = os.getcwd();

    os.chdir(URLLISTS_DIR);

    try:
        for line in fileinput.input(input_file):
            url_list.append(line);
            
    except IOError:
        print "Cannot process input file", input_file, "...";
        sys.exit(0);

    os.chdir(curr_dir);
        
    new_url_list = [];

    for i in range(repeat):
        
        print "RUNID:", i, "***************************";
        while url_list:

            line = url_list.pop();

            try:
                srv, path, ip, size = string.split(line);

            except:
                srv, ip = string.split(line);
                path = "/";
                
            status, date = commands.getstatusoutput("date \"+%Y:%m:%d:%H:%M:%S\"");
            if status:
                print "Cannot execute date command!";
                sys.exit();
                
            if test == "Reno":
                status, results = ExecuteRenoTest(m, srv, ip, path, i);

            elif test == "ECN":

                # For ECN Test: Check connectivity first without ECN
                cmd = "sudo tbit -t Timestamp " + srv;
                status, o = commands.getstatusoutput(cmd);
                if status:
                    results = "ERROR: NO_CONNECTION_TIMESTAMP";
                else:
                    status, results = ExecuteECNTest(m, srv, ip, path, "TCP", i);

            elif test == "NewECN":

                # For ECN-related Tests: Check connectivity first without ECN
                cmd = "sudo tbit -t Timestamp " + srv;
                status, o = commands.getstatusoutput(cmd);
                if status:
                    results = "ERROR: NO_CONNECTION_TIMESTAMP";
                else:
                    status, results = ExecuteNewECNTest(m, srv, ip, path, i);
                
            elif test == "ECN_IPOnly":
                status = ExecuteECNTest(m, srv, ip, path, "IP", i);

            elif test == "SackSndr3P":
                status, results = ExecuteSackSndr3pTest(m, srv, ip, path, i);
                    
            elif test == "Sack":
                status, results = ExecuteSackTest(m, srv, ip, path, i);

            elif test == "Sack":
                status = ExecuteSackSndrTest(m, srv, ip, path, i);                
                
            elif test == "WinHalf":
                status, results = ExecuteWinHalfTest(m, srv, ip, path, i);

            elif test == "Timestamp":
                status, results = ExecuteTimestampTest(m, srv, ip, path, i);

            elif test == "TahoeNoFR":
                status, results = ExecuteTahoeNoFRTest(m, srv, ip, path, i);
            
            elif test == "SackRcvr":
                status, results = ExecuteSackRcvrTest(m, srv, ip, path, i);

            elif test == "TimeWait":
                status, results = ExecuteTimeWaitTest(m, srv, ip, path, i);

            elif test == "DelAck":
                status, results = ExecuteDelACKTest(m, srv, ip, path, i);

            elif test == "InitWin":
                status, results = ExecuteInitWinTest(m, srv, ip, path, i);

            elif test == "MinMSS":
                status, results = ExecuteMinMSSTest(m, srv, ip, path, i);

            elif test == "Reordering":
                status, reordering = ExecuteReorderingVsMSSTest(m, srv, ip, path, i);
                if reordering == 0 or reordering == 1:
                    results = "reordering = " + str(reordering);
                else:
                    results = reordering;

            elif test == "Redirection":
                status, results = ExecuteRedirectionTest(m, srv, ip, path, i);

            elif test == "TotData":
                status, results = ExecuteTotDataTest(m, srv, ip, path, i);                            
                
            else:
                print "Error: Could not run test: ", test, " Try again!"
                sys.exit();

            if not status or i == repeat - 1:
                MASTERLOG.write(date + "  " + str(i) + " " + srv + " " + ip + " " + results + "\n");
                print date + " " + str(i) + " " + srv + " " + ip + " " + results;
                
            if status and i < repeat - 1:
                new_url_list.append(line);
                
        url_list = new_url_list;
        new_url_list = [];

    assert(len(url_list) == 0);
    MASTERLOG.close();
    
    return 0;


if __name__ == "__main__":
        
    if len(sys.argv) < 7:
        usage();
        sys.exit(1);
        
    input_file = sys.argv[1];
    test = sys.argv[2];
    mss_value = int(sys.argv[3]);
    repeat = int(sys.argv[4]);
    output_file = sys.argv[5];
    processing_only = int(sys.argv[6]);

    # args to be passed to specific procedures
    # (e.g proc results requires the value of mss)
    args = {};
    
    status = 0;
    # Set working directory properly
    if test == "Reno":
        os.chdir(RENOTEST_DIR);

    elif test == "ECN" or test == "ECN_IPOnly":
        os.chdir(ECNTEST_DIR);        

    elif test == "SackSndr3P":
        os.chdir(SACKSNDR3PTEST_DIR);

    elif test == "InitWin":
        os.chdir(INITWINTEST_DIR);

    elif test == "Sack":
        os.chdir(ISSACKTEST_DIR);

    elif test == "WinHalf":
        os.chdir(WINHALFTEST_DIR);

    elif test == "Timestamp":
        os.chdir(TIMESTAMPTEST_DIR);

    elif test == "TahoeNoFR":
        os.chdir(TAHOENOFRTEST_DIR);

    elif test == "SackRcvr":
        os.chdir(SACKRCVRTEST_DIR);

    elif test == "TimeWait":
        os.chdir(TIMEWAITTEST_DIR);

    elif test == "DelAck":
        os.chdir(DELACKTEST_DIR);

    elif test == "MinMSS":
        os.chdir(MINMSSTEST_DIR);

    elif test == "Reordering":
        os.chdir(REORDERINGTEST_DIR);

    elif test == "NewECN":
        os.chdir(NEWECNTEST_DIR);

    elif test == "Redirection":
        os.chdir(REDIRECTIONTEST_DIR);

    elif test == "TotData":
        os.chdir(TOTDATATEST_DIR);        

    else:
        print "Cannot find directory for test: ", test;
        sys.exit(1);

    if not processing_only:
        status = run_test(input_file, test, mss_value, repeat);
    
    if not status:
        args["m"] = mss_value;
        proc_results(test, output_file, args);

    os.chdir(TEST_DIR);






