Source code analysis of iperf3 server and client configuration parameter exchange process

From article
7, iperf3 source code analysis: state machine and state transition process —> server code when running forward TCP one-way test
Eight, iperf3 source code analysis: state machine and state transition process —> running forward TCP one-way test Client code nine during the test
, iperf3 source code analysis: main function main flow, detailed explanation of the interaction process between the server and the client during the forward TCP one-way test
We know that the configuration parameter exchange process between the server and the client and the state machine change process are as follows (Note: Only the iperf3 client will send the configuration parameters to the server, and the parameters of the server will not be sent to the client ):

1. Server and client configuration parameter exchange process and state machine changes

1) When the server receives the control connection establishment request sent by the client, it will receive the connection request and put it in the test->ctrl_sck pointer after successfully establishing the connection request. 2) Then the server actively enters the PARAM_EXCHANGE state
, And send the PARAM_EXCHANGE instruction to the client
3) After receiving the PARAM_EXCHANGE instruction, the client starts to send the configuration parameters to the server through the control connection pointed to by the test->ctrl_sck pointer
4) After the server receives the configuration parameters, save and configure, Complete the configuration parameter exchange process after the CREATE_STREAM state

As shown in the figure below, the client is on the left and the server is on the right:

insert image description here

2. The server code calling process

iperf_exchange_parameters—>get_parameters—>JSON_read,
control the connection through test->ctrl_sck, analyze the received parameters, and store them in each parameter configuration item under the test->pointer to complete the parameter exchange.

debug out: set the state from 15 to 9
debug out: func = iperf_exchange_parameters,line = 2087, file = iperf_api.c
debug out: func = get_parameters           ,line = 2268, file = iperf_api.c
debug out: func = JSON_read                ,line = 2662, file = iperf_api.c
get_parameters:
{
    
    
	"udp":	true,
	"omit":	0,
	"time":	0,
	"num":	8192,
	"blockcount":	0,
	"parallel":	1,
	"len":	1024,
	"bandwidth":	1048576,
	"pacing_timer":	1000,
	"client_version":	"3.13"
}
debug out: func = iperf_exchange_parameters,line = 2104, file = iperf_api.c


3. Client code calling process

iperf_exchange_parameters—>send_parameters—>JSON_write
sends the parameters of the client to the server in JSON format, controls the connection through test->ctrl_sck.

debug out: receive and change the state from 0 to 9
debug out: func = iperf_exchange_parameters,line = 2082, file = iperf_api.c
debug out: func = send_parameters          ,line = 2166, file = iperf_api.c
send_parameters:
{
    
    
	"udp":	true,
	"omit":	0,
	"time":	0,
	"num":	8192,
	"blockcount":	0,
	"parallel":	1,
	"len":	1024,
	"bandwidth":	1048576,
	"pacing_timer":	1000,
	"client_version":	"3.13"
}
debug out: func = send_parameters          ,line = 2250, file = iperf_api.c
debug out: func = JSON_write               ,line = 2635, file = iperf_api.c

4. Which parameters will be synchronized from the client to the server

Through the send_parameters function, we can see that the following parameters will be sent from the client to the server:

option name configuration item Save location
Protocol TypeTCP/UDP/SCTP -u or --udp or --sctp test->protocol->id
TBD -o or –omit test->omit
TBD -A or --affinity test->server_affinity)
TBD TBD test->duration
TBD TBD test->settings->bytes
TBD TBD test->settings->blocks
TBD -N, --no-delay test->no_delay
TBD -M, --set-mss test->settings->mss
TBD TBD test->num_streams
TBD -w, --window test->settings->socket_bufsize)
TBD TBD test->settings->blksize
TBD TBD test->settings->rate
TBD –fq-rate test->settings->fqrate
TBD –pacing-timer test->settings->pacing_timer
TBD TBD test->settings->burst
TBD -S, --them test->settings->tos
TBD -L, --flowlabel test->settings->flowlabel
TBD -T, --title test->title
TBD –extra-data test->extra_data
TBD TBD test->congestion
TBD TBD test->congestion_used
TBD –dont-fragment test->settings->dont_fragment
TBD -Z, --zerocopy test->zerocopy
TBD –repeating-payload test->repeating_payload
TBD TBD test->settings->rate
TBD -R, --reverse, --bidir test->mode
TBD –get-server-output test->get_server_output
TBD –udp-counters-64bit test->udp_counters_64bit

For the specific source code, see the two functions of send_parameters called by the client and get_parameters called by the server

static int
send_parameters(struct iperf_test *test)
{
    
    
    int r = 0;
    cJSON *j;
    PRINTFILEFUNCLINE
    j = cJSON_CreateObject();
    if (j == NULL) {
    
    
	i_errno = IESENDPARAMS;
	r = -1;
    } else {
    
    
	if (test->protocol->id == Ptcp)
	    cJSON_AddTrueToObject(j, "tcp");
	else if (test->protocol->id == Pudp)
	    cJSON_AddTrueToObject(j, "udp");
        else if (test->protocol->id == Psctp)
            cJSON_AddTrueToObject(j, "sctp");
	cJSON_AddNumberToObject(j, "omit", test->omit);
	if (test->server_affinity != -1)
	    cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
	cJSON_AddNumberToObject(j, "time", test->duration);
        cJSON_AddNumberToObject(j, "num", test->settings->bytes);
        cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
	if (test->settings->mss)
	    cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
	if (test->no_delay)
	    cJSON_AddTrueToObject(j, "nodelay");
	cJSON_AddNumberToObject(j, "parallel", test->num_streams);
	if (test->reverse)
	    cJSON_AddTrueToObject(j, "reverse");
	if (test->bidirectional)
	            cJSON_AddTrueToObject(j, "bidirectional");
	if (test->settings->socket_bufsize)
	    cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
	if (test->settings->blksize)
	    cJSON_AddNumberToObject(j, "len", test->settings->blksize);
	if (test->settings->rate)
	    cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
	if (test->settings->fqrate)
	    cJSON_AddNumberToObject(j, "fqrate", test->settings->fqrate);
	if (test->settings->pacing_timer)
	    cJSON_AddNumberToObject(j, "pacing_timer", test->settings->pacing_timer);
	if (test->settings->burst)
	    cJSON_AddNumberToObject(j, "burst", test->settings->burst);
	if (test->settings->tos)
	    cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
	if (test->settings->flowlabel)
	    cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
	if (test->title)
	    cJSON_AddStringToObject(j, "title", test->title);
	if (test->extra_data)
	    cJSON_AddStringToObject(j, "extra_data", test->extra_data);
	if (test->congestion)
	    cJSON_AddStringToObject(j, "congestion", test->congestion);
	if (test->congestion_used)
	    cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
	if (test->get_server_output)
	    cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
	if (test->udp_counters_64bit)
	    cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
	if (test->repeating_payload)
	    cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
	if (test->zerocopy)
	    cJSON_AddNumberToObject(j, "zerocopy", test->zerocopy);
#if defined(HAVE_DONT_FRAGMENT)
	if (test->settings->dont_fragment)
	    cJSON_AddNumberToObject(j, "dont_fragment", test->settings->dont_fragment);
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
	/* Send authentication parameters */
	if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
    
    
	    int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);

	    if (rc) {
    
    
		cJSON_Delete(j);
		i_errno = IESENDPARAMS;
		return -1;
	    }

	    cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
	}
#endif // HAVE_SSL
	cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);

	if (test->debug) {
    
    
	    char *str = cJSON_Print(j);
	    printf("send_parameters:\n%s\n", str);
	    cJSON_free(str);
	}
    PRINTFILEFUNCLINE
	if (JSON_write(test->ctrl_sck, j) < 0) {
    
    
	    i_errno = IESENDPARAMS;
	    r = -1;
	}
	cJSON_Delete(j);
    }
    return r;
}

#----------------------------------------------------------------------------
static int
get_parameters(struct iperf_test *test)
{
    
    
    int r = 0;
    cJSON *j;
    cJSON *j_p;
    PRINTFILEFUNCLINE
    j = JSON_read(test->ctrl_sck);
    if (j == NULL) {
    
    
	i_errno = IERECVPARAMS;
        r = -1;
    } else {
    
    
	if (test->debug) {
    
    
            char *str;
            str = cJSON_Print(j);
            printf("get_parameters:\n%s\n", str );
            cJSON_free(str);
	}

	if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
	    set_protocol(test, Ptcp);
	if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL)
	    set_protocol(test, Pudp);
        if ((j_p = cJSON_GetObjectItem(j, "sctp")) != NULL)
            set_protocol(test, Psctp);
	if ((j_p = cJSON_GetObjectItem(j, "omit")) != NULL)
	    test->omit = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "server_affinity")) != NULL)
	    test->server_affinity = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
	    test->duration = j_p->valueint;
        test->settings->bytes = 0;
	if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
	    test->settings->bytes = j_p->valueint;
        test->settings->blocks = 0;
	if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)
	    test->settings->blocks = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)
	    test->settings->mss = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "nodelay")) != NULL)
	    test->no_delay = 1;
	if ((j_p = cJSON_GetObjectItem(j, "parallel")) != NULL)
	    test->num_streams = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)
	    iperf_set_test_reverse(test, 1);
        if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL)
            iperf_set_test_bidirectional(test, 1);
	if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
	    test->settings->socket_bufsize = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
	    test->settings->blksize = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
	    test->settings->rate = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "fqrate")) != NULL)
	    test->settings->fqrate = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "pacing_timer")) != NULL)
	    test->settings->pacing_timer = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
	    test->settings->burst = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
	    test->settings->tos = j_p->valueint;
	if ((j_p = cJSON_GetObjectItem(j, "flowlabel")) != NULL)
	    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, "extra_data")) != NULL)
	    test->extra_data = strdup(j_p->valuestring);
	if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
	    test->congestion = strdup(j_p->valuestring);
	if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL)
	    test->congestion_used = strdup(j_p->valuestring);
	if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
	    iperf_set_test_get_server_output(test, 1);
	if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
	    iperf_set_test_udp_counters_64bit(test, 1);
	if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
	    test->repeating_payload = 1;
	if ((j_p = cJSON_GetObjectItem(j, "zerocopy")) != NULL)
	    test->zerocopy = j_p->valueint;
#if defined(HAVE_DONT_FRAGMENT)
	if ((j_p = cJSON_GetObjectItem(j, "dont_fragment")) != NULL)
	    test->settings->dont_fragment = j_p->valueint;
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
	if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
        test->settings->authtoken = strdup(j_p->valuestring);
#endif //HAVE_SSL
	if (test->mode && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
	    test->sender_has_retransmits = 1;
	if (test->settings->rate)
	    cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
	cJSON_Delete(j);
    }
    return r;
}

Guess you like

Origin blog.csdn.net/meihualing/article/details/129673386