xref: /iperf/src/iperf_server_api.c (revision 150a09e9)
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' ||
608f4e66c9SBrian Tierney 	(strncmp(param->cookie, sp->settings->cookie, COOKIE_SIZE) == 0))
61a951c980SBrian Tierney     {
628f4e66c9SBrian Tierney 	strncpy(sp->settings->cookie, param->cookie, COOKIE_SIZE);
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     {
738f4e66c9SBrian Tierney 	fprintf(stderr, "Connection from new client denied.\n");
748f4e66c9SBrian Tierney 	printf("cookie still set to %s \n", sp->settings->cookie);
75a951c980SBrian Tierney 	param->state = ACCESS_DENIED;
76a951c980SBrian Tierney 	buf[0] = ACCESS_DENIED;
77a951c980SBrian Tierney     }
788f4e66c9SBrian Tierney     memcpy(sp->buffer, buf, sizeof(struct param_exchange));;
798f4e66c9SBrian Tierney     printf("param_received: Sending message (%d) back to client \n", sp->buffer[0]);
808f4e66c9SBrian Tierney     result = Nwrite(sp->socket, sp->buffer, sizeof(struct param_exchange), Ptcp);
81a951c980SBrian Tierney     if (result < 0)
82a951c980SBrian Tierney 	perror("param_received: Error sending param ack to client");
838f4e66c9SBrian Tierney     free(buf);
84a951c980SBrian Tierney     return param->state;
85a951c980SBrian Tierney }
86a951c980SBrian Tierney 
87a951c980SBrian Tierney /*************************************************************/
88a951c980SBrian Tierney 
89a951c980SBrian Tierney /**
90a951c980SBrian Tierney  * send_result_to_client - sends result string from server to client
91a951c980SBrian Tierney  */
92a951c980SBrian Tierney 
93a951c980SBrian Tierney void
94a951c980SBrian Tierney send_result_to_client(struct iperf_stream * sp)
95a951c980SBrian Tierney {
96a951c980SBrian Tierney     int       result;
97a951c980SBrian Tierney     int       size = sp->settings->blksize;
98a951c980SBrian Tierney 
99a951c980SBrian Tierney     char     *buf = (char *) malloc(size);
100a951c980SBrian Tierney 
101a951c980SBrian Tierney     if (!buf)
102a951c980SBrian Tierney     {
103a951c980SBrian Tierney 	perror("malloc: unable to allocate transmit buffer");
104a951c980SBrian Tierney     }
105a951c980SBrian Tierney     /* adding the string terminator to the message */
106a951c980SBrian Tierney     buf[strlen((char *) sp->data)] = '\0';
107a951c980SBrian Tierney 
108a951c980SBrian Tierney     memcpy(buf, sp->data, strlen((char *) sp->data));
109a951c980SBrian Tierney 
110a951c980SBrian Tierney     printf("send_result_to_client: sending %d bytes \n", (int) strlen((char *) sp->data));
111a951c980SBrian Tierney     result = send(sp->socket, buf, size, 0);
112a951c980SBrian Tierney     printf("RESULT SENT TO CLIENT\n");
113a951c980SBrian Tierney 
114a951c980SBrian Tierney     free(buf);
115a951c980SBrian Tierney }
116a951c980SBrian Tierney 
117a951c980SBrian Tierney /**************************************************************************/
118a951c980SBrian Tierney void
119a951c980SBrian Tierney iperf_run_server(struct iperf_test * test)
120a951c980SBrian Tierney {
121a951c980SBrian Tierney     struct timeval tv;
122a951c980SBrian Tierney     struct iperf_stream *np, *sp;
123*150a09e9SBrian Tierney     int       j, result=0, message, cnt=0;
124a951c980SBrian Tierney     char     *results_string = NULL;
125a951c980SBrian Tierney 
126c27f38e5SBrian Tierney     printf("in iperf_run_server \n");
127*150a09e9SBrian Tierney 
128a951c980SBrian Tierney     FD_ZERO(&test->read_set);
129a951c980SBrian Tierney     FD_SET(test->listener_sock_tcp, &test->read_set);
130a951c980SBrian Tierney     FD_SET(test->listener_sock_udp, &test->read_set);
131a951c980SBrian Tierney 
132a951c980SBrian Tierney     test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp;
1338f4e66c9SBrian Tierney     //printf("iperf_run_server: max_fd set to %d \n", test->max_fd);
134a951c980SBrian Tierney 
135a951c980SBrian Tierney     test->num_streams = 0;
136a951c980SBrian Tierney     test->default_settings->state = TEST_RUNNING;
137a951c980SBrian Tierney 
138a951c980SBrian Tierney     printf("iperf_run_server: Waiting for client connect.... \n");
139*150a09e9SBrian Tierney 
140a951c980SBrian Tierney     while (test->default_settings->state != TEST_END)
141a951c980SBrian Tierney     {
142a951c980SBrian Tierney 	memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set));
143a951c980SBrian Tierney 	tv.tv_sec = 15;
144a951c980SBrian Tierney 	tv.tv_usec = 0;
145a951c980SBrian Tierney 
146a951c980SBrian Tierney 	/* using select to check on multiple descriptors. */
147c27f38e5SBrian Tierney 	//printf("calling select.. sock = %d \n", test->max_fd + 1);
148a951c980SBrian Tierney 	result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv);
149a951c980SBrian Tierney 	if (result == 0)
150a951c980SBrian Tierney 	{
151a951c980SBrian Tierney 	    //printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec);
152a951c980SBrian Tierney 	    continue;
153a951c980SBrian Tierney 	} else if (result < 0 && errno != EINTR)
154a951c980SBrian Tierney 	{
155c27f38e5SBrian Tierney 	    printf("Error in select(): %s, socket = %d\n", strerror(errno), test->max_fd + 1);
156a951c980SBrian Tierney 	    exit(0);
157a951c980SBrian Tierney 	} else if (result > 0)
158a951c980SBrian Tierney 	{
159a951c980SBrian Tierney 	    /* Accept a new TCP connection */
160a951c980SBrian Tierney 	    if (FD_ISSET(test->listener_sock_tcp, &test->temp_set))
161a951c980SBrian Tierney 	    {
162a951c980SBrian Tierney 		test->protocol = Ptcp;
163a951c980SBrian Tierney 		test->accept = iperf_tcp_accept;
164a951c980SBrian Tierney 		test->new_stream = iperf_new_tcp_stream;
165a951c980SBrian Tierney 		test->accept(test);
166a951c980SBrian Tierney 		test->default_settings->state = TEST_RUNNING;
167a951c980SBrian Tierney 		FD_CLR(test->listener_sock_tcp, &test->temp_set);
168c27f38e5SBrian Tierney 		printf("iperf_run_server: accepted TCP connection \n");
169a951c980SBrian Tierney 	    }
170a951c980SBrian Tierney 	    /* Accept a new UDP connection */
171a951c980SBrian Tierney 	    else if (FD_ISSET(test->listener_sock_udp, &test->temp_set))
172a951c980SBrian Tierney 	    {
173a951c980SBrian Tierney 		test->protocol = Pudp;
174a951c980SBrian Tierney 		test->accept = iperf_udp_accept;
175a951c980SBrian Tierney 		test->new_stream = iperf_new_udp_stream;
176a951c980SBrian Tierney 		test->accept(test);
177a951c980SBrian Tierney 		test->default_settings->state = TEST_RUNNING;
178a951c980SBrian Tierney 		FD_CLR(test->listener_sock_udp, &test->temp_set);
179a951c980SBrian Tierney 	    }
180a951c980SBrian Tierney 	    /* Process the sockets for read operation */
1818f4e66c9SBrian Tierney 	    /* XXX: Need to try to read equal amounts from each socket, so keep
1828f4e66c9SBrian Tierney 		track of last socket read from, and always start with the next
1838f4e66c9SBrian Tierney 		socket
1848f4e66c9SBrian Tierney 		*/
185a951c980SBrian Tierney 	    for (j = 0; j < test->max_fd + 1; j++)
186a951c980SBrian Tierney 	    {
187a951c980SBrian Tierney 		if (FD_ISSET(j, &test->temp_set))
188a951c980SBrian Tierney 		{
189a951c980SBrian Tierney 		    /* find the correct stream - possibly time consuming */
190a951c980SBrian Tierney 		    np = find_stream_by_socket(test, j);
191c27f38e5SBrian Tierney 		    message = np->rcv(np);	/* get data from client using
192c27f38e5SBrian Tierney 						 * receiver callback  */
193a951c980SBrian Tierney 		    //printf("iperf_run_server: iperf_tcp_recv returned %d \n", message);
194c27f38e5SBrian Tierney 	            if (message < 0)
195c27f38e5SBrian Tierney 		    {
196c27f38e5SBrian Tierney 			printf("Error reading data from client \n");
197c27f38e5SBrian Tierney 			close(np->socket);
198c27f38e5SBrian Tierney 		        return;
199c27f38e5SBrian Tierney 		    }
200a951c980SBrian Tierney 		    np->settings->state = message;
201a951c980SBrian Tierney 
202a951c980SBrian Tierney 		    if (message == PARAM_EXCHANGE)
203a951c980SBrian Tierney 		    {
204a951c980SBrian Tierney 			/* copy the received settings into test */
205a951c980SBrian Tierney 			memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings));
206a951c980SBrian Tierney 		    }
207c27f38e5SBrian Tierney 		    if (message == ACCESS_DENIED)	/* this might get set by
208c27f38e5SBrian Tierney 							 * PARAM_EXCHANGE */
209a951c980SBrian Tierney 		    {
210a951c980SBrian Tierney 			/* XXX: test this! */
211a951c980SBrian Tierney 			close(np->socket);
2128d41fbd7SBrian Tierney 			FD_CLR(np->socket, &test->read_set);
213a36921c2SBrian Tierney 			iperf_free_stream(np);
214a951c980SBrian Tierney 		    }
215a951c980SBrian Tierney 		    if (message == STREAM_END)
216a951c980SBrian Tierney 		    {
217a951c980SBrian Tierney 			gettimeofday(&np->result->end_time, NULL);
218a951c980SBrian Tierney 		    }
219a951c980SBrian Tierney 		    if (message == RESULT_REQUEST)
220a951c980SBrian Tierney 		    {
221a951c980SBrian Tierney 			np->settings->state = RESULT_RESPOND;
222a951c980SBrian Tierney 			results_string = test->reporter_callback(test);
223a951c980SBrian Tierney 			np->data = results_string;
224a951c980SBrian Tierney 			send_result_to_client(np);
225a951c980SBrian Tierney 		    }
226a951c980SBrian Tierney 		    if (message == ALL_STREAMS_END)
227a951c980SBrian Tierney 		    {
2288f4e66c9SBrian Tierney 		        printf("client send ALL_STREAMS_END message, printing results \n");
229a951c980SBrian Tierney 			/* print server results */
230a951c980SBrian Tierney 			results_string = test->reporter_callback(test);
231a951c980SBrian Tierney 			puts(results_string);	/* send to stdio */
232a951c980SBrian Tierney 		    }
233a951c980SBrian Tierney 		    if (message == TEST_END)
234a951c980SBrian Tierney 		    {
235a951c980SBrian Tierney 			/* FREE ALL STREAMS  */
236a951c980SBrian Tierney 			np = test->streams;
237a951c980SBrian Tierney 			do
238a951c980SBrian Tierney 			{
239a951c980SBrian Tierney 			    sp = np;
240c27f38e5SBrian Tierney 			    //printf(" closing socket: %d \n", sp->socket);
241a951c980SBrian Tierney 			    close(sp->socket);
242c27f38e5SBrian Tierney 			    FD_CLR(sp->socket, &test->read_set);
243c27f38e5SBrian Tierney 			    np = sp->next;	/* get next pointer before
244c27f38e5SBrian Tierney 						 * freeing */
245a36921c2SBrian Tierney 			    iperf_free_stream(sp);
246a951c980SBrian Tierney 			} while (np != NULL);
247a951c980SBrian Tierney 
248a951c980SBrian Tierney 			test->default_settings->state = TEST_END;
249c27f38e5SBrian Tierney 			/* reset cookie when client is finished */
2508f4e66c9SBrian Tierney 			printf("got TEST_END message, reseting cookie \n");
2518f4e66c9SBrian Tierney 			memset(test->default_settings->cookie, '\0', COOKIE_SIZE);
252c27f38e5SBrian Tierney 			break; /* always break out of for loop on TEST_END message */
253a951c980SBrian Tierney 		    }
254a951c980SBrian Tierney 		}		/* end if (FD_ISSET(j, &temp_set)) */
255a951c980SBrian Tierney 	    }			/* end for (j=0;...) */
256a951c980SBrian Tierney 
257a951c980SBrian Tierney 	}			/* end else (result>0)   */
258a951c980SBrian Tierney     }				/* end while */
259c27f38e5SBrian Tierney     printf("Test Complete. \n\n");
260c27f38e5SBrian Tierney     return;
261a951c980SBrian Tierney 
262a951c980SBrian Tierney }
263