diff options
-rw-r--r-- | Doc/Zsh/.distfiles | 3 | ||||
-rw-r--r-- | Doc/Zsh/builtins.yo | 1 | ||||
-rw-r--r-- | Doc/Zsh/mod_socket.yo | 64 | ||||
-rw-r--r-- | Src/Modules/.distfiles | 1 | ||||
-rw-r--r-- | Src/Modules/socket.c | 286 | ||||
-rw-r--r-- | Src/Modules/socket.mdd | 6 |
6 files changed, 360 insertions, 1 deletions
diff --git a/Doc/Zsh/.distfiles b/Doc/Zsh/.distfiles index 21fd2d5ea..1953af938 100644 --- a/Doc/Zsh/.distfiles +++ b/Doc/Zsh/.distfiles @@ -6,7 +6,8 @@ DISTFILES_SRC=' mod_clone.yo mod_compctl.yo mod_complete.yo mod_complist.yo mod_computil.yo mod_deltochar.yo mod_example.yo mod_files.yo mod_langinfo.yo mod_mapfile.yo mod_mathfunc.yo mod_parameter.yo mod_pcre.yo mod_sched.yo - mod_stat.yo mod_tcp.yo mod_termcap.yo mod_terminfo.yo mod_zftp.yo mod_zle.yo + mod_socket.yo mod_stat.yo mod_tcp.yo mod_termcap.yo mod_terminfo.yo + mod_zftp.yo mod_zle.yo mod_zleparameter.yo mod_zselect.yo mod_zutil.yo mod_zprof.yo mod_zpty.yo modules.yo modlist.yo modmenu.yo manmodmenu.yo options.yo params.yo prompt.yo redirect.yo restricted.yo seealso.yo diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 2d902f336..88e7e266f 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1733,6 +1733,7 @@ module(zparseopts)(zsh/zutil) module(zprof)(zsh/zprof) module(zpty)(zsh/zpty) module(zregexparse)(zsh/zutil) +module(zsocket)(zsh/net/socket) module(zstyle)(zsh/zutil) module(ztcp)(zsh/net/tcp) enditem() diff --git a/Doc/Zsh/mod_socket.yo b/Doc/Zsh/mod_socket.yo new file mode 100644 index 000000000..9c503ffe5 --- /dev/null +++ b/Doc/Zsh/mod_socket.yo @@ -0,0 +1,64 @@ +COMMENT(!MOD!zsh/net/socket +Manipulation of Unix domain sockets +!MOD!) +The tt(zsh/net/socket) module makes available one builtin command: + +startitem() +findex(zsocket) +cindex(sockets) +cindex(sockets, Unix domain) +item(tt(zsocket) [ tt(-adltv) ] [ var(args) ])( +tt(zsocket) is implemented as a builtin to allow full use of shell +command line editing, file I/O, and job control mechanisms. + +subsect(Outbound Connections) +cindex(sockets, outbound Unix domain) + +startitem() +item(tt(zsocket) [ tt(-v) ] [ tt(-d) var(fd) ] var(filename))( +Open a new Unix domain connection to var(filename). +The shell parameter tt(REPLY) will be set to the file descriptor +associated with that connection. Currently, only stream connections +are supported. + +If tt(-d) is specified, the first non-option argument +will be taken as the target file descriptor for the +connection. + +In order to elicit more verbose output, use tt(-v). +) +enditem() + +subsect(Inbound Connections) +cindex(sockets, inbound Unix domain) + +startitem() +item(tt(zsocket) tt(-l) [ tt(-v) ] [ tt(-d) var(fd) ] var(filename))( +tt(zsocket -l) will open a socket listening on var(filename). +The shell parameter tt(REPLY) will be set to the file descriptor +associated with that listener. + +If tt(-d) is specified, the first non-option argument +will be taken as the target file descriptor for +the connection. + +In order to elicit more verbose output, use tt(-v). +) +item(tt(zsocket) tt(-a) [ tt(-tv) ] [ tt(-d) var(targetfd) ] var(listenfd))( +tt(zsocket -a) will accept an incoming connection +to the socket associated with var(listenfd). +The shell parameter tt(REPLY) will +be set to the file descriptor associated with +the inbound connection. + +If tt(-d) is specified, the first non-option argument +will be taken as the target file descriptor for the +connection. + +If tt(-t) is specified, tt(zsocket) will return +if no incoming connection is pending. Otherwise +it will wait for one. + +In order to elicit more verbose output, use tt(-v). +) +enditem() diff --git a/Src/Modules/.distfiles b/Src/Modules/.distfiles index dd71e65f3..213b55649 100644 --- a/Src/Modules/.distfiles +++ b/Src/Modules/.distfiles @@ -10,6 +10,7 @@ DISTFILES_SRC=' mathfunc.mdd mathfunc.c parameter.mdd parameter.c pcre.mdd pcre.c + socket.mdd socket.c stat.mdd stat.c tcp.mdd tcp.c tcp.h termcap.mdd termcap.c 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; +} diff --git a/Src/Modules/socket.mdd b/Src/Modules/socket.mdd new file mode 100644 index 000000000..7147456d3 --- /dev/null +++ b/Src/Modules/socket.mdd @@ -0,0 +1,6 @@ +name=zsh/net/socket +link=dynamic +load=no + +objects="socket.o" +autobins="zsocket" |