xref: /iperf/src/iperf_server_api.c (revision c27f38e5)
1a951c980SBrian Tierney 
2a951c980SBrian Tierney /*
3a951c980SBrian Tierney  * Copyright (c) 2009, The Regents of the University of California, through
4a951c980SBrian Tierney  * Lawrence Berkeley National Laboratory (subject to receipt of any required
5a951c980SBrian Tierney  * approvals from the U.S. Dept. of Energy).  All rights reserved.
6a951c980SBrian Tierney  */
7a951c980SBrian Tierney 
8a951c980SBrian Tierney /* iperf_server_api.c: Functions to be used by an iperf server
9a951c980SBrian Tierney */
10a951c980SBrian Tierney 
11a951c980SBrian Tierney #include <stdio.h>
12a951c980SBrian Tierney #include <stdlib.h>
13a951c980SBrian Tierney #include <string.h>
14a951c980SBrian Tierney #include <getopt.h>
15a951c980SBrian Tierney #include <errno.h>
16a951c980SBrian Tierney #include <signal.h>
17a951c980SBrian Tierney #include <unistd.h>
18a951c980SBrian Tierney #include <assert.h>
19a951c980SBrian Tierney #include <fcntl.h>
20a951c980SBrian Tierney #include <sys/socket.h>
21a951c980SBrian Tierney #include <sys/types.h>
22a951c980SBrian Tierney #include <netinet/in.h>
23a951c980SBrian Tierney #include <arpa/inet.h>
24a951c980SBrian Tierney #include <netdb.h>
25a951c980SBrian Tierney #include <pthread.h>
26a951c980SBrian Tierney #include <stdint.h>
27a951c980SBrian Tierney #include <netinet/tcp.h>
28a951c980SBrian Tierney #include <sys/time.h>
29a951c980SBrian Tierney #include <sys/resource.h>
30a951c980SBrian Tierney #include <sched.h>
31a951c980SBrian Tierney #include <signal.h>
32a951c980SBrian Tierney #include <setjmp.h>
33a951c980SBrian Tierney 
34a951c980SBrian Tierney #include "iperf.h"
35a951c980SBrian Tierney #include "iperf_server_api.h"
36a951c980SBrian Tierney #include "iperf_api.h"
37a951c980SBrian Tierney #include "iperf_udp.h"
38a951c980SBrian Tierney #include "iperf_tcp.h"
39a951c980SBrian Tierney #include "timer.h"
40a951c980SBrian Tierney #include "net.h"
41a951c980SBrian Tierney #include "units.h"
42a951c980SBrian Tierney #include "tcp_window_size.h"
43a951c980SBrian Tierney #include "uuid.h"
44a951c980SBrian Tierney #include "locale.h"
45a951c980SBrian Tierney 
46a951c980SBrian Tierney /*********************************************************************/
47a951c980SBrian Tierney /**
48a951c980SBrian Tierney  * param_received - handles the param_Exchange part for server
49a951c980SBrian Tierney  * returns state on success, -1 on failure
50a951c980SBrian Tierney  *
51a951c980SBrian Tierney  */
52a951c980SBrian Tierney 
53a951c980SBrian Tierney int
54a951c980SBrian Tierney param_received(struct iperf_stream * sp, struct param_exchange * param)
55a951c980SBrian Tierney {
56a951c980SBrian Tierney     int       result;
57a951c980SBrian Tierney     char     *buf = (char *) malloc(sizeof(struct param_exchange));
58a951c980SBrian Tierney 
59a951c980SBrian Tierney     if (sp->settings->cookie[0] == '\0' ||
60a951c980SBrian Tierney 	(strncmp(param->cookie, sp->settings->cookie, 37) == 0))
61a951c980SBrian Tierney     {
62a951c980SBrian Tierney 	strncpy(sp->settings->cookie, param->cookie, 37);
63a951c980SBrian Tierney 	sp->settings->blksize = param->blksize;
64a951c980SBrian Tierney 	sp->settings->socket_bufsize = param->recv_window;
65a951c980SBrian Tierney 	sp->settings->unit_format = param->format;
66a951c980SBrian Tierney 	printf("Got params from client: block size = %d, recv_window = %d cookie = %s\n",
67a951c980SBrian Tierney 	       sp->settings->blksize, sp->settings->socket_bufsize, sp->settings->cookie);
68a951c980SBrian Tierney 	param->state = TEST_START;
69a951c980SBrian Tierney 	buf[0] = TEST_START;
70a951c980SBrian Tierney 
71a951c980SBrian Tierney     } else
72a951c980SBrian Tierney     {
73a951c980SBrian Tierney 	fprintf(stderr, "Connection from new client denied\n");
74a951c980SBrian Tierney 	param->state = ACCESS_DENIED;
75a951c980SBrian Tierney 	buf[0] = ACCESS_DENIED;
76a951c980SBrian Tierney     }
77a951c980SBrian Tierney     free(buf);
78a36921c2SBrian Tierney     //printf("param_received: Sending message back to client \n");
79a951c980SBrian Tierney     result = send(sp->socket, buf, sizeof(struct param_exchange), 0);
80a951c980SBrian Tierney     if (result < 0)
81a951c980SBrian Tierney 	perror("param_received: Error sending param ack to client");
82a951c980SBrian Tierney     return param->state;
83a951c980SBrian Tierney }
84a951c980SBrian Tierney 
85a951c980SBrian Tierney /*************************************************************/
86a951c980SBrian Tierney 
87a951c980SBrian Tierney /**
88a951c980SBrian Tierney  * send_result_to_client - sends result string from server to client
89a951c980SBrian Tierney  */
90a951c980SBrian Tierney 
91a951c980SBrian Tierney void
92a951c980SBrian Tierney send_result_to_client(struct iperf_stream * sp)
93a951c980SBrian Tierney {
94a951c980SBrian Tierney     int       result;
95a951c980SBrian Tierney     int       size = sp->settings->blksize;
96a951c980SBrian Tierney 
97a951c980SBrian Tierney     char     *buf = (char *) malloc(size);
98a951c980SBrian Tierney 
99a951c980SBrian Tierney     if (!buf)
100a951c980SBrian Tierney     {
101a951c980SBrian Tierney 	perror("malloc: unable to allocate transmit buffer");
102a951c980SBrian Tierney     }
103a951c980SBrian Tierney     /* adding the string terminator to the message */
104a951c980SBrian Tierney     buf[strlen((char *) sp->data)] = '\0';
105a951c980SBrian Tierney 
106a951c980SBrian Tierney     memcpy(buf, sp->data, strlen((char *) sp->data));
107a951c980SBrian Tierney 
108a951c980SBrian Tierney     printf("send_result_to_client: sending %d bytes \n", (int) strlen((char *) sp->data));
109a951c980SBrian Tierney     result = send(sp->socket, buf, size, 0);
110a951c980SBrian Tierney     printf("RESULT SENT TO CLIENT\n");
111a951c980SBrian Tierney 
112a951c980SBrian Tierney     free(buf);
113a951c980SBrian Tierney }
114a951c980SBrian Tierney 
115a951c980SBrian Tierney /**************************************************************************/
116a951c980SBrian Tierney void
117a951c980SBrian Tierney iperf_run_server(struct iperf_test * test)
118a951c980SBrian Tierney {
119a951c980SBrian Tierney     struct timeval tv;
120a951c980SBrian Tierney     struct iperf_stream *np, *sp;
121a951c980SBrian Tierney     int       j, result, message;
122a951c980SBrian Tierney     char     *results_string = NULL;
123a951c980SBrian Tierney 
124*c27f38e5SBrian Tierney     printf("in iperf_run_server \n");
125a951c980SBrian Tierney     FD_ZERO(&test->read_set);
126a951c980SBrian Tierney     FD_SET(test->listener_sock_tcp, &test->read_set);
127a951c980SBrian Tierney     FD_SET(test->listener_sock_udp, &test->read_set);
128a951c980SBrian Tierney 
129a951c980SBrian Tierney     test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp;
130*c27f38e5SBrian Tierney     printf("iperf_run_server: max_fd set to %d \n", test->max_fd);
131a951c980SBrian Tierney 
132a951c980SBrian Tierney     test->num_streams = 0;
133a951c980SBrian Tierney     test->default_settings->state = TEST_RUNNING;
134a951c980SBrian Tierney 
135a951c980SBrian Tierney     printf("iperf_run_server: Waiting for client connect.... \n");
136a951c980SBrian Tierney     while (test->default_settings->state != TEST_END)
137a951c980SBrian Tierney     {
138a951c980SBrian Tierney 	memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set));
139a951c980SBrian Tierney 	tv.tv_sec = 15;
140a951c980SBrian Tierney 	tv.tv_usec = 0;
141a951c980SBrian Tierney 
142a951c980SBrian Tierney 	/* using select to check on multiple descriptors. */
143*c27f38e5SBrian Tierney 	//printf("calling select.. sock = %d \n", test->max_fd + 1);
144a951c980SBrian Tierney 	result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv);
145a951c980SBrian Tierney 	if (result == 0)
146a951c980SBrian Tierney 	{
147a951c980SBrian Tierney 	    //printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec);
148a951c980SBrian Tierney 	    continue;
149a951c980SBrian Tierney 	} else if (result < 0 && errno != EINTR)
150a951c980SBrian Tierney 	{
151*c27f38e5SBrian Tierney 	    printf("Error in select(): %s, socket = %d\n", strerror(errno), test->max_fd + 1);
152a951c980SBrian Tierney 	    exit(0);
153a951c980SBrian Tierney 	} else if (result > 0)
154a951c980SBrian Tierney 	{
155a951c980SBrian Tierney 	    /* Accept a new TCP connection */
156a951c980SBrian Tierney 	    if (FD_ISSET(test->listener_sock_tcp, &test->temp_set))
157a951c980SBrian Tierney 	    {
158a951c980SBrian Tierney 		test->protocol = Ptcp;
159a951c980SBrian Tierney 		test->accept = iperf_tcp_accept;
160a951c980SBrian Tierney 		test->new_stream = iperf_new_tcp_stream;
161a951c980SBrian Tierney 		test->accept(test);
162a951c980SBrian Tierney 		test->default_settings->state = TEST_RUNNING;
163a951c980SBrian Tierney 		FD_CLR(test->listener_sock_tcp, &test->temp_set);
164*c27f38e5SBrian Tierney 		printf("iperf_run_server: accepted TCP connection \n");
165a951c980SBrian Tierney 	    }
166a951c980SBrian Tierney 	    /* Accept a new UDP connection */
167a951c980SBrian Tierney 	    else if (FD_ISSET(test->listener_sock_udp, &test->temp_set))
168a951c980SBrian Tierney 	    {
169a951c980SBrian Tierney 		test->protocol = Pudp;
170a951c980SBrian Tierney 		test->accept = iperf_udp_accept;
171a951c980SBrian Tierney 		test->new_stream = iperf_new_udp_stream;
172a951c980SBrian Tierney 		test->accept(test);
173a951c980SBrian Tierney 		test->default_settings->state = TEST_RUNNING;
174a951c980SBrian Tierney 		FD_CLR(test->listener_sock_udp, &test->temp_set);
175a951c980SBrian Tierney 	    }
176a951c980SBrian Tierney 	    /* Process the sockets for read operation */
177a951c980SBrian Tierney 	    for (j = 0; j < test->max_fd + 1; j++)
178a951c980SBrian Tierney 	    {
179a951c980SBrian Tierney 		if (FD_ISSET(j, &test->temp_set))
180a951c980SBrian Tierney 		{
181a951c980SBrian Tierney 		    /* find the correct stream - possibly time consuming */
182a951c980SBrian Tierney 		    np = find_stream_by_socket(test, j);
183*c27f38e5SBrian Tierney 		    message = np->rcv(np);	/* get data from client using
184*c27f38e5SBrian Tierney 						 * receiver callback  */
185a951c980SBrian Tierney 		    //printf("iperf_run_server: iperf_tcp_recv returned %d \n", message);
186*c27f38e5SBrian Tierney 	            if (message < 0)
187*c27f38e5SBrian Tierney 		    {
188*c27f38e5SBrian Tierney 			printf("Error reading data from client \n");
189*c27f38e5SBrian Tierney 			close(np->socket);
190*c27f38e5SBrian Tierney 		        return;
191*c27f38e5SBrian Tierney 		    }
192a951c980SBrian Tierney 		    np->settings->state = message;
193a951c980SBrian Tierney 
194a951c980SBrian Tierney 		    if (message == PARAM_EXCHANGE)
195a951c980SBrian Tierney 		    {
196a951c980SBrian Tierney 			/* copy the received settings into test */
197a951c980SBrian Tierney 			memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings));
198a951c980SBrian Tierney 		    }
199*c27f38e5SBrian Tierney 		    if (message == ACCESS_DENIED)	/* this might get set by
200*c27f38e5SBrian Tierney 							 * PARAM_EXCHANGE */
201a951c980SBrian Tierney 		    {
202a951c980SBrian Tierney 			/* XXX: test this! */
203a951c980SBrian Tierney 			close(np->socket);
204a36921c2SBrian Tierney 			//FD_CLR(np->socket, &test->read_set);
205a36921c2SBrian Tierney 			iperf_free_stream(np);
206a951c980SBrian Tierney 		    }
207a951c980SBrian Tierney 		    if (message == STREAM_END)
208a951c980SBrian Tierney 		    {
209a951c980SBrian Tierney 			/*
210a951c980SBrian Tierney 			 * XXX: should I expect one of these per stream. If
211a951c980SBrian Tierney 			 * so, only timestamp the 1st one??
212a951c980SBrian Tierney 			 */
213a951c980SBrian Tierney 			gettimeofday(&np->result->end_time, NULL);
214a951c980SBrian Tierney 		    }
215a951c980SBrian Tierney 		    if (message == RESULT_REQUEST)
216a951c980SBrian Tierney 		    {
217a951c980SBrian Tierney 			np->settings->state = RESULT_RESPOND;
218a951c980SBrian Tierney 			results_string = test->reporter_callback(test);
219a951c980SBrian Tierney 			np->data = results_string;
220a951c980SBrian Tierney 			send_result_to_client(np);
221a951c980SBrian Tierney 		    }
222a951c980SBrian Tierney 		    if (message == ALL_STREAMS_END)
223a951c980SBrian Tierney 		    {
224a951c980SBrian Tierney 			/* print server results */
225a951c980SBrian Tierney 			results_string = test->reporter_callback(test);
226a951c980SBrian Tierney 			puts(results_string);	/* send to stdio */
227a951c980SBrian Tierney 		    }
228a951c980SBrian Tierney 		    if (message == TEST_END)
229a951c980SBrian Tierney 		    {
230a951c980SBrian Tierney 			/* FREE ALL STREAMS  */
231a951c980SBrian Tierney 			np = test->streams;
232a951c980SBrian Tierney 			do
233a951c980SBrian Tierney 			{
234a951c980SBrian Tierney 			    sp = np;
235*c27f38e5SBrian Tierney 			    //printf(" closing socket: %d \n", sp->socket);
236a951c980SBrian Tierney 			    close(sp->socket);
237*c27f38e5SBrian Tierney 			    FD_CLR(sp->socket, &test->read_set);
238*c27f38e5SBrian Tierney 			    np = sp->next;	/* get next pointer before
239*c27f38e5SBrian Tierney 						 * freeing */
240a36921c2SBrian Tierney 			    iperf_free_stream(sp);
241a951c980SBrian Tierney 			} while (np != NULL);
242a951c980SBrian Tierney 
243a951c980SBrian Tierney 			test->default_settings->state = TEST_END;
244*c27f38e5SBrian Tierney 			/* reset cookie when client is finished */
245a951c980SBrian Tierney 			memset(test->default_settings->cookie, '\0', 37);
246*c27f38e5SBrian Tierney 			break; /* always break out of for loop on TEST_END message */
247a951c980SBrian Tierney 		    }
248a951c980SBrian Tierney 		}		/* end if (FD_ISSET(j, &temp_set)) */
249a951c980SBrian Tierney 	    }			/* end for (j=0;...) */
250a951c980SBrian Tierney 
251a951c980SBrian Tierney 	}			/* end else (result>0)   */
252a951c980SBrian Tierney     }				/* end while */
253*c27f38e5SBrian Tierney     printf("Test Complete. \n\n");
254*c27f38e5SBrian Tierney     return;
255a951c980SBrian Tierney 
256a951c980SBrian Tierney }
257