/* * Copyright (c) 2003-2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: t-sr-msg.c,v 1.13 2006/10/05 04:27:35 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/test.h" #include "sm/io.h" #include "sm/ctype.h" #include "sm/fcntl.h" #include "prterr.h" #if MTA_USE_STATETHREADS #include "sm/stsock.h" #endif #include "sm/unixsock.h" #include "sm/cmsg.h" #include "sm/socket.h" /* struct msghdr */ #include "sm/uio.h" /* struct iovec */ #include /* ** Test send/recvmsg() */ extern char *optarg; extern int optind; extern int optopt; extern int opterr; static int Verbose; #define SM_BUFSIZE 8192 #define NSOCKET "./rdwrfd" /* socket to use to exchange fd */ #define TEST_MSG "Send some text over the wire" #if MTA_USE_STATETHREADS # define sm_sock_close(fd) un_st_socket_close(fd) # define SM_INVALID_SOCKET NULL # define SM_IS_INVALID_SOCKET(fd) ((fd) == NULL) #else /* MTA_USE_STATETHREADS */ # define sm_sock_close(fd) close(fd) # define SM_INVALID_SOCKET (-1) # define SM_IS_INVALID_SOCKET(fd) ((fd) < 0) #endif /* MTA_USE_STATETHREADS */ static void usage(const char *prg) { fprintf(stderr, "usage: %s options\n", prg); fprintf(stderr, "-c: act as client [default]\n"); fprintf(stderr, "-s: act as server\n"); fprintf(stderr, "-V: increase verbosity\n"); exit(0); } /* ** CLIENT -- send a message ** ** Parameters: ** none ** ** Returns: ** none */ static int client(void) { fd_T fd; int res; #if MTA_USE_STATETHREADS sm_ret_T ret; #endif struct msghdr msg; struct iovec iov[1]; char buf[SM_BUFSIZE]; if (Verbose > 1) fprintf(stderr, "clt: connect\n"); sm_memzero(&msg, sizeof(msg)); /* connect to server */ #if MTA_USE_STATETHREADS ret = un_st_client_connect(NSOCKET, -1, &fd); if (sm_is_err(ret)) return ret; #else /* MTA_USE_STATETHREADS */ (void) unix_client_connect(NSOCKET, &fd); if (Verbose > 1) fprintf(stderr, "clt: connected=%d\n", fd); SM_TEST(fd >= 0); if (fd < 0) return -1; #endif /* MTA_USE_STATETHREADS */ sm_snprintf(buf, sizeof(buf), TEST_MSG); msg.msg_name = NULL; msg.msg_namelen = 0; iov[0].iov_base = buf; iov[0].iov_len = strlen(buf) + 1; msg.msg_iov = iov; msg.msg_iovlen = 1; res = sm_sendmsg(fd, &msg, 0); SM_TEST(res >= 0); if (sm_is_err(res)) fprintf(stderr, "clt: write_fd failed=%x, errno=%d\n", res, errno); sm_sock_close(fd); sleep(1); return 0; } /* ** SERVER -- receive message ** ** Parameters: ** none ** ** Returns: ** none */ static int server(void) { fd_T fd, lfd; int servfd, r; #if MTA_USE_STATETHREADS sm_ret_T ret; int st_addrlen; #else sockaddr_len_T addrlen; #endif ssize_t i; struct sockaddr addr; struct msghdr msg; struct iovec iov[1]; char buf[SM_BUFSIZE]; sm_memzero(&msg, sizeof(msg)); sm_memzero(&buf, sizeof(buf)); lfd = fd = SM_INVALID_SOCKET; servfd = -1; r = 0; #if MTA_USE_STATETHREADS ret = un_st_server_listen(NSOCKET, 10, &lfd); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) return ret; SM_TEST(lfd != NULL); st_addrlen = sizeof(addr); if (Verbose > 1) fprintf(stderr, "srv: accept\n"); fd = st_accept(lfd, &addr, &st_addrlen, -1); SM_TEST(!SM_IS_INVALID_SOCKET(fd)); if (SM_IS_INVALID_SOCKET(fd)) { r = -1; goto err; } #else /* MTA_USE_STATETHREADS */ lfd = unix_server_listen(NSOCKET, 10); SM_TEST(lfd >= 0); if (lfd < 0) return -1; addrlen = sizeof(addr); if (Verbose > 1) fprintf(stderr, "srv: accept\n"); fd = unix_server_accept(lfd, &addr, &addrlen); SM_TEST(fd >= 0); if (fd < 0) { r = -1; goto err; } #endif /* MTA_USE_STATETHREADS */ iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); msg.msg_iov = iov; msg.msg_iovlen = 1; errno = 0; i = sm_recvmsg(fd, &msg, 0); SM_TEST(i > 0); if (i <= 0) return -1; SM_TEST(strcmp(buf, TEST_MSG) == 0); fd = SM_INVALID_SOCKET; if (Verbose > 0) fprintf(stderr, "srv: sm_recvmsg done=%d, buf='%s', errno=%d\n", (int) i, buf, errno); err: if (!SM_IS_INVALID_SOCKET(fd)) sm_sock_close(fd); if (!SM_IS_INVALID_SOCKET(lfd)) sm_sock_close(lfd); return r; } int main(int argc, char *argv[]) { bool clt, any; int c; opterr = 0; clt = true; any = false; Verbose = 0; while ((c = getopt(argc, argv, "csV")) != -1) { any = true; switch (c) { case 'c': clt = true; break; case 's': clt = false; break; case 'V': ++Verbose; break; default: usage(argv[0]); return(1); } } sm_test_begin(argc, argv, "test write/read fd"); if (!any) goto end; #if MTA_USE_STATETHREADS c = st_init(); SM_TEST(c >= 0); if (c < 0) return sm_test_end(); #endif /* MTA_USE_STATETHREADS */ if (clt) c = client(); else c = server(); SM_TEST(c == 0); end: unlink(NSOCKET); return sm_test_end(); }