This article directory
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:
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;
}