307 lines
5.6 KiB
C
307 lines
5.6 KiB
C
|
/*
|
||
|
socket.c
|
||
|
|
||
|
Created: Feb 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
|
||
|
|
||
|
Open a TCP connection
|
||
|
*/
|
||
|
|
||
|
#define _POSIX_C_SOURCE 2
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <signal.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/wait.h>
|
||
|
|
||
|
#include <net/hton.h>
|
||
|
#include <net/netlib.h>
|
||
|
#include <net/gen/in.h>
|
||
|
#include <net/gen/inet.h>
|
||
|
#include <netdb.h>
|
||
|
#include <net/gen/socket.h>
|
||
|
#include <net/gen/tcp.h>
|
||
|
#include <net/gen/tcp_io.h>
|
||
|
|
||
|
#define BUF_SIZE 10240
|
||
|
|
||
|
char *progname;
|
||
|
int tcpfd= -1;
|
||
|
char buf[BUF_SIZE];
|
||
|
static int bulk= 0;
|
||
|
static int push= 0;
|
||
|
static int stdout_issocket= 0;
|
||
|
static int timeout;
|
||
|
|
||
|
static void do_conn(char *hostname, char *portname);
|
||
|
static void alrm_conn(int sig);
|
||
|
static void alrm_io(int sig);
|
||
|
static void fullduplex(void);
|
||
|
static void fatal(char *msg, ...);
|
||
|
static void usage(void);
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
int c;
|
||
|
char *hostname;
|
||
|
char *portname;
|
||
|
char *check;
|
||
|
int B_flag, P_flag, s_flag;
|
||
|
char *t_arg;
|
||
|
|
||
|
(progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
|
||
|
|
||
|
B_flag= 0;
|
||
|
P_flag= 0;
|
||
|
s_flag= 0;
|
||
|
t_arg= NULL;
|
||
|
while (c= getopt(argc, argv, "BPst:?"), c != -1)
|
||
|
{
|
||
|
switch(c)
|
||
|
{
|
||
|
case 'B': B_flag= 1; break;
|
||
|
case 'P': P_flag= 1; break;
|
||
|
case 's': s_flag= 1; break;
|
||
|
case 't': t_arg= optarg; break;
|
||
|
case '?': usage();
|
||
|
default:
|
||
|
fatal("getopt failed: '%c'", c);
|
||
|
}
|
||
|
}
|
||
|
if (t_arg)
|
||
|
{
|
||
|
timeout= strtol(t_arg, &check, 0);
|
||
|
if (check[0] != '\0')
|
||
|
fatal("unable to parse timeout '%s'\n", t_arg);
|
||
|
if (timeout <= 0)
|
||
|
fatal("bad timeout '%d'\n", timeout);
|
||
|
}
|
||
|
else
|
||
|
timeout= 0;
|
||
|
|
||
|
if (optind+2 != argc)
|
||
|
usage();
|
||
|
hostname= argv[optind++];
|
||
|
portname= argv[optind++];
|
||
|
|
||
|
bulk= B_flag;
|
||
|
push= P_flag;
|
||
|
stdout_issocket= s_flag;
|
||
|
|
||
|
do_conn(hostname, portname);
|
||
|
|
||
|
/* XXX */
|
||
|
if (timeout)
|
||
|
{
|
||
|
signal(SIGALRM, alrm_io);
|
||
|
alarm(timeout);
|
||
|
}
|
||
|
|
||
|
fullduplex();
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
static void do_conn(char *hostname, char *portname)
|
||
|
{
|
||
|
ipaddr_t addr;
|
||
|
tcpport_t port;
|
||
|
struct hostent *he;
|
||
|
struct servent *se;
|
||
|
char *tcp_device, *check;
|
||
|
nwio_tcpconf_t tcpconf;
|
||
|
nwio_tcpcl_t tcpcl;
|
||
|
nwio_tcpopt_t tcpopt;
|
||
|
|
||
|
if (!inet_aton(hostname, &addr))
|
||
|
{
|
||
|
he= gethostbyname(hostname);
|
||
|
if (he == NULL)
|
||
|
fatal("unknown hostname '%s'", hostname);
|
||
|
if (he->h_addrtype != AF_INET || he->h_length != sizeof(addr))
|
||
|
fatal("bad address for '%s'", hostname);
|
||
|
memcpy(&addr, he->h_addr, sizeof(addr));
|
||
|
}
|
||
|
|
||
|
port= strtol(portname, &check, 0);
|
||
|
if (check[0] != 0)
|
||
|
{
|
||
|
se= getservbyname(portname, "tcp");
|
||
|
if (se == NULL)
|
||
|
fatal("unkown port '%s'", portname);
|
||
|
port= ntohs(se->s_port);
|
||
|
}
|
||
|
|
||
|
tcp_device= getenv("TCP_DEVICE");
|
||
|
if (tcp_device == NULL) tcp_device= TCP_DEVICE;
|
||
|
|
||
|
tcpfd= open(tcp_device, O_RDWR);
|
||
|
if (tcpfd == -1)
|
||
|
fatal("unable to open '%s': %s", tcp_device, strerror(errno));
|
||
|
tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
|
||
|
NWTC_SET_RP;
|
||
|
tcpconf.nwtc_remaddr= addr;
|
||
|
tcpconf.nwtc_remport= htons(port);;
|
||
|
if (ioctl(tcpfd, NWIOSTCPCONF, &tcpconf) == -1)
|
||
|
fatal("NWIOSTCPCONF failed: %s", strerror(errno));
|
||
|
|
||
|
if (timeout)
|
||
|
{
|
||
|
signal(SIGALRM, alrm_conn);
|
||
|
alarm(timeout);
|
||
|
}
|
||
|
|
||
|
tcpcl.nwtcl_flags= 0;
|
||
|
if (ioctl(tcpfd, NWIOTCPCONN, &tcpcl) == -1)
|
||
|
{
|
||
|
fatal("unable to connect to %s:%u: %s", inet_ntoa(addr),
|
||
|
ntohs(tcpconf.nwtc_remport), strerror(errno));
|
||
|
}
|
||
|
|
||
|
alarm(0);
|
||
|
|
||
|
if (bulk)
|
||
|
{
|
||
|
tcpopt.nwto_flags= NWTO_BULK;
|
||
|
if (ioctl(tcpfd, NWIOSTCPOPT, &tcpopt) == -1)
|
||
|
fatal("NWIOSTCPOPT failed: %s", strerror(errno));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void alrm_conn(int sig)
|
||
|
{
|
||
|
fatal("timeout during connect");
|
||
|
}
|
||
|
|
||
|
static void alrm_io(int sig)
|
||
|
{
|
||
|
fatal("timeout during io");
|
||
|
}
|
||
|
|
||
|
static void fullduplex(void)
|
||
|
{
|
||
|
pid_t cpid;
|
||
|
int o, r, s, s_errno, loc;
|
||
|
|
||
|
cpid= fork();
|
||
|
switch(cpid)
|
||
|
{
|
||
|
case -1: fatal("fork failed: %s", strerror(errno));
|
||
|
case 0:
|
||
|
/* Read from TCP, write to stdout. */
|
||
|
for (;;)
|
||
|
{
|
||
|
r= read(tcpfd, buf, BUF_SIZE);
|
||
|
if (r == 0)
|
||
|
break;
|
||
|
if (r == -1)
|
||
|
{
|
||
|
r= errno;
|
||
|
if (stdout_issocket)
|
||
|
ioctl(1, NWIOTCPSHUTDOWN, NULL);
|
||
|
fatal("error reading from TCP conn.: %s",
|
||
|
strerror(errno));
|
||
|
}
|
||
|
s= r;
|
||
|
for (o= 0; o<s; o += r)
|
||
|
{
|
||
|
r= write(1, buf+o, s-o);
|
||
|
if (r <= 0)
|
||
|
{
|
||
|
fatal("error writing to stdout: %s",
|
||
|
r == 0 ? "EOF" :
|
||
|
strerror(errno));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (stdout_issocket)
|
||
|
{
|
||
|
r= ioctl(1, NWIOTCPSHUTDOWN, NULL);
|
||
|
if (r == -1)
|
||
|
{
|
||
|
fatal("NWIOTCPSHUTDOWN failed on stdout: %s",
|
||
|
strerror(errno));
|
||
|
}
|
||
|
}
|
||
|
exit(0);
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Read from stdin, write to TCP. */
|
||
|
for (;;)
|
||
|
{
|
||
|
r= read(0, buf, BUF_SIZE);
|
||
|
if (r == 0)
|
||
|
break;
|
||
|
if (r == -1)
|
||
|
{
|
||
|
s_errno= errno;
|
||
|
kill(cpid, SIGTERM);
|
||
|
fatal("error reading from stdin: %s",
|
||
|
strerror(s_errno));
|
||
|
}
|
||
|
s= r;
|
||
|
for (o= 0; o<s; o += r)
|
||
|
{
|
||
|
r= write(tcpfd, buf+o, s-o);
|
||
|
if (r <= 0)
|
||
|
{
|
||
|
s_errno= errno;
|
||
|
kill(cpid, SIGTERM);
|
||
|
fatal("error writing to TCP conn.: %s",
|
||
|
r == 0 ? "EOF" :
|
||
|
strerror(s_errno));
|
||
|
}
|
||
|
}
|
||
|
if (push)
|
||
|
ioctl(tcpfd, NWIOTCPPUSH, NULL);
|
||
|
}
|
||
|
if (ioctl(tcpfd, NWIOTCPSHUTDOWN, NULL) == -1)
|
||
|
{
|
||
|
s_errno= errno;
|
||
|
kill(cpid, SIGTERM);
|
||
|
fatal("unable to shut down TCP conn.: %s", strerror(s_errno));
|
||
|
}
|
||
|
|
||
|
r= waitpid(cpid, &loc, 0);
|
||
|
if (r == -1)
|
||
|
{
|
||
|
s_errno= errno;
|
||
|
kill(cpid, SIGTERM);
|
||
|
fatal("waitpid failed: %s", strerror(s_errno));
|
||
|
}
|
||
|
if (WIFEXITED(loc))
|
||
|
exit(WEXITSTATUS(loc));
|
||
|
kill(getpid(), WTERMSIG(loc));
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
static void fatal(char *fmt, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
|
||
|
va_start(ap, fmt);
|
||
|
fprintf(stderr, "%s: ", progname);
|
||
|
vfprintf(stderr, fmt, ap);
|
||
|
fprintf(stderr, "\n");
|
||
|
va_end(ap);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
static void usage(void)
|
||
|
{
|
||
|
fprintf(stderr, "Usage: %s [-BPs] [-t timeout] hostname portname\n",
|
||
|
progname);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* $PchId: socket.c,v 1.3 2005/01/31 22:33:20 philip Exp $
|
||
|
*/
|