diff --git a/tests/Android.mk b/tests/Android.mk index 8dffa2ff5..a37ea4a75 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -81,6 +81,7 @@ libBionicStandardTests_src_files := \ system_properties_test.cpp \ time_test.cpp \ unistd_test.cpp \ + accept4_test.cpp \ libBionicStandardTests_cflags := \ $(test_cflags) \ diff --git a/tests/accept4_test.cpp b/tests/accept4_test.cpp new file mode 100644 index 000000000..2e6c80871 --- /dev/null +++ b/tests/accept4_test.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Contributed by: Intel Corporation, 2014 + */ + +#include + +#if defined(__BIONIC__) + #define SOCK_CLOEXEC_SUPPORTED 1 +#elif defined(__GLIBC_PREREQ) + #if __GLIBC_PREREQ(2, 9) + #define SOCK_CLOEXEC_SUPPORTED 1 + #endif +#endif + +#if defined(SOCK_CLOEXEC_SUPPORTED) + +#include +#include +#include +#include +#include + +#define SOCK_PATH "test" + +static void* ConnectFn(void*) { + int fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (fd < 0) { + GTEST_LOG_(ERROR) << "socket call failed: " << strerror(errno); + return reinterpret_cast(-1); + } + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + addr.sun_path[0] = '\0'; + strcpy(addr.sun_path + 1, SOCK_PATH); + + if (connect(fd, reinterpret_cast(&addr), sizeof(addr)) < 0) { + GTEST_LOG_(ERROR) << "connect call failed: " << strerror(errno); + close(fd); + return reinterpret_cast(-1); + } + + close(fd); + + return NULL; +} +#endif + +TEST(accept4, smoke) { +#if defined(SOCK_CLOEXEC_SUPPORTED) + int fd = socket(PF_UNIX, SOCK_SEQPACKET, 0); + ASSERT_NE(fd, -1) << strerror(errno); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + addr.sun_path[0] = '\0'; + strcpy(addr.sun_path + 1, SOCK_PATH); + + ASSERT_NE(-1, bind(fd, reinterpret_cast(&addr), sizeof(addr))) << strerror(errno); + + ASSERT_NE(-1, listen(fd, 1)) << strerror(errno); + + pthread_t thread; + ASSERT_EQ(0, pthread_create(&thread, NULL, ConnectFn, NULL)); + + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(fd, &read_set); + timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + ASSERT_LT(0, select(fd+1, &read_set, NULL, NULL, &tv)); + + socklen_t len = sizeof(addr); + int fd_acc = accept4(fd, reinterpret_cast(&addr), &len, SOCK_CLOEXEC); + ASSERT_NE(fd_acc, -1) << strerror(errno); + + // Check that the flag was set properly. + ASSERT_EQ(FD_CLOEXEC, fcntl(fd_acc, F_GETFD) & FD_CLOEXEC); + + void* ret_val; + pthread_join(thread, &ret_val); + ASSERT_EQ(NULL, ret_val); + + close(fd_acc); + close(fd); +#else + GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif +}