accf_data_attach.c revision 132649
1/*-
2 * Copyright (c) 2004 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/tools/regression/sockets/accf_data_attach/accf_data_attach.c 132649 2004-07-26 03:53:47Z rwatson $
27 */
28
29#include <sys/types.h>
30#include <sys/socket.h>
31
32#include <netinet/in.h>
33
34#include <err.h>
35#include <errno.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#define	ACCF_NAME	"dataready"
42
43/*
44 * A number of small tests to confirm that attaching ACCF_DATA accept filters
45 * to inet4 ports works as expected.  We test:
46 *
47 * - That no accept filter is attached on a newly created socket.
48 * - That bind() has no affect on the accept filter state.
49 * - That we can't attach an accept filter to a socket that isn't in the
50 *   listen state.
51 * - That after we fail to attach the filter, querying the kernel shows no
52 *   filter attached.
53 * - That we can attach an accept filter to a socket that is in the listen
54 *   state.
55 * - That once an accept filter is attached, we can query to make sure it is
56 *   attached.
57 */
58int
59main(int argc, char *argv[])
60{
61	struct accept_filter_arg afa;
62	struct sockaddr_in sin;
63	socklen_t len;
64	int lso, ret;
65
66	/*
67	 * Step 0. Open socket().
68	 */
69	lso = socket(PF_INET, SOCK_STREAM, 0);
70	if (lso == -1)
71		err(1, "socket");
72
73	/*
74	 * Step 1. After socket().  Should return EINVAL, since no accept
75	 * filter should be attached.
76	 */
77	bzero(&afa, sizeof(afa));
78	len = sizeof(afa);
79	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
80	if (ret != -1) {
81		fprintf(stderr, "FAIL: getsockopt() after socket() "
82		    "succeeded\n");
83		exit(-1);
84	}
85	if (errno != EINVAL) {
86		fprintf(stderr, "FAIL: getsockopt() after socket() "
87		    "failed with %d (%s)\n", errno, strerror(errno));
88		exit(-1);
89	}
90
91	/*
92	 * Step 2. Bind().  Ideally this will succeed.
93	 */
94	bzero(&sin, sizeof(sin));
95	sin.sin_len = sizeof(sin);
96	sin.sin_family = AF_INET;
97	sin.sin_port = htons(8080);
98	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
99	if (bind(lso, (struct sockaddr *)&sin, sizeof(sin)) < 0)
100		err(1, "bind");
101
102	/*
103	 * Step 3: After bind().  getsockopt() should return EINVAL, since no
104	 *  accept filter should be attached.
105	 */
106	len = sizeof(afa);
107	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
108	if (ret != -1) {
109		fprintf(stderr, "FAIL: getsockopt() after bind() succeeded\n");
110		exit(-1);
111	}
112	if (errno != EINVAL) {
113		fprintf(stderr, "FAIL: getsockopt() after bind() failed "
114		    "with %d (%s)\n", errno, strerror(errno));
115		exit(-1);
116	}
117
118	/*
119	 * Step 4: Setsockopt() before listen().  Should fail, since it's not
120	 * yet a listen() socket.
121	 */
122	bzero(&afa, sizeof(afa));
123	strcpy(afa.af_name, ACCF_NAME);
124	ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa));
125	if (ret == 0) {
126		fprintf(stderr, "FAIL: setsockopt() before listen() "
127		    "succeeded\n");
128		exit(-1);
129	}
130
131	/*
132	 * Step 5: Getsockopt() after pre-listen() setsockopt().  Should
133	 * fail with EINVAL, since setsockopt() should have failed.
134	 */
135	len = sizeof(afa);
136	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
137	if (ret == 0) {
138		fprintf(stderr, "FAIL: getsockopt() after pre-listen() "
139		    "setsockopt() succeeded\n");
140		exit(-1);
141	}
142	if (errno != EINVAL) {
143		fprintf(stderr, "FAIL: pre-listen() getsockopt() failed "
144		    "with %d (%s)\n", errno, strerror(errno));
145		exit(-1);
146	}
147
148	/*
149	 * Step 6: listen().
150	 */
151	if (listen(lso, -1) < 0)
152		err(1, "listen");
153
154	/*
155	 * Step 7: After listen().  This call to setsockopt() should succeed.
156	 */
157	bzero(&afa, sizeof(afa));
158	strcpy(afa.af_name, ACCF_NAME);
159	ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa));
160	if (ret != 0) {
161		fprintf(stderr, "FAIL: setsockopt() after listen() failed "
162		    "with %d (%s)\n", errno, strerror(errno));
163		exit(-1);
164	}
165	if (len != sizeof(afa)) {
166		fprintf(stderr, "FAIL: setsockopt() after listen() returned "
167		    "wrong size (%d vs expected %d)\n", len, sizeof(afa));
168		exit(-1);
169	}
170
171	/*
172	 * Step 8: After setsockopt().  Should succeed and identify
173	 * ACCF_NAME.
174	 */
175	bzero(&afa, sizeof(afa));
176	len = sizeof(afa);
177	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
178	if (ret != 0) {
179		fprintf(stderr, "FAIL: getsockopt() after listen() "
180		    "setsockopt() failed with %d (%s)\n", errno,
181		    strerror(errno));
182		exit(-1);
183	}
184	if (len != sizeof(afa)) {
185		fprintf(stderr, "FAIL: getsockopt() after setsockopet() "
186		    " after listen() returned wrong size (got %d expected "
187		    "%d)\n", len, sizeof(afa));
188		exit(-1);
189	}
190	if (strcmp(afa.af_name, ACCF_NAME) != 0) {
191		fprintf(stderr, "FAIL: getsockopt() after setsockopt() "
192		    "after listen() mismatch (got %s expected %s)\n",
193		    afa.af_name, ACCF_NAME);
194		exit(-1);
195	}
196
197	printf("PASS\n");
198	close(lso);
199	return (0);
200}
201