xref: /iperf/src/iperf_server_api.c (revision 98ce496b)
1a951c980SBrian Tierney /*
27d375156SJon Dugan  * Copyright (c) 2009-2011, The Regents of the University of California,
37d375156SJon Dugan  * through Lawrence Berkeley National Laboratory (subject to receipt of any
47d375156SJon Dugan  * required approvals from the U.S. Dept. of Energy).  All rights reserved.
57d375156SJon Dugan  *
67d375156SJon Dugan  * This code is distributed under a BSD style license, see the LICENSE file
77d375156SJon Dugan  * for complete information.
8a951c980SBrian Tierney  */
9a951c980SBrian Tierney 
10a951c980SBrian Tierney /* iperf_server_api.c: Functions to be used by an iperf server
11a951c980SBrian Tierney */
12a951c980SBrian Tierney 
13a951c980SBrian Tierney #include <stdio.h>
14a951c980SBrian Tierney #include <stdlib.h>
15a951c980SBrian Tierney #include <string.h>
16a951c980SBrian Tierney #include <getopt.h>
17a951c980SBrian Tierney #include <errno.h>
18a951c980SBrian Tierney #include <unistd.h>
19a951c980SBrian Tierney #include <assert.h>
20a951c980SBrian Tierney #include <fcntl.h>
21a951c980SBrian Tierney #include <sys/socket.h>
22a951c980SBrian Tierney #include <sys/types.h>
23a951c980SBrian Tierney #include <netinet/in.h>
24a951c980SBrian Tierney #include <arpa/inet.h>
25a951c980SBrian Tierney #include <netdb.h>
26a951c980SBrian Tierney #include <pthread.h>
27a951c980SBrian Tierney #include <stdint.h>
28a951c980SBrian Tierney #include <netinet/tcp.h>
29a951c980SBrian Tierney #include <sys/time.h>
30a951c980SBrian Tierney #include <sys/resource.h>
31a951c980SBrian Tierney #include <sched.h>
32a951c980SBrian Tierney #include <setjmp.h>
33a951c980SBrian Tierney 
34a951c980SBrian Tierney #include "iperf.h"
35a951c980SBrian Tierney #include "iperf_api.h"
36a951c980SBrian Tierney #include "iperf_udp.h"
37a951c980SBrian Tierney #include "iperf_tcp.h"
388a0b5a5dSsethdelliott #include "iperf_util.h"
39a951c980SBrian Tierney #include "timer.h"
40a951c980SBrian Tierney #include "net.h"
41a951c980SBrian Tierney #include "units.h"
42a951c980SBrian Tierney #include "tcp_window_size.h"
43b0b16b86SJon Dugan #include "iperf_util.h"
44a951c980SBrian Tierney #include "locale.h"
45a951c980SBrian Tierney 
46a3281a3dSBrian Tierney 
47982c704aSsethdelliott int
48982c704aSsethdelliott iperf_server_listen(struct iperf_test *test)
49982c704aSsethdelliott {
50f99bd3b2Ssethdelliott     if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
51b60a49ddSsethdelliott         i_errno = IELISTEN;
52b60a49ddSsethdelliott         return (-1);
53982c704aSsethdelliott     }
54982c704aSsethdelliott 
55982c704aSsethdelliott     printf("-----------------------------------------------------------\n");
56982c704aSsethdelliott     printf("Server listening on %d\n", test->server_port);
57982c704aSsethdelliott 
58982c704aSsethdelliott     // This needs to be changed to reflect if client has different window size
59982c704aSsethdelliott     // make sure we got what we asked for
60ba2672a2Ssethdelliott     /* XXX: This needs to be moved to the stream listener
6166ce7ad4Ssethdelliott     if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {
62982c704aSsethdelliott         // Needs to set some sort of error number/message
63982c704aSsethdelliott         perror("SO_RCVBUF");
64982c704aSsethdelliott         return -1;
65982c704aSsethdelliott     }
66ba2672a2Ssethdelliott     */
67982c704aSsethdelliott 
68ba2672a2Ssethdelliott     // XXX: This code needs to be moved to after parameter exhange
69c81883bfSsethdelliott     /*
70*98ce496bSjef     char ubuf[UNIT_LEN];
71*98ce496bSjef     int x;
72*98ce496bSjef 
7366ce7ad4Ssethdelliott     if (test->protocol->id == Ptcp) {
74112a907cSsethdelliott         if (test->settings->socket_bufsize > 0) {
75982c704aSsethdelliott             unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
76982c704aSsethdelliott             printf("TCP window size: %s\n", ubuf);
77982c704aSsethdelliott         } else {
78982c704aSsethdelliott             printf("Using TCP Autotuning\n");
79982c704aSsethdelliott         }
80982c704aSsethdelliott     }
81c81883bfSsethdelliott     */
82982c704aSsethdelliott     printf("-----------------------------------------------------------\n");
83982c704aSsethdelliott 
84982c704aSsethdelliott     FD_ZERO(&test->read_set);
85efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
8666ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
8766ce7ad4Ssethdelliott     test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd;
88982c704aSsethdelliott 
89982c704aSsethdelliott     return 0;
90982c704aSsethdelliott }
91982c704aSsethdelliott 
92982c704aSsethdelliott int
93982c704aSsethdelliott iperf_accept(struct iperf_test *test)
94982c704aSsethdelliott {
95982c704aSsethdelliott     int s;
96465b565cSsethdelliott     int rbuf = ACCESS_DENIED;
97af70b448Ssethdelliott     char cookie[COOKIE_SIZE];
98982c704aSsethdelliott     socklen_t len;
99982c704aSsethdelliott     struct sockaddr_in addr;
100982c704aSsethdelliott 
101b68ac00eSsethdelliott     len = sizeof(addr);
10266ce7ad4Ssethdelliott     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
103b60a49ddSsethdelliott         i_errno = IEACCEPT;
104b60a49ddSsethdelliott         return (-1);
105982c704aSsethdelliott     }
106af70b448Ssethdelliott 
107af70b448Ssethdelliott     if (test->ctrl_sck == -1) {
108af70b448Ssethdelliott         /* Server free, accept new client */
109112a907cSsethdelliott         if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
110b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
111b60a49ddSsethdelliott             return (-1);
112af70b448Ssethdelliott         }
113af70b448Ssethdelliott 
114465b565cSsethdelliott         FD_SET(s, &test->read_set);
115465b565cSsethdelliott         FD_SET(s, &test->write_set);
116465b565cSsethdelliott         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
117465b565cSsethdelliott         test->ctrl_sck = s;
118982c704aSsethdelliott 
119af70b448Ssethdelliott         test->state = PARAM_EXCHANGE;
120af70b448Ssethdelliott         if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
121b60a49ddSsethdelliott             i_errno = IESENDMESSAGE;
122b60a49ddSsethdelliott             return (-1);
123af70b448Ssethdelliott         }
124b60a49ddSsethdelliott         if (iperf_exchange_parameters(test) < 0) {
125b60a49ddSsethdelliott             return (-1);
126b60a49ddSsethdelliott         }
1274df383f6Ssethdelliott         if (test->on_connect) {
1284df383f6Ssethdelliott             test->on_connect(test);
1294df383f6Ssethdelliott         }
130982c704aSsethdelliott     } else {
131b60a49ddSsethdelliott         // XXX: Do we even need to receive cookie if we're just going to deny anyways?
132af70b448Ssethdelliott         if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
133b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
134b60a49ddSsethdelliott             return (-1);
135465b565cSsethdelliott         }
136efb7bbe4Ssethdelliott         if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) {
137b60a49ddSsethdelliott             i_errno = IESENDMESSAGE;
138b60a49ddSsethdelliott             return (-1);
139465b565cSsethdelliott         }
140465b565cSsethdelliott         close(s);
141982c704aSsethdelliott     }
142982c704aSsethdelliott 
143b60a49ddSsethdelliott     return (0);
144af70b448Ssethdelliott }
145af70b448Ssethdelliott 
146b68ac00eSsethdelliott 
147a951c980SBrian Tierney /**************************************************************************/
148982c704aSsethdelliott int
149465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test)
150982c704aSsethdelliott {
151b68ac00eSsethdelliott     int rval;
152efdc02f7Ssethdelliott     struct iperf_stream *sp;
153efdc02f7Ssethdelliott 
154b60a49ddSsethdelliott     // XXX: Need to rethink how this behaves to fit API
155b60a49ddSsethdelliott     if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) {
156b68ac00eSsethdelliott         if (rval == 0) {
157b68ac00eSsethdelliott             fprintf(stderr, "The client has unexpectedly closed the connection.\n");
158b60a49ddSsethdelliott             i_errno = IECTRLCLOSE;
159b68ac00eSsethdelliott             test->state = IPERF_DONE;
160b60a49ddSsethdelliott             return (0);
161b68ac00eSsethdelliott         } else {
162b60a49ddSsethdelliott             i_errno = IERECVMESSAGE;
163b60a49ddSsethdelliott             return (-1);
164982c704aSsethdelliott         }
165b68ac00eSsethdelliott     }
166982c704aSsethdelliott 
167982c704aSsethdelliott     switch(test->state) {
168ba2672a2Ssethdelliott         case TEST_START:
169ba2672a2Ssethdelliott             break;
170465b565cSsethdelliott         case TEST_END:
1713331e801Ssethdelliott             cpu_util(&test->cpu_util);
172f1b3bd81Ssethdelliott             test->stats_callback(test);
173dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
174efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->read_set);
175efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->write_set);
176efdc02f7Ssethdelliott                 close(sp->socket);
177efdc02f7Ssethdelliott             }
178181d61afSsethdelliott             test->state = EXCHANGE_RESULTS;
179efb7bbe4Ssethdelliott             if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
180b60a49ddSsethdelliott                 i_errno = IESENDMESSAGE;
181b60a49ddSsethdelliott                 return (-1);
182181d61afSsethdelliott             }
183b60a49ddSsethdelliott             if (iperf_exchange_results(test) < 0)
184b60a49ddSsethdelliott                 return (-1);
185873952e3Ssethdelliott             test->state = DISPLAY_RESULTS;
186efb7bbe4Ssethdelliott             if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
187b60a49ddSsethdelliott                 i_errno = IESENDMESSAGE;
188b60a49ddSsethdelliott                 return (-1);
189465b565cSsethdelliott             }
1904df383f6Ssethdelliott             if (test->on_test_finish)
1914df383f6Ssethdelliott                 test->on_test_finish(test);
192181d61afSsethdelliott             test->reporter_callback(test);
193465b565cSsethdelliott             break;
194873952e3Ssethdelliott         case IPERF_DONE:
195873952e3Ssethdelliott             break;
196465b565cSsethdelliott         case CLIENT_TERMINATE:
197ffdcc7d4Ssethdelliott             i_errno = IECLIENTTERM;
198ffdcc7d4Ssethdelliott 
199ffdcc7d4Ssethdelliott             // XXX: Remove this line below!
2001ac522ecSsethdelliott             fprintf(stderr, "The client has terminated.\n");
201dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
2021ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->read_set);
2031ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->write_set);
2041ac522ecSsethdelliott                 close(sp->socket);
2051ac522ecSsethdelliott             }
2061ac522ecSsethdelliott             test->state = IPERF_DONE;
2071ac522ecSsethdelliott             break;
208ba2672a2Ssethdelliott         default:
209b60a49ddSsethdelliott             i_errno = IEMESSAGE;
210b60a49ddSsethdelliott             return (-1);
211982c704aSsethdelliott     }
212982c704aSsethdelliott 
213b60a49ddSsethdelliott     return (0);
214982c704aSsethdelliott }
215982c704aSsethdelliott 
2160bd8d9daSsethdelliott /* XXX: This function is not used anymore */
217efdc02f7Ssethdelliott void
218efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test)
219efdc02f7Ssethdelliott {
2200bd8d9daSsethdelliott     struct iperf_stream *sp;
221efdc02f7Ssethdelliott 
222efdc02f7Ssethdelliott     close(test->ctrl_sck);
223efdc02f7Ssethdelliott 
224efdc02f7Ssethdelliott     /* Free streams */
225dd4bc008Ssethdelliott     while (!SLIST_EMPTY(&test->streams)) {
226dd4bc008Ssethdelliott         sp = SLIST_FIRST(&test->streams);
227dd4bc008Ssethdelliott         SLIST_REMOVE_HEAD(&test->streams, streams);
228dd4bc008Ssethdelliott         iperf_free_stream(sp);
229dd4bc008Ssethdelliott     }
230f1b3bd81Ssethdelliott     free_timer(test->timer);
231f1b3bd81Ssethdelliott     free_timer(test->stats_timer);
232f1b3bd81Ssethdelliott     free_timer(test->reporter_timer);
233f1b3bd81Ssethdelliott     test->timer = NULL;
234f1b3bd81Ssethdelliott     test->stats_timer = NULL;
235f1b3bd81Ssethdelliott     test->reporter_timer = NULL;
236efdc02f7Ssethdelliott 
237dd4bc008Ssethdelliott     SLIST_INIT(&test->streams);
23832885561Ssethdelliott 
239efdc02f7Ssethdelliott     test->role = 's';
24066ce7ad4Ssethdelliott     set_protocol(test, Ptcp);
24132885561Ssethdelliott     test->duration = DURATION;
24232885561Ssethdelliott     test->state = 0;
24332885561Ssethdelliott     test->server_hostname = NULL;
24432885561Ssethdelliott 
24532885561Ssethdelliott     test->ctrl_sck = -1;
24666ce7ad4Ssethdelliott     test->prot_listener = -1;
24732885561Ssethdelliott 
248f1b3bd81Ssethdelliott     test->bytes_sent = 0;
249f1b3bd81Ssethdelliott 
25032885561Ssethdelliott     test->reverse = 0;
251b68ac00eSsethdelliott     test->no_delay = 0;
25232885561Ssethdelliott 
253efdc02f7Ssethdelliott     FD_ZERO(&test->read_set);
254efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
25566ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
25666ce7ad4Ssethdelliott     test->max_fd = test->listener;
25732885561Ssethdelliott 
25832885561Ssethdelliott     test->num_streams = 1;
259112a907cSsethdelliott     test->settings->socket_bufsize = 0;
260112a907cSsethdelliott     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
261112a907cSsethdelliott     test->settings->rate = RATE;   /* UDP only */
262112a907cSsethdelliott     test->settings->mss = 0;
263112a907cSsethdelliott     memset(test->cookie, 0, COOKIE_SIZE);
264efdc02f7Ssethdelliott }
265efdc02f7Ssethdelliott 
2667fa9f68fSsethdelliott int
267a951c980SBrian Tierney iperf_run_server(struct iperf_test *test)
268a951c980SBrian Tierney {
269112a907cSsethdelliott     int result, s, streams_accepted;
270efdc02f7Ssethdelliott     fd_set temp_read_set, temp_write_set;
2718a0b5a5dSsethdelliott     struct iperf_stream *sp;
2727fa9f68fSsethdelliott     struct timeval tv;
2730bd8d9daSsethdelliott     time_t sec, usec;
274a951c980SBrian Tierney 
275982c704aSsethdelliott     // Open socket and listen
276982c704aSsethdelliott     if (iperf_server_listen(test) < 0) {
277b60a49ddSsethdelliott         return (-1);
278e99faeaeSBrian Tierney     }
279a951c980SBrian Tierney 
2803331e801Ssethdelliott     // Begin calculating CPU utilization
2813331e801Ssethdelliott     cpu_util(NULL);
2823331e801Ssethdelliott 
283efdc02f7Ssethdelliott     test->state = IPERF_START;
284112a907cSsethdelliott     streams_accepted = 0;
285a951c980SBrian Tierney 
286873952e3Ssethdelliott     while (test->state != IPERF_DONE) {
287982c704aSsethdelliott 
288efdc02f7Ssethdelliott         memcpy(&temp_read_set, &test->read_set, sizeof(fd_set));
289efdc02f7Ssethdelliott         memcpy(&temp_write_set, &test->write_set, sizeof(fd_set));
290982c704aSsethdelliott         tv.tv_sec = 15;
291982c704aSsethdelliott         tv.tv_usec = 0;
292982c704aSsethdelliott 
293efdc02f7Ssethdelliott         result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv);
294982c704aSsethdelliott         if (result < 0 && errno != EINTR) {
295b60a49ddSsethdelliott             i_errno = IESELECT;
296b60a49ddSsethdelliott             return (-1);
297982c704aSsethdelliott         } else if (result > 0) {
29866ce7ad4Ssethdelliott             if (FD_ISSET(test->listener, &temp_read_set)) {
299b68ac00eSsethdelliott                 if (test->state != CREATE_STREAMS) {
300465b565cSsethdelliott                     if (iperf_accept(test) < 0) {
301b60a49ddSsethdelliott                         return (-1);
302982c704aSsethdelliott                     }
30366ce7ad4Ssethdelliott                     FD_CLR(test->listener, &temp_read_set);
304982c704aSsethdelliott                 }
305b68ac00eSsethdelliott             }
306efdc02f7Ssethdelliott             if (FD_ISSET(test->ctrl_sck, &temp_read_set)) {
307b60a49ddSsethdelliott                 if (iperf_handle_message_server(test) < 0)
308b60a49ddSsethdelliott                     return (-1);
309efdc02f7Ssethdelliott                 FD_CLR(test->ctrl_sck, &temp_read_set);
310982c704aSsethdelliott             }
311465b565cSsethdelliott 
312465b565cSsethdelliott             if (test->state == CREATE_STREAMS) {
3138a0b5a5dSsethdelliott                 if (FD_ISSET(test->prot_listener, &temp_read_set)) {
3148a0b5a5dSsethdelliott 
31566ce7ad4Ssethdelliott                     if ((s = test->protocol->accept(test)) < 0)
316b60a49ddSsethdelliott                         return (-1);
3178a0b5a5dSsethdelliott 
3188a0b5a5dSsethdelliott                     if (!is_closed(s)) {
31966ce7ad4Ssethdelliott                         sp = iperf_new_stream(test, s);
3208a0b5a5dSsethdelliott                         if (!sp)
321b60a49ddSsethdelliott                             return (-1);
32266ce7ad4Ssethdelliott 
3238a0b5a5dSsethdelliott                         FD_SET(s, &test->read_set);
3248a0b5a5dSsethdelliott                         FD_SET(s, &test->write_set);
3258a0b5a5dSsethdelliott                         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
32666ce7ad4Ssethdelliott 
327112a907cSsethdelliott                         streams_accepted++;
3284df383f6Ssethdelliott                         if (test->on_new_stream)
3294df383f6Ssethdelliott                             test->on_new_stream(sp);
330b68ac00eSsethdelliott                     }
3318a0b5a5dSsethdelliott                     FD_CLR(test->prot_listener, &temp_read_set);
332b68ac00eSsethdelliott                 }
3338a0b5a5dSsethdelliott 
334112a907cSsethdelliott                 if (streams_accepted == test->num_streams) {
33566ce7ad4Ssethdelliott                     if (test->protocol->id != Ptcp) {
3368a0b5a5dSsethdelliott                         FD_CLR(test->prot_listener, &test->read_set);
3378a0b5a5dSsethdelliott                         close(test->prot_listener);
33866ce7ad4Ssethdelliott                     } else {
3390bd8d9daSsethdelliott                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
34066ce7ad4Ssethdelliott                             FD_CLR(test->listener, &test->read_set);
34166ce7ad4Ssethdelliott                             close(test->listener);
342f99bd3b2Ssethdelliott                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
343b60a49ddSsethdelliott                                 i_errno = IELISTEN;
344c81883bfSsethdelliott                                 return (-1);
345c81883bfSsethdelliott                             }
34666ce7ad4Ssethdelliott                             test->listener = s;
347c81883bfSsethdelliott                             test->max_fd = (s > test->max_fd ? s : test->max_fd);
34866ce7ad4Ssethdelliott                             FD_SET(test->listener, &test->read_set);
349c81883bfSsethdelliott                         }
3508556db5dSsethdelliott                     }
3518a0b5a5dSsethdelliott                     test->prot_listener = -1;
352465b565cSsethdelliott                     test->state = TEST_START;
353b68ac00eSsethdelliott                     if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
354b60a49ddSsethdelliott                         i_errno = IESENDMESSAGE;
355b60a49ddSsethdelliott                         return (-1);
356982c704aSsethdelliott                     }
357b60a49ddSsethdelliott                     if (iperf_init_test(test) < 0)
358b60a49ddSsethdelliott                         return (-1);
359f1b3bd81Ssethdelliott                     test->state = TEST_RUNNING;
360f1b3bd81Ssethdelliott                     if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
361b60a49ddSsethdelliott                         i_errno = IESENDMESSAGE;
362b60a49ddSsethdelliott                         return (-1);
363f1b3bd81Ssethdelliott                     }
364982c704aSsethdelliott                 }
365982c704aSsethdelliott             }
366982c704aSsethdelliott 
367f1b3bd81Ssethdelliott             if (test->state == TEST_RUNNING) {
368465b565cSsethdelliott                 if (test->reverse) {
369465b565cSsethdelliott                     // Reverse mode. Server sends.
370b60a49ddSsethdelliott                     if (iperf_send(test) < 0)
371b60a49ddSsethdelliott                         return (-1);
372982c704aSsethdelliott                 } else {
373465b565cSsethdelliott                     // Regular mode. Server receives.
374b60a49ddSsethdelliott                     if (iperf_recv(test) < 0)
375b60a49ddSsethdelliott                         return (-1);
376e99faeaeSBrian Tierney                 }
377f1b3bd81Ssethdelliott 
378f1b3bd81Ssethdelliott                 /* Perform callbacks */
379f1b3bd81Ssethdelliott                 if (timer_expired(test->stats_timer)) {
380f1b3bd81Ssethdelliott                     test->stats_callback(test);
3810bd8d9daSsethdelliott                     sec = (time_t) test->stats_interval;
3820bd8d9daSsethdelliott                     usec = (test->stats_interval - sec) * SEC_TO_US;
3830bd8d9daSsethdelliott                     if (update_timer(test->stats_timer, sec, usec) < 0)
384b60a49ddSsethdelliott                         return (-1);
385f1b3bd81Ssethdelliott                 }
386f1b3bd81Ssethdelliott                 if (timer_expired(test->reporter_timer)) {
387f1b3bd81Ssethdelliott                     test->reporter_callback(test);
3880bd8d9daSsethdelliott                     sec = (time_t) test->reporter_interval;
3890bd8d9daSsethdelliott                     usec = (test->reporter_interval - sec) * SEC_TO_US;
3900bd8d9daSsethdelliott                     if (update_timer(test->reporter_timer, sec, usec) < 0)
391b60a49ddSsethdelliott                         return (-1);
392f1b3bd81Ssethdelliott                 }
393f1b3bd81Ssethdelliott             }
394a951c980SBrian Tierney         }
395982c704aSsethdelliott     }
396e99faeaeSBrian Tierney 
39702a35f07Ssethdelliott     /* Close open test sockets */
3980bd8d9daSsethdelliott     close(test->ctrl_sck);
3990bd8d9daSsethdelliott     close(test->listener);
400efdc02f7Ssethdelliott 
401b60a49ddSsethdelliott     return (0);
402a3281a3dSBrian Tierney }
403