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