2 * Command-Line Socket Interface
4 * (c) 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
6 * This program can be freely distributed and used according
7 * to the terms of the GNU General Public Licence.
22 #include <netinet/in.h>
27 #include <sys/signal.h>
30 #include <sys/types.h>
32 static char *opts = "vtuxb:lde";
34 static enum { ip, ux } addr = ip;
35 static enum { deflt, tcp, udp, uxp } proto = deflt;
36 static int listen_p, verbose, daemon_p, both_eof_p;
37 static char *cmd, *my_name;
39 static struct sockaddr sa_bind, sa_conn;
40 static char *na_bind, *na_conn;
44 #define NORET __attribute__((noreturn))
49 static void usage(void) NORET;
50 static void mdie(char *, ...) NORET;
51 static void die(char *, ...) NORET;
57 Usage: %s [-vtuxde] ([-b <local>] <remote> | -l <local>) [<command>]\n\
60 -t\tUse TCP socket (default)\n\
62 -x\tUse UNIX-domain socket\n\
63 -b\tBind local end to specified address\n\
65 -d\tDaemon mode (listen only) -- process multiple connections\n\
66 -e\tTerminate only if EOF seen in both directions\n\
75 char *e = strerror(errno);
78 fprintf(stderr, "%s: ", my_name);
79 vfprintf(stderr, x, args);
80 fprintf(stderr, ": %s\n", e);
90 fprintf(stderr, "%s: ", my_name);
91 vfprintf(stderr, x, args);
97 parse_addr(struct sockaddr *sa, char *a, int need_port, int need_addr)
105 struct sockaddr_in *s = (struct sockaddr_in *) sa;
106 char *p = strchr(a, ':');
111 die("%s: port number required", a);
112 s->sin_family = AF_INET;
115 struct hostent *e = gethostbyname(a);
118 if (e->h_addrtype != AF_INET && e->h_length != sizeof(struct in_addr))
119 die("%s: invalid address type", a);
120 memcpy(&s->sin_addr, e->h_addr, sizeof(struct in_addr));
124 die("Host name required");
127 struct servent *e = NULL;
131 e = getservbyname(p, "tcp");
135 else if (!e && proto != tcp)
137 e = getservbyname(p, "udp");
144 long int i = strtol(p, &z, 10);
145 if (i <= 0 || i > 0xffff || (z && *z))
146 die("%s: invalid port", p);
147 s->sin_port = htons(i);
150 s->sin_port = e->s_port;
157 struct sockaddr_un *s = (struct sockaddr_un *) sa;
158 if (strlen(a) >= sizeof(s->sun_path))
159 die("%s: address too long", a);
160 s->sun_family = AF_UNIX;
161 strcpy(s->sun_path, a);
169 name_addr(struct sockaddr *sa)
175 struct sockaddr_in *a = (struct sockaddr_in *) sa;
176 struct hostent *h = gethostbyaddr((char *) &a->sin_addr.s_addr, sizeof(struct in_addr), AF_INET);
183 struct sockaddr_un *a = (struct sockaddr_un *) sa;
192 sigchld_handler(int sig)
194 while (wait3(NULL, WNOHANG, NULL) > 0)
203 bzero(&sa, sizeof(sa));
204 sa.sa_handler = sigchld_handler;
205 sa.sa_flags = SA_RESTART;
206 if (sigaction(SIGCHLD, &sa, NULL) < 0)
215 char *sh = getenv("SHELL");
220 if (dup(sk) != 0 || dup(sk) != 1)
223 execl(sh, sh, "-c", cmd, NULL);
228 char ib[4096], ob[4096];
231 char *ibe = ib + sizeof(ib);
234 char *obe = ob + sizeof(ob);
240 if (fcntl(0, F_SETFL, O_NDELAY) < 0 ||
241 fcntl(1, F_SETFL, O_NDELAY) < 0 ||
242 fcntl(sk, F_SETFL, O_NDELAY) < 0)
248 if (ibr < ibe && !ieof)
252 if (obr < obe && !oeof)
256 if (ibr == ib && ieof == 1)
261 if (ibr == ib && obr == ob &&
262 (both_eof_p ? (ieof && oeof) : (ieof || oeof)))
264 if (select(sk+1, &in, &out, NULL, NULL) < 0)
266 if (FD_ISSET(sk, &out))
269 n = write(sk, ibw, ibr - ibw);
270 if (n < 0 && errno != EAGAIN && errno != EINTR)
271 mdie("socket write");
276 if (FD_ISSET(1, &out))
279 n = write(1, obw, obr - obw);
280 if (n < 0 && errno != EAGAIN && errno != EINTR)
286 if (FD_ISSET(0, &in))
289 n = read(0, ibr, ibe - ibr);
290 if (n < 0 && errno != EAGAIN && errno != EINTR)
297 if (FD_ISSET(sk, &in))
300 n = read(sk, obr, obe - obr);
301 if (n < 0 && errno != EAGAIN && errno != EINTR)
313 main(int argc, char **argv)
318 while ((c = getopt(argc, argv, opts)) > 0)
343 na_bind = parse_addr(&sa_bind, optarg, 0, 0);
352 if (argc == optind + 2)
353 cmd = argv[optind+1];
354 else if (argc != optind + 1)
361 na_bind = parse_addr(&sa_bind, argv[optind], 1, 0);
365 na_conn = parse_addr(&sa_conn, argv[optind], 1, 1);
371 sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
374 sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
377 sk = socket(PF_UNIX, SOCK_STREAM, 0);
387 if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
388 mdie("setsockopt(SO_REUSEADDR)");
389 if (bind(sk, &sa_bind, sizeof(sa_bind)) < 0)
395 int l = sizeof(sa_conn);
397 fprintf(stderr, "Listening on %s\n", na_bind);
398 if (listen(sk, (daemon_p ? 10 : 1)) < 0)
404 int ns = accept(sk, &sa_conn, &l);
408 fprintf(stderr, "Got connection from %s\n", name_addr(&sa_conn));
435 fprintf(stderr, "Connecting to %s\n", na_conn);
436 if (connect(sk, &sa_conn, sizeof(sa_conn)) < 0)