1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms
5 * of the Common Development and Distribution License
6 * (the "License").  You may not use this file except
7 * in compliance with the License.
8 *
9 * You can obtain a copy of the license at
10 * src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing
13 * permissions and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL
16 * HEADER in each file and include the License file at
17 * usr/src/OPENSOLARIS.LICENSE.  If applicable,
18 * add the following below this CDDL HEADER, with the
19 * fields enclosed by brackets "[]" replaced with your
20 * own identifying information: Portions Copyright [yyyy]
21 * [name of copyright owner]
22 *
23 * CDDL HEADER END
24 */
25
26/*
27 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <netinet/in.h>
35#include <netinet/tcp.h>
36#include <arpa/inet.h>
37#include <netdb.h>
38#include <string.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <fcntl.h>
43#include <errno.h>
44#include <sys/poll.h>
45
46#include "libmicro.h"
47
48#define	FIRSTPORT		12345
49
50typedef struct {
51	int			ts_once;
52	int			*ts_lsns;
53	int			*ts_accs;
54	int			*ts_cons;
55	struct sockaddr_in	*ts_adds;
56} tsd_t;
57
58static int			opta = 0;
59static int			optc = 0;
60static struct hostent		*host;
61
62int
63benchmark_init()
64{
65	lm_defB = 256;
66	lm_tsdsize = sizeof (tsd_t);
67
68	(void) sprintf(lm_optstr, "ac");
69
70	(void) sprintf(lm_usage,
71	    "       [-a] (measure accept() only)\n"
72	    "       [-c] (measure connect() only)\n"
73	    "notes: measures connect()/accept()\n");
74
75	return (0);
76}
77
78/*ARGSUSED*/
79int
80benchmark_optswitch(int opt, char *optarg)
81{
82	switch (opt) {
83	case 'a':
84		opta = 1;
85		break;
86	case 'c':
87		optc = 1;
88		break;
89	default:
90		return (-1);
91	}
92
93	if (opta && optc) {
94		(void) printf("warning: -a overrides -c\n");
95		optc = 0;
96	}
97
98	return (0);
99}
100
101int
102benchmark_initrun()
103{
104	(void) setfdlimit(3 * lm_optB * lm_optT + 10);
105
106	return (0);
107}
108
109int
110benchmark_initbatch_once(void *tsd)
111{
112	tsd_t			*ts = (tsd_t *)tsd;
113	int			i, j;
114
115	int			errors = 0;
116
117	ts->ts_lsns = (int *)malloc(lm_optB * sizeof (int));
118	if (ts->ts_lsns == NULL) {
119		errors ++;
120	}
121	ts->ts_accs = (int *)malloc(lm_optB * sizeof (int));
122	if (ts->ts_accs == NULL) {
123		errors ++;
124	}
125	ts->ts_cons = (int *)malloc(lm_optB * sizeof (int));
126	if (ts->ts_cons == NULL) {
127		errors ++;
128	}
129	ts->ts_adds =
130	    (struct sockaddr_in *)malloc(lm_optB *
131	    sizeof (struct sockaddr_in));
132	if (ts->ts_accs == NULL) {
133		errors ++;
134	}
135
136	j = FIRSTPORT;
137	for (i = 0; i < lm_optB; i++) {
138		ts->ts_lsns[i] = socket(AF_INET, SOCK_STREAM, 0);
139		if (ts->ts_lsns[i] == -1) {
140			perror("socket");
141			errors ++;
142		}
143
144		/*
145		 * make accept socket non-blocking so in case of errors
146		 * we don't hang
147		 */
148
149		if (fcntl(ts->ts_lsns[i], F_SETFL, O_NDELAY) == -1) {
150			perror("fcntl");
151			errors ++;
152		}
153
154
155		if ((host = gethostbyname("localhost")) == NULL) {
156			errors ++;
157		}
158
159		for (;;) {
160			(void) memset(&ts->ts_adds[i], 0,
161			    sizeof (struct sockaddr_in));
162			ts->ts_adds[i].sin_family = AF_INET;
163			ts->ts_adds[i].sin_port = htons(j++);
164			(void) memcpy(&ts->ts_adds[i].sin_addr.s_addr,
165			    host->h_addr_list[0], sizeof (struct in_addr));
166
167			if (bind(ts->ts_lsns[i],
168			    (struct sockaddr *)&ts->ts_adds[i],
169			    sizeof (struct sockaddr_in)) == 0) {
170				break;
171			}
172
173			if (errno != EADDRINUSE) {
174				errors ++;
175			}
176		}
177
178		if (listen(ts->ts_lsns[i], 5) == -1) {
179			perror("listen");
180			errors ++;
181		}
182	}
183	return (errors);
184}
185
186int
187benchmark_initbatch(void *tsd)
188{
189	tsd_t			*ts = (tsd_t *)tsd;
190	int			i;
191	int			errors = 0;
192	int			result;
193
194	if (ts->ts_once++ == 0) {
195		if (errors += benchmark_initbatch_once(tsd) == -1) {
196			return (-1);
197		}
198	}
199
200
201	for (i = 0; i < lm_optB; i++) {
202		ts->ts_cons[i] = socket(AF_INET, SOCK_STREAM, 0);
203		if (ts->ts_cons[i] == -1) {
204			perror("init:socket");
205			errors ++;
206		}
207
208		if (fcntl(ts->ts_cons[i], F_SETFL, O_NDELAY) == -1) {
209			perror("init:fcntl");
210			errors ++;
211		}
212
213		if (opta) {
214			result = connect(ts->ts_cons[i],
215			    (struct sockaddr *)&ts->ts_adds[i],
216			    sizeof (struct sockaddr_in));
217			if ((result == -1) && (errno != EINPROGRESS)) {
218				perror("init:connect");
219				errors ++;
220			}
221		}
222	}
223
224	return (errors);
225}
226
227int
228benchmark(void *tsd, result_t *res)
229
230
231
232{
233	tsd_t			*ts = (tsd_t *)tsd;
234	int			i;
235	int			result;
236	struct sockaddr_in	addr;
237	socklen_t		size;
238
239	for (i = 0; i < lm_optB; i++) {
240		if (!opta) {
241		again:
242			result = connect(ts->ts_cons[i],
243			    (struct sockaddr *)&ts->ts_adds[i],
244			    sizeof (struct sockaddr_in));
245			if (result != 0 && errno != EISCONN) {
246				if (errno == EINPROGRESS) {
247					struct pollfd pollfd;
248					if (optc)
249						continue;
250					pollfd.fd = ts->ts_cons[i];
251					pollfd.events = POLLOUT;
252					if (poll(&pollfd, 1, -1) == 1)
253						goto again;
254				}
255
256				res->re_errors ++;
257				perror("benchmark:connect");
258				continue;
259			}
260		}
261
262		if (!optc) {
263			size = sizeof (struct sockaddr);
264			for (;;) {
265				struct pollfd pollfd;
266				result = accept(ts->ts_lsns[i],
267				    (struct sockaddr *)&addr, &size);
268				if (result > 0 || (result == -1 &&
269				    errno != EAGAIN))
270					break;
271				pollfd.fd = ts->ts_lsns[i];
272				pollfd.events = POLLIN;
273				if (poll(&pollfd, 1, -1) != 1)
274					break;
275			}
276
277			ts->ts_accs[i] = result;
278			if (result == -1) {
279				res->re_errors ++;
280				perror("benchmark:accept");
281				continue;
282			}
283		}
284	}
285	res->re_count = i;
286
287	return (0);
288}
289
290int
291benchmark_finibatch(void *tsd)
292{
293	tsd_t			*ts = (tsd_t *)tsd;
294	int			i;
295
296	for (i = 0; i < lm_optB; i++) {
297
298		if (!optc) {
299			(void) close(ts->ts_accs[i]);
300		}
301		(void) close(ts->ts_cons[i]);
302	}
303
304	return (0);
305}
306