mirror of
https://github.com/zsh-users/zsh
synced 2024-07-21 18:24:18 +00:00
17558: zsh/net/socket , zsocket builtin
This commit is contained in:
parent
b442b34170
commit
c6b5b1f147
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
64
Doc/Zsh/mod_socket.yo
Normal file
64
Doc/Zsh/mod_socket.yo
Normal file
|
@ -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()
|
|
@ -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
|
||||
|
|
286
Src/Modules/socket.c
Normal file
286
Src/Modules/socket.c
Normal file
|
@ -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;
|
||||
}
|
6
Src/Modules/socket.mdd
Normal file
6
Src/Modules/socket.mdd
Normal file
|
@ -0,0 +1,6 @@
|
|||
name=zsh/net/socket
|
||||
link=dynamic
|
||||
load=no
|
||||
|
||||
objects="socket.o"
|
||||
autobins="zsocket"
|
Loading…
Reference in a new issue