/*
* 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 <stdio.h>
/*
** 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();
}
syntax highlighted by Code2HTML, v. 0.9.1