1*875abb87SDavid van Moolenbroek /*
2*875abb87SDavid van Moolenbroek socket.c
3*875abb87SDavid van Moolenbroek
4*875abb87SDavid van Moolenbroek Created: Feb 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
5*875abb87SDavid van Moolenbroek
6*875abb87SDavid van Moolenbroek Open a TCP connection
7*875abb87SDavid van Moolenbroek */
8*875abb87SDavid van Moolenbroek
9*875abb87SDavid van Moolenbroek #include <errno.h>
10*875abb87SDavid van Moolenbroek #include <fcntl.h>
11*875abb87SDavid van Moolenbroek #include <stdarg.h>
12*875abb87SDavid van Moolenbroek #include <stdio.h>
13*875abb87SDavid van Moolenbroek #include <stdlib.h>
14*875abb87SDavid van Moolenbroek #include <signal.h>
15*875abb87SDavid van Moolenbroek #include <string.h>
16*875abb87SDavid van Moolenbroek #include <unistd.h>
17*875abb87SDavid van Moolenbroek
18*875abb87SDavid van Moolenbroek #include <sys/ioctl.h>
19*875abb87SDavid van Moolenbroek #include <sys/wait.h>
20*875abb87SDavid van Moolenbroek
21*875abb87SDavid van Moolenbroek #include <net/hton.h>
22*875abb87SDavid van Moolenbroek #include <net/netlib.h>
23*875abb87SDavid van Moolenbroek #include <net/gen/in.h>
24*875abb87SDavid van Moolenbroek #include <net/gen/inet.h>
25*875abb87SDavid van Moolenbroek #include <netdb.h>
26*875abb87SDavid van Moolenbroek #include <net/gen/socket.h>
27*875abb87SDavid van Moolenbroek #include <net/gen/tcp.h>
28*875abb87SDavid van Moolenbroek #include <net/gen/tcp_io.h>
29*875abb87SDavid van Moolenbroek #include <arpa/inet.h>
30*875abb87SDavid van Moolenbroek
31*875abb87SDavid van Moolenbroek #define BUF_SIZE 10240
32*875abb87SDavid van Moolenbroek
33*875abb87SDavid van Moolenbroek char *progname;
34*875abb87SDavid van Moolenbroek int tcpfd= -1;
35*875abb87SDavid van Moolenbroek char buf[BUF_SIZE];
36*875abb87SDavid van Moolenbroek static int bulk= 0;
37*875abb87SDavid van Moolenbroek static int push= 0;
38*875abb87SDavid van Moolenbroek static int stdout_issocket= 0;
39*875abb87SDavid van Moolenbroek static int timeout;
40*875abb87SDavid van Moolenbroek
41*875abb87SDavid van Moolenbroek static void do_conn(char *hostname, char *portname);
42*875abb87SDavid van Moolenbroek static void alrm_conn(int sig);
43*875abb87SDavid van Moolenbroek static void alrm_io(int sig);
44*875abb87SDavid van Moolenbroek static void fullduplex(void);
45*875abb87SDavid van Moolenbroek static void fatal(char *msg, ...);
46*875abb87SDavid van Moolenbroek static void usage(void);
47*875abb87SDavid van Moolenbroek
main(int argc,char * argv[])48*875abb87SDavid van Moolenbroek int main(int argc, char *argv[])
49*875abb87SDavid van Moolenbroek {
50*875abb87SDavid van Moolenbroek int c;
51*875abb87SDavid van Moolenbroek char *hostname;
52*875abb87SDavid van Moolenbroek char *portname;
53*875abb87SDavid van Moolenbroek char *check;
54*875abb87SDavid van Moolenbroek int B_flag, P_flag, s_flag;
55*875abb87SDavid van Moolenbroek char *t_arg;
56*875abb87SDavid van Moolenbroek
57*875abb87SDavid van Moolenbroek (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
58*875abb87SDavid van Moolenbroek
59*875abb87SDavid van Moolenbroek B_flag= 0;
60*875abb87SDavid van Moolenbroek P_flag= 0;
61*875abb87SDavid van Moolenbroek s_flag= 0;
62*875abb87SDavid van Moolenbroek t_arg= NULL;
63*875abb87SDavid van Moolenbroek while (c= getopt(argc, argv, "BPst:?"), c != -1)
64*875abb87SDavid van Moolenbroek {
65*875abb87SDavid van Moolenbroek switch(c)
66*875abb87SDavid van Moolenbroek {
67*875abb87SDavid van Moolenbroek case 'B': B_flag= 1; break;
68*875abb87SDavid van Moolenbroek case 'P': P_flag= 1; break;
69*875abb87SDavid van Moolenbroek case 's': s_flag= 1; break;
70*875abb87SDavid van Moolenbroek case 't': t_arg= optarg; break;
71*875abb87SDavid van Moolenbroek case '?': usage();
72*875abb87SDavid van Moolenbroek default:
73*875abb87SDavid van Moolenbroek fatal("getopt failed: '%c'", c);
74*875abb87SDavid van Moolenbroek }
75*875abb87SDavid van Moolenbroek }
76*875abb87SDavid van Moolenbroek if (t_arg)
77*875abb87SDavid van Moolenbroek {
78*875abb87SDavid van Moolenbroek timeout= strtol(t_arg, &check, 0);
79*875abb87SDavid van Moolenbroek if (check[0] != '\0')
80*875abb87SDavid van Moolenbroek fatal("unable to parse timeout '%s'\n", t_arg);
81*875abb87SDavid van Moolenbroek if (timeout <= 0)
82*875abb87SDavid van Moolenbroek fatal("bad timeout '%d'\n", timeout);
83*875abb87SDavid van Moolenbroek }
84*875abb87SDavid van Moolenbroek else
85*875abb87SDavid van Moolenbroek timeout= 0;
86*875abb87SDavid van Moolenbroek
87*875abb87SDavid van Moolenbroek if (optind+2 != argc)
88*875abb87SDavid van Moolenbroek usage();
89*875abb87SDavid van Moolenbroek hostname= argv[optind++];
90*875abb87SDavid van Moolenbroek portname= argv[optind++];
91*875abb87SDavid van Moolenbroek
92*875abb87SDavid van Moolenbroek bulk= B_flag;
93*875abb87SDavid van Moolenbroek push= P_flag;
94*875abb87SDavid van Moolenbroek stdout_issocket= s_flag;
95*875abb87SDavid van Moolenbroek
96*875abb87SDavid van Moolenbroek do_conn(hostname, portname);
97*875abb87SDavid van Moolenbroek
98*875abb87SDavid van Moolenbroek /* XXX */
99*875abb87SDavid van Moolenbroek if (timeout)
100*875abb87SDavid van Moolenbroek {
101*875abb87SDavid van Moolenbroek signal(SIGALRM, alrm_io);
102*875abb87SDavid van Moolenbroek alarm(timeout);
103*875abb87SDavid van Moolenbroek }
104*875abb87SDavid van Moolenbroek
105*875abb87SDavid van Moolenbroek fullduplex();
106*875abb87SDavid van Moolenbroek exit(0);
107*875abb87SDavid van Moolenbroek }
108*875abb87SDavid van Moolenbroek
do_conn(char * hostname,char * portname)109*875abb87SDavid van Moolenbroek static void do_conn(char *hostname, char *portname)
110*875abb87SDavid van Moolenbroek {
111*875abb87SDavid van Moolenbroek ipaddr_t addr;
112*875abb87SDavid van Moolenbroek tcpport_t port;
113*875abb87SDavid van Moolenbroek struct hostent *he;
114*875abb87SDavid van Moolenbroek struct servent *se;
115*875abb87SDavid van Moolenbroek char *tcp_device, *check;
116*875abb87SDavid van Moolenbroek nwio_tcpconf_t tcpconf;
117*875abb87SDavid van Moolenbroek nwio_tcpcl_t tcpcl;
118*875abb87SDavid van Moolenbroek nwio_tcpopt_t tcpopt;
119*875abb87SDavid van Moolenbroek
120*875abb87SDavid van Moolenbroek if (!inet_aton(hostname, (struct in_addr *)&addr))
121*875abb87SDavid van Moolenbroek {
122*875abb87SDavid van Moolenbroek he= gethostbyname(hostname);
123*875abb87SDavid van Moolenbroek if (he == NULL)
124*875abb87SDavid van Moolenbroek fatal("unknown hostname '%s'", hostname);
125*875abb87SDavid van Moolenbroek if (he->h_addrtype != AF_INET || he->h_length != sizeof(addr))
126*875abb87SDavid van Moolenbroek fatal("bad address for '%s'", hostname);
127*875abb87SDavid van Moolenbroek memcpy(&addr, he->h_addr, sizeof(addr));
128*875abb87SDavid van Moolenbroek }
129*875abb87SDavid van Moolenbroek
130*875abb87SDavid van Moolenbroek port= strtol(portname, &check, 0);
131*875abb87SDavid van Moolenbroek if (check[0] != 0)
132*875abb87SDavid van Moolenbroek {
133*875abb87SDavid van Moolenbroek se= getservbyname(portname, "tcp");
134*875abb87SDavid van Moolenbroek if (se == NULL)
135*875abb87SDavid van Moolenbroek fatal("unkown port '%s'", portname);
136*875abb87SDavid van Moolenbroek port= ntohs(se->s_port);
137*875abb87SDavid van Moolenbroek }
138*875abb87SDavid van Moolenbroek
139*875abb87SDavid van Moolenbroek tcp_device= getenv("TCP_DEVICE");
140*875abb87SDavid van Moolenbroek if (tcp_device == NULL) tcp_device= TCP_DEVICE;
141*875abb87SDavid van Moolenbroek
142*875abb87SDavid van Moolenbroek tcpfd= open(tcp_device, O_RDWR);
143*875abb87SDavid van Moolenbroek if (tcpfd == -1)
144*875abb87SDavid van Moolenbroek fatal("unable to open '%s': %s", tcp_device, strerror(errno));
145*875abb87SDavid van Moolenbroek tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
146*875abb87SDavid van Moolenbroek NWTC_SET_RP;
147*875abb87SDavid van Moolenbroek tcpconf.nwtc_remaddr= addr;
148*875abb87SDavid van Moolenbroek tcpconf.nwtc_remport= htons(port);;
149*875abb87SDavid van Moolenbroek if (ioctl(tcpfd, NWIOSTCPCONF, &tcpconf) == -1)
150*875abb87SDavid van Moolenbroek fatal("NWIOSTCPCONF failed: %s", strerror(errno));
151*875abb87SDavid van Moolenbroek
152*875abb87SDavid van Moolenbroek if (timeout)
153*875abb87SDavid van Moolenbroek {
154*875abb87SDavid van Moolenbroek signal(SIGALRM, alrm_conn);
155*875abb87SDavid van Moolenbroek alarm(timeout);
156*875abb87SDavid van Moolenbroek }
157*875abb87SDavid van Moolenbroek
158*875abb87SDavid van Moolenbroek tcpcl.nwtcl_flags= 0;
159*875abb87SDavid van Moolenbroek if (ioctl(tcpfd, NWIOTCPCONN, &tcpcl) == -1)
160*875abb87SDavid van Moolenbroek {
161*875abb87SDavid van Moolenbroek fatal("unable to connect to %s:%u: %s",
162*875abb87SDavid van Moolenbroek inet_ntoa(*(struct in_addr *)&addr),
163*875abb87SDavid van Moolenbroek ntohs(tcpconf.nwtc_remport), strerror(errno));
164*875abb87SDavid van Moolenbroek }
165*875abb87SDavid van Moolenbroek
166*875abb87SDavid van Moolenbroek alarm(0);
167*875abb87SDavid van Moolenbroek
168*875abb87SDavid van Moolenbroek if (bulk)
169*875abb87SDavid van Moolenbroek {
170*875abb87SDavid van Moolenbroek tcpopt.nwto_flags= NWTO_BULK;
171*875abb87SDavid van Moolenbroek if (ioctl(tcpfd, NWIOSTCPOPT, &tcpopt) == -1)
172*875abb87SDavid van Moolenbroek fatal("NWIOSTCPOPT failed: %s", strerror(errno));
173*875abb87SDavid van Moolenbroek }
174*875abb87SDavid van Moolenbroek }
175*875abb87SDavid van Moolenbroek
alrm_conn(int sig)176*875abb87SDavid van Moolenbroek static void alrm_conn(int sig)
177*875abb87SDavid van Moolenbroek {
178*875abb87SDavid van Moolenbroek fatal("timeout during connect");
179*875abb87SDavid van Moolenbroek }
180*875abb87SDavid van Moolenbroek
alrm_io(int sig)181*875abb87SDavid van Moolenbroek static void alrm_io(int sig)
182*875abb87SDavid van Moolenbroek {
183*875abb87SDavid van Moolenbroek fatal("timeout during io");
184*875abb87SDavid van Moolenbroek }
185*875abb87SDavid van Moolenbroek
fullduplex(void)186*875abb87SDavid van Moolenbroek static void fullduplex(void)
187*875abb87SDavid van Moolenbroek {
188*875abb87SDavid van Moolenbroek pid_t cpid;
189*875abb87SDavid van Moolenbroek int o, r, s, s_errno, loc;
190*875abb87SDavid van Moolenbroek
191*875abb87SDavid van Moolenbroek cpid= fork();
192*875abb87SDavid van Moolenbroek switch(cpid)
193*875abb87SDavid van Moolenbroek {
194*875abb87SDavid van Moolenbroek case -1: fatal("fork failed: %s", strerror(errno));
195*875abb87SDavid van Moolenbroek case 0:
196*875abb87SDavid van Moolenbroek /* Read from TCP, write to stdout. */
197*875abb87SDavid van Moolenbroek for (;;)
198*875abb87SDavid van Moolenbroek {
199*875abb87SDavid van Moolenbroek r= read(tcpfd, buf, BUF_SIZE);
200*875abb87SDavid van Moolenbroek if (r == 0)
201*875abb87SDavid van Moolenbroek break;
202*875abb87SDavid van Moolenbroek if (r == -1)
203*875abb87SDavid van Moolenbroek {
204*875abb87SDavid van Moolenbroek r= errno;
205*875abb87SDavid van Moolenbroek if (stdout_issocket)
206*875abb87SDavid van Moolenbroek ioctl(1, NWIOTCPSHUTDOWN, NULL);
207*875abb87SDavid van Moolenbroek fatal("error reading from TCP conn.: %s",
208*875abb87SDavid van Moolenbroek strerror(errno));
209*875abb87SDavid van Moolenbroek }
210*875abb87SDavid van Moolenbroek s= r;
211*875abb87SDavid van Moolenbroek for (o= 0; o<s; o += r)
212*875abb87SDavid van Moolenbroek {
213*875abb87SDavid van Moolenbroek r= write(1, buf+o, s-o);
214*875abb87SDavid van Moolenbroek if (r <= 0)
215*875abb87SDavid van Moolenbroek {
216*875abb87SDavid van Moolenbroek fatal("error writing to stdout: %s",
217*875abb87SDavid van Moolenbroek r == 0 ? "EOF" :
218*875abb87SDavid van Moolenbroek strerror(errno));
219*875abb87SDavid van Moolenbroek }
220*875abb87SDavid van Moolenbroek }
221*875abb87SDavid van Moolenbroek }
222*875abb87SDavid van Moolenbroek if (stdout_issocket)
223*875abb87SDavid van Moolenbroek {
224*875abb87SDavid van Moolenbroek r= ioctl(1, NWIOTCPSHUTDOWN, NULL);
225*875abb87SDavid van Moolenbroek if (r == -1)
226*875abb87SDavid van Moolenbroek {
227*875abb87SDavid van Moolenbroek fatal("NWIOTCPSHUTDOWN failed on stdout: %s",
228*875abb87SDavid van Moolenbroek strerror(errno));
229*875abb87SDavid van Moolenbroek }
230*875abb87SDavid van Moolenbroek }
231*875abb87SDavid van Moolenbroek exit(0);
232*875abb87SDavid van Moolenbroek default:
233*875abb87SDavid van Moolenbroek break;
234*875abb87SDavid van Moolenbroek }
235*875abb87SDavid van Moolenbroek
236*875abb87SDavid van Moolenbroek /* Read from stdin, write to TCP. */
237*875abb87SDavid van Moolenbroek for (;;)
238*875abb87SDavid van Moolenbroek {
239*875abb87SDavid van Moolenbroek r= read(0, buf, BUF_SIZE);
240*875abb87SDavid van Moolenbroek if (r == 0)
241*875abb87SDavid van Moolenbroek break;
242*875abb87SDavid van Moolenbroek if (r == -1)
243*875abb87SDavid van Moolenbroek {
244*875abb87SDavid van Moolenbroek s_errno= errno;
245*875abb87SDavid van Moolenbroek kill(cpid, SIGTERM);
246*875abb87SDavid van Moolenbroek fatal("error reading from stdin: %s",
247*875abb87SDavid van Moolenbroek strerror(s_errno));
248*875abb87SDavid van Moolenbroek }
249*875abb87SDavid van Moolenbroek s= r;
250*875abb87SDavid van Moolenbroek for (o= 0; o<s; o += r)
251*875abb87SDavid van Moolenbroek {
252*875abb87SDavid van Moolenbroek r= write(tcpfd, buf+o, s-o);
253*875abb87SDavid van Moolenbroek if (r <= 0)
254*875abb87SDavid van Moolenbroek {
255*875abb87SDavid van Moolenbroek s_errno= errno;
256*875abb87SDavid van Moolenbroek kill(cpid, SIGTERM);
257*875abb87SDavid van Moolenbroek fatal("error writing to TCP conn.: %s",
258*875abb87SDavid van Moolenbroek r == 0 ? "EOF" :
259*875abb87SDavid van Moolenbroek strerror(s_errno));
260*875abb87SDavid van Moolenbroek }
261*875abb87SDavid van Moolenbroek }
262*875abb87SDavid van Moolenbroek if (push)
263*875abb87SDavid van Moolenbroek ioctl(tcpfd, NWIOTCPPUSH, NULL);
264*875abb87SDavid van Moolenbroek }
265*875abb87SDavid van Moolenbroek if (ioctl(tcpfd, NWIOTCPSHUTDOWN, NULL) == -1)
266*875abb87SDavid van Moolenbroek {
267*875abb87SDavid van Moolenbroek s_errno= errno;
268*875abb87SDavid van Moolenbroek kill(cpid, SIGTERM);
269*875abb87SDavid van Moolenbroek fatal("unable to shut down TCP conn.: %s", strerror(s_errno));
270*875abb87SDavid van Moolenbroek }
271*875abb87SDavid van Moolenbroek
272*875abb87SDavid van Moolenbroek r= waitpid(cpid, &loc, 0);
273*875abb87SDavid van Moolenbroek if (r == -1)
274*875abb87SDavid van Moolenbroek {
275*875abb87SDavid van Moolenbroek s_errno= errno;
276*875abb87SDavid van Moolenbroek kill(cpid, SIGTERM);
277*875abb87SDavid van Moolenbroek fatal("waitpid failed: %s", strerror(s_errno));
278*875abb87SDavid van Moolenbroek }
279*875abb87SDavid van Moolenbroek if (WIFEXITED(loc))
280*875abb87SDavid van Moolenbroek exit(WEXITSTATUS(loc));
281*875abb87SDavid van Moolenbroek kill(getpid(), WTERMSIG(loc));
282*875abb87SDavid van Moolenbroek exit(1);
283*875abb87SDavid van Moolenbroek }
284*875abb87SDavid van Moolenbroek
fatal(char * fmt,...)285*875abb87SDavid van Moolenbroek static void fatal(char *fmt, ...)
286*875abb87SDavid van Moolenbroek {
287*875abb87SDavid van Moolenbroek va_list ap;
288*875abb87SDavid van Moolenbroek
289*875abb87SDavid van Moolenbroek va_start(ap, fmt);
290*875abb87SDavid van Moolenbroek fprintf(stderr, "%s: ", progname);
291*875abb87SDavid van Moolenbroek vfprintf(stderr, fmt, ap);
292*875abb87SDavid van Moolenbroek fprintf(stderr, "\n");
293*875abb87SDavid van Moolenbroek va_end(ap);
294*875abb87SDavid van Moolenbroek exit(1);
295*875abb87SDavid van Moolenbroek }
296*875abb87SDavid van Moolenbroek
usage(void)297*875abb87SDavid van Moolenbroek static void usage(void)
298*875abb87SDavid van Moolenbroek {
299*875abb87SDavid van Moolenbroek fprintf(stderr, "Usage: %s [-BPs] [-t timeout] hostname portname\n",
300*875abb87SDavid van Moolenbroek progname);
301*875abb87SDavid van Moolenbroek exit(1);
302*875abb87SDavid van Moolenbroek }
303*875abb87SDavid van Moolenbroek
304*875abb87SDavid van Moolenbroek /*
305*875abb87SDavid van Moolenbroek * $PchId: socket.c,v 1.3 2005/01/31 22:33:20 philip Exp $
306*875abb87SDavid van Moolenbroek */
307