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 <net/gen/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 $
 | |
|  */
 | 
