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 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 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 176 static void alrm_conn(int sig) 177 { 178 fatal("timeout during connect"); 179 } 180 181 static void alrm_io(int sig) 182 { 183 fatal("timeout during io"); 184 } 185 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 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 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