/* * Copyright (c) 2002-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-rdwr-fd.c,v 1.21 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 /* MTA_USE_STATETHREADS */ #include "sm/unixsock.h" #include "sm/cmsg.h" #include /* ** Test write/read fd. ** Uses ** write_fd() ** read_fd() */ 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 FNAME "rdwrfd.txt" /* file which contains data to send */ static char *fname = NULL; static char *socketname = NULL; #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 fd ** ** Parameters: ** rd -- read from file? ** ** Returns: ** none */ static void client(bool rd) { int rdfd; fd_T fd; int res; #if MTA_USE_STATETHREADS sm_ret_T ret; #endif /* MTA_USE_STATETHREADS */ char buf[SM_BUFSIZE]; if (Verbose > 1) fprintf(stderr, "clt: connect\n"); /* connect to server */ #if MTA_USE_STATETHREADS ret = un_st_client_connect(socketname, -1, &fd); if (sm_is_err(ret)) return; #else /* MTA_USE_STATETHREADS */ (void) unix_client_connect(socketname, &fd); if (Verbose > 1) fprintf(stderr, "clt: connected=%d\n", fd); SM_TEST(fd >= 0); if (fd < 0) return; #endif /* MTA_USE_STATETHREADS */ /* open file descriptor that will be sent to server */ if (rd) rdfd = open(FNAME, O_RDONLY); else rdfd = open(fname, O_WRONLY|O_CREAT, 0660); SM_TEST(rdfd >= 0); if (rdfd < 0) { sm_sock_close(fd); return; } fprintf(stderr, "clt: send fd=%d\n", rdfd); sm_snprintf(buf, sizeof(buf), "Send %d\n", rdfd); /* send rdfd to server */ res = sm_write_fd(fd, (void *) buf, 1, rdfd); 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); close(rdfd); } /* ** SERVER -- receive filedescriptor ** ** Parameters: ** rd -- read from file? ** ** Returns: ** none */ static void server(bool rd) { fd_T fd, lfd; int servfd; #if MTA_USE_STATETHREADS sm_ret_T ret; int st_addrlen; #else sockaddr_len_T addrlen; #endif ssize_t i; struct sockaddr addr; char buf[SM_BUFSIZE]; lfd = fd = SM_INVALID_SOCKET; servfd = -1; #if MTA_USE_STATETHREADS ret = un_st_server_listen(socketname, 10, &lfd); if (sm_is_err(ret)) return; 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)) goto err; #else /* MTA_USE_STATETHREADS */ lfd = servfd = -1; lfd = unix_server_listen(socketname, 10); SM_TEST(lfd >= 0); if (lfd < 0) return; 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) goto err; #endif /* MTA_USE_STATETHREADS */ /* XXX receive filedescriptor */ i = sm_read_fd(fd, buf, 1, &servfd); SM_TEST(servfd >= 0); if (servfd >= 0) { if (Verbose > 0) fprintf(stderr, "srv: got fd=%d\n", servfd); if (rd) { /* read from it... */ while ((i = read(servfd, buf, sizeof(buf))) > 0) { /* XXX not nice if non-ascii... */ write(STDOUT_FILENO, buf, i); } } else { char wbuf[SM_BUFSIZE]; for (i = 0; i < sizeof(wbuf); i++) { wbuf[i] = 'A' + (i % 32); if (i % 78 == 0) wbuf[i] = '\n'; } i = write(servfd, wbuf, sizeof(wbuf)); SM_TEST(i == sizeof(wbuf)); /* XXX not nice if non-ascii... */ write(STDOUT_FILENO, wbuf, i); } } else fprintf(stderr, "srv: read_fd failed=%x, errno=%d\n", servfd, errno); fd = SM_INVALID_SOCKET; if (Verbose > 0) fprintf(stderr, "srv: read_sock done=%d, errno=%d\n", (int) i, errno); err: if (!SM_IS_INVALID_SOCKET(fd)) sm_sock_close(fd); if (!SM_IS_INVALID_SOCKET(lfd)) sm_sock_close(lfd); } int main(int argc, char *argv[]) { bool clt, any, rd; int c; opterr = 0; clt = true; rd = true; any = false; Verbose = 0; while ((c = getopt(argc, argv, "cS:sVw:")) != -1) { any = true; switch (c) { case 'c': clt = true; break; case 'S': socketname = strdup(optarg); SM_TEST_E(socketname != NULL); (void) unlink(socketname); break; case 's': clt = false; break; case 'V': ++Verbose; break; case 'w': rd = false; fname = strdup(optarg); SM_TEST_E(fname != NULL); (void) unlink(fname); break; default: usage(argv[0]); return(1); } } sm_test_begin(argc, argv, "test write/read fd"); if (!any) goto end; if (NULL == socketname) socketname = NSOCKET; #if MTA_USE_STATETHREADS c = st_init(); SM_TEST(c >= 0); if (c < 0) exit(c); #endif /* MTA_USE_STATETHREADS */ if (clt) client(rd); else server(rd); end: unlink(socketname); error: return sm_test_end(); }