* [LTP] [PATCH v2 1/2] connect01: Convert to new API
@ 2024-05-14 4:51 Yang Xu via ltp
2024-05-14 4:51 ` [LTP] [PATCH v2 2/2] connect01: Add negative tests Yang Xu via ltp
` (2 more replies)
0 siblings, 3 replies; 24+ messages in thread
From: Yang Xu via ltp @ 2024-05-14 4:51 UTC (permalink / raw)
To: ltp
Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
testcases/kernel/syscalls/connect/connect01.c | 401 +++++++-----------
1 file changed, 146 insertions(+), 255 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 660c4f7a9..52a6f154b 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -1,308 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) Linux Test Project, 2006-2024
*/
-/*
- * Test Name: connect01
+/*\
+ * [Description]
*
- * Test Description:
- * Verify that connect() returns the proper errno for various failure cases
- *
- * Usage: <for command-line>
- * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS:
- * None.
+ * Verify that connect() returns the proper errno for various failure case
*
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/un.h>
-
-#include <netinet/in.h>
-
-#include "test.h"
-#include "safe_macros.h"
-
-char *TCID = "connect01";
-int testno;
-
-int s, s2; /* socket descriptor */
-struct sockaddr_in sin1, sin2, sin3, sin4;
-static int sfd; /* shared between start_server and do_child */
-
-void setup(void), setup0(void), setup1(void), setup2(void),
-cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
-
-static pid_t start_server(struct sockaddr_in *);
+#include <sys/wait.h>
+#include <pwd.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
-struct test_case_t { /* test case structure */
- int domain; /* PF_INET, PF_UNIX, ... */
- int type; /* SOCK_STREAM, SOCK_DGRAM ... */
- int proto; /* protocol number (usually 0 = default) */
- struct sockaddr *sockaddr; /* socket address buffer */
- int salen; /* connect's 3rd argument */
- int retval; /* syscall return value */
- int experrno; /* expected errno */
- void (*setup) (void);
- void (*cleanup) (void);
+static int fd_share;
+static int fd_server;
+
+static struct sockaddr_in sock1;
+static struct sockaddr_in sock2;
+static struct sockaddr_in sock3;
+
+static pid_t pid;
+
+static void setup1(unsigned int);
+static void setup2(unsigned int);
+static void setup3(unsigned int);
+static void cleanup1(void);
+
+static struct test_case_t {
+ int domain;
+ int type;
+ int proto;
+ struct sockaddr *sockaddr;
+ int salen;
+ int exp_errno;
+ void (*setup)(unsigned int i);
+ void (*cleanup)(void);
char *desc;
-} tdat[] = {
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(struct sockaddr_in), -1, EBADF, setup0,
- cleanup0, "bad file descriptor"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
- sizeof(struct sockaddr_in), -1, EFAULT, setup1,
- cleanup1, "invalid socket buffer"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
- 0, 0, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
- "invalid socket"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, EISCONN, setup2, cleanup1,
- "already connected"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
- sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
- "connection refused"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
- sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
- "invalid address family"}
-,};
-
-int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-/**
- * bionic's connect() implementation calls netdClientInitConnect() before
- * sending the request to the kernel. We need to bypass this, or the test will
- * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
- * tests started to segfault on glibc upgrade or in special conditions where
- * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
- * safer to call the raw syscall regardless of the libc implementation.
- */
-#include "lapi/syscalls.h"
+} tcases[] = {
+ {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock1,
+ sizeof(struct sockaddr_in), EBADF, setup1, cleanup1,
+ "sockfd is not a valid open file descriptor"},
+ {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
+ sizeof(struct sockaddr_in), EFAULT, setup2, cleanup1,
+ "socket structure address is outside the user's address space"},
+ {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock1,
+ 3, EINVAL, setup2, cleanup1,
+ "addrlen is not valid"},
+ {0, 0, 0, (struct sockaddr *)&sock1,
+ sizeof(sock1), ENOTSOCK, setup1, cleanup1,
+ "file descriptor sockfd does not refer to a socket"},
+ {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock1,
+ sizeof(sock1), EISCONN, setup3, cleanup1,
+ "socket is already connected"},
+ {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock2,
+ sizeof(sock2), ECONNREFUSED, setup2, cleanup1,
+ "connect on a socket found no one listening on remote address"},
+ {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock3,
+ sizeof(sock3), EAFNOSUPPORT, setup2, cleanup1,
+ "address doesn't have the correct address family in sa_family"},
+};
static int sys_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen)
+ socklen_t addrlen)
{
return tst_syscall(__NR_connect, sockfd, addr, addrlen);
}
-#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
-
-int main(int argc, char *argv[])
+static void do_child(void)
{
- int lc;
-
- tst_parse_opts(argc, argv, NULL, NULL);
+ struct sockaddr_in sock;
+ fd_set fd_set_all;
+ fd_set fd_set_read;
+ int nfds;
+ ssize_t bytes;
+ int fd;
+ char data;
+
+ FD_ZERO(&fd_set_all);
+ FD_SET(fd_server, &fd_set_all);
+ nfds = fd_server + 1;
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); ++lc) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; ++testno) {
- tdat[testno].setup();
+ while (1) {
+ socklen_t len;
- TEST(connect
- (s, tdat[testno].sockaddr, tdat[testno].salen));
+ memcpy(&fd_set_read, &fd_set_all, sizeof(fd_set_read));
+ if (select(nfds, &fd_set_read, NULL, NULL, NULL) < 0)
+ if (errno != EINTR)
+ exit(1);
+ if (FD_ISSET(fd_server, &fd_set_read)) {
+ int newfd;
- if (TEST_RETURN != tdat[testno].retval ||
- (TEST_RETURN < 0 &&
- TEST_ERRNO != tdat[testno].experrno)) {
- tst_resm(TFAIL, "%s ; returned"
- " %ld (expected %d), errno %d (expected"
- " %d)", tdat[testno].desc,
- TEST_RETURN, tdat[testno].retval,
- TEST_ERRNO, tdat[testno].experrno);
- } else {
- tst_resm(TPASS, "%s successful",
- tdat[testno].desc);
+ len = sizeof(sock);
+ newfd = SAFE_ACCEPT(fd_server, (struct sockaddr *)&sock,
+ &len);
+ if (newfd >= 0) {
+ FD_SET(newfd, &fd_set_all);
+ nfds = MAX(nfds, newfd + 1);
}
- tdat[testno].cleanup();
}
+ for (fd = 0; fd < nfds; fd++)
+ if (fd != fd_server && FD_ISSET(fd, &fd_set_read)) {
+ bytes = read(fd, &data, 1);
+ if (bytes == 0) {
+ close(fd);
+ FD_CLR(fd, &fd_set_all);
+ }
+ }
}
- cleanup();
-
- tst_exit();
}
-pid_t pid;
-
-void setup(void)
+static void start_server(struct sockaddr_in *sock)
{
- TEST_PAUSE; /* if -p option specified */
-
- pid = start_server(&sin1);
+ socklen_t slen = sizeof(*sock);
- sin2.sin_family = AF_INET;
- /* this port must be unused! */
- sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
- sin2.sin_addr.s_addr = INADDR_ANY;
+ sock->sin_family = AF_INET;
+ sock->sin_port = 0;
+ sock->sin_addr.s_addr = INADDR_ANY;
- sin3.sin_family = AF_INET;
- sin3.sin_port = 0;
- /* assumes no route to this network! */
- sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
- sin4.sin_family = 47; /* bogus address family */
- sin4.sin_port = 0;
- sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
+ fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
+ SAFE_LISTEN(fd_server, 10);
+ SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
+ pid = SAFE_FORK();
+ if (!pid) {
+ do_child();
+ exit(0);
+ }
+ close(fd_server);
}
-void cleanup(void)
+static void setup(void)
{
- (void)kill(pid, SIGKILL);
+ sock2.sin_family = AF_INET;
+ sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
+ sock2.sin_addr.s_addr = INADDR_ANY;
+ sock3.sin_family = 47;
+ sock3.sin_port = 0;
+ sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
}
-void setup0(void)
+static void setup1(unsigned int i)
{
- if (tdat[testno].experrno == EBADF)
- s = 400; /* anything not an open file */
- else if ((s = open("/dev/null", O_WRONLY)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
+ struct test_case_t *tc = &tcases[i];
+ if (tc->exp_errno == EBADF)
+ fd_share = -1;
+ else
+ fd_share = SAFE_OPEN("/dev/null", O_WRONLY);
}
-void cleanup0(void)
+static void setup2(unsigned int i)
{
- close(s);
- s = -1;
-}
+ struct test_case_t *tc = &tcases[i];
-void setup1(void)
-{
- s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
- tdat[testno].proto);
+ fd_share = SAFE_SOCKET(tc->domain, tc->type, tc->proto);
}
-void cleanup1(void)
+static void setup3(unsigned int i)
{
- (void)close(s);
- s = -1;
+ setup2(i);
+ SAFE_CONNECT(fd_server, (const struct sockaddr *)&sock1, sizeof(sock1));
}
-void setup2(void)
+static void cleanup1(void)
{
- setup1(); /* get a socket in s */
- SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
+ if (fd_share > 0)
+ SAFE_CLOSE(fd_share);
}
-pid_t start_server(struct sockaddr_in *sin0)
+static void verify_connect(unsigned int i)
{
- pid_t pid;
- socklen_t slen = sizeof(*sin0);
-
- sin0->sin_family = AF_INET;
- sin0->sin_port = 0; /* pick random free port */
- sin0->sin_addr.s_addr = INADDR_ANY;
-
- sfd = socket(PF_INET, SOCK_STREAM, 0);
- if (sfd < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
- return -1;
- }
- if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
- return -1;
- }
- if (listen(sfd, 10) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
- return -1;
- }
- SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
-
- switch ((pid = tst_fork())) {
- case 0: /* child */
- do_child();
- break;
- case -1:
- tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
- /* fall through */
- default: /* parent */
- (void)close(sfd);
- return pid;
- }
-
- return -1;
+ struct test_case_t *tc = &tcases[i];
+
+ start_server(&sock1);
+ if (tc->setup)
+ tc->setup(i);
+ TST_EXP_FAIL(sys_connect(fd_share, tc->sockaddr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ SAFE_KILL(pid, SIGKILL);
+ SAFE_WAITPID(pid, NULL, 0);
+ if (tc->cleanup)
+ tc->cleanup();
}
-void do_child(void)
-{
- struct sockaddr_in fsin;
- fd_set afds, rfds;
- int nfds, cc, fd;
- char c;
-
- FD_ZERO(&afds);
- FD_SET(sfd, &afds);
-
- nfds = sfd + 1;
-
- /* accept connections until killed */
- while (1) {
- socklen_t fromlen;
-
- memcpy(&rfds, &afds, sizeof(rfds));
-
- if (select(nfds, &rfds, NULL, NULL,
- NULL) < 0)
- if (errno != EINTR)
- exit(1);
- if (FD_ISSET(sfd, &rfds)) {
- int newfd;
-
- fromlen = sizeof(fsin);
- newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
- if (newfd >= 0) {
- FD_SET(newfd, &afds);
- nfds = MAX(nfds, newfd + 1);
- }
- }
- for (fd = 0; fd < nfds; ++fd)
- if (fd != sfd && FD_ISSET(fd, &rfds)) {
- if ((cc = read(fd, &c, 1)) == 0) {
- (void)close(fd);
- FD_CLR(fd, &afds);
- }
- }
- }
-}
+static struct tst_test test = {
+ .setup = setup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_connect,
+ .forks_child = 1,
+};
--
2.39.3
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* [LTP] [PATCH v2 2/2] connect01: Add negative tests
2024-05-14 4:51 [LTP] [PATCH v2 1/2] connect01: Convert to new API Yang Xu via ltp
@ 2024-05-14 4:51 ` Yang Xu via ltp
2024-07-17 12:30 ` [LTP] [PATCH v2 1/2] connect01: Convert to new API Cyril Hrubis
2026-05-25 9:02 ` [LTP] [PATCH v3 0/2] " Wei Gao via ltp
2 siblings, 0 replies; 24+ messages in thread
From: Yang Xu via ltp @ 2024-05-14 4:51 UTC (permalink / raw)
To: ltp
Add negative cases for connect(), when errno is EPROTOTYPE or EACCES
Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
testcases/kernel/syscalls/connect/connect01.c | 54 ++++++++++++++++++-
1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 52a6f154b..97d360482 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -18,19 +18,26 @@
#include "tst_test.h"
#include "lapi/syscalls.h"
+#define SOCK_FILE "sock_file"
+
+static struct passwd *pw;
+
static int fd_share;
static int fd_server;
static struct sockaddr_in sock1;
static struct sockaddr_in sock2;
static struct sockaddr_in sock3;
+static struct sockaddr_un sock4;
static pid_t pid;
static void setup1(unsigned int);
static void setup2(unsigned int);
static void setup3(unsigned int);
+static void setup4(unsigned int);
static void cleanup1(void);
+static void cleanup2(void);
static struct test_case_t {
int domain;
@@ -64,6 +71,12 @@ static struct test_case_t {
{PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock3,
sizeof(sock3), EAFNOSUPPORT, setup2, cleanup1,
"address doesn't have the correct address family in sa_family"},
+ {AF_UNIX, SOCK_DGRAM, 0, (struct sockaddr *)&sock4,
+ sizeof(sock4), EPROTOTYPE, setup4, cleanup2,
+ "socket type does not support the protocol"},
+ {AF_UNIX, SOCK_STREAM, 0, (struct sockaddr *)&sock4,
+ sizeof(sock4), EACCES, setup4, cleanup2,
+ "write permission is denied on the socket file"},
};
static int sys_connect(int sockfd, const struct sockaddr *addr,
@@ -145,6 +158,11 @@ static void setup(void)
sock3.sin_family = 47;
sock3.sin_port = 0;
sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
+
+ sock4.sun_family = AF_UNIX;
+ strncpy(sock4.sun_path, SOCK_FILE, sizeof(sock4.sun_path));
+
+ pw = SAFE_GETPWNAM("nobody");
}
static void setup1(unsigned int i)
@@ -170,21 +188,53 @@ static void setup3(unsigned int i)
SAFE_CONNECT(fd_server, (const struct sockaddr *)&sock1, sizeof(sock1));
}
+static void setup4(unsigned int i)
+{
+ struct test_case_t *tc = &tcases[i];
+
+ fd_share = SAFE_SOCKET(tc->domain, tc->type, tc->proto);
+ fd_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, tc->sockaddr, tc->salen);
+ SAFE_LISTEN(fd_server, 5);
+}
+
static void cleanup1(void)
{
if (fd_share > 0)
SAFE_CLOSE(fd_share);
}
+static void cleanup2(void)
+{
+ if (fd_share > 0)
+ SAFE_CLOSE(fd_share);
+ if (fd_server > 0)
+ SAFE_CLOSE(fd_server);
+ SAFE_UNLINK(SOCK_FILE);
+}
+
static void verify_connect(unsigned int i)
{
struct test_case_t *tc = &tcases[i];
+ pid_t pid_child;
start_server(&sock1);
if (tc->setup)
tc->setup(i);
- TST_EXP_FAIL(sys_connect(fd_share, tc->sockaddr, tc->salen),
- tc->exp_errno, "%s", tc->desc);
+ if (tc->exp_errno == EACCES) {
+ pid_child = SAFE_FORK();
+ if (!pid_child) {
+ SAFE_SETUID(pw->pw_uid);
+ TST_EXP_FAIL(
+ sys_connect(fd_share, tc->sockaddr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ exit(0);
+ }
+ SAFE_WAITPID(pid_child, NULL, 0);
+ } else {
+ TST_EXP_FAIL(sys_connect(fd_share, tc->sockaddr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ }
SAFE_KILL(pid, SIGKILL);
SAFE_WAITPID(pid, NULL, 0);
if (tc->cleanup)
--
2.39.3
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [LTP] [PATCH v2 1/2] connect01: Convert to new API
2024-05-14 4:51 [LTP] [PATCH v2 1/2] connect01: Convert to new API Yang Xu via ltp
2024-05-14 4:51 ` [LTP] [PATCH v2 2/2] connect01: Add negative tests Yang Xu via ltp
@ 2024-07-17 12:30 ` Cyril Hrubis
2026-05-25 9:02 ` [LTP] [PATCH v3 0/2] " Wei Gao via ltp
2 siblings, 0 replies; 24+ messages in thread
From: Cyril Hrubis @ 2024-07-17 12:30 UTC (permalink / raw)
To: Yang Xu; +Cc: ltp
Hi!
> --- a/testcases/kernel/syscalls/connect/connect01.c
> +++ b/testcases/kernel/syscalls/connect/connect01.c
> @@ -1,308 +1,199 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> /*
> - *
> - * Copyright (c) International Business Machines Corp., 2001
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
> - * the GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + * Copyright (c) International Business Machines Corp., 2001
> + * Copyright (c) Linux Test Project, 2006-2024
> */
>
> -/*
> - * Test Name: connect01
> +/*\
> + * [Description]
> *
> - * Test Description:
> - * Verify that connect() returns the proper errno for various failure cases
> - *
> - * Usage: <for command-line>
> - * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
> - * where, -c n : Run n copies concurrently.
> - * -e : Turn on errno logging.
> - * -i n : Execute test n times.
> - * -I x : Execute test for x seconds.
> - * -P x : Pause for x seconds between iterations.
> - * -t : Turn on syscall timing.
> - *
> - * HISTORY
> - * 07/2001 Ported by Wayne Boyer
> - *
> - * RESTRICTIONS:
> - * None.
> + * Verify that connect() returns the proper errno for various failure case
> *
> */
>
> -#include <stdio.h>
> -#include <unistd.h>
> -#include <errno.h>
> -#include <fcntl.h>
> -
> #include <sys/types.h>
> #include <sys/socket.h>
> -#include <sys/signal.h>
> -#include <sys/un.h>
> -
> -#include <netinet/in.h>
> -
> -#include "test.h"
> -#include "safe_macros.h"
> -
> -char *TCID = "connect01";
> -int testno;
> -
> -int s, s2; /* socket descriptor */
> -struct sockaddr_in sin1, sin2, sin3, sin4;
> -static int sfd; /* shared between start_server and do_child */
> -
> -void setup(void), setup0(void), setup1(void), setup2(void),
> -cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
> -
> -static pid_t start_server(struct sockaddr_in *);
> +#include <sys/wait.h>
> +#include <pwd.h>
> +#include "tst_test.h"
> +#include "lapi/syscalls.h"
>
> -struct test_case_t { /* test case structure */
> - int domain; /* PF_INET, PF_UNIX, ... */
> - int type; /* SOCK_STREAM, SOCK_DGRAM ... */
> - int proto; /* protocol number (usually 0 = default) */
> - struct sockaddr *sockaddr; /* socket address buffer */
> - int salen; /* connect's 3rd argument */
> - int retval; /* syscall return value */
> - int experrno; /* expected errno */
> - void (*setup) (void);
> - void (*cleanup) (void);
> +static int fd_share;
> +static int fd_server;
> +
> +static struct sockaddr_in sock1;
> +static struct sockaddr_in sock2;
> +static struct sockaddr_in sock3;
> +
> +static pid_t pid;
> +
> +static void setup1(unsigned int);
> +static void setup2(unsigned int);
> +static void setup3(unsigned int);
> +static void cleanup1(void);
> +
> +static struct test_case_t {
> + int domain;
> + int type;
> + int proto;
> + struct sockaddr *sockaddr;
> + int salen;
> + int exp_errno;
> + void (*setup)(unsigned int i);
> + void (*cleanup)(void);
> char *desc;
> -} tdat[] = {
> - {
> - PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
> - sizeof(struct sockaddr_in), -1, EBADF, setup0,
> - cleanup0, "bad file descriptor"},
> - {
> - PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
> - sizeof(struct sockaddr_in), -1, EFAULT, setup1,
> - cleanup1, "invalid socket buffer"},
> - {
> - PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
> - 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
> - 0, 0, 0, (struct sockaddr *)&sin1,
> - sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
> - "invalid socket"}
> - , {
> - PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
> - sizeof(sin1), -1, EISCONN, setup2, cleanup1,
> - "already connected"}
> - , {
> - PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
> - sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
> - "connection refused"}
> - , {
> - PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
> - sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
> - "invalid address family"}
> -,};
> -
> -int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
> -
> -/**
> - * bionic's connect() implementation calls netdClientInitConnect() before
> - * sending the request to the kernel. We need to bypass this, or the test will
> - * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
> - * tests started to segfault on glibc upgrade or in special conditions where
> - * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
> - * safer to call the raw syscall regardless of the libc implementation.
> - */
> -#include "lapi/syscalls.h"
> +} tcases[] = {
> + {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock1,
> + sizeof(struct sockaddr_in), EBADF, setup1, cleanup1,
> + "sockfd is not a valid open file descriptor"},
> + {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
> + sizeof(struct sockaddr_in), EFAULT, setup2, cleanup1,
> + "socket structure address is outside the user's address space"},
> + {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock1,
> + 3, EINVAL, setup2, cleanup1,
> + "addrlen is not valid"},
> + {0, 0, 0, (struct sockaddr *)&sock1,
> + sizeof(sock1), ENOTSOCK, setup1, cleanup1,
> + "file descriptor sockfd does not refer to a socket"},
> + {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock1,
> + sizeof(sock1), EISCONN, setup3, cleanup1,
> + "socket is already connected"},
> + {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock2,
> + sizeof(sock2), ECONNREFUSED, setup2, cleanup1,
> + "connect on a socket found no one listening on remote address"},
> + {PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sock3,
> + sizeof(sock3), EAFNOSUPPORT, setup2, cleanup1,
> + "address doesn't have the correct address family in sa_family"},
> +};
>
> static int sys_connect(int sockfd, const struct sockaddr *addr,
> - socklen_t addrlen)
> + socklen_t addrlen)
> {
> return tst_syscall(__NR_connect, sockfd, addr, addrlen);
> }
>
> -#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
> -
> -int main(int argc, char *argv[])
> +static void do_child(void)
> {
> - int lc;
> -
> - tst_parse_opts(argc, argv, NULL, NULL);
> + struct sockaddr_in sock;
> + fd_set fd_set_all;
> + fd_set fd_set_read;
> + int nfds;
> + ssize_t bytes;
> + int fd;
> + char data;
> +
> + FD_ZERO(&fd_set_all);
> + FD_SET(fd_server, &fd_set_all);
> + nfds = fd_server + 1;
>
> - setup();
> -
> - for (lc = 0; TEST_LOOPING(lc); ++lc) {
> - tst_count = 0;
> - for (testno = 0; testno < TST_TOTAL; ++testno) {
> - tdat[testno].setup();
> + while (1) {
> + socklen_t len;
>
> - TEST(connect
> - (s, tdat[testno].sockaddr, tdat[testno].salen));
> + memcpy(&fd_set_read, &fd_set_all, sizeof(fd_set_read));
> + if (select(nfds, &fd_set_read, NULL, NULL, NULL) < 0)
> + if (errno != EINTR)
> + exit(1);
> + if (FD_ISSET(fd_server, &fd_set_read)) {
> + int newfd;
>
> - if (TEST_RETURN != tdat[testno].retval ||
> - (TEST_RETURN < 0 &&
> - TEST_ERRNO != tdat[testno].experrno)) {
> - tst_resm(TFAIL, "%s ; returned"
> - " %ld (expected %d), errno %d (expected"
> - " %d)", tdat[testno].desc,
> - TEST_RETURN, tdat[testno].retval,
> - TEST_ERRNO, tdat[testno].experrno);
> - } else {
> - tst_resm(TPASS, "%s successful",
> - tdat[testno].desc);
> + len = sizeof(sock);
> + newfd = SAFE_ACCEPT(fd_server, (struct sockaddr *)&sock,
> + &len);
> + if (newfd >= 0) {
> + FD_SET(newfd, &fd_set_all);
> + nfds = MAX(nfds, newfd + 1);
> }
> - tdat[testno].cleanup();
> }
> + for (fd = 0; fd < nfds; fd++)
> + if (fd != fd_server && FD_ISSET(fd, &fd_set_read)) {
> + bytes = read(fd, &data, 1);
> + if (bytes == 0) {
> + close(fd);
> + FD_CLR(fd, &fd_set_all);
> + }
> + }
> }
> - cleanup();
> -
> - tst_exit();
First of all since this is a test that tests invalid connect()
parameters there is no point in having a full blown server that reads
the data from the socket. I guess that this could be simplified just
a loop over SAFE_ACCEPT() that would ingore the file descriptor since we
are not actually writing to the socket anything.
So the whole function could be just:
while (1)
SAFE_ACCEPT(fd_server, ...);
Which could be moved into the start_server() function.
> }
>
> -pid_t pid;
> -
> -void setup(void)
> +static void start_server(struct sockaddr_in *sock)
> {
> - TEST_PAUSE; /* if -p option specified */
> -
> - pid = start_server(&sin1);
> + socklen_t slen = sizeof(*sock);
>
> - sin2.sin_family = AF_INET;
> - /* this port must be unused! */
> - sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
> - sin2.sin_addr.s_addr = INADDR_ANY;
> + sock->sin_family = AF_INET;
> + sock->sin_port = 0;
> + sock->sin_addr.s_addr = INADDR_ANY;
>
> - sin3.sin_family = AF_INET;
> - sin3.sin_port = 0;
> - /* assumes no route to this network! */
> - sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
> -
> - sin4.sin_family = 47; /* bogus address family */
> - sin4.sin_port = 0;
> - sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
> + fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
> + SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
> + SAFE_LISTEN(fd_server, 10);
> + SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
>
> + pid = SAFE_FORK();
> + if (!pid) {
> + do_child();
> + exit(0);
> + }
> + close(fd_server);
> }
>
> -void cleanup(void)
> +static void setup(void)
> {
> - (void)kill(pid, SIGKILL);
> + sock2.sin_family = AF_INET;
> + sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
> + sock2.sin_addr.s_addr = INADDR_ANY;
>
> + sock3.sin_family = 47;
> + sock3.sin_port = 0;
> + sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
> }
>
> -void setup0(void)
> +static void setup1(unsigned int i)
> {
> - if (tdat[testno].experrno == EBADF)
> - s = 400; /* anything not an open file */
> - else if ((s = open("/dev/null", O_WRONLY)) == -1)
> - tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
> + struct test_case_t *tc = &tcases[i];
>
> + if (tc->exp_errno == EBADF)
> + fd_share = -1;
> + else
> + fd_share = SAFE_OPEN("/dev/null", O_WRONLY);
> }
>
> -void cleanup0(void)
> +static void setup2(unsigned int i)
> {
> - close(s);
> - s = -1;
> -}
> + struct test_case_t *tc = &tcases[i];
>
> -void setup1(void)
> -{
> - s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
> - tdat[testno].proto);
> + fd_share = SAFE_SOCKET(tc->domain, tc->type, tc->proto);
> }
>
> -void cleanup1(void)
> +static void setup3(unsigned int i)
> {
> - (void)close(s);
> - s = -1;
> + setup2(i);
> + SAFE_CONNECT(fd_server, (const struct sockaddr *)&sock1, sizeof(sock1));
And if we move this SAFE_CONNECT() to the test setup we can start the
server once in the test setup, then SAFE_CONNECT() there and the EISCON
would be set up once for the duration of the test and we would stop the
server once in the test cleanup.
And if we put a pointer to a fd into the test structure we can
initialize all the different setups once in the test setup and get rid
of the setup and cleanup function from the testcase structure as well.
We do the same for the sockaddr and I do not see a reason why we cannot
do so for the file descriptor.
> }
>
> -void setup2(void)
> +static void cleanup1(void)
> {
> - setup1(); /* get a socket in s */
> - SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
> + if (fd_share > 0)
> + SAFE_CLOSE(fd_share);
> }
>
> -pid_t start_server(struct sockaddr_in *sin0)
> +static void verify_connect(unsigned int i)
> {
> - pid_t pid;
> - socklen_t slen = sizeof(*sin0);
> -
> - sin0->sin_family = AF_INET;
> - sin0->sin_port = 0; /* pick random free port */
> - sin0->sin_addr.s_addr = INADDR_ANY;
> -
> - sfd = socket(PF_INET, SOCK_STREAM, 0);
> - if (sfd < 0) {
> - tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
> - return -1;
> - }
> - if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
> - tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
> - return -1;
> - }
> - if (listen(sfd, 10) < 0) {
> - tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
> - return -1;
> - }
> - SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
> -
> - switch ((pid = tst_fork())) {
> - case 0: /* child */
> - do_child();
> - break;
> - case -1:
> - tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
> - /* fall through */
> - default: /* parent */
> - (void)close(sfd);
> - return pid;
> - }
> -
> - return -1;
> + struct test_case_t *tc = &tcases[i];
> +
> + start_server(&sock1);
> + if (tc->setup)
> + tc->setup(i);
> + TST_EXP_FAIL(sys_connect(fd_share, tc->sockaddr, tc->salen),
> + tc->exp_errno, "%s", tc->desc);
> + SAFE_KILL(pid, SIGKILL);
> + SAFE_WAITPID(pid, NULL, 0);
> + if (tc->cleanup)
> + tc->cleanup();
> }
>
> -void do_child(void)
> -{
> - struct sockaddr_in fsin;
> - fd_set afds, rfds;
> - int nfds, cc, fd;
> - char c;
> -
> - FD_ZERO(&afds);
> - FD_SET(sfd, &afds);
> -
> - nfds = sfd + 1;
> -
> - /* accept connections until killed */
> - while (1) {
> - socklen_t fromlen;
> -
> - memcpy(&rfds, &afds, sizeof(rfds));
> -
> - if (select(nfds, &rfds, NULL, NULL,
> - NULL) < 0)
> - if (errno != EINTR)
> - exit(1);
> - if (FD_ISSET(sfd, &rfds)) {
> - int newfd;
> -
> - fromlen = sizeof(fsin);
> - newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
> - if (newfd >= 0) {
> - FD_SET(newfd, &afds);
> - nfds = MAX(nfds, newfd + 1);
> - }
> - }
> - for (fd = 0; fd < nfds; ++fd)
> - if (fd != sfd && FD_ISSET(fd, &rfds)) {
> - if ((cc = read(fd, &c, 1)) == 0) {
> - (void)close(fd);
> - FD_CLR(fd, &afds);
> - }
> - }
> - }
> -}
> +static struct tst_test test = {
> + .setup = setup,
> + .tcnt = ARRAY_SIZE(tcases),
> + .test = verify_connect,
> + .forks_child = 1,
> +};
> --
> 2.39.3
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread* [LTP] [PATCH v3 0/2] connect01: Convert to new API
2024-05-14 4:51 [LTP] [PATCH v2 1/2] connect01: Convert to new API Yang Xu via ltp
2024-05-14 4:51 ` [LTP] [PATCH v2 2/2] connect01: Add negative tests Yang Xu via ltp
2024-07-17 12:30 ` [LTP] [PATCH v2 1/2] connect01: Convert to new API Cyril Hrubis
@ 2026-05-25 9:02 ` Wei Gao via ltp
2026-05-25 9:02 ` [LTP] [PATCH v3 1/2] " Wei Gao via ltp
2026-05-25 9:02 ` [LTP] [PATCH v3 " Wei Gao via ltp
2 siblings, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-05-25 9:02 UTC (permalink / raw)
To: ltp
Wei Gao (2):
connect01: Convert to new API
connect01: Add negative tests
testcases/kernel/syscalls/connect/connect01.c | 396 ++++++------------
1 file changed, 134 insertions(+), 262 deletions(-)
v2->v3:
Update patchset base v2 comments.
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v3 1/2] connect01: Convert to new API
2026-05-25 9:02 ` [LTP] [PATCH v3 0/2] " Wei Gao via ltp
@ 2026-05-25 9:02 ` Wei Gao via ltp
2026-05-25 10:12 ` [LTP] " linuxtestproject.agent
2026-06-04 4:49 ` [LTP] [PATCH v4 0/2] " Wei Gao via ltp
2026-05-25 9:02 ` [LTP] [PATCH v3 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-05-25 9:02 UTC (permalink / raw)
To: ltp
Convert the connect01 test case from the legacy LTP API to the new
tst_test API.
Refactor the test according to reviewer feedback:
- Simplified the server child process to a single accept/exit loop.
- Moved the server lifecycle to the global setup/cleanup.
- The server now accepts a single connection for the EISCONN test case
and exits immediately, which avoids blocking the test runner.
- Centralized test case initialization into the global setup.
- Used tst_get_bad_addr() for the EFAULT test case to ensure
architectural compatibility.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 360 +++++-------------
1 file changed, 95 insertions(+), 265 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 6cb8adab3..923c4be81 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -1,308 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) Linux Test Project, 2006-2024
*/
-/*
- * Test Name: connect01
- *
- * Test Description:
- * Verify that connect() returns the proper errno for various failure cases
- *
- * Usage: <for command-line>
- * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS:
- * None.
- *
+/*\
+ * Verify that connect() returns the proper errno for various failure cases.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/un.h>
-
+#include <sys/wait.h>
#include <netinet/in.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
-#include "test.h"
-#include "tso_safe_macros.h"
-
-char *TCID = "connect01";
-int testno;
-
-int s, s2; /* socket descriptor */
-struct sockaddr_in sin1, sin2, sin3, sin4;
-static int sfd; /* shared between start_server and do_child */
+static int fd_invalid = -1;
+static int fd_socket;
+static int fd_null;
+static int fd_connected;
+static int fd_server;
-void setup(void), setup0(void), setup1(void), setup2(void),
-cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
+static struct sockaddr_in sock1;
+static struct sockaddr_in sock2;
+static struct sockaddr_in sock3;
+static void *bad_addr;
-static pid_t start_server(struct sockaddr_in *);
+static pid_t pid;
-struct test_case_t { /* test case structure */
- int domain; /* PF_INET, PF_UNIX, ... */
- int type; /* SOCK_STREAM, SOCK_DGRAM ... */
- int proto; /* protocol number (usually 0 = default) */
- struct sockaddr *sockaddr; /* socket address buffer */
- int salen; /* connect's 3rd argument */
- int retval; /* syscall return value */
- int experrno; /* expected errno */
- void (*setup) (void);
- void (*cleanup) (void);
+static struct test_case_t {
+ int *fd;
+ void *addr;
+ socklen_t salen;
+ int exp_errno;
char *desc;
-} tdat[] = {
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(struct sockaddr_in), -1, EBADF, setup0,
- cleanup0, "bad file descriptor"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
- sizeof(struct sockaddr_in), -1, EFAULT, setup1,
- cleanup1, "invalid socket buffer"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
- 0, 0, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
- "invalid socket"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, EISCONN, setup2, cleanup1,
- "already connected"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
- sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
- "connection refused"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
- sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
- "invalid address family"}
-,};
-
-int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-/**
- * bionic's connect() implementation calls netdClientInitConnect() before
- * sending the request to the kernel. We need to bypass this, or the test will
- * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
- * tests started to segfault on glibc upgrade or in special conditions where
- * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
- * safer to call the raw syscall regardless of the libc implementation.
- */
-#include "lapi/syscalls.h"
+} tcases[] = {
+ {&fd_invalid, &sock1, sizeof(sock1), EBADF,
+ "sockfd is not a valid open file descriptor"},
+ {&fd_socket, NULL, sizeof(sock1), EFAULT,
+ "socket structure address is outside the user's address space"},
+ {&fd_socket, &sock1, 3, EINVAL,
+ "addrlen is not valid"},
+ {&fd_null, &sock1, sizeof(sock1), ENOTSOCK,
+ "file descriptor sockfd does not refer to a socket"},
+ {&fd_connected, &sock1, sizeof(sock1), EISCONN,
+ "socket is already connected"},
+ {&fd_socket, &sock2, sizeof(sock2), ECONNREFUSED,
+ "connect on a socket found no one listening on remote address"},
+ {&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
+ "address doesn't have the correct address family in sa_family"},
+};
static int sys_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen)
+ socklen_t addrlen)
{
return tst_syscall(__NR_connect, sockfd, addr, addrlen);
}
-#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
-
-int main(int argc, char *argv[])
+static void start_server(struct sockaddr_in *sock)
{
- int lc;
+ socklen_t slen = sizeof(*sock);
- tst_parse_opts(argc, argv, NULL, NULL);
+ sock->sin_family = AF_INET;
+ sock->sin_port = 0;
+ sock->sin_addr.s_addr = INADDR_ANY;
- setup();
+ fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
+ SAFE_LISTEN(fd_server, 10);
+ SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
- for (lc = 0; TEST_LOOPING(lc); ++lc) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; ++testno) {
- tdat[testno].setup();
+ pid = SAFE_FORK();
- TEST(connect
- (s, tdat[testno].sockaddr, tdat[testno].salen));
+ if (!pid) {
+ int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
- if (TEST_RETURN != tdat[testno].retval ||
- (TEST_RETURN < 0 &&
- TEST_ERRNO != tdat[testno].experrno)) {
- tst_resm(TFAIL, "%s ; returned"
- " %ld (expected %d), errno %d (expected"
- " %d)", tdat[testno].desc,
- TEST_RETURN, tdat[testno].retval,
- TEST_ERRNO, tdat[testno].experrno);
- } else {
- tst_resm(TPASS, "%s successful",
- tdat[testno].desc);
- }
- tdat[testno].cleanup();
- }
+ SAFE_CLOSE(nfd);
+ exit(0);
}
- cleanup();
-
- tst_exit();
+ close(fd_server);
}
-pid_t pid;
-
-void setup(void)
+static void setup(void)
{
- TEST_PAUSE; /* if -p option specified */
-
- pid = start_server(&sin1);
-
- sin2.sin_family = AF_INET;
- /* this port must be unused! */
- sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
- sin2.sin_addr.s_addr = INADDR_ANY;
-
- sin3.sin_family = AF_INET;
- sin3.sin_port = 0;
- /* assumes no route to this network! */
- sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
- sin4.sin_family = 47; /* bogus address family */
- sin4.sin_port = 0;
- sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
-}
+ bad_addr = tst_get_bad_addr(NULL);
+ start_server(&sock1);
-void cleanup(void)
-{
- (void)kill(pid, SIGKILL);
+ fd_socket = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ fd_null = SAFE_OPEN("/dev/null", O_WRONLY);
-}
+ fd_connected = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_CONNECT(fd_connected, (const struct sockaddr *)&sock1, sizeof(sock1));
-void setup0(void)
-{
- if (tdat[testno].experrno == EBADF)
- s = 400; /* anything not an open file */
- else if ((s = open("/dev/null", O_WRONLY)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
+ /* Wait for server to accept and exit */
+ SAFE_WAITPID(pid, NULL, 0);
+ pid = 0;
-}
+ sock2.sin_family = AF_INET;
+ sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
+ sock2.sin_addr.s_addr = INADDR_ANY;
-void cleanup0(void)
-{
- close(s);
- s = -1;
+ sock3.sin_family = 47;
+ sock3.sin_port = 0;
+ sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
}
-void setup1(void)
+static void cleanup(void)
{
- s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
- tdat[testno].proto);
-}
-
-void cleanup1(void)
-{
- (void)close(s);
- s = -1;
-}
-
-void setup2(void)
-{
- setup1(); /* get a socket in s */
- SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
-}
-
-pid_t start_server(struct sockaddr_in *sin0)
-{
- pid_t pid;
- socklen_t slen = sizeof(*sin0);
-
- sin0->sin_family = AF_INET;
- sin0->sin_port = 0; /* pick random free port */
- sin0->sin_addr.s_addr = INADDR_ANY;
-
- sfd = socket(PF_INET, SOCK_STREAM, 0);
- if (sfd < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
- return -1;
- }
- if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
- return -1;
+ if (fd_socket > 0)
+ SAFE_CLOSE(fd_socket);
+ if (fd_null > 0)
+ SAFE_CLOSE(fd_null);
+ if (fd_connected > 0)
+ SAFE_CLOSE(fd_connected);
+
+ if (pid > 0) {
+ SAFE_KILL(pid, SIGKILL);
+ SAFE_WAITPID(pid, NULL, 0);
}
- if (listen(sfd, 10) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
- return -1;
- }
- SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
-
- switch ((pid = tst_fork())) {
- case 0: /* child */
- do_child();
- break;
- case -1:
- tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
- /* fall through */
- default: /* parent */
- (void)close(sfd);
- return pid;
- }
-
- return -1;
}
-void do_child(void)
+static void verify_connect(unsigned int i)
{
- struct sockaddr_in fsin;
- fd_set afds, rfds;
- int nfds, cc, fd;
- char c;
-
- FD_ZERO(&afds);
- FD_SET(sfd, &afds);
-
- nfds = sfd + 1;
+ struct test_case_t *tc = &tcases[i];
+ void *addr = tc->addr ? tc->addr : bad_addr;
- /* accept connections until killed */
- while (1) {
- socklen_t fromlen;
-
- memcpy(&rfds, &afds, sizeof(rfds));
-
- if (select(nfds, &rfds, NULL, NULL,
- NULL) < 0)
- if (errno != EINTR)
- exit(1);
- if (FD_ISSET(sfd, &rfds)) {
- int newfd;
-
- fromlen = sizeof(fsin);
- newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
- if (newfd >= 0) {
- FD_SET(newfd, &afds);
- nfds = MAX(nfds, newfd + 1);
- }
- }
- for (fd = 0; fd < nfds; ++fd)
- if (fd != sfd && FD_ISSET(fd, &rfds)) {
- if ((cc = read(fd, &c, 1)) == 0) {
- (void)close(fd);
- FD_CLR(fd, &afds);
- }
- }
- }
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_connect,
+ .forks_child = 1,
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [LTP] connect01: Convert to new API
2026-05-25 9:02 ` [LTP] [PATCH v3 1/2] " Wei Gao via ltp
@ 2026-05-25 10:12 ` linuxtestproject.agent
2026-05-28 4:43 ` Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 0/2] " Wei Gao via ltp
1 sibling, 1 reply; 24+ messages in thread
From: linuxtestproject.agent @ 2026-05-25 10:12 UTC (permalink / raw)
To: Wei Gao; +Cc: ltp
Hi Wei,
On Mon, 25 May 2026, Wei Gao wrote:
> connect01: Convert to new API
> +// SPDX-License-Identifier: GPL-2.0-or-later
> /*
> - *
> - * Copyright (c) International Business Machines Corp., 2001
> + * Copyright (c) International Business Machines Corp., 2001
> + * Copyright (c) Linux Test Project, 2006-2024
The patch is from 2026; the LTP copyright year should be updated to 2006-2026.
> +static int sys_connect(int sockfd, const struct sockaddr *addr,
> + socklen_t addrlen)
Indentation regressed from two tabs to one. The continuation parameter should
be aligned with the opening parenthesis (or at minimum two tabs to match the
original), per kernel coding style.
> + pid = SAFE_FORK();
> +
> + if (!pid) {
> + int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
> +
> + SAFE_CLOSE(nfd);
> + exit(0);
> + }
> + close(fd_server);
Use SAFE_CLOSE() here for consistency.
[...]
--- [PATCH 2/2] connect01: Add negative tests ---
> + fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
> + SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
> + SAFE_LISTEN(fd_unix_server, 5);
> +
> + fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
> + fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
> +
> + pw = SAFE_GETPWNAM("nobody");
The EACCES test relies on "nobody" not having write permission to SOCK_FILE.
The socket file's permissions are umask-dependent; with umask 0000 the file
gets mode 0777 and the test would fail spuriously. Add an explicit
`SAFE_CHMOD(SOCK_FILE, 0700)` after the SAFE_BIND() to make this reliable.
> + if (tc->exp_errno == EACCES) {
> + if (!SAFE_FORK()) {
> + SAFE_SETUID(pw->pw_uid);
> + TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
> + tc->exp_errno, "%s", tc->desc);
> + exit(0);
> + }
Result propagation via shared memory with .forks_child = 1 is correct, but
the exit code is always 0 even on failure. Use `tst_exit()` or exit with the
appropriate code so that unexpected crashes are also caught by the parent.
Alternatively this is a style nit if tst_exit() is not the expected pattern
here.
---
Note:
Our agent completed the review of the patch. The full review can be
found at: https://github.com/linux-test-project/ltp-agent/actions/runs/26394925194
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [LTP] connect01: Convert to new API
2026-05-25 10:12 ` [LTP] " linuxtestproject.agent
@ 2026-05-28 4:43 ` Wei Gao via ltp
0 siblings, 0 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-05-28 4:43 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: ltp
On Mon, May 25, 2026 at 10:12:54AM +0000, linuxtestproject.agent@gmail.com wrote:
> Hi Wei,
>
> On Mon, 25 May 2026, Wei Gao wrote:
> > connect01: Convert to new API
>
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > /*
> > - *
> > - * Copyright (c) International Business Machines Corp., 2001
> > + * Copyright (c) International Business Machines Corp., 2001
> > + * Copyright (c) Linux Test Project, 2006-2024
>
> The patch is from 2026; the LTP copyright year should be updated to 2006-2026.
>
> > +static int sys_connect(int sockfd, const struct sockaddr *addr,
> > + socklen_t addrlen)
>
> Indentation regressed from two tabs to one. The continuation parameter should
> be aligned with the opening parenthesis (or at minimum two tabs to match the
> original), per kernel coding style.
>
> > + pid = SAFE_FORK();
> > +
> > + if (!pid) {
> > + int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
> > +
> > + SAFE_CLOSE(nfd);
> > + exit(0);
> > + }
> > + close(fd_server);
>
> Use SAFE_CLOSE() here for consistency.
>
> [...]
>
> --- [PATCH 2/2] connect01: Add negative tests ---
>
> > + fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
> > + SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
> > + SAFE_LISTEN(fd_unix_server, 5);
> > +
> > + fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
> > + fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
> > +
> > + pw = SAFE_GETPWNAM("nobody");
>
> The EACCES test relies on "nobody" not having write permission to SOCK_FILE.
> The socket file's permissions are umask-dependent; with umask 0000 the file
> gets mode 0777 and the test would fail spuriously. Add an explicit
> `SAFE_CHMOD(SOCK_FILE, 0700)` after the SAFE_BIND() to make this reliable.
>
> > + if (tc->exp_errno == EACCES) {
> > + if (!SAFE_FORK()) {
> > + SAFE_SETUID(pw->pw_uid);
> > + TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
> > + tc->exp_errno, "%s", tc->desc);
> > + exit(0);
> > + }
>
> Result propagation via shared memory with .forks_child = 1 is correct, but
> the exit code is always 0 even on failure. Use `tst_exit()` or exit with the
> appropriate code so that unexpected crashes are also caught by the parent.
> Alternatively this is a style nit if tst_exit() is not the expected pattern
> here.
I think TST_EXP_FAIL already report failure so exit(0) is acceptable.
>
> ---
> Note:
>
> Our agent completed the review of the patch. The full review can be
> found at: https://github.com/linux-test-project/ltp-agent/actions/runs/26394925194
>
> The agent can sometimes produce false positives although often its
> findings are genuine. If you find issues with the review, please
> comment this email or ignore the suggestions.
>
> Regards,
> LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v4 0/2] connect01: Convert to new API
2026-05-25 9:02 ` [LTP] [PATCH v3 1/2] " Wei Gao via ltp
2026-05-25 10:12 ` [LTP] " linuxtestproject.agent
@ 2026-06-04 4:49 ` Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 1/2] " Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-04 4:49 UTC (permalink / raw)
To: ltp
v2->v3:
- Update copyright year to 2026.
- Fix parameter continuation indentation for sys_connect() per kernel coding style.
- Use SAFE_CLOSE() instead of close() for the server socket in start_server().
- Add explicit SAFE_CHMOD() to SOCK_FILE to make the EACCES test umask-independent.
Wei Gao (2):
connect01: Convert to new API
connect01: Add negative tests
testcases/kernel/syscalls/connect/connect01.c | 395 ++++++------------
1 file changed, 134 insertions(+), 261 deletions(-)
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v4 1/2] connect01: Convert to new API
2026-06-04 4:49 ` [LTP] [PATCH v4 0/2] " Wei Gao via ltp
@ 2026-06-04 4:49 ` Wei Gao via ltp
2026-06-04 7:15 ` [LTP] " linuxtestproject.agent
2026-06-16 1:47 ` [LTP] [PATCH v5 0/2] " Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-04 4:49 UTC (permalink / raw)
To: ltp
Convert the connect01 test case from the legacy LTP API to the new
tst_test API.
Refactor the test according to reviewer feedback:
- Simplified the server child process to a single accept/exit loop.
- Moved the server lifecycle to the global setup/cleanup.
- The server now accepts a single connection for the EISCONN test case
and exits immediately, which avoids blocking the test runner.
- Centralized test case initialization into the global setup.
- Used tst_get_bad_addr() for the EFAULT test case to ensure
architectural compatibility.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 358 +++++-------------
1 file changed, 94 insertions(+), 264 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 6cb8adab3..565148fc5 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -1,123 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) Linux Test Project, 2006-2026
*/
-/*
- * Test Name: connect01
- *
- * Test Description:
- * Verify that connect() returns the proper errno for various failure cases
- *
- * Usage: <for command-line>
- * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS:
- * None.
- *
+/*\
+ * Verify that connect() returns the proper errno for various failure cases.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/un.h>
-
+#include <sys/wait.h>
#include <netinet/in.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
-#include "test.h"
-#include "tso_safe_macros.h"
-
-char *TCID = "connect01";
-int testno;
-
-int s, s2; /* socket descriptor */
-struct sockaddr_in sin1, sin2, sin3, sin4;
-static int sfd; /* shared between start_server and do_child */
+static int fd_invalid = -1;
+static int fd_socket;
+static int fd_null;
+static int fd_connected;
+static int fd_server;
-void setup(void), setup0(void), setup1(void), setup2(void),
-cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
+static struct sockaddr_in sock1;
+static struct sockaddr_in sock2;
+static struct sockaddr_in sock3;
+static void *bad_addr;
-static pid_t start_server(struct sockaddr_in *);
+static pid_t pid;
-struct test_case_t { /* test case structure */
- int domain; /* PF_INET, PF_UNIX, ... */
- int type; /* SOCK_STREAM, SOCK_DGRAM ... */
- int proto; /* protocol number (usually 0 = default) */
- struct sockaddr *sockaddr; /* socket address buffer */
- int salen; /* connect's 3rd argument */
- int retval; /* syscall return value */
- int experrno; /* expected errno */
- void (*setup) (void);
- void (*cleanup) (void);
+static struct test_case_t {
+ int *fd;
+ void *addr;
+ socklen_t salen;
+ int exp_errno;
char *desc;
-} tdat[] = {
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(struct sockaddr_in), -1, EBADF, setup0,
- cleanup0, "bad file descriptor"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
- sizeof(struct sockaddr_in), -1, EFAULT, setup1,
- cleanup1, "invalid socket buffer"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
- 0, 0, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
- "invalid socket"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, EISCONN, setup2, cleanup1,
- "already connected"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
- sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
- "connection refused"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
- sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
- "invalid address family"}
-,};
-
-int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-/**
- * bionic's connect() implementation calls netdClientInitConnect() before
- * sending the request to the kernel. We need to bypass this, or the test will
- * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
- * tests started to segfault on glibc upgrade or in special conditions where
- * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
- * safer to call the raw syscall regardless of the libc implementation.
- */
-#include "lapi/syscalls.h"
+} tcases[] = {
+ {&fd_invalid, &sock1, sizeof(sock1), EBADF,
+ "sockfd is not a valid open file descriptor"},
+ {&fd_socket, NULL, sizeof(sock1), EFAULT,
+ "socket structure address is outside the user's address space"},
+ {&fd_socket, &sock1, 3, EINVAL,
+ "addrlen is not valid"},
+ {&fd_null, &sock1, sizeof(sock1), ENOTSOCK,
+ "file descriptor sockfd does not refer to a socket"},
+ {&fd_connected, &sock1, sizeof(sock1), EISCONN,
+ "socket is already connected"},
+ {&fd_socket, &sock2, sizeof(sock2), ECONNREFUSED,
+ "connect on a socket found no one listening on remote address"},
+ {&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
+ "address doesn't have the correct address family in sa_family"},
+};
static int sys_connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
@@ -125,184 +57,82 @@ static int sys_connect(int sockfd, const struct sockaddr *addr,
return tst_syscall(__NR_connect, sockfd, addr, addrlen);
}
-#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
-
-int main(int argc, char *argv[])
+static void start_server(struct sockaddr_in *sock)
{
- int lc;
+ socklen_t slen = sizeof(*sock);
- tst_parse_opts(argc, argv, NULL, NULL);
+ sock->sin_family = AF_INET;
+ sock->sin_port = 0;
+ sock->sin_addr.s_addr = INADDR_ANY;
- setup();
+ fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
+ SAFE_LISTEN(fd_server, 10);
+ SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
- for (lc = 0; TEST_LOOPING(lc); ++lc) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; ++testno) {
- tdat[testno].setup();
+ pid = SAFE_FORK();
- TEST(connect
- (s, tdat[testno].sockaddr, tdat[testno].salen));
+ if (!pid) {
+ int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
- if (TEST_RETURN != tdat[testno].retval ||
- (TEST_RETURN < 0 &&
- TEST_ERRNO != tdat[testno].experrno)) {
- tst_resm(TFAIL, "%s ; returned"
- " %ld (expected %d), errno %d (expected"
- " %d)", tdat[testno].desc,
- TEST_RETURN, tdat[testno].retval,
- TEST_ERRNO, tdat[testno].experrno);
- } else {
- tst_resm(TPASS, "%s successful",
- tdat[testno].desc);
- }
- tdat[testno].cleanup();
- }
+ SAFE_CLOSE(nfd);
+ exit(0);
}
- cleanup();
-
- tst_exit();
+ SAFE_CLOSE(fd_server);
}
-pid_t pid;
-
-void setup(void)
+static void setup(void)
{
- TEST_PAUSE; /* if -p option specified */
-
- pid = start_server(&sin1);
-
- sin2.sin_family = AF_INET;
- /* this port must be unused! */
- sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
- sin2.sin_addr.s_addr = INADDR_ANY;
-
- sin3.sin_family = AF_INET;
- sin3.sin_port = 0;
- /* assumes no route to this network! */
- sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
- sin4.sin_family = 47; /* bogus address family */
- sin4.sin_port = 0;
- sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
-}
+ bad_addr = tst_get_bad_addr(NULL);
+ start_server(&sock1);
-void cleanup(void)
-{
- (void)kill(pid, SIGKILL);
+ fd_socket = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ fd_null = SAFE_OPEN("/dev/null", O_WRONLY);
-}
+ fd_connected = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_CONNECT(fd_connected, (const struct sockaddr *)&sock1, sizeof(sock1));
-void setup0(void)
-{
- if (tdat[testno].experrno == EBADF)
- s = 400; /* anything not an open file */
- else if ((s = open("/dev/null", O_WRONLY)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
+ /* Wait for server to accept and exit */
+ SAFE_WAITPID(pid, NULL, 0);
+ pid = 0;
-}
+ sock2.sin_family = AF_INET;
+ sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
+ sock2.sin_addr.s_addr = INADDR_ANY;
-void cleanup0(void)
-{
- close(s);
- s = -1;
+ sock3.sin_family = 47;
+ sock3.sin_port = 0;
+ sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
}
-void setup1(void)
+static void cleanup(void)
{
- s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
- tdat[testno].proto);
-}
-
-void cleanup1(void)
-{
- (void)close(s);
- s = -1;
-}
-
-void setup2(void)
-{
- setup1(); /* get a socket in s */
- SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
-}
-
-pid_t start_server(struct sockaddr_in *sin0)
-{
- pid_t pid;
- socklen_t slen = sizeof(*sin0);
-
- sin0->sin_family = AF_INET;
- sin0->sin_port = 0; /* pick random free port */
- sin0->sin_addr.s_addr = INADDR_ANY;
-
- sfd = socket(PF_INET, SOCK_STREAM, 0);
- if (sfd < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
- return -1;
- }
- if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
- return -1;
+ if (fd_socket > 0)
+ SAFE_CLOSE(fd_socket);
+ if (fd_null > 0)
+ SAFE_CLOSE(fd_null);
+ if (fd_connected > 0)
+ SAFE_CLOSE(fd_connected);
+
+ if (pid > 0) {
+ SAFE_KILL(pid, SIGKILL);
+ SAFE_WAITPID(pid, NULL, 0);
}
- if (listen(sfd, 10) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
- return -1;
- }
- SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
-
- switch ((pid = tst_fork())) {
- case 0: /* child */
- do_child();
- break;
- case -1:
- tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
- /* fall through */
- default: /* parent */
- (void)close(sfd);
- return pid;
- }
-
- return -1;
}
-void do_child(void)
+static void verify_connect(unsigned int i)
{
- struct sockaddr_in fsin;
- fd_set afds, rfds;
- int nfds, cc, fd;
- char c;
-
- FD_ZERO(&afds);
- FD_SET(sfd, &afds);
-
- nfds = sfd + 1;
+ struct test_case_t *tc = &tcases[i];
+ void *addr = tc->addr ? tc->addr : bad_addr;
- /* accept connections until killed */
- while (1) {
- socklen_t fromlen;
-
- memcpy(&rfds, &afds, sizeof(rfds));
-
- if (select(nfds, &rfds, NULL, NULL,
- NULL) < 0)
- if (errno != EINTR)
- exit(1);
- if (FD_ISSET(sfd, &rfds)) {
- int newfd;
-
- fromlen = sizeof(fsin);
- newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
- if (newfd >= 0) {
- FD_SET(newfd, &afds);
- nfds = MAX(nfds, newfd + 1);
- }
- }
- for (fd = 0; fd < nfds; ++fd)
- if (fd != sfd && FD_ISSET(fd, &rfds)) {
- if ((cc = read(fd, &c, 1)) == 0) {
- (void)close(fd);
- FD_CLR(fd, &afds);
- }
- }
- }
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_connect,
+ .forks_child = 1,
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [LTP] connect01: Convert to new API
2026-06-04 4:49 ` [LTP] [PATCH v4 1/2] " Wei Gao via ltp
@ 2026-06-04 7:15 ` linuxtestproject.agent
2026-06-16 1:47 ` [LTP] [PATCH v5 0/2] " Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: linuxtestproject.agent @ 2026-06-04 7:15 UTC (permalink / raw)
To: Wei Gao; +Cc: ltp
On Thu, Jun 04, 2026 at 04:49:55 +0000, Wei Gao wrote:
> connect01: Convert to new API
> connect01: Add negative tests
Hi Wei,
Overall the series is in good shape. The conversion to the new API is
clean and the new EPROTOTYPE/EACCES test cases make sense. One bug needs
fixing and there are a few minor observations.
---
Patch 1: connect01: Convert to new API
> Convert the connect01 test case from the legacy LTP API to the new
> tst_test API.
>
> Refactor the test according to reviewer feedback:
> - Simplified the server child process to a single accept/exit loop.
> - Moved the server lifecycle to the global setup/cleanup.
> - The server now accepts a single connection for the EISCONN test case
> and exits immediately, which avoids blocking the test runner.
> - Centralized test case initialization into the global setup.
> - Used tst_get_bad_addr() for the EFAULT test case to ensure
> architectural compatibility.
The bulleted list is fine, though LTP commit messages generally prefer
plain prose over bullet points for the body.
> +static void start_server(struct sockaddr_in *sock)
> +{
> + socklen_t slen = sizeof(*sock);
> +
> + sock->sin_family = AF_INET;
> + sock->sin_port = 0;
> + sock->sin_addr.s_addr = INADDR_ANY;
> +
> + fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
> + SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
> + SAFE_LISTEN(fd_server, 10);
> + SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
> +
> + pid = SAFE_FORK();
> +
> + if (!pid) {
> + int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
> +
> + SAFE_CLOSE(nfd);
> + exit(0);
> + }
> + SAFE_CLOSE(fd_server);
> +}
The single-accept server child is a nice simplification. Note that
fd_server is closed in the parent here but the static variable still
holds the (now-closed) fd number. cleanup() doesn't close fd_server,
which is correct since the parent already closed it. No issue, but
mentioning for clarity.
> + if (fd_socket > 0)
> + SAFE_CLOSE(fd_socket);
> + if (fd_null > 0)
> + SAFE_CLOSE(fd_null);
> + if (fd_connected > 0)
> + SAFE_CLOSE(fd_connected);
Nit: these guards should be `>= 0` (or `!= -1`) since a valid fd can
theoretically be 0 if stdin is closed before the test runs. Using `> 0`
works in practice (socket fds are typically > 2) but is technically
incorrect. This is a pre-existing LTP pattern, so not a blocker.
Patch 1 otherwise looks correct. The test case order is fine — after
ECONNREFUSED the TCP socket returns to TCP_CLOSE state, and the
subsequent EAFNOSUPPORT check happens before any connection attempt, so
fd_socket reuse is safe here.
---
Patch 2: connect01: Add negative tests
> + {&fd_unix_dgram, &sock4, sizeof(sock4), EPROTOTYPE,
> + "socket type does not support the protocol"},
The EPROTOTYPE errno is correct: connecting an AF_UNIX SOCK_DGRAM
socket to a path bound by a SOCK_STREAM server returns -EPROTOTYPE in
unix_find_other(). ✓
> + {&fd_unix_stream, &sock4, sizeof(sock4), EACCES,
> + "write permission is denied on the socket file"},
> + SAFE_CHMOD(SOCK_FILE, 0700);
Correct: the socket file is owned by root with mode 0700. The "nobody"
user has no write permission on it, so connect() returns EACCES. ✓
> +static void verify_connect(unsigned int i)
> +{
> + struct test_case_t *tc = &tcases[i];
> + void *addr = tc->addr ? tc->addr : bad_addr;
> +
> + if (tc->exp_errno == EACCES) {
> + if (!SAFE_FORK()) {
> + SAFE_SETUID(pw->pw_uid);
> + TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
> + tc->exp_errno, "%s", tc->desc);
> + exit(0);
> + }
> + } else {
BUG: The parent never waits for the child. After SAFE_FORK() returns
the child PID (the `if (!SAFE_FORK())` branch is false in the parent),
the parent returns immediately from verify_connect() without reaping
the child. The child becomes a zombie and there is a race condition:
the next test iteration may start before the child has reported its
result via TST_EXP_FAIL.
The established LTP pattern for this (see e.g. msgget02.c) is to call
tst_reap_children() in the parent after the fork:
if (tc->exp_errno == EACCES) {
if (!SAFE_FORK()) {
SAFE_SETUID(pw->pw_uid);
TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
tc->exp_errno, "%s", tc->desc);
exit(0);
}
tst_reap_children();
} else {
TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
tc->exp_errno, "%s", tc->desc);
}
> + .needs_root = 1,
> + .needs_tmpdir = 1,
Both are necessary and correct given the chmod and socket file creation.
---
Summary:
- Patch 1: Reviewed, looks good (nits only, not blocking)
- Patch 2: Needs fix — add tst_reap_children() after the SAFE_FORK()
block in verify_connect()
Please send a v2 with the fix applied to patch 2.
Thanks,
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread* [LTP] [PATCH v5 0/2] connect01: Convert to new API
2026-06-04 4:49 ` [LTP] [PATCH v4 1/2] " Wei Gao via ltp
2026-06-04 7:15 ` [LTP] " linuxtestproject.agent
@ 2026-06-16 1:47 ` Wei Gao via ltp
2026-06-16 1:47 ` [LTP] [PATCH v5 1/2] " Wei Gao via ltp
2026-06-16 1:47 ` [LTP] [PATCH v5 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 1:47 UTC (permalink / raw)
To: ltp
v4->v5:
- Reformat commit message body
- Initialize all socket file descriptors to -1.
- Use != -1 guards check fd
- Add tst_reap_children() after the SAFE_FORK()
Wei Gao (2):
connect01: Convert to new API
connect01: Add negative tests
testcases/kernel/syscalls/connect/connect01.c | 401 ++++++------------
1 file changed, 139 insertions(+), 262 deletions(-)
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v5 1/2] connect01: Convert to new API
2026-06-16 1:47 ` [LTP] [PATCH v5 0/2] " Wei Gao via ltp
@ 2026-06-16 1:47 ` Wei Gao via ltp
2026-06-16 4:07 ` [LTP] " linuxtestproject.agent
2026-06-16 5:24 ` [LTP] [PATCH v6 0/2] " Wei Gao via ltp
2026-06-16 1:47 ` [LTP] [PATCH v5 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 1:47 UTC (permalink / raw)
To: ltp
Convert the connect01 test case from the legacy LTP API to the new tst_test API.
Simplify the server child process to a single accept/exit loop and move the server
lifecycle to the global setup and cleanup. The server now accepts a single connection
for the EISCONN test case and exits immediately, which avoids blocking the test runner.
Centralize test case initialization into the global setup and use tst_get_bad_addr()
for the EFAULT test case to ensure architectural compatibility.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 363 +++++-------------
1 file changed, 98 insertions(+), 265 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 6cb8adab3..5a3ff2fcc 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -1,308 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) Linux Test Project, 2006-2026
*/
-/*
- * Test Name: connect01
- *
- * Test Description:
- * Verify that connect() returns the proper errno for various failure cases
- *
- * Usage: <for command-line>
- * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS:
- * None.
- *
+/*\
+ * Verify that :manpage:`connect(2)` returns the proper errno for various failure cases.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/un.h>
-
+#include <sys/wait.h>
#include <netinet/in.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
-#include "test.h"
-#include "tso_safe_macros.h"
-
-char *TCID = "connect01";
-int testno;
-
-int s, s2; /* socket descriptor */
-struct sockaddr_in sin1, sin2, sin3, sin4;
-static int sfd; /* shared between start_server and do_child */
+static int fd_invalid = -1;
+static int fd_socket = -1;
+static int fd_null = -1;
+static int fd_connected = -1;
+static int fd_server = -1;
-void setup(void), setup0(void), setup1(void), setup2(void),
-cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
+static struct sockaddr_in sock1;
+static struct sockaddr_in sock2;
+static struct sockaddr_in sock3;
+static void *bad_addr;
-static pid_t start_server(struct sockaddr_in *);
+static pid_t pid;
-struct test_case_t { /* test case structure */
- int domain; /* PF_INET, PF_UNIX, ... */
- int type; /* SOCK_STREAM, SOCK_DGRAM ... */
- int proto; /* protocol number (usually 0 = default) */
- struct sockaddr *sockaddr; /* socket address buffer */
- int salen; /* connect's 3rd argument */
- int retval; /* syscall return value */
- int experrno; /* expected errno */
- void (*setup) (void);
- void (*cleanup) (void);
+static struct test_case_t {
+ int *fd;
+ void *addr;
+ socklen_t salen;
+ int exp_errno;
char *desc;
-} tdat[] = {
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(struct sockaddr_in), -1, EBADF, setup0,
- cleanup0, "bad file descriptor"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
- sizeof(struct sockaddr_in), -1, EFAULT, setup1,
- cleanup1, "invalid socket buffer"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
- 0, 0, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
- "invalid socket"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, EISCONN, setup2, cleanup1,
- "already connected"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
- sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
- "connection refused"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
- sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
- "invalid address family"}
-,};
-
-int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-/**
- * bionic's connect() implementation calls netdClientInitConnect() before
- * sending the request to the kernel. We need to bypass this, or the test will
- * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
- * tests started to segfault on glibc upgrade or in special conditions where
- * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
- * safer to call the raw syscall regardless of the libc implementation.
- */
-#include "lapi/syscalls.h"
+} tcases[] = {
+ {&fd_invalid, &sock1, sizeof(sock1), EBADF,
+ "sockfd is not a valid open file descriptor"},
+ {&fd_socket, NULL, sizeof(sock1), EFAULT,
+ "socket structure address is outside the user's address space"},
+ {&fd_socket, &sock1, 3, EINVAL,
+ "addrlen is not valid"},
+ {&fd_null, &sock1, sizeof(sock1), ENOTSOCK,
+ "file descriptor sockfd does not refer to a socket"},
+ {&fd_connected, &sock1, sizeof(sock1), EISCONN,
+ "socket is already connected"},
+ {&fd_socket, &sock2, sizeof(sock2), ECONNREFUSED,
+ "connect on a socket found no one listening on remote address"},
+ {&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
+ "address doesn't have the correct address family in sa_family"},
+};
static int sys_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen)
+ socklen_t addrlen)
{
return tst_syscall(__NR_connect, sockfd, addr, addrlen);
}
-#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
-
-int main(int argc, char *argv[])
+static void start_server(struct sockaddr_in *sock)
{
- int lc;
+ socklen_t slen = sizeof(*sock);
- tst_parse_opts(argc, argv, NULL, NULL);
+ sock->sin_family = AF_INET;
+ sock->sin_port = 0;
+ sock->sin_addr.s_addr = INADDR_ANY;
- setup();
+ fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
+ SAFE_LISTEN(fd_server, 10);
+ SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
- for (lc = 0; TEST_LOOPING(lc); ++lc) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; ++testno) {
- tdat[testno].setup();
+ pid = SAFE_FORK();
- TEST(connect
- (s, tdat[testno].sockaddr, tdat[testno].salen));
+ if (!pid) {
+ int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
- if (TEST_RETURN != tdat[testno].retval ||
- (TEST_RETURN < 0 &&
- TEST_ERRNO != tdat[testno].experrno)) {
- tst_resm(TFAIL, "%s ; returned"
- " %ld (expected %d), errno %d (expected"
- " %d)", tdat[testno].desc,
- TEST_RETURN, tdat[testno].retval,
- TEST_ERRNO, tdat[testno].experrno);
- } else {
- tst_resm(TPASS, "%s successful",
- tdat[testno].desc);
- }
- tdat[testno].cleanup();
- }
+ SAFE_CLOSE(nfd);
+ exit(0);
}
- cleanup();
-
- tst_exit();
+ SAFE_CLOSE(fd_server);
+ fd_server = -1;
}
-pid_t pid;
-
-void setup(void)
+static void setup(void)
{
- TEST_PAUSE; /* if -p option specified */
-
- pid = start_server(&sin1);
-
- sin2.sin_family = AF_INET;
- /* this port must be unused! */
- sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
- sin2.sin_addr.s_addr = INADDR_ANY;
-
- sin3.sin_family = AF_INET;
- sin3.sin_port = 0;
- /* assumes no route to this network! */
- sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
- sin4.sin_family = 47; /* bogus address family */
- sin4.sin_port = 0;
- sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
-}
+ bad_addr = tst_get_bad_addr(NULL);
+ start_server(&sock1);
-void cleanup(void)
-{
- (void)kill(pid, SIGKILL);
+ fd_socket = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ fd_null = SAFE_OPEN("/dev/null", O_WRONLY);
-}
+ fd_connected = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_CONNECT(fd_connected, (const struct sockaddr *)&sock1, sizeof(sock1));
-void setup0(void)
-{
- if (tdat[testno].experrno == EBADF)
- s = 400; /* anything not an open file */
- else if ((s = open("/dev/null", O_WRONLY)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
+ /* Wait for server to accept and exit */
+ SAFE_WAITPID(pid, NULL, 0);
+ pid = 0;
-}
+ sock2.sin_family = AF_INET;
+ sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
+ sock2.sin_addr.s_addr = INADDR_ANY;
-void cleanup0(void)
-{
- close(s);
- s = -1;
+ sock3.sin_family = 47;
+ sock3.sin_port = 0;
+ sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
}
-void setup1(void)
+static void cleanup(void)
{
- s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
- tdat[testno].proto);
-}
-
-void cleanup1(void)
-{
- (void)close(s);
- s = -1;
-}
-
-void setup2(void)
-{
- setup1(); /* get a socket in s */
- SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
-}
-
-pid_t start_server(struct sockaddr_in *sin0)
-{
- pid_t pid;
- socklen_t slen = sizeof(*sin0);
-
- sin0->sin_family = AF_INET;
- sin0->sin_port = 0; /* pick random free port */
- sin0->sin_addr.s_addr = INADDR_ANY;
-
- sfd = socket(PF_INET, SOCK_STREAM, 0);
- if (sfd < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
- return -1;
- }
- if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
- return -1;
+ if (fd_socket != -1)
+ SAFE_CLOSE(fd_socket);
+ if (fd_null != -1)
+ SAFE_CLOSE(fd_null);
+ if (fd_connected != -1)
+ SAFE_CLOSE(fd_connected);
+ if (fd_server != -1)
+ SAFE_CLOSE(fd_server);
+
+ if (pid > 0) {
+ SAFE_KILL(pid, SIGKILL);
+ SAFE_WAITPID(pid, NULL, 0);
}
- if (listen(sfd, 10) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
- return -1;
- }
- SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
-
- switch ((pid = tst_fork())) {
- case 0: /* child */
- do_child();
- break;
- case -1:
- tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
- /* fall through */
- default: /* parent */
- (void)close(sfd);
- return pid;
- }
-
- return -1;
}
-void do_child(void)
+static void verify_connect(unsigned int i)
{
- struct sockaddr_in fsin;
- fd_set afds, rfds;
- int nfds, cc, fd;
- char c;
-
- FD_ZERO(&afds);
- FD_SET(sfd, &afds);
-
- nfds = sfd + 1;
+ struct test_case_t *tc = &tcases[i];
+ void *addr = tc->addr ? tc->addr : bad_addr;
- /* accept connections until killed */
- while (1) {
- socklen_t fromlen;
-
- memcpy(&rfds, &afds, sizeof(rfds));
-
- if (select(nfds, &rfds, NULL, NULL,
- NULL) < 0)
- if (errno != EINTR)
- exit(1);
- if (FD_ISSET(sfd, &rfds)) {
- int newfd;
-
- fromlen = sizeof(fsin);
- newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
- if (newfd >= 0) {
- FD_SET(newfd, &afds);
- nfds = MAX(nfds, newfd + 1);
- }
- }
- for (fd = 0; fd < nfds; ++fd)
- if (fd != sfd && FD_ISSET(fd, &rfds)) {
- if ((cc = read(fd, &c, 1)) == 0) {
- (void)close(fd);
- FD_CLR(fd, &afds);
- }
- }
- }
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_connect,
+ .forks_child = 1,
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [LTP] connect01: Convert to new API
2026-06-16 1:47 ` [LTP] [PATCH v5 1/2] " Wei Gao via ltp
@ 2026-06-16 4:07 ` linuxtestproject.agent
2026-06-16 5:24 ` [LTP] [PATCH v6 0/2] " Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: linuxtestproject.agent @ 2026-06-16 4:07 UTC (permalink / raw)
To: Wei Gao; +Cc: ltp
Hi Wei,
On Tue, 16 Jun 2026, Wei Gao <wegao@suse.com> wrote:
> connect01: Convert to new API
--- [PATCH 1/2] ---
> + SAFE_CLOSE(fd_server);
> + fd_server = -1;
SAFE_CLOSE() already resets its argument to -1. The manual
assignment is redundant and can be dropped.
--- [PATCH 2/2] ---
> connect01: Add negative tests
>
> Add negative cases for connect(), when errno is EPROTOTYPE or EACCES.
The body restates the subject. Could it say why these specific
error paths are worth covering now? e.g. "These error paths were
not exercised by the existing test."
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v6 0/2] connect01: Convert to new API
2026-06-16 1:47 ` [LTP] [PATCH v5 1/2] " Wei Gao via ltp
2026-06-16 4:07 ` [LTP] " linuxtestproject.agent
@ 2026-06-16 5:24 ` Wei Gao via ltp
2026-06-16 5:24 ` [LTP] [PATCH v6 1/2] " Wei Gao via ltp
2026-06-16 5:24 ` [LTP] [PATCH v6 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 5:24 UTC (permalink / raw)
To: ltp
v5->v6:
- Removed the manual fd_server = -1
- Improved Commit Body
Wei Gao (2):
connect01: Convert to new API
connect01: Add negative tests
testcases/kernel/syscalls/connect/connect01.c | 400 ++++++------------
1 file changed, 138 insertions(+), 262 deletions(-)
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v6 1/2] connect01: Convert to new API
2026-06-16 5:24 ` [LTP] [PATCH v6 0/2] " Wei Gao via ltp
@ 2026-06-16 5:24 ` Wei Gao via ltp
2026-06-16 8:35 ` [LTP] " linuxtestproject.agent
2026-06-16 9:31 ` [LTP] [PATCH v7 0/2] " Wei Gao via ltp
2026-06-16 5:24 ` [LTP] [PATCH v6 " Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 5:24 UTC (permalink / raw)
To: ltp
Convert the connect01 test case from the legacy LTP API to the new tst_test API.
Simplify the server child process to a single accept/exit loop and move the server
lifecycle to the global setup and cleanup. The server now accepts a single connection
for the EISCONN test case and exits immediately, which avoids blocking the test runner.
Centralize test case initialization into the global setup and use tst_get_bad_addr()
for the EFAULT test case to ensure architectural compatibility.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 362 +++++-------------
1 file changed, 97 insertions(+), 265 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 6cb8adab3..fd288559e 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -1,308 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) Linux Test Project, 2006-2026
*/
-/*
- * Test Name: connect01
- *
- * Test Description:
- * Verify that connect() returns the proper errno for various failure cases
- *
- * Usage: <for command-line>
- * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS:
- * None.
- *
+/*\
+ * Verify that :manpage:`connect(2)` returns the proper errno for various failure cases.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/un.h>
-
+#include <sys/wait.h>
#include <netinet/in.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
-#include "test.h"
-#include "tso_safe_macros.h"
-
-char *TCID = "connect01";
-int testno;
-
-int s, s2; /* socket descriptor */
-struct sockaddr_in sin1, sin2, sin3, sin4;
-static int sfd; /* shared between start_server and do_child */
+static int fd_invalid = -1;
+static int fd_socket = -1;
+static int fd_null = -1;
+static int fd_connected = -1;
+static int fd_server = -1;
-void setup(void), setup0(void), setup1(void), setup2(void),
-cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
+static struct sockaddr_in sock1;
+static struct sockaddr_in sock2;
+static struct sockaddr_in sock3;
+static void *bad_addr;
-static pid_t start_server(struct sockaddr_in *);
+static pid_t pid;
-struct test_case_t { /* test case structure */
- int domain; /* PF_INET, PF_UNIX, ... */
- int type; /* SOCK_STREAM, SOCK_DGRAM ... */
- int proto; /* protocol number (usually 0 = default) */
- struct sockaddr *sockaddr; /* socket address buffer */
- int salen; /* connect's 3rd argument */
- int retval; /* syscall return value */
- int experrno; /* expected errno */
- void (*setup) (void);
- void (*cleanup) (void);
+static struct test_case_t {
+ int *fd;
+ void *addr;
+ socklen_t salen;
+ int exp_errno;
char *desc;
-} tdat[] = {
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(struct sockaddr_in), -1, EBADF, setup0,
- cleanup0, "bad file descriptor"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
- sizeof(struct sockaddr_in), -1, EFAULT, setup1,
- cleanup1, "invalid socket buffer"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
- 0, 0, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
- "invalid socket"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, EISCONN, setup2, cleanup1,
- "already connected"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
- sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
- "connection refused"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
- sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
- "invalid address family"}
-,};
-
-int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-/**
- * bionic's connect() implementation calls netdClientInitConnect() before
- * sending the request to the kernel. We need to bypass this, or the test will
- * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
- * tests started to segfault on glibc upgrade or in special conditions where
- * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
- * safer to call the raw syscall regardless of the libc implementation.
- */
-#include "lapi/syscalls.h"
+} tcases[] = {
+ {&fd_invalid, &sock1, sizeof(sock1), EBADF,
+ "sockfd is not a valid open file descriptor"},
+ {&fd_socket, NULL, sizeof(sock1), EFAULT,
+ "socket structure address is outside the user's address space"},
+ {&fd_socket, &sock1, 3, EINVAL,
+ "addrlen is not valid"},
+ {&fd_null, &sock1, sizeof(sock1), ENOTSOCK,
+ "file descriptor sockfd does not refer to a socket"},
+ {&fd_connected, &sock1, sizeof(sock1), EISCONN,
+ "socket is already connected"},
+ {&fd_socket, &sock2, sizeof(sock2), ECONNREFUSED,
+ "connect on a socket found no one listening on remote address"},
+ {&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
+ "address doesn't have the correct address family in sa_family"},
+};
static int sys_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen)
+ socklen_t addrlen)
{
return tst_syscall(__NR_connect, sockfd, addr, addrlen);
}
-#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
-
-int main(int argc, char *argv[])
+static void start_server(struct sockaddr_in *sock)
{
- int lc;
+ socklen_t slen = sizeof(*sock);
- tst_parse_opts(argc, argv, NULL, NULL);
+ sock->sin_family = AF_INET;
+ sock->sin_port = 0;
+ sock->sin_addr.s_addr = INADDR_ANY;
- setup();
+ fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
+ SAFE_LISTEN(fd_server, 10);
+ SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
- for (lc = 0; TEST_LOOPING(lc); ++lc) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; ++testno) {
- tdat[testno].setup();
+ pid = SAFE_FORK();
- TEST(connect
- (s, tdat[testno].sockaddr, tdat[testno].salen));
+ if (!pid) {
+ int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
- if (TEST_RETURN != tdat[testno].retval ||
- (TEST_RETURN < 0 &&
- TEST_ERRNO != tdat[testno].experrno)) {
- tst_resm(TFAIL, "%s ; returned"
- " %ld (expected %d), errno %d (expected"
- " %d)", tdat[testno].desc,
- TEST_RETURN, tdat[testno].retval,
- TEST_ERRNO, tdat[testno].experrno);
- } else {
- tst_resm(TPASS, "%s successful",
- tdat[testno].desc);
- }
- tdat[testno].cleanup();
- }
+ SAFE_CLOSE(nfd);
+ exit(0);
}
- cleanup();
-
- tst_exit();
+ SAFE_CLOSE(fd_server);
}
-pid_t pid;
-
-void setup(void)
+static void setup(void)
{
- TEST_PAUSE; /* if -p option specified */
-
- pid = start_server(&sin1);
-
- sin2.sin_family = AF_INET;
- /* this port must be unused! */
- sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
- sin2.sin_addr.s_addr = INADDR_ANY;
-
- sin3.sin_family = AF_INET;
- sin3.sin_port = 0;
- /* assumes no route to this network! */
- sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
- sin4.sin_family = 47; /* bogus address family */
- sin4.sin_port = 0;
- sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
-}
+ bad_addr = tst_get_bad_addr(NULL);
+ start_server(&sock1);
-void cleanup(void)
-{
- (void)kill(pid, SIGKILL);
+ fd_socket = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ fd_null = SAFE_OPEN("/dev/null", O_WRONLY);
-}
+ fd_connected = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_CONNECT(fd_connected, (const struct sockaddr *)&sock1, sizeof(sock1));
-void setup0(void)
-{
- if (tdat[testno].experrno == EBADF)
- s = 400; /* anything not an open file */
- else if ((s = open("/dev/null", O_WRONLY)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
+ /* Wait for server to accept and exit */
+ SAFE_WAITPID(pid, NULL, 0);
+ pid = 0;
-}
+ sock2.sin_family = AF_INET;
+ sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
+ sock2.sin_addr.s_addr = INADDR_ANY;
-void cleanup0(void)
-{
- close(s);
- s = -1;
+ sock3.sin_family = 47;
+ sock3.sin_port = 0;
+ sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
}
-void setup1(void)
+static void cleanup(void)
{
- s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
- tdat[testno].proto);
-}
-
-void cleanup1(void)
-{
- (void)close(s);
- s = -1;
-}
-
-void setup2(void)
-{
- setup1(); /* get a socket in s */
- SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
-}
-
-pid_t start_server(struct sockaddr_in *sin0)
-{
- pid_t pid;
- socklen_t slen = sizeof(*sin0);
-
- sin0->sin_family = AF_INET;
- sin0->sin_port = 0; /* pick random free port */
- sin0->sin_addr.s_addr = INADDR_ANY;
-
- sfd = socket(PF_INET, SOCK_STREAM, 0);
- if (sfd < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
- return -1;
- }
- if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
- return -1;
+ if (fd_socket != -1)
+ SAFE_CLOSE(fd_socket);
+ if (fd_null != -1)
+ SAFE_CLOSE(fd_null);
+ if (fd_connected != -1)
+ SAFE_CLOSE(fd_connected);
+ if (fd_server != -1)
+ SAFE_CLOSE(fd_server);
+
+ if (pid > 0) {
+ SAFE_KILL(pid, SIGKILL);
+ SAFE_WAITPID(pid, NULL, 0);
}
- if (listen(sfd, 10) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
- return -1;
- }
- SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
-
- switch ((pid = tst_fork())) {
- case 0: /* child */
- do_child();
- break;
- case -1:
- tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
- /* fall through */
- default: /* parent */
- (void)close(sfd);
- return pid;
- }
-
- return -1;
}
-void do_child(void)
+static void verify_connect(unsigned int i)
{
- struct sockaddr_in fsin;
- fd_set afds, rfds;
- int nfds, cc, fd;
- char c;
-
- FD_ZERO(&afds);
- FD_SET(sfd, &afds);
-
- nfds = sfd + 1;
+ struct test_case_t *tc = &tcases[i];
+ void *addr = tc->addr ? tc->addr : bad_addr;
- /* accept connections until killed */
- while (1) {
- socklen_t fromlen;
-
- memcpy(&rfds, &afds, sizeof(rfds));
-
- if (select(nfds, &rfds, NULL, NULL,
- NULL) < 0)
- if (errno != EINTR)
- exit(1);
- if (FD_ISSET(sfd, &rfds)) {
- int newfd;
-
- fromlen = sizeof(fsin);
- newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
- if (newfd >= 0) {
- FD_SET(newfd, &afds);
- nfds = MAX(nfds, newfd + 1);
- }
- }
- for (fd = 0; fd < nfds; ++fd)
- if (fd != sfd && FD_ISSET(fd, &rfds)) {
- if ((cc = read(fd, &c, 1)) == 0) {
- (void)close(fd);
- FD_CLR(fd, &afds);
- }
- }
- }
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_connect,
+ .forks_child = 1,
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [LTP] connect01: Convert to new API
2026-06-16 5:24 ` [LTP] [PATCH v6 1/2] " Wei Gao via ltp
@ 2026-06-16 8:35 ` linuxtestproject.agent
2026-06-16 9:31 ` [LTP] [PATCH v7 0/2] " Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: linuxtestproject.agent @ 2026-06-16 8:35 UTC (permalink / raw)
To: Wei Gao; +Cc: ltp
Hi Wei,
On Tue, Jun 16, 2026, Wei Gao wrote:
> connect01: Convert to new API
--- [PATCH 2/2] ---
> + .needs_root = 1,
Ground Rule 4 requires the doc comment to explain why root is
needed. The EACCES case drops to nobody via SAFE_SETUID, which
requires starting as root. Could the doc block mention this?
For example:
/*\
* Verify that :manpage:`connect(2)` returns the proper errno
* for various failure cases.
*
* Requires root to test EACCES by dropping privileges to an
* unprivileged user.
*/
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v7 0/2] connect01: Convert to new API
2026-06-16 5:24 ` [LTP] [PATCH v6 1/2] " Wei Gao via ltp
2026-06-16 8:35 ` [LTP] " linuxtestproject.agent
@ 2026-06-16 9:31 ` Wei Gao via ltp
2026-06-16 9:31 ` [LTP] [PATCH v7 1/2] " Wei Gao via ltp
2026-06-16 9:31 ` [LTP] [PATCH v7 2/2] connect01: Add negative tests Wei Gao via ltp
1 sibling, 2 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 9:31 UTC (permalink / raw)
To: ltp
v6->v7:
- Add doc comment to explain why root is needed.
Wei Gao (2):
connect01: Convert to new API
connect01: Add negative tests
testcases/kernel/syscalls/connect/connect01.c | 402 ++++++------------
1 file changed, 141 insertions(+), 261 deletions(-)
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 24+ messages in thread
* [LTP] [PATCH v7 1/2] connect01: Convert to new API
2026-06-16 9:31 ` [LTP] [PATCH v7 0/2] " Wei Gao via ltp
@ 2026-06-16 9:31 ` Wei Gao via ltp
2026-06-16 10:12 ` [LTP] " linuxtestproject.agent
2026-06-16 9:31 ` [LTP] [PATCH v7 2/2] connect01: Add negative tests Wei Gao via ltp
1 sibling, 1 reply; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 9:31 UTC (permalink / raw)
To: ltp
Convert the connect01 test case from the legacy LTP API to the new tst_test API.
Simplify the server child process to a single accept/exit loop and move the server
lifecycle to the global setup and cleanup. The server now accepts a single connection
for the EISCONN test case and exits immediately, which avoids blocking the test runner.
Centralize test case initialization into the global setup and use tst_get_bad_addr()
for the EFAULT test case to ensure architectural compatibility.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 362 +++++-------------
1 file changed, 97 insertions(+), 265 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 6cb8adab3..fd288559e 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -1,308 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (c) Linux Test Project, 2006-2026
*/
-/*
- * Test Name: connect01
- *
- * Test Description:
- * Verify that connect() returns the proper errno for various failure cases
- *
- * Usage: <for command-line>
- * connect01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * HISTORY
- * 07/2001 Ported by Wayne Boyer
- *
- * RESTRICTIONS:
- * None.
- *
+/*\
+ * Verify that :manpage:`connect(2)` returns the proper errno for various failure cases.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/un.h>
-
+#include <sys/wait.h>
#include <netinet/in.h>
+#include "tst_test.h"
+#include "lapi/syscalls.h"
-#include "test.h"
-#include "tso_safe_macros.h"
-
-char *TCID = "connect01";
-int testno;
-
-int s, s2; /* socket descriptor */
-struct sockaddr_in sin1, sin2, sin3, sin4;
-static int sfd; /* shared between start_server and do_child */
+static int fd_invalid = -1;
+static int fd_socket = -1;
+static int fd_null = -1;
+static int fd_connected = -1;
+static int fd_server = -1;
-void setup(void), setup0(void), setup1(void), setup2(void),
-cleanup(void), cleanup0(void), cleanup1(void), do_child(void);
+static struct sockaddr_in sock1;
+static struct sockaddr_in sock2;
+static struct sockaddr_in sock3;
+static void *bad_addr;
-static pid_t start_server(struct sockaddr_in *);
+static pid_t pid;
-struct test_case_t { /* test case structure */
- int domain; /* PF_INET, PF_UNIX, ... */
- int type; /* SOCK_STREAM, SOCK_DGRAM ... */
- int proto; /* protocol number (usually 0 = default) */
- struct sockaddr *sockaddr; /* socket address buffer */
- int salen; /* connect's 3rd argument */
- int retval; /* syscall return value */
- int experrno; /* expected errno */
- void (*setup) (void);
- void (*cleanup) (void);
+static struct test_case_t {
+ int *fd;
+ void *addr;
+ socklen_t salen;
+ int exp_errno;
char *desc;
-} tdat[] = {
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(struct sockaddr_in), -1, EBADF, setup0,
- cleanup0, "bad file descriptor"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)-1,
- sizeof(struct sockaddr_in), -1, EFAULT, setup1,
- cleanup1, "invalid socket buffer"},
- {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- 3, -1, EINVAL, setup1, cleanup1, "invalid salen"}, {
- 0, 0, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, ENOTSOCK, setup0, cleanup0,
- "invalid socket"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin1,
- sizeof(sin1), -1, EISCONN, setup2, cleanup1,
- "already connected"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin2,
- sizeof(sin2), -1, ECONNREFUSED, setup1, cleanup1,
- "connection refused"}
- , {
- PF_INET, SOCK_STREAM, 0, (struct sockaddr *)&sin4,
- sizeof(sin4), -1, EAFNOSUPPORT, setup1, cleanup1,
- "invalid address family"}
-,};
-
-int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-/**
- * bionic's connect() implementation calls netdClientInitConnect() before
- * sending the request to the kernel. We need to bypass this, or the test will
- * segfault during the addr = (struct sockaddr *)-1 testcase. We had cases where
- * tests started to segfault on glibc upgrade or in special conditions where
- * libc had to convert structure layouts between 32bit/64bit userspace/kernel =>
- * safer to call the raw syscall regardless of the libc implementation.
- */
-#include "lapi/syscalls.h"
+} tcases[] = {
+ {&fd_invalid, &sock1, sizeof(sock1), EBADF,
+ "sockfd is not a valid open file descriptor"},
+ {&fd_socket, NULL, sizeof(sock1), EFAULT,
+ "socket structure address is outside the user's address space"},
+ {&fd_socket, &sock1, 3, EINVAL,
+ "addrlen is not valid"},
+ {&fd_null, &sock1, sizeof(sock1), ENOTSOCK,
+ "file descriptor sockfd does not refer to a socket"},
+ {&fd_connected, &sock1, sizeof(sock1), EISCONN,
+ "socket is already connected"},
+ {&fd_socket, &sock2, sizeof(sock2), ECONNREFUSED,
+ "connect on a socket found no one listening on remote address"},
+ {&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
+ "address doesn't have the correct address family in sa_family"},
+};
static int sys_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen)
+ socklen_t addrlen)
{
return tst_syscall(__NR_connect, sockfd, addr, addrlen);
}
-#define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen)
-
-int main(int argc, char *argv[])
+static void start_server(struct sockaddr_in *sock)
{
- int lc;
+ socklen_t slen = sizeof(*sock);
- tst_parse_opts(argc, argv, NULL, NULL);
+ sock->sin_family = AF_INET;
+ sock->sin_port = 0;
+ sock->sin_addr.s_addr = INADDR_ANY;
- setup();
+ fd_server = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_BIND(fd_server, (struct sockaddr *)sock, slen);
+ SAFE_LISTEN(fd_server, 10);
+ SAFE_GETSOCKNAME(fd_server, (struct sockaddr *)sock, &slen);
- for (lc = 0; TEST_LOOPING(lc); ++lc) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; ++testno) {
- tdat[testno].setup();
+ pid = SAFE_FORK();
- TEST(connect
- (s, tdat[testno].sockaddr, tdat[testno].salen));
+ if (!pid) {
+ int nfd = SAFE_ACCEPT(fd_server, NULL, NULL);
- if (TEST_RETURN != tdat[testno].retval ||
- (TEST_RETURN < 0 &&
- TEST_ERRNO != tdat[testno].experrno)) {
- tst_resm(TFAIL, "%s ; returned"
- " %ld (expected %d), errno %d (expected"
- " %d)", tdat[testno].desc,
- TEST_RETURN, tdat[testno].retval,
- TEST_ERRNO, tdat[testno].experrno);
- } else {
- tst_resm(TPASS, "%s successful",
- tdat[testno].desc);
- }
- tdat[testno].cleanup();
- }
+ SAFE_CLOSE(nfd);
+ exit(0);
}
- cleanup();
-
- tst_exit();
+ SAFE_CLOSE(fd_server);
}
-pid_t pid;
-
-void setup(void)
+static void setup(void)
{
- TEST_PAUSE; /* if -p option specified */
-
- pid = start_server(&sin1);
-
- sin2.sin_family = AF_INET;
- /* this port must be unused! */
- sin2.sin_port = TST_GET_UNUSED_PORT(NULL, AF_INET, SOCK_STREAM);
- sin2.sin_addr.s_addr = INADDR_ANY;
-
- sin3.sin_family = AF_INET;
- sin3.sin_port = 0;
- /* assumes no route to this network! */
- sin3.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
- sin4.sin_family = 47; /* bogus address family */
- sin4.sin_port = 0;
- sin4.sin_addr.s_addr = htonl(0x0AFFFEFD);
-
-}
+ bad_addr = tst_get_bad_addr(NULL);
+ start_server(&sock1);
-void cleanup(void)
-{
- (void)kill(pid, SIGKILL);
+ fd_socket = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ fd_null = SAFE_OPEN("/dev/null", O_WRONLY);
-}
+ fd_connected = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
+ SAFE_CONNECT(fd_connected, (const struct sockaddr *)&sock1, sizeof(sock1));
-void setup0(void)
-{
- if (tdat[testno].experrno == EBADF)
- s = 400; /* anything not an open file */
- else if ((s = open("/dev/null", O_WRONLY)) == -1)
- tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
+ /* Wait for server to accept and exit */
+ SAFE_WAITPID(pid, NULL, 0);
+ pid = 0;
-}
+ sock2.sin_family = AF_INET;
+ sock2.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
+ sock2.sin_addr.s_addr = INADDR_ANY;
-void cleanup0(void)
-{
- close(s);
- s = -1;
+ sock3.sin_family = 47;
+ sock3.sin_port = 0;
+ sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
}
-void setup1(void)
+static void cleanup(void)
{
- s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
- tdat[testno].proto);
-}
-
-void cleanup1(void)
-{
- (void)close(s);
- s = -1;
-}
-
-void setup2(void)
-{
- setup1(); /* get a socket in s */
- SAFE_CONNECT(cleanup, s, (const struct sockaddr *)&sin1, sizeof(sin1));
-}
-
-pid_t start_server(struct sockaddr_in *sin0)
-{
- pid_t pid;
- socklen_t slen = sizeof(*sin0);
-
- sin0->sin_family = AF_INET;
- sin0->sin_port = 0; /* pick random free port */
- sin0->sin_addr.s_addr = INADDR_ANY;
-
- sfd = socket(PF_INET, SOCK_STREAM, 0);
- if (sfd < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
- return -1;
- }
- if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
- return -1;
+ if (fd_socket != -1)
+ SAFE_CLOSE(fd_socket);
+ if (fd_null != -1)
+ SAFE_CLOSE(fd_null);
+ if (fd_connected != -1)
+ SAFE_CLOSE(fd_connected);
+ if (fd_server != -1)
+ SAFE_CLOSE(fd_server);
+
+ if (pid > 0) {
+ SAFE_KILL(pid, SIGKILL);
+ SAFE_WAITPID(pid, NULL, 0);
}
- if (listen(sfd, 10) < 0) {
- tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
- return -1;
- }
- SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
-
- switch ((pid = tst_fork())) {
- case 0: /* child */
- do_child();
- break;
- case -1:
- tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
- /* fall through */
- default: /* parent */
- (void)close(sfd);
- return pid;
- }
-
- return -1;
}
-void do_child(void)
+static void verify_connect(unsigned int i)
{
- struct sockaddr_in fsin;
- fd_set afds, rfds;
- int nfds, cc, fd;
- char c;
-
- FD_ZERO(&afds);
- FD_SET(sfd, &afds);
-
- nfds = sfd + 1;
+ struct test_case_t *tc = &tcases[i];
+ void *addr = tc->addr ? tc->addr : bad_addr;
- /* accept connections until killed */
- while (1) {
- socklen_t fromlen;
-
- memcpy(&rfds, &afds, sizeof(rfds));
-
- if (select(nfds, &rfds, NULL, NULL,
- NULL) < 0)
- if (errno != EINTR)
- exit(1);
- if (FD_ISSET(sfd, &rfds)) {
- int newfd;
-
- fromlen = sizeof(fsin);
- newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
- if (newfd >= 0) {
- FD_SET(newfd, &afds);
- nfds = MAX(nfds, newfd + 1);
- }
- }
- for (fd = 0; fd < nfds; ++fd)
- if (fd != sfd && FD_ISSET(fd, &rfds)) {
- if ((cc = read(fd, &c, 1)) == 0) {
- (void)close(fd);
- FD_CLR(fd, &afds);
- }
- }
- }
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_connect,
+ .forks_child = 1,
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread* [LTP] [PATCH v7 2/2] connect01: Add negative tests
2026-06-16 9:31 ` [LTP] [PATCH v7 0/2] " Wei Gao via ltp
2026-06-16 9:31 ` [LTP] [PATCH v7 1/2] " Wei Gao via ltp
@ 2026-06-16 9:31 ` Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 9:31 UTC (permalink / raw)
To: ltp
Add negative cases for connect(), when errno is EPROTOTYPE or EACCES.
These error paths were not exercised by the existing test.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 54 +++++++++++++++++--
1 file changed, 51 insertions(+), 3 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index fd288559e..79aa899eb 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -5,26 +5,39 @@
*/
/*\
- * Verify that :manpage:`connect(2)` returns the proper errno for various failure cases.
+ * Verify that :manpage:`connect(2)` returns the proper errno
+ * for various failure cases.
+ *
+ * Requires root to test EACCES by dropping privileges to an
+ * unprivileged user.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
+#include <pwd.h>
#include "tst_test.h"
#include "lapi/syscalls.h"
+#define SOCK_FILE "sock_file"
+
static int fd_invalid = -1;
static int fd_socket = -1;
static int fd_null = -1;
static int fd_connected = -1;
static int fd_server = -1;
+static int fd_unix_dgram = -1;
+static int fd_unix_stream = -1;
+static int fd_unix_server = -1;
static struct sockaddr_in sock1;
static struct sockaddr_in sock2;
static struct sockaddr_in sock3;
+static struct sockaddr_un sock4;
static void *bad_addr;
+static struct passwd *pw;
static pid_t pid;
@@ -49,6 +62,10 @@ static struct test_case_t {
"connect on a socket found no one listening on remote address"},
{&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
"address doesn't have the correct address family in sa_family"},
+ {&fd_unix_dgram, &sock4, sizeof(sock4), EPROTOTYPE,
+ "socket type does not support the protocol"},
+ {&fd_unix_stream, &sock4, sizeof(sock4), EACCES,
+ "write permission is denied on the socket file"},
};
static int sys_connect(int sockfd, const struct sockaddr *addr,
@@ -103,6 +120,19 @@ static void setup(void)
sock3.sin_family = 47;
sock3.sin_port = 0;
sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
+
+ sock4.sun_family = AF_UNIX;
+ strncpy(sock4.sun_path, SOCK_FILE, sizeof(sock4.sun_path));
+
+ fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+ SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
+ SAFE_CHMOD(SOCK_FILE, 0700);
+ SAFE_LISTEN(fd_unix_server, 5);
+
+ fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+
+ pw = SAFE_GETPWNAM("nobody");
}
static void cleanup(void)
@@ -115,6 +145,12 @@ static void cleanup(void)
SAFE_CLOSE(fd_connected);
if (fd_server != -1)
SAFE_CLOSE(fd_server);
+ if (fd_unix_dgram != -1)
+ SAFE_CLOSE(fd_unix_dgram);
+ if (fd_unix_stream != -1)
+ SAFE_CLOSE(fd_unix_stream);
+ if (fd_unix_server != -1)
+ SAFE_CLOSE(fd_unix_server);
if (pid > 0) {
SAFE_KILL(pid, SIGKILL);
@@ -127,8 +163,18 @@ static void verify_connect(unsigned int i)
struct test_case_t *tc = &tcases[i];
void *addr = tc->addr ? tc->addr : bad_addr;
- TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
- tc->exp_errno, "%s", tc->desc);
+ if (tc->exp_errno == EACCES) {
+ if (!SAFE_FORK()) {
+ SAFE_SETUID(pw->pw_uid);
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ exit(0);
+ }
+ tst_reap_children();
+ } else {
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ }
}
static struct tst_test test = {
@@ -137,4 +183,6 @@ static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = verify_connect,
.forks_child = 1,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [LTP] [PATCH v6 2/2] connect01: Add negative tests
2026-06-16 5:24 ` [LTP] [PATCH v6 0/2] " Wei Gao via ltp
2026-06-16 5:24 ` [LTP] [PATCH v6 1/2] " Wei Gao via ltp
@ 2026-06-16 5:24 ` Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 5:24 UTC (permalink / raw)
To: ltp
Add negative cases for connect(), when errno is EPROTOTYPE or EACCES.
These error paths were not exercised by the existing test.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 48 ++++++++++++++++++-
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index fd288559e..7b18b664e 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -11,20 +11,29 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
+#include <pwd.h>
#include "tst_test.h"
#include "lapi/syscalls.h"
+#define SOCK_FILE "sock_file"
+
static int fd_invalid = -1;
static int fd_socket = -1;
static int fd_null = -1;
static int fd_connected = -1;
static int fd_server = -1;
+static int fd_unix_dgram = -1;
+static int fd_unix_stream = -1;
+static int fd_unix_server = -1;
static struct sockaddr_in sock1;
static struct sockaddr_in sock2;
static struct sockaddr_in sock3;
+static struct sockaddr_un sock4;
static void *bad_addr;
+static struct passwd *pw;
static pid_t pid;
@@ -49,6 +58,10 @@ static struct test_case_t {
"connect on a socket found no one listening on remote address"},
{&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
"address doesn't have the correct address family in sa_family"},
+ {&fd_unix_dgram, &sock4, sizeof(sock4), EPROTOTYPE,
+ "socket type does not support the protocol"},
+ {&fd_unix_stream, &sock4, sizeof(sock4), EACCES,
+ "write permission is denied on the socket file"},
};
static int sys_connect(int sockfd, const struct sockaddr *addr,
@@ -103,6 +116,19 @@ static void setup(void)
sock3.sin_family = 47;
sock3.sin_port = 0;
sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
+
+ sock4.sun_family = AF_UNIX;
+ strncpy(sock4.sun_path, SOCK_FILE, sizeof(sock4.sun_path));
+
+ fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+ SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
+ SAFE_CHMOD(SOCK_FILE, 0700);
+ SAFE_LISTEN(fd_unix_server, 5);
+
+ fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+
+ pw = SAFE_GETPWNAM("nobody");
}
static void cleanup(void)
@@ -115,6 +141,12 @@ static void cleanup(void)
SAFE_CLOSE(fd_connected);
if (fd_server != -1)
SAFE_CLOSE(fd_server);
+ if (fd_unix_dgram != -1)
+ SAFE_CLOSE(fd_unix_dgram);
+ if (fd_unix_stream != -1)
+ SAFE_CLOSE(fd_unix_stream);
+ if (fd_unix_server != -1)
+ SAFE_CLOSE(fd_unix_server);
if (pid > 0) {
SAFE_KILL(pid, SIGKILL);
@@ -127,8 +159,18 @@ static void verify_connect(unsigned int i)
struct test_case_t *tc = &tcases[i];
void *addr = tc->addr ? tc->addr : bad_addr;
- TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
- tc->exp_errno, "%s", tc->desc);
+ if (tc->exp_errno == EACCES) {
+ if (!SAFE_FORK()) {
+ SAFE_SETUID(pw->pw_uid);
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ exit(0);
+ }
+ tst_reap_children();
+ } else {
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ }
}
static struct tst_test test = {
@@ -137,4 +179,6 @@ static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = verify_connect,
.forks_child = 1,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [LTP] [PATCH v5 2/2] connect01: Add negative tests
2026-06-16 1:47 ` [LTP] [PATCH v5 0/2] " Wei Gao via ltp
2026-06-16 1:47 ` [LTP] [PATCH v5 1/2] " Wei Gao via ltp
@ 2026-06-16 1:47 ` Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-16 1:47 UTC (permalink / raw)
To: ltp
Add negative cases for connect(), when errno is EPROTOTYPE or EACCES.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 48 ++++++++++++++++++-
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 5a3ff2fcc..6b88c5e42 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -11,20 +11,29 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
+#include <pwd.h>
#include "tst_test.h"
#include "lapi/syscalls.h"
+#define SOCK_FILE "sock_file"
+
static int fd_invalid = -1;
static int fd_socket = -1;
static int fd_null = -1;
static int fd_connected = -1;
static int fd_server = -1;
+static int fd_unix_dgram = -1;
+static int fd_unix_stream = -1;
+static int fd_unix_server = -1;
static struct sockaddr_in sock1;
static struct sockaddr_in sock2;
static struct sockaddr_in sock3;
+static struct sockaddr_un sock4;
static void *bad_addr;
+static struct passwd *pw;
static pid_t pid;
@@ -49,6 +58,10 @@ static struct test_case_t {
"connect on a socket found no one listening on remote address"},
{&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
"address doesn't have the correct address family in sa_family"},
+ {&fd_unix_dgram, &sock4, sizeof(sock4), EPROTOTYPE,
+ "socket type does not support the protocol"},
+ {&fd_unix_stream, &sock4, sizeof(sock4), EACCES,
+ "write permission is denied on the socket file"},
};
static int sys_connect(int sockfd, const struct sockaddr *addr,
@@ -104,6 +117,19 @@ static void setup(void)
sock3.sin_family = 47;
sock3.sin_port = 0;
sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
+
+ sock4.sun_family = AF_UNIX;
+ strncpy(sock4.sun_path, SOCK_FILE, sizeof(sock4.sun_path));
+
+ fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+ SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
+ SAFE_CHMOD(SOCK_FILE, 0700);
+ SAFE_LISTEN(fd_unix_server, 5);
+
+ fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+
+ pw = SAFE_GETPWNAM("nobody");
}
static void cleanup(void)
@@ -116,6 +142,12 @@ static void cleanup(void)
SAFE_CLOSE(fd_connected);
if (fd_server != -1)
SAFE_CLOSE(fd_server);
+ if (fd_unix_dgram != -1)
+ SAFE_CLOSE(fd_unix_dgram);
+ if (fd_unix_stream != -1)
+ SAFE_CLOSE(fd_unix_stream);
+ if (fd_unix_server != -1)
+ SAFE_CLOSE(fd_unix_server);
if (pid > 0) {
SAFE_KILL(pid, SIGKILL);
@@ -128,8 +160,18 @@ static void verify_connect(unsigned int i)
struct test_case_t *tc = &tcases[i];
void *addr = tc->addr ? tc->addr : bad_addr;
- TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
- tc->exp_errno, "%s", tc->desc);
+ if (tc->exp_errno == EACCES) {
+ if (!SAFE_FORK()) {
+ SAFE_SETUID(pw->pw_uid);
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ exit(0);
+ }
+ tst_reap_children();
+ } else {
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ }
}
static struct tst_test test = {
@@ -138,4 +180,6 @@ static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = verify_connect,
.forks_child = 1,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [LTP] [PATCH v4 2/2] connect01: Add negative tests
2026-06-04 4:49 ` [LTP] [PATCH v4 0/2] " Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 1/2] " Wei Gao via ltp
@ 2026-06-04 4:49 ` Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-06-04 4:49 UTC (permalink / raw)
To: ltp
Add negative cases for connect(), when errno is EPROTOTYPE or EACCES.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 47 ++++++++++++++++++-
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 565148fc5..76836ce20 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -11,20 +11,29 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
+#include <pwd.h>
#include "tst_test.h"
#include "lapi/syscalls.h"
+#define SOCK_FILE "sock_file"
+
static int fd_invalid = -1;
static int fd_socket;
static int fd_null;
static int fd_connected;
static int fd_server;
+static int fd_unix_dgram;
+static int fd_unix_stream;
+static int fd_unix_server;
static struct sockaddr_in sock1;
static struct sockaddr_in sock2;
static struct sockaddr_in sock3;
+static struct sockaddr_un sock4;
static void *bad_addr;
+static struct passwd *pw;
static pid_t pid;
@@ -49,6 +58,10 @@ static struct test_case_t {
"connect on a socket found no one listening on remote address"},
{&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
"address doesn't have the correct address family in sa_family"},
+ {&fd_unix_dgram, &sock4, sizeof(sock4), EPROTOTYPE,
+ "socket type does not support the protocol"},
+ {&fd_unix_stream, &sock4, sizeof(sock4), EACCES,
+ "write permission is denied on the socket file"},
};
static int sys_connect(int sockfd, const struct sockaddr *addr,
@@ -103,6 +116,19 @@ static void setup(void)
sock3.sin_family = 47;
sock3.sin_port = 0;
sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
+
+ sock4.sun_family = AF_UNIX;
+ strncpy(sock4.sun_path, SOCK_FILE, sizeof(sock4.sun_path));
+
+ fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+ SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
+ SAFE_CHMOD(SOCK_FILE, 0700);
+ SAFE_LISTEN(fd_unix_server, 5);
+
+ fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+
+ pw = SAFE_GETPWNAM("nobody");
}
static void cleanup(void)
@@ -113,6 +139,12 @@ static void cleanup(void)
SAFE_CLOSE(fd_null);
if (fd_connected > 0)
SAFE_CLOSE(fd_connected);
+ if (fd_unix_dgram > 0)
+ SAFE_CLOSE(fd_unix_dgram);
+ if (fd_unix_stream > 0)
+ SAFE_CLOSE(fd_unix_stream);
+ if (fd_unix_server > 0)
+ SAFE_CLOSE(fd_unix_server);
if (pid > 0) {
SAFE_KILL(pid, SIGKILL);
@@ -125,8 +157,17 @@ static void verify_connect(unsigned int i)
struct test_case_t *tc = &tcases[i];
void *addr = tc->addr ? tc->addr : bad_addr;
- TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
- tc->exp_errno, "%s", tc->desc);
+ if (tc->exp_errno == EACCES) {
+ if (!SAFE_FORK()) {
+ SAFE_SETUID(pw->pw_uid);
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ exit(0);
+ }
+ } else {
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ }
}
static struct tst_test test = {
@@ -135,4 +176,6 @@ static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = verify_connect,
.forks_child = 1,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [LTP] [PATCH v3 2/2] connect01: Add negative tests
2026-05-25 9:02 ` [LTP] [PATCH v3 0/2] " Wei Gao via ltp
2026-05-25 9:02 ` [LTP] [PATCH v3 1/2] " Wei Gao via ltp
@ 2026-05-25 9:02 ` Wei Gao via ltp
1 sibling, 0 replies; 24+ messages in thread
From: Wei Gao via ltp @ 2026-05-25 9:02 UTC (permalink / raw)
To: ltp
Add negative cases for connect(), when errno is EPROTOTYPE or EACCES.
Signed-off-by: Wei Gao <wegao@suse.com>
---
testcases/kernel/syscalls/connect/connect01.c | 46 ++++++++++++++++++-
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c
index 923c4be81..078569c48 100644
--- a/testcases/kernel/syscalls/connect/connect01.c
+++ b/testcases/kernel/syscalls/connect/connect01.c
@@ -11,20 +11,29 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
+#include <pwd.h>
#include "tst_test.h"
#include "lapi/syscalls.h"
+#define SOCK_FILE "sock_file"
+
static int fd_invalid = -1;
static int fd_socket;
static int fd_null;
static int fd_connected;
static int fd_server;
+static int fd_unix_dgram;
+static int fd_unix_stream;
+static int fd_unix_server;
static struct sockaddr_in sock1;
static struct sockaddr_in sock2;
static struct sockaddr_in sock3;
+static struct sockaddr_un sock4;
static void *bad_addr;
+static struct passwd *pw;
static pid_t pid;
@@ -49,6 +58,10 @@ static struct test_case_t {
"connect on a socket found no one listening on remote address"},
{&fd_socket, &sock3, sizeof(sock3), EAFNOSUPPORT,
"address doesn't have the correct address family in sa_family"},
+ {&fd_unix_dgram, &sock4, sizeof(sock4), EPROTOTYPE,
+ "socket type does not support the protocol"},
+ {&fd_unix_stream, &sock4, sizeof(sock4), EACCES,
+ "write permission is denied on the socket file"},
};
static int sys_connect(int sockfd, const struct sockaddr *addr,
@@ -103,6 +116,18 @@ static void setup(void)
sock3.sin_family = 47;
sock3.sin_port = 0;
sock3.sin_addr.s_addr = htonl(0x0AFFFEFD);
+
+ sock4.sun_family = AF_UNIX;
+ strncpy(sock4.sun_path, SOCK_FILE, sizeof(sock4.sun_path));
+
+ fd_unix_server = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+ SAFE_BIND(fd_unix_server, (struct sockaddr *)&sock4, sizeof(sock4));
+ SAFE_LISTEN(fd_unix_server, 5);
+
+ fd_unix_dgram = SAFE_SOCKET(AF_UNIX, SOCK_DGRAM, 0);
+ fd_unix_stream = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
+
+ pw = SAFE_GETPWNAM("nobody");
}
static void cleanup(void)
@@ -113,6 +138,12 @@ static void cleanup(void)
SAFE_CLOSE(fd_null);
if (fd_connected > 0)
SAFE_CLOSE(fd_connected);
+ if (fd_unix_dgram > 0)
+ SAFE_CLOSE(fd_unix_dgram);
+ if (fd_unix_stream > 0)
+ SAFE_CLOSE(fd_unix_stream);
+ if (fd_unix_server > 0)
+ SAFE_CLOSE(fd_unix_server);
if (pid > 0) {
SAFE_KILL(pid, SIGKILL);
@@ -125,8 +156,17 @@ static void verify_connect(unsigned int i)
struct test_case_t *tc = &tcases[i];
void *addr = tc->addr ? tc->addr : bad_addr;
- TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
- tc->exp_errno, "%s", tc->desc);
+ if (tc->exp_errno == EACCES) {
+ if (!SAFE_FORK()) {
+ SAFE_SETUID(pw->pw_uid);
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ exit(0);
+ }
+ } else {
+ TST_EXP_FAIL(sys_connect(*tc->fd, addr, tc->salen),
+ tc->exp_errno, "%s", tc->desc);
+ }
}
static struct tst_test test = {
@@ -135,4 +175,6 @@ static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = verify_connect,
.forks_child = 1,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-06-16 10:13 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-14 4:51 [LTP] [PATCH v2 1/2] connect01: Convert to new API Yang Xu via ltp
2024-05-14 4:51 ` [LTP] [PATCH v2 2/2] connect01: Add negative tests Yang Xu via ltp
2024-07-17 12:30 ` [LTP] [PATCH v2 1/2] connect01: Convert to new API Cyril Hrubis
2026-05-25 9:02 ` [LTP] [PATCH v3 0/2] " Wei Gao via ltp
2026-05-25 9:02 ` [LTP] [PATCH v3 1/2] " Wei Gao via ltp
2026-05-25 10:12 ` [LTP] " linuxtestproject.agent
2026-05-28 4:43 ` Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 0/2] " Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 1/2] " Wei Gao via ltp
2026-06-04 7:15 ` [LTP] " linuxtestproject.agent
2026-06-16 1:47 ` [LTP] [PATCH v5 0/2] " Wei Gao via ltp
2026-06-16 1:47 ` [LTP] [PATCH v5 1/2] " Wei Gao via ltp
2026-06-16 4:07 ` [LTP] " linuxtestproject.agent
2026-06-16 5:24 ` [LTP] [PATCH v6 0/2] " Wei Gao via ltp
2026-06-16 5:24 ` [LTP] [PATCH v6 1/2] " Wei Gao via ltp
2026-06-16 8:35 ` [LTP] " linuxtestproject.agent
2026-06-16 9:31 ` [LTP] [PATCH v7 0/2] " Wei Gao via ltp
2026-06-16 9:31 ` [LTP] [PATCH v7 1/2] " Wei Gao via ltp
2026-06-16 10:12 ` [LTP] " linuxtestproject.agent
2026-06-16 9:31 ` [LTP] [PATCH v7 2/2] connect01: Add negative tests Wei Gao via ltp
2026-06-16 5:24 ` [LTP] [PATCH v6 " Wei Gao via ltp
2026-06-16 1:47 ` [LTP] [PATCH v5 " Wei Gao via ltp
2026-06-04 4:49 ` [LTP] [PATCH v4 " Wei Gao via ltp
2026-05-25 9:02 ` [LTP] [PATCH v3 " Wei Gao via ltp
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.