/*
* Copyright (c) 2002 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.
*
* $Id: clt2.c,v 1.3 2006/02/16 19:19:40 ca Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "st.h"
#if !HAVE_SNPRINTF
# define snprintf sm_snprintf
# include "sm/string.h"
#endif /* !HAVE_SNPRINTF */
#define IOBUFSIZE (16*1024)
#define REPS 10
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
#define SEC2USEC(s) ((s)*1000000LL)
#define REQUEST_TIMEOUT SEC2USEC(3)
static char *prog; /* Program name */
static struct sockaddr_in rmt_addr; /* Remote address */
static int debug = 0;
static st_netfd_t rmt_nfd = NULL;
static void
print_sys_error(const char *msg)
{
fprintf(stderr, "%s: %s: %s\n", prog, msg, strerror(errno));
}
static void
read_address(const char *str, struct sockaddr_in *sin)
{
char host[128], *p;
struct hostent *hp;
short port;
strlcpy(host, str, sizeof(host));
if ((p = strchr(host, ':')) == NULL)
{
fprintf(stderr, "%s: invalid address: %s\n", prog, host);
exit(1);
}
*p++ = '\0';
port = (short) atoi(p);
if (port < 1)
{
fprintf(stderr, "%s: invalid port: %s\n", prog, p);
exit(1);
}
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (host[0] == '\0')
{
sin->sin_addr.s_addr = INADDR_ANY;
return;
}
sin->sin_addr.s_addr = inet_addr(host);
if (sin->sin_addr.s_addr == INADDR_NONE)
{
/* not dotted-decimal */
if ((hp = gethostbyname(host)) == NULL)
{
fprintf(stderr, "%s: can't resolve address: %s\n", prog, host);
exit(1);
}
memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
}
}
static int
con2srv(void)
{
int sock;
char buf[IOBUFSIZE];
/* Connect to remote host */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
snprintf(buf, sizeof(buf), "socket=%d", sock);
print_sys_error(buf);
goto done;
}
if ((rmt_nfd = st_netfd_open_socket(sock)) == NULL)
{
snprintf(buf, sizeof(buf), "st_netfd_open_socket");
print_sys_error(buf);
close(sock);
goto done;
}
if (st_connect(rmt_nfd, (struct sockaddr *)&rmt_addr,
sizeof(rmt_addr), REQUEST_TIMEOUT) < 0)
{
snprintf(buf, sizeof(buf), "connect");
print_sys_error(buf);
st_netfd_close(rmt_nfd);
goto done;
}
if (debug > 2)
fprintf(stderr, "client: connected\n");
return 1;
done:
return -1;
}
static void *
wrsrv(void *arg)
{
int n, r, l;
char buf[IOBUFSIZE];
for (n = 0; n < REPS; n++)
{
snprintf(buf, sizeof(buf), "CMD %d\n", n);
l = strlen(buf);
r = st_write(rmt_nfd, buf, l, REQUEST_TIMEOUT);
if (r != l)
{
fprintf(stderr,
"error write s='%s' n=%d, l=%d, r=%d, errno=%d\n",
buf, n, l, r, errno);
return NULL;
}
st_usleep(1);
}
return NULL;
}
static void *
rdsrv(void *arg)
{
int n;
char buf[IOBUFSIZE];
while (1)
{
n = st_read(rmt_nfd, buf, IOBUFSIZE, REQUEST_TIMEOUT);
if (n <= 0)
{
fprintf(stderr,
"error read n=%d, errno=%d\n", n, errno);
goto fail;
}
if (debug > 3)
{
fprintf(stderr, "rcvd: \"");
write(STDERR_FILENO, buf, n);
fprintf(stderr, "\"\n");
}
while (n > 0)
if (buf[--n] == 'Q')
return NULL;
st_usleep(1);
}
fail:
return NULL;
}
int
main(int argc, char *argv[])
{
st_thread_t thr1;
extern char *optarg;
int opt, r, raddr, *rv;
prog = argv[0];
raddr = 0;
/* Parse arguments */
while((opt = getopt(argc, argv, "c:d:hr:t:S")) != -1)
{
switch (opt)
{
case 'd':
debug = atoi(optarg);
if (debug < 0)
{
fprintf(stderr, "%s: invalid number for debug: %s\n", prog, optarg);
exit(1);
}
break;
case 'r':
read_address(optarg, &rmt_addr);
if (rmt_addr.sin_addr.s_addr == INADDR_ANY)
{
fprintf(stderr, "%s: invalid remote address: %s\n", prog, optarg);
exit(1);
}
raddr = 1;
break;
case 'h':
case '?':
fprintf(stderr, "Usage: %s -l <[host]:port> -r <host:port> "
"[-S]\n", prog);
exit(1);
}
}
if (!raddr)
{
fprintf(stderr, "%s: remote address required\n", prog);
exit(1);
}
if (debug)
fprintf(stderr, "%s: starting client\n", prog);
/* Initialize the ST library */
if (st_init() < 0)
{
print_sys_error("st_init");
exit(1);
}
if (con2srv() < 0)
exit(1);
thr1 = st_thread_create(wrsrv, (void *) 1, 1, 0);
if (NULL == thr1)
{
print_sys_error("st_thread_create");
exit(1);
}
rdsrv((void *) 2);
r = st_thread_join(thr1, (void **) &rv);
if (rmt_nfd != NULL)
{
st_netfd_close(rmt_nfd);
rmt_nfd = NULL;
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1