1 /* 2 * Copyright (c) 2009-2011, The Regents of the University of California, 3 * through Lawrence Berkeley National Laboratory (subject to receipt of any 4 * required approvals from the U.S. Dept. of Energy). All rights reserved. 5 * 6 * This code is distributed under a BSD style license, see the LICENSE file 7 * for complete information. 8 */ 9 10 #include <errno.h> 11 #include <setjmp.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 #include <sys/types.h> 16 #include <sys/select.h> 17 #include <sys/uio.h> 18 19 #include "iperf.h" 20 #include "iperf_api.h" 21 #include "iperf_client_api.h" 22 #include "iperf_error.h" 23 #include "iperf_util.h" 24 #include "net.h" 25 #include "timer.h" 26 27 28 int 29 iperf_create_streams(struct iperf_test *test) 30 { 31 int i, s; 32 struct iperf_stream *sp; 33 34 for (i = 0; i < test->num_streams; ++i) { 35 36 if ((s = test->protocol->connect(test)) < 0) 37 return (-1); 38 39 FD_SET(s, &test->read_set); 40 FD_SET(s, &test->write_set); 41 test->max_fd = (test->max_fd < s) ? s : test->max_fd; 42 43 sp = iperf_new_stream(test, s); 44 if (!sp) 45 return (-1); 46 47 /* Perform the new stream callback */ 48 if (test->on_new_stream) 49 test->on_new_stream(sp); 50 } 51 52 return (0); 53 } 54 55 int 56 iperf_handle_message_client(struct iperf_test *test) 57 { 58 int rval, perr; 59 60 if ((rval = read(test->ctrl_sck, &test->state, sizeof(char))) <= 0) { 61 if (rval == 0) { 62 i_errno = IECTRLCLOSE; 63 return (-1); 64 } else { 65 i_errno = IERECVMESSAGE; 66 return (-1); 67 } 68 } 69 70 switch (test->state) { 71 case PARAM_EXCHANGE: 72 if (iperf_exchange_parameters(test) < 0) 73 return (-1); 74 if (test->on_connect) 75 test->on_connect(test); 76 break; 77 case CREATE_STREAMS: 78 if (iperf_create_streams(test) < 0) 79 return (-1); 80 break; 81 case TEST_START: 82 if (iperf_init_test(test) < 0) 83 return (-1); 84 break; 85 case TEST_RUNNING: 86 break; 87 case EXCHANGE_RESULTS: 88 if (iperf_exchange_results(test) < 0) 89 return (-1); 90 break; 91 case DISPLAY_RESULTS: 92 if (test->on_test_finish) 93 test->on_test_finish(test); 94 iperf_client_end(test); 95 break; 96 case IPERF_DONE: 97 break; 98 case SERVER_TERMINATE: 99 i_errno = IESERVERTERM; 100 return (-1); 101 case ACCESS_DENIED: 102 i_errno = IEACCESSDENIED; 103 return (-1); 104 case SERVER_ERROR: 105 if (Nread(test->ctrl_sck, &i_errno, sizeof(i_errno), Ptcp) < 0) { 106 i_errno = IECTRLREAD; 107 return (-1); 108 } 109 i_errno = ntohl(i_errno); 110 if (Nread(test->ctrl_sck, &perr, sizeof(perr), Ptcp) < 0) { 111 i_errno = IECTRLREAD; 112 return (-1); 113 } 114 errno = ntohl(perr); 115 return (-1); 116 default: 117 i_errno = IEMESSAGE; 118 return (-1); 119 } 120 121 return (0); 122 } 123 124 125 126 /* iperf_connect -- client to server connection function */ 127 int 128 iperf_connect(struct iperf_test *test) 129 { 130 FD_ZERO(&test->read_set); 131 FD_ZERO(&test->write_set); 132 133 make_cookie(test->cookie); 134 135 /* Create and connect the control channel */ 136 test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->server_hostname, test->server_port); 137 if (test->ctrl_sck < 0) { 138 i_errno = IECONNECT; 139 return (-1); 140 } 141 142 if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 143 i_errno = IESENDCOOKIE; 144 return (-1); 145 } 146 147 FD_SET(test->ctrl_sck, &test->read_set); 148 FD_SET(test->ctrl_sck, &test->write_set); 149 test->max_fd = (test->ctrl_sck > test->max_fd) ? test->ctrl_sck : test->max_fd; 150 151 return (0); 152 } 153 154 155 int 156 iperf_client_end(struct iperf_test *test) 157 { 158 struct iperf_stream *sp; 159 160 /* Close all stream sockets */ 161 SLIST_FOREACH(sp, &test->streams, streams) { 162 close(sp->socket); 163 } 164 165 /* show final summary */ 166 test->reporter_callback(test); 167 168 test->state = IPERF_DONE; 169 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 170 i_errno = IESENDMESSAGE; 171 return (-1); 172 } 173 174 return (0); 175 } 176 177 178 int 179 iperf_run_client(struct iperf_test * test) 180 { 181 int result; 182 fd_set temp_read_set, temp_write_set; 183 struct timeval tv; 184 time_t sec, usec; 185 186 /* Start the client and connect to the server */ 187 if (iperf_connect(test) < 0) { 188 return (-1); 189 } 190 191 // Begin calculating CPU utilization 192 cpu_util(NULL); 193 194 while (test->state != IPERF_DONE) { 195 196 memcpy(&temp_read_set, &test->read_set, sizeof(fd_set)); 197 memcpy(&temp_write_set, &test->write_set, sizeof(fd_set)); 198 tv.tv_sec = 15; 199 tv.tv_usec = 0; 200 201 result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv); 202 if (result < 0 && errno != EINTR) { 203 i_errno = IESELECT; 204 return (-1); 205 } else if (result > 0) { 206 if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { 207 if (iperf_handle_message_client(test) < 0) 208 return (-1); 209 FD_CLR(test->ctrl_sck, &temp_read_set); 210 } 211 212 if (test->state == TEST_RUNNING) { 213 if (test->reverse) { 214 // Reverse mode. Client receives. 215 if (iperf_recv(test) < 0) 216 return (-1); 217 } else { 218 // Regular mode. Client sends. 219 if (iperf_send(test) < 0) 220 return (-1); 221 } 222 223 /* Perform callbacks */ 224 if (timer_expired(test->stats_timer)) { 225 test->stats_callback(test); 226 sec = (time_t) test->stats_interval; 227 usec = (test->stats_interval - sec) * SEC_TO_US; 228 if (update_timer(test->stats_timer, sec, usec) < 0) 229 return (-1); 230 } 231 if (timer_expired(test->reporter_timer)) { 232 test->reporter_callback(test); 233 sec = (time_t) test->reporter_interval; 234 usec = (test->reporter_interval - sec) * SEC_TO_US; 235 if (update_timer(test->reporter_timer, sec, usec) < 0) 236 return (-1); 237 } 238 239 /* Send TEST_END if all data has been sent or timer expired */ 240 if (all_data_sent(test) || timer_expired(test->timer)) { 241 cpu_util(&test->cpu_util); 242 test->stats_callback(test); 243 test->state = TEST_END; 244 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 245 i_errno = IESENDMESSAGE; 246 return (-1); 247 } 248 } 249 } 250 } 251 } 252 253 return (0); 254 } 255