From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24130 invoked from network); 18 Aug 2002 02:09:23 -0000 Received: from sunsite.dk (130.225.247.90) by ns1.primenet.com.au with SMTP; 18 Aug 2002 02:09:23 -0000 Received: (qmail 12082 invoked by alias); 18 Aug 2002 02:09:14 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 17558 Received: (qmail 12067 invoked from network); 18 Aug 2002 02:09:12 -0000 Date: Sat, 17 Aug 2002 22:09:05 -0400 From: Clint Adams To: zsh-workers@sunsite.dk Subject: PATCH: Unix domain socket module Message-ID: <20020818020905.GA26266@dman.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-Virus-Scanned: by amavisd-milter (http://amavis.org/) This implements the zsocket builtin for IPC via local Unix domain sockets. Omitted is the ability to do SOCK_DGRAM. Index: Src/Modules/.distfiles =================================================================== RCS file: /cvsroot/zsh/zsh/Src/Modules/.distfiles,v retrieving revision 1.6 diff -u -r1.6 .distfiles --- Src/Modules/.distfiles 6 Jun 2002 04:54:50 -0000 1.6 +++ Src/Modules/.distfiles 18 Aug 2002 02:01:55 -0000 @@ -10,6 +10,7 @@ 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 Index: Src/Modules/socket.c =================================================================== RCS file: Src/Modules/socket.c diff -N Src/Modules/socket.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Src/Modules/socket.c 18 Aug 2002 02:01:56 -0000 @@ -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 +#include + +#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 +#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; +} Index: Src/Modules/socket.mdd =================================================================== RCS file: Src/Modules/socket.mdd diff -N Src/Modules/socket.mdd --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Src/Modules/socket.mdd 18 Aug 2002 02:01:56 -0000 @@ -0,0 +1,6 @@ +name=zsh/net/socket +link=dynamic +load=no + +objects="socket.o" +autobins="zsocket" Index: Doc/Zsh/.distfiles =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/.distfiles,v retrieving revision 1.9 diff -u -r1.9 .distfiles --- Doc/Zsh/.distfiles 17 Jun 2002 13:29:24 -0000 1.9 +++ Doc/Zsh/.distfiles 18 Aug 2002 02:01:56 -0000 @@ -6,7 +6,8 @@ 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 Index: Doc/Zsh/builtins.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v retrieving revision 1.48 diff -u -r1.48 builtins.yo --- Doc/Zsh/builtins.yo 6 Aug 2002 13:05:51 -0000 1.48 +++ Doc/Zsh/builtins.yo 18 Aug 2002 02:02:00 -0000 @@ -1733,6 +1733,7 @@ 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() Index: Doc/Zsh/mod_socket.yo =================================================================== RCS file: Doc/Zsh/mod_socket.yo diff -N Doc/Zsh/mod_socket.yo --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Doc/Zsh/mod_socket.yo 18 Aug 2002 02:02:00 -0000 @@ -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()