2 * Copyright (c) 2009 Nicira Networks.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
24 #include "poll-loop.h"
25 #include "socket-util.h"
41 fpv_create(const char *type, struct fake_pvconn *fpv)
44 if (!strcmp(type, "unix")) {
45 static int unix_count = 0;
49 bind_path = xasprintf("fake-pvconn.%d", unix_count++);
50 fd = make_unix_socket(SOCK_STREAM, false, false, bind_path, NULL);
52 ovs_fatal(-fd, "%s: could not bind to Unix domain socket",
56 fpv->pvconn_name = xasprintf("punix:%s", bind_path);
57 fpv->vconn_name = xasprintf("unix:%s", bind_path);
60 } else if (!strcmp(type, "tcp")) {
61 struct sockaddr_in sin;
65 /* Create TCP socket. */
66 fd = socket(PF_INET, SOCK_STREAM, 0);
68 ovs_fatal(errno, "failed to create TCP socket");
71 /* Bind TCP socket to localhost on any available port. */
72 sin.sin_family = AF_INET;
73 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
74 sin.sin_port = htons(0);
75 if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
76 ovs_fatal(errno, "failed to bind TCP socket");
79 /* Retrieve socket's port number. */
81 if (getsockname(fd, &sin, &sin_len) < 0) {
82 ovs_fatal(errno, "failed to read TCP socket name");
84 if (sin_len != sizeof sin || sin.sin_family != AF_INET) {
85 ovs_fatal(errno, "bad TCP socket name");
89 fpv->pvconn_name = xasprintf("ptcp:%"PRIu16":127.0.0.1",
91 fpv->vconn_name = xasprintf("tcp:127.0.0.1:%"PRIu16,
99 if (listen(fpv->fd, 0) < 0) {
100 ovs_fatal(errno, "%s: listen failed", fpv->vconn_name);
105 fpv_accept(struct fake_pvconn *fpv)
109 fd = accept(fpv->fd, NULL, NULL);
111 ovs_fatal(errno, "%s: accept failed", fpv->pvconn_name);
117 fpv_close(struct fake_pvconn *fpv)
120 if (close(fpv->fd) < 0) {
121 ovs_fatal(errno, "failed to close %s fake pvconn", fpv->type);
128 fpv_destroy(struct fake_pvconn *fpv)
131 free(fpv->pvconn_name);
132 free(fpv->vconn_name);
135 /* Connects to a fake_pvconn with vconn_open(), then closes the listener and
136 * verifies that vconn_connect() reports 'expected_error'. */
138 test_refuse_connection(const char *type, int expected_error)
140 struct fake_pvconn fpv;
143 fpv_create(type, &fpv);
144 assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
146 assert(vconn_connect(vconn) == expected_error);
151 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
152 * closes it immediately, and verifies that vconn_connect() reports
153 * 'expected_error'. */
155 test_accept_then_close(const char *type, int expected_error)
157 struct fake_pvconn fpv;
160 fpv_create(type, &fpv);
161 assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
162 close(fpv_accept(&fpv));
164 assert(vconn_connect(vconn) == expected_error);
169 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
170 * reads the hello message from it, then closes the connection and verifies
171 * that vconn_connect() reports 'expected_error'. */
173 test_read_hello(const char *type, int expected_error)
175 struct fake_pvconn fpv;
179 fpv_create(type, &fpv);
180 assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
181 fd = fpv_accept(&fpv);
183 assert(!set_nonblocking(fd));
185 struct ofp_header hello;
188 retval = read(fd, &hello, sizeof hello);
189 if (retval == sizeof hello) {
190 assert(hello.version == OFP_VERSION);
191 assert(hello.type == OFPT_HELLO);
192 assert(hello.length == htons(sizeof hello));
195 assert(errno == EAGAIN);
198 assert(vconn_connect(vconn) == EAGAIN);
199 vconn_connect_wait(vconn);
200 poll_fd_wait(fd, POLLIN);
204 assert(vconn_connect(vconn) == expected_error);
208 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
209 * sends the 'out' bytes in 'out_size' to it (presumably an OFPT_HELLO
210 * message), then verifies that vconn_connect() reports
211 * 'expect_connect_error'. */
213 test_send_hello(const char *type, const void *out, size_t out_size,
214 int expect_connect_error)
216 struct fake_pvconn fpv;
218 bool read_hello, connected;
222 fpv_create(type, &fpv);
223 assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
224 fd = fpv_accept(&fpv);
227 write(fd, out, out_size);
229 assert(!set_nonblocking(fd));
231 read_hello = connected = false;
234 struct ofp_header hello;
235 int retval = read(fd, &hello, sizeof hello);
236 if (retval == sizeof hello) {
237 assert(hello.version == OFP_VERSION);
238 assert(hello.type == OFPT_HELLO);
239 assert(hello.length == htons(sizeof hello));
242 assert(errno == EAGAIN);
247 int error = vconn_connect(vconn);
248 if (error == expect_connect_error) {
257 assert(error == EAGAIN);
261 if (read_hello && connected) {
266 vconn_connect_wait(vconn);
269 poll_fd_wait(fd, POLLIN);
274 assert(vconn_recv(vconn, &msg) == EOF);
278 /* Try connecting and sending a normal hello, which should succeed. */
280 test_send_plain_hello(const char *type)
282 struct ofp_header hello;
284 hello.version = OFP_VERSION;
285 hello.type = OFPT_HELLO;
286 hello.length = htons(sizeof hello);
287 hello.xid = htonl(0x12345678);
288 test_send_hello(type, &hello, sizeof hello, 0);
291 /* Try connecting and sending an extra-long hello, which should succeed (since
292 * the specification says that implementations must accept and ignore extra
295 test_send_long_hello(const char *type)
297 struct ofp_header hello;
298 char buffer[sizeof hello * 2];
300 hello.version = OFP_VERSION;
301 hello.type = OFPT_HELLO;
302 hello.length = htons(sizeof buffer);
303 hello.xid = htonl(0x12345678);
304 memset(buffer, 0, sizeof buffer);
305 memcpy(buffer, &hello, sizeof hello);
306 test_send_hello(type, buffer, sizeof buffer, 0);
309 /* Try connecting and sending an echo request instead of a hello, which should
310 * fail with EPROTO. */
312 test_send_echo_hello(const char *type)
314 struct ofp_header echo;
316 echo.version = OFP_VERSION;
317 echo.type = OFPT_ECHO_REQUEST;
318 echo.length = htons(sizeof echo);
319 echo.xid = htonl(0x89abcdef);
320 test_send_hello(type, &echo, sizeof echo, EPROTO);
323 /* Try connecting and sending a hello packet that has its length field as 0,
324 * which should fail with EPROTO. */
326 test_send_short_hello(const char *type)
328 struct ofp_header hello;
330 memset(&hello, 0, sizeof hello);
331 test_send_hello(type, &hello, sizeof hello, EPROTO);
334 /* Try connecting and sending a hello packet that has a bad version, which
335 * should fail with EPROTO. */
337 test_send_invalid_version_hello(const char *type)
339 struct ofp_header hello;
341 hello.version = OFP_VERSION - 1;
342 hello.type = OFPT_HELLO;
343 hello.length = htons(sizeof hello);
344 hello.xid = htonl(0x12345678);
345 test_send_hello(type, &hello, sizeof hello, EPROTO);
349 main(int argc UNUSED, char *argv[])
351 set_program_name(argv[0]);
354 signal(SIGPIPE, SIG_IGN);
355 vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_EMER);
359 test_refuse_connection("unix", EPIPE);
360 test_refuse_connection("tcp", ECONNRESET);
362 test_accept_then_close("unix", EPIPE);
363 test_accept_then_close("tcp", ECONNRESET);
365 test_read_hello("unix", ECONNRESET);
366 test_read_hello("tcp", ECONNRESET);
368 test_send_plain_hello("unix");
369 test_send_plain_hello("tcp");
371 test_send_long_hello("unix");
372 test_send_long_hello("tcp");
374 test_send_echo_hello("unix");
375 test_send_echo_hello("tcp");
377 test_send_short_hello("unix");
378 test_send_short_hello("tcp");
380 test_send_invalid_version_hello("unix");
381 test_send_invalid_version_hello("tcp");