# HG changeset patch
# User Susant Sahani <ssahani@redhat.com>
# Date 1386843052 -19800
#      Thu Dec 12 15:40:52 2013 +0530
# Branch iperf-dev
# Node ID cc1abc0436094d9011972f0cffe524bf95e6701f
# Parent  c37286118cc5dd5431a64112d90182ca7a374af8
TCP congestion control support for Linux

 Added TCP Congestion control support.
  -C, --linux-congestion <algo>  set TCP congestion control algorithm (Linux only)

diff -r c37286118cc5 -r cc1abc043609 src/iperf.h
--- a/src/iperf.h	Mon Dec 09 17:52:59 2013 -0800
+++ b/src/iperf.h	Thu Dec 12 15:40:52 2013 +0530
@@ -156,6 +156,7 @@
     char     *diskfile_name;			/* -F option */
     int       affinity, server_affinity;	/* -A option */
     char     *title;				/* -T option */
+    char     *congestion;                       /* -C option */
 
     int       ctrl_sck;
     int       listener;
diff -r c37286118cc5 -r cc1abc043609 src/iperf_api.c
--- a/src/iperf_api.c	Mon Dec 09 17:52:59 2013 -0800
+++ b/src/iperf_api.c	Thu Dec 12 15:40:52 2013 +0530
@@ -524,8 +524,8 @@
     /*  XXX: The following ifdef needs to be split up. linux-congestion is not
      * necessarily supported by systems that support tos.
      */
-#ifdef ADD_WHEN_SUPPORTED
-        {"linux-congestion", required_argument, NULL, 'L'},
+#if defined(linux)
+        {"linux-congestion", required_argument, NULL, 'C'},
 #endif
         {NULL, 0, NULL, 0}
     };
@@ -536,7 +536,7 @@
 
     blksize = 0;
     server_flag = client_flag = rate_flag = 0;
-    while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:l:P:Rw:B:M:N46S:L:ZO:F:A:T:h", longopts, NULL)) != -1) {
+    while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:l:P:Rw:B:M:C:N46S:L:ZO:F:A:T:h", longopts, NULL)) != -1) {
         switch (flag) {
             case 'p':
                 test->server_port = atoi(optarg);
@@ -632,6 +632,16 @@
                 test->bind_address = (char *) malloc(strlen(optarg)+1);
                 strncpy(test->bind_address, optarg, strlen(optarg)+1);
                 break;
+            case 'C':
+#if defined(linux)
+                test->congestion = (char *) malloc(strlen(optarg)+1);
+                strncpy(test->congestion, optarg, strlen(optarg)+1);
+                client_flag = 1;
+#else /* notdef */
+                i_errno = IEUNIMP;
+                return -1;
+#endif /* notdef */
+            break;
             case 'M':
                 test->settings->mss = atoi(optarg);
                 if (test->settings->mss > MAX_MSS) {
@@ -1023,6 +1033,8 @@
 	    cJSON_AddIntToObject(j, "flowlabel", test->settings->flowlabel);
 	if (test->title)
 	    cJSON_AddStringToObject(j, "title", test->title);
+        if (test->congestion)
+            cJSON_AddStringToObject(j, "congestion", test->congestion);
 	if (JSON_write(test->ctrl_sck, j) < 0) {
 	    i_errno = IESENDPARAMS;
 	    r = -1;
@@ -1078,6 +1090,8 @@
 	    test->settings->flowlabel = j_p->valueint;
 	if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
 	    test->title = strdup(j_p->valuestring);
+        if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
+            test->congestion = strdup(j_p->valuestring);
 	if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
 	    test->sender_has_retransmits = 1;
 	cJSON_Delete(j);
@@ -1465,6 +1479,8 @@
     free(test->settings);
     if (test->title)
 	free(test->title);
+    if(test->congestion)
+        free(test->congestion);
     if (test->omit_timer != NULL)
 	tmr_cancel(test->omit_timer);
     if (test->timer != NULL)
diff -r c37286118cc5 -r cc1abc043609 src/iperf_api.h
--- a/src/iperf_api.h	Mon Dec 09 17:52:59 2013 -0800
+++ b/src/iperf_api.h	Thu Dec 12 15:40:52 2013 +0530
@@ -274,6 +274,7 @@
     IEPROTOCOL = 131,       // Protocol does not exist
     IEAFFINITY = 132,       // Unable to set CPU affinity (check perror)
     IEDAEMON = 133,	    // Unable to become a daemon process
+    IESETCONGESTION = 134,  // Unable to TCP TCP_CONGESTION
     /* Stream errors */
     IECREATESTREAM = 200,   // Unable to create a new stream (check herror/perror)
     IEINITSTREAM = 201,     // Unable to initialize stream (check herror/perror)
diff -r c37286118cc5 -r cc1abc043609 src/iperf_error.c
--- a/src/iperf_error.c	Mon Dec 09 17:52:59 2013 -0800
+++ b/src/iperf_error.c	Thu Dec 12 15:40:52 2013 +0530
@@ -284,6 +284,9 @@
             snprintf(errstr, len, "unable to update timer");
             perr = 1;
             break;
+        case IESETCONGESTION:
+            snprintf(errstr, len, "unable to set TCP CONGESTION");
+        break;
     }
 
     if (herr || perr)
diff -r c37286118cc5 -r cc1abc043609 src/iperf_tcp.c
--- a/src/iperf_tcp.c	Mon Dec 09 17:52:59 2013 -0800
+++ b/src/iperf_tcp.c	Thu Dec 12 15:40:52 2013 +0530
@@ -172,6 +172,16 @@
                 return -1;
             }
         }
+#if defined(linux)
+        if (test->congestion) {
+            if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
+                close(s);
+                freeaddrinfo(res);
+                i_errno = IESETCONGESTION;
+                return -1;
+            } 
+        }
+#endif
         opt = 1;
         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
             close(s);
@@ -302,6 +312,16 @@
 	    sa6P->sin6_flowinfo = htonl(test->settings->flowlabel);
 	}
     }
+#if defined(linux)
+    if (test->congestion) {
+        if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
+            close(s);
+            freeaddrinfo(server_res);
+            i_errno = IESETCONGESTION;
+            return -1;
+        }
+    }
+#endif
 
     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
 	close(s);
diff -r c37286118cc5 -r cc1abc043609 src/locale.c
--- a/src/locale.c	Mon Dec 09 17:52:59 2013 -0800
+++ b/src/locale.c	Thu Dec 12 15:40:52 2013 +0530
@@ -94,6 +94,9 @@
                            "  -R, --reverse             run in reverse mode (server sends, client receives)\n"
                            "  -w, --window    #[KMG]    TCP window size (socket buffer size)\n"
                            "  -B, --bind      <host>    bind to a specific interface or multicast address\n"
+#if defined(linux)
+                           "  -C, --linux-congestion <algo>  set TCP congestion control algorithm (Linux only)\n"
+#endif
                            "  -M, --set-mss   #         set TCP maximum segment size (MTU - 40 bytes)\n"
                            "  -N, --nodelay             set TCP no delay, disabling Nagle's Algorithm\n"
                            "  -4, --version4            only use IPv4\n"
