minix3/commands/swifi/socket.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 $
*/