diff options
Diffstat (limited to 'Src/Modules/socket.c')
-rw-r--r-- | Src/Modules/socket.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c new file mode 100644 index 000000000..68e895e68 --- /dev/null +++ b/Src/Modules/socket.c @@ -0,0 +1,286 @@ +/* + * socket.c - Unix domain socket module + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 2002 Peter Stephenson + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Peter Stephenson or the Zsh Development + * Group be liable to any party for direct, indirect, special, incidental, + * or consequential damages arising out of the use of this software and + * its documentation, even if Peter Stephenson, and the Zsh + * Development Group have been advised of the possibility of such damage. + * + * Peter Stephenson and the Zsh Development Group specifically + * disclaim any warranties, including, but not limited to, the implied + * warranties of merchantability and fitness for a particular purpose. The + * software provided hereunder is on an "as is" basis, and Peter Stephenson + * and the Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "socket.mdh" +#include "socket.pro" + +#include <sys/socket.h> +#include <sys/un.h> + +#ifndef UNIX_PATH_MAX +# define UNIX_PATH_MAX 108 +#endif + +/* + * We need to include the zsh headers later to avoid clashes with + * the definitions on some systems, however we need the configuration + * file to decide whether we can include netinet/in_systm.h, which + * doesn't exist on cygwin. + */ + +/* + * We use poll() in preference to select because some subset of manuals says + * that's the thing to do, plus it's a bit less fiddly. I don't actually + * have access to a system with poll but not select, however, though + * both bits of the code have been tested on a machine with both. + */ +#ifdef HAVE_POLL_H +# include <poll.h> +#endif +#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM) +# undef HAVE_POLL +#endif + +static int +bin_zsocket(char *nam, char **args, char *ops, int func) +{ + int err=1, verbose=0, test=0, targetfd=0; + SOCKLEN_T len; + char **dargs; + struct sockaddr_un sun; + int sfd; + + if (ops['v']) + verbose = 1; + + if (ops['t']) + test = 1; + + if (ops['d']) { + targetfd = atoi(args[0]); + dargs = args + 1; + if (!targetfd) { + zwarnnam(nam, "%s is an invalid argument to -d", args[0], 0); + return 1; + } + } + else + dargs = args; + + + if (ops['l']) { + char *localfn; + + if (!dargs[0]) { + zwarnnam(nam, "-l requires an argument", NULL, 0); + return 1; + } + + localfn = dargs[0]; + + sfd = socket(PF_UNIX, SOCK_STREAM, 0); + + if (sfd == -1) { + zwarnnam(nam, "socket error: %e ", NULL, errno); + return 1; + } + + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, localfn, UNIX_PATH_MAX); + + if (bind(sfd, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) + { + zwarnnam(nam, "could not bind to %s: %e", sun.sun_path, errno); + close(sfd); + return 1; + } + + if (listen(sfd, 1)) + { + zwarnnam(nam, "could not listen on socket: %e", NULL, errno); + close(sfd); + return 1; + } + + if (targetfd) { + redup(sfd, targetfd); + sfd = targetfd; + } + else { + /* move the fd since no one will want to read from it */ + sfd = movefd(sfd); + } + + setiparam("REPLY", sfd); + + if (verbose) + printf("%s listener is on fd %d\n", sun.sun_path, sfd); + + return 0; + + } + else if (ops['a']) + { + int lfd, rfd; + + if (!dargs[0]) { + zwarnnam(nam, "-a requires an argument", NULL, 0); + return 1; + } + + lfd = atoi(dargs[0]); + + if (!lfd) { + zwarnnam(nam, "invalid numerical argument", NULL, 0); + return 1; + } + + if (test) { +#if defined(HAVE_POLL) || defined(HAVE_SELECT) +# ifdef HAVE_POLL + struct pollfd pfd; + int ret; + + pfd.fd = lfd; + pfd.events = POLLIN; + if ((ret = poll(&pfd, 1, 0)) == 0) return 1; + else if (ret == -1) + { + zwarnnam(nam, "poll error: %e", NULL, errno); + return 1; + } +# else + fd_set rfds; + struct timeval tv; + int ret; + + FD_ZERO(&rfds); + FD_SET(lfd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + if (ret = select(lfd+1, &rfds, NULL, NULL, &tv)) return 1; + else if (ret == -1) + { + zwarnnam(nam, "select error: %e", NULL, errno); + return 1; + } + +# endif + +#else + zwarnnam(nam, "not currently supported", NULL, 0); + return 1; +#endif + } + + if ((rfd = accept(lfd, (struct sockaddr *)&sun, &len)) == -1) + { + zwarnnam(nam, "could not accept connection: %e", NULL, errno); + return 1; + } + + if (targetfd) { + redup(rfd, targetfd); + sfd = targetfd; + } + else { + sfd = rfd; + } + + setiparam("REPLY", sfd); + + if (verbose) + printf("new connection from %s is on fd %d\n", sun.sun_path, sfd); + } + else + { + if (!dargs[0]) { + zwarnnam(nam, "zsocket requires an argument", NULL, 0); + return 1; + } + + sfd = socket(PF_UNIX, SOCK_STREAM, 0); + + if (sfd == -1) { + zwarnnam(nam, "socket creation failed: %e", NULL, errno); + return 1; + } + + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, dargs[0], UNIX_PATH_MAX); + + if ((err = connect(sfd, (struct sockaddr *)&sun, sizeof(struct sockaddr_un)))) { + zwarnnam(nam, "connection failed: %e", NULL, errno); + close(sfd); + return 1; + } + else + { + if (targetfd) { + redup(sfd, targetfd); + sfd = targetfd; + } + + setiparam("REPLY", sfd); + + if (verbose) + printf("%s is now on fd %d\n", sun.sun_path, sfd); + } + + } + + return 0; +} + +static struct builtin bintab[] = { + BUILTIN("zsocket", 0, bin_zsocket, 0, 3, 0, "adltv", NULL), +}; + +/* The load/unload routines required by the zsh library interface */ + +/**/ +int +setup_(Module m) +{ + return 0; +} + +/**/ +int +boot_(Module m) +{ + return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); +} + + +/**/ +int +cleanup_(Module m) +{ + deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; +} + +/**/ +int +finish_(Module m) +{ + return 0; +} |