2 * Command-Line Socket Interface
4 * (c) 1998--2001 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.
12 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
29 #define SOCK_VERSION "1.1"
31 static char *opts = "vtuxb:lden";
33 static enum { ip, ux } addr = ip;
34 static enum { deflt, tcp, udp, uxp } proto = deflt;
35 static int listen_p, verbose, daemon_p, single_eof_p, avoid_dns_p;
36 static char *cmd, *my_name;
38 static struct sockaddr *sa_bind, *sa_conn;
39 static char *na_bind, *na_conn;
40 static int sock_addr_length;
43 #define NORET __attribute__((noreturn))
48 static void usage(void) NORET;
49 static void mdie(char *, ...) NORET;
50 static void die(char *, ...) NORET;
56 Usage: %s [-vtuxde] ([-b <local>] <remote> | -l <local>) [<command>]\n\
59 -t\tUse TCP socket (default)\n\
61 -x\tUse UNIX-domain socket\n\
62 -b\tBind local end to specified address\n\
64 -d\tDaemon mode (listen only) -- process multiple connections\n\
65 -e\tTerminate as soon as EOF is seen in any direction\n\
66 -n\tAvoid reverse DNS lookups\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);
99 void *x = malloc(size);
101 die("Out of memory");
105 static struct sockaddr *
109 sock_addr_length = (addr == ux) ? sizeof(struct sockaddr_un) : sizeof(struct sockaddr_in);
110 sa = xmalloc(sock_addr_length);
111 memset(sa, 0, sizeof(*sa));
112 sa->sa_family = (addr == ux) ? AF_UNIX : AF_INET;
117 parse_addr(struct sockaddr **sap, char *a, int need_port, int need_addr)
120 struct sockaddr *sa = alloc_sockaddr();
126 struct sockaddr_in *s = (struct sockaddr_in *) sa;
127 char *p = strchr(a, ':');
132 die("%s: port number required", a);
133 s->sin_family = AF_INET;
134 if (!*a && need_addr)
138 struct hostent *e = gethostbyname(a);
141 if (e->h_addrtype != AF_INET && e->h_length != sizeof(struct in_addr))
142 die("%s: invalid address type", a);
143 memcpy(&s->sin_addr, e->h_addr, sizeof(struct in_addr));
148 struct servent *e = NULL;
152 e = getservbyname(p, "tcp");
156 else if (!e && proto != tcp)
158 e = getservbyname(p, "udp");
165 long int i = strtol(p, &z, 10);
166 if (i <= 0 || i > 0xffff || (z && *z))
167 die("%s: invalid port", p);
168 s->sin_port = htons(i);
171 s->sin_port = e->s_port;
178 struct sockaddr_un *s = (struct sockaddr_un *) sa;
179 if (strlen(a) >= sizeof(s->sun_path))
180 die("%s: address too long", a);
181 s->sun_family = AF_UNIX;
182 strcpy(s->sun_path, a);
191 name_addr(struct sockaddr *sa)
197 struct sockaddr_in *a = (struct sockaddr_in *) sa;
198 struct hostent *h = avoid_dns_p ? NULL : gethostbyaddr((char *) &a->sin_addr.s_addr, sizeof(struct in_addr), AF_INET);
202 return inet_ntoa(a->sin_addr);
206 struct sockaddr_un *a = (struct sockaddr_un *) sa;
215 sigchld_handler(int sig)
217 while (waitpid(-1, NULL, WNOHANG) > 0)
226 memset(&sa, 0, sizeof(sa));
227 sa.sa_handler = sigchld_handler;
228 sa.sa_flags = SA_RESTART;
229 if (sigaction(SIGCHLD, &sa, NULL) < 0)
238 char *sh = getenv("SHELL");
243 if (dup(sk) != 0 || dup(sk) != 1)
246 execl(sh, sh, "-c", cmd, NULL);
251 char ib[4096], ob[4096];
254 char *ibe = ib + sizeof(ib);
257 char *obe = ob + sizeof(ob);
270 if (!ieof && fcntl(0, F_SETFL, O_NDELAY) < 0 ||
271 !oeof && fcntl(1, F_SETFL, O_NDELAY) < 0 ||
272 fcntl(sk, F_SETFL, O_NDELAY) < 0)
278 if (ibr < ibe && !ieof)
282 if (obr < obe && !oeof)
286 if (ibr == ib && ieof == 1)
291 if (ibr == ib && obr == ob &&
292 (single_eof_p ? (ieof || oeof) : (ieof && oeof)))
294 if (select(sk+1, &in, &out, NULL, NULL) < 0)
296 if (FD_ISSET(sk, &out))
299 n = write(sk, ibw, ibr - ibw);
300 if (n < 0 && errno != EAGAIN && errno != EINTR)
301 mdie("socket write");
306 if (FD_ISSET(1, &out))
309 n = write(1, obw, obr - obw);
310 if (n < 0 && errno != EAGAIN && errno != EINTR)
316 if (FD_ISSET(0, &in))
319 n = read(0, ibr, ibe - ibr);
320 if (n < 0 && errno != EAGAIN && errno != EINTR)
327 if (FD_ISSET(sk, &in))
330 n = read(sk, obr, obe - obr);
331 if (n < 0 && errno != EAGAIN && errno != EINTR)
343 main(int argc, char **argv)
347 if (argc == 2 && !strcmp(argv[1], "--version"))
349 puts("This is sock " SOCK_VERSION ". Be happy.");
354 while ((c = getopt(argc, argv, opts)) > 0)
396 if (argc == optind + 2)
397 cmd = argv[optind+1];
398 else if (argc != optind + 1)
408 na_bind = parse_addr(&sa_bind, argv[optind], 1, 0);
413 na_bind = parse_addr(&sa_bind, na_bind, 0, 0);
414 na_conn = parse_addr(&sa_conn, argv[optind], 1, 1);
421 sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
424 sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
427 sk = socket(PF_UNIX, SOCK_STREAM, 0);
437 if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one)) < 0)
438 mdie("setsockopt(SO_REUSEADDR)");
439 if (bind(sk, sa_bind, sock_addr_length) < 0)
445 struct sockaddr *sa_incoming;
447 fprintf(stderr, "Listening on %s\n", na_bind);
453 if (listen(sk, (daemon_p ? 10 : 1)) < 0)
457 sa_incoming = alloc_sockaddr();
460 socklen_t l = sock_addr_length;
461 int ns = accept(sk, sa_incoming, &l);
465 fprintf(stderr, "Got connection from %s\n", name_addr(sa_incoming));
492 fprintf(stderr, "Connecting to %s\n", na_conn);
493 if (connect(sk, sa_conn, sock_addr_length) < 0)