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