mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-22 16:20:23 +02:00
Merge of 23168: error when failing to bind to a port didn't use native byte order.
This commit is contained in:
parent
d9fa816688
commit
41de8626a7
1 changed files with 712 additions and 0 deletions
712
Src/Modules/tcp.c
Normal file
712
Src/Modules/tcp.c
Normal file
|
@ -0,0 +1,712 @@
|
|||
/*
|
||||
* tcp.c - TCP module
|
||||
*
|
||||
* This file is part of zsh, the Z shell.
|
||||
*
|
||||
* Copyright (c) 1998-2001 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include "tcp.h"
|
||||
#include "tcp.mdh"
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
#ifdef USE_LOCAL_H_ERRNO
|
||||
int h_errno;
|
||||
#endif
|
||||
|
||||
/* We use the RFC 2553 interfaces. If the functions don't exist in the
|
||||
* library, simulate them. */
|
||||
|
||||
#ifndef INET_ADDRSTRLEN
|
||||
# define INET_ADDRSTRLEN 16
|
||||
#endif
|
||||
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
# define INET6_ADDRSTRLEN 46
|
||||
#endif
|
||||
|
||||
/**/
|
||||
#ifndef HAVE_INET_NTOP
|
||||
|
||||
/**/
|
||||
mod_export char const *
|
||||
zsh_inet_ntop(int af, void const *cp, char *buf, size_t len)
|
||||
{
|
||||
if (af != AF_INET) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return NULL;
|
||||
}
|
||||
if (len < INET_ADDRSTRLEN) {
|
||||
errno = ENOSPC;
|
||||
return NULL;
|
||||
}
|
||||
strcpy(buf, inet_ntoa(*(struct in_addr *)cp));
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**/
|
||||
#else /* !HAVE_INET_NTOP */
|
||||
|
||||
/**/
|
||||
# define zsh_inet_ntop inet_ntop
|
||||
|
||||
/**/
|
||||
#endif /* !HAVE_INET_NTOP */
|
||||
|
||||
/**/
|
||||
#ifndef HAVE_INET_ATON
|
||||
|
||||
# ifndef INADDR_NONE
|
||||
# define INADDR_NONE 0xffffffffUL
|
||||
# endif
|
||||
|
||||
/**/
|
||||
mod_export int zsh_inet_aton(char const *src, struct in_addr *dst)
|
||||
{
|
||||
return (dst->s_addr = inet_addr(src)) != INADDR_NONE;
|
||||
}
|
||||
|
||||
/**/
|
||||
#else /* !HAVE_INET_ATON */
|
||||
|
||||
/**/
|
||||
# define zsh_inet_aton inet_aton
|
||||
|
||||
/**/
|
||||
#endif /* !HAVE_INET_ATON */
|
||||
|
||||
/**/
|
||||
#ifndef HAVE_INET_PTON
|
||||
|
||||
/**/
|
||||
mod_export int
|
||||
zsh_inet_pton(int af, char const *src, void *dst)
|
||||
{
|
||||
if (af != AF_INET) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
return !!zsh_inet_aton(src, dst);
|
||||
}
|
||||
|
||||
#else /* !HAVE_INET_PTON */
|
||||
|
||||
# define zsh_inet_pton inet_pton
|
||||
|
||||
/**/
|
||||
#endif /* !HAVE_INET_PTON */
|
||||
|
||||
/**/
|
||||
#ifndef HAVE_GETIPNODEBYNAME
|
||||
|
||||
/**/
|
||||
# ifndef HAVE_GETHOSTBYNAME2
|
||||
|
||||
/**/
|
||||
mod_export struct hostent *
|
||||
zsh_gethostbyname2(char const *name, int af)
|
||||
{
|
||||
if (af != AF_INET) {
|
||||
h_errno = NO_RECOVERY;
|
||||
return NULL;
|
||||
}
|
||||
return gethostbyname(name);
|
||||
}
|
||||
|
||||
/**/
|
||||
#else /* !HAVE_GETHOSTBYNAME2 */
|
||||
|
||||
/**/
|
||||
# define zsh_gethostbyname2 gethostbyname2
|
||||
|
||||
/**/
|
||||
# endif /* !HAVE_GETHOSTBYNAME2 */
|
||||
|
||||
/* note: this is not a complete implementation. If ignores the flags,
|
||||
and does not provide the memory allocation of the standard interface.
|
||||
Each returned structure will overwrite the previous one. */
|
||||
|
||||
/**/
|
||||
mod_export struct hostent *
|
||||
zsh_getipnodebyname(char const *name, int af, UNUSED(int flags), int *errorp)
|
||||
{
|
||||
static struct hostent ahe;
|
||||
static char nbuf[16];
|
||||
static char *addrlist[] = { nbuf, NULL };
|
||||
# ifdef SUPPORT_IPV6
|
||||
static char pbuf[INET6_ADDRSTRLEN];
|
||||
# else
|
||||
static char pbuf[INET_ADDRSTRLEN];
|
||||
# endif
|
||||
struct hostent *he;
|
||||
if (zsh_inet_pton(af, name, nbuf) == 1) {
|
||||
zsh_inet_ntop(af, nbuf, pbuf, sizeof(pbuf));
|
||||
ahe.h_name = pbuf;
|
||||
ahe.h_aliases = addrlist+1;
|
||||
ahe.h_addrtype = af;
|
||||
ahe.h_length = (af == AF_INET) ? 4 : 16;
|
||||
ahe.h_addr_list = addrlist;
|
||||
return &ahe;
|
||||
}
|
||||
he = zsh_gethostbyname2(name, af);
|
||||
if (!he)
|
||||
*errorp = h_errno;
|
||||
return he;
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export void
|
||||
freehostent(UNUSED(struct hostent *ptr))
|
||||
{
|
||||
}
|
||||
|
||||
/**/
|
||||
#else /* !HAVE_GETIPNODEBYNAME */
|
||||
|
||||
/**/
|
||||
# define zsh_getipnodebyname getipnodebyname
|
||||
|
||||
/**/
|
||||
#endif /* !HAVE_GETIPNODEBYNAME */
|
||||
|
||||
LinkList ztcp_sessions;
|
||||
|
||||
/* "allocate" a tcp_session */
|
||||
static Tcp_session
|
||||
zts_alloc(int ztflags)
|
||||
{
|
||||
Tcp_session sess;
|
||||
|
||||
sess = (Tcp_session)zshcalloc(sizeof(struct tcp_session));
|
||||
if (!sess) return NULL;
|
||||
sess->fd=-1;
|
||||
sess->flags=ztflags;
|
||||
|
||||
zinsertlinknode(ztcp_sessions, lastnode(ztcp_sessions), (void *)sess);
|
||||
|
||||
return sess;
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export Tcp_session
|
||||
tcp_socket(int domain, int type, int protocol, int ztflags)
|
||||
{
|
||||
Tcp_session sess;
|
||||
|
||||
sess = zts_alloc(ztflags);
|
||||
if (!sess) return NULL;
|
||||
|
||||
sess->fd = socket(domain, type, protocol);
|
||||
return sess;
|
||||
}
|
||||
|
||||
static int
|
||||
ztcp_free_session(Tcp_session sess)
|
||||
{
|
||||
zfree(sess, sizeof(struct tcp_session));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
zts_delete(Tcp_session sess)
|
||||
{
|
||||
LinkNode node;
|
||||
|
||||
node = linknodebydatum(ztcp_sessions, (void *)sess);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
ztcp_free_session(getdata(node));
|
||||
remnode(ztcp_sessions, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Tcp_session
|
||||
zts_byfd(int fd)
|
||||
{
|
||||
LinkNode node;
|
||||
|
||||
for (node = firstnode(ztcp_sessions); node; incnode(node))
|
||||
if (((Tcp_session)getdata(node))->fd == fd)
|
||||
return (Tcp_session)getdata(node);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_cleanup(void)
|
||||
{
|
||||
LinkNode node, next;
|
||||
|
||||
for (node = firstnode(ztcp_sessions); node; node = next) {
|
||||
next = node->next;
|
||||
tcp_close((Tcp_session)getdata(node));
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export int
|
||||
tcp_close(Tcp_session sess)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (sess)
|
||||
{
|
||||
if (sess->fd != -1)
|
||||
{
|
||||
err = close(sess->fd);
|
||||
if (err)
|
||||
zwarn("connection close failed: %e", NULL, errno);
|
||||
}
|
||||
zts_delete(sess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export int
|
||||
tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port)
|
||||
{
|
||||
int salen;
|
||||
#ifdef SUPPORT_IPV6
|
||||
if (zhost->h_addrtype==AF_INET6) {
|
||||
memcpy(&(sess->peer.in6.sin6_addr), addrp, zhost->h_length);
|
||||
sess->peer.in6.sin6_port = d_port;
|
||||
sess->peer.in6.sin6_flowinfo = 0;
|
||||
# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
sess->peer.in6.sin6_scope_id = 0;
|
||||
# endif
|
||||
sess->peer.in6.sin6_family = zhost->h_addrtype;
|
||||
salen = sizeof(struct sockaddr_in6);
|
||||
} else
|
||||
#endif /* SUPPORT_IPV6 */
|
||||
{
|
||||
memcpy(&(sess->peer.in.sin_addr), addrp, zhost->h_length);
|
||||
sess->peer.in.sin_port = d_port;
|
||||
sess->peer.in.sin_family = zhost->h_addrtype;
|
||||
salen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
return connect(sess->fd, (struct sockaddr *)&(sess->peer), salen);
|
||||
}
|
||||
|
||||
static int
|
||||
bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
|
||||
{
|
||||
int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0;
|
||||
ZSOCKLEN_T len;
|
||||
char **addrp, *desthost, *localname, *remotename;
|
||||
struct hostent *zthost = NULL, *ztpeer = NULL;
|
||||
struct servent *srv;
|
||||
Tcp_session sess = NULL;
|
||||
|
||||
if (OPT_ISSET(ops,'f'))
|
||||
force = 1;
|
||||
|
||||
if (OPT_ISSET(ops,'v'))
|
||||
verbose = 1;
|
||||
|
||||
if (OPT_ISSET(ops,'t'))
|
||||
test = 1;
|
||||
|
||||
if (OPT_ISSET(ops,'d')) {
|
||||
targetfd = atoi(OPT_ARG(ops,'d'));
|
||||
if (!targetfd) {
|
||||
zwarnnam(nam, "%s is an invalid argument to -d",
|
||||
OPT_ARG(ops,'d'), 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (OPT_ISSET(ops,'c')) {
|
||||
if (!args[0]) {
|
||||
tcp_cleanup();
|
||||
}
|
||||
else {
|
||||
targetfd = atoi(args[0]);
|
||||
sess = zts_byfd(targetfd);
|
||||
if(!targetfd) {
|
||||
zwarnnam(nam, "%s is an invalid argument to -c", args[0], 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sess)
|
||||
{
|
||||
if ((sess->flags & ZTCP_ZFTP) && !force)
|
||||
{
|
||||
zwarnnam(nam, "use -f to force closure of a zftp control connection", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
tcp_close(sess);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
zwarnnam(nam, "fd %s not found in tcp table", args[0], 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (OPT_ISSET(ops,'l')) {
|
||||
int lport = 0;
|
||||
|
||||
if (!args[0]) {
|
||||
zwarnnam(nam, "-l requires an argument", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
srv = getservbyname(args[0], "tcp");
|
||||
if (srv)
|
||||
lport = srv->s_port;
|
||||
else
|
||||
lport = htons(atoi(args[0]));
|
||||
if (!lport) { zwarnnam(nam, "bad service name or port number", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN);
|
||||
|
||||
if (!sess) {
|
||||
zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
#ifdef SO_OOBINLINE
|
||||
len = 1;
|
||||
setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
|
||||
#endif
|
||||
if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr)))
|
||||
{
|
||||
zwarnnam(nam, "bad address: %s", "0.0.0.0", 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sess->sock.in.sin_family = AF_INET;
|
||||
sess->sock.in.sin_port = lport;
|
||||
|
||||
|
||||
if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in)))
|
||||
{
|
||||
char buf[DIGBUFSIZE];
|
||||
convbase(buf, (zlong)ntohs(lport), 10);
|
||||
zwarnnam(nam, "could not bind to port %s: %e", buf, errno);
|
||||
tcp_close(sess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(sess->fd, 1))
|
||||
{
|
||||
zwarnnam(nam, "could not listen on socket: %e", NULL, errno);
|
||||
tcp_close(sess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (targetfd) {
|
||||
redup(sess->fd,targetfd);
|
||||
sess->fd = targetfd;
|
||||
}
|
||||
else {
|
||||
/* move the fd since no one will want to read from it */
|
||||
sess->fd = movefd(sess->fd);
|
||||
}
|
||||
|
||||
setiparam("REPLY", sess->fd);
|
||||
|
||||
if (verbose)
|
||||
printf("%d listener is on fd %d\n", ntohs(sess->sock.in.sin_port), sess->fd);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
else if (OPT_ISSET(ops,'a'))
|
||||
{
|
||||
int lfd, rfd;
|
||||
|
||||
if (!args[0]) {
|
||||
zwarnnam(nam, "-a requires an argument", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lfd = atoi(args[0]);
|
||||
|
||||
if (!lfd) {
|
||||
zwarnnam(nam, "invalid numerical argument", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sess = zts_byfd(lfd);
|
||||
if (!sess) {
|
||||
zwarnnam(nam, "fd %s is not registered as a tcp connection", args[0], 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(sess->flags & ZTCP_LISTEN))
|
||||
{
|
||||
zwarnnam(nam, "tcp connection not a listener", 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
|
||||
}
|
||||
sess = zts_alloc(ZTCP_INBOUND);
|
||||
|
||||
len = sizeof(sess->peer.in);
|
||||
if ((rfd = accept(lfd, (struct sockaddr *)&sess->peer.in, &len)) == -1)
|
||||
{
|
||||
zwarnnam(nam, "could not accept connection: %e", NULL, errno);
|
||||
tcp_close(sess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (targetfd) {
|
||||
redup(rfd, targetfd);
|
||||
sess->fd = targetfd;
|
||||
}
|
||||
else {
|
||||
sess->fd = rfd;
|
||||
}
|
||||
|
||||
setiparam("REPLY", sess->fd);
|
||||
|
||||
if (verbose)
|
||||
printf("%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!args[0]) {
|
||||
LinkNode node;
|
||||
for(node = firstnode(ztcp_sessions); node; incnode(node))
|
||||
{
|
||||
sess = (Tcp_session)getdata(node);
|
||||
|
||||
if (sess->fd != -1)
|
||||
{
|
||||
zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET);
|
||||
if (zthost)
|
||||
localname = zthost->h_name;
|
||||
else
|
||||
localname = ztrdup(inet_ntoa(sess->sock.in.sin_addr));
|
||||
ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET);
|
||||
if (ztpeer)
|
||||
remotename = ztpeer->h_name;
|
||||
else
|
||||
remotename = ztrdup(inet_ntoa(sess->peer.in.sin_addr));
|
||||
if (OPT_ISSET(ops,'L')) {
|
||||
int schar;
|
||||
if (sess->flags & ZTCP_ZFTP)
|
||||
schar = 'Z';
|
||||
else if (sess->flags & ZTCP_LISTEN)
|
||||
schar = 'L';
|
||||
else if (sess->flags & ZTCP_INBOUND)
|
||||
schar = 'I';
|
||||
else
|
||||
schar = 'O';
|
||||
printf("%d %c %s %d %s %d\n",
|
||||
sess->fd, schar,
|
||||
localname, ntohs(sess->sock.in.sin_port),
|
||||
remotename, ntohs(sess->peer.in.sin_port));
|
||||
} else {
|
||||
printf("%s:%d %s %s:%d is on fd %d%s\n",
|
||||
localname, ntohs(sess->sock.in.sin_port),
|
||||
((sess->flags & ZTCP_LISTEN) ? "-<" :
|
||||
((sess->flags & ZTCP_INBOUND) ? "<-" : "->")),
|
||||
remotename, ntohs(sess->peer.in.sin_port),
|
||||
sess->fd,
|
||||
(sess->flags & ZTCP_ZFTP) ? " ZFTP" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (!args[1]) {
|
||||
destport = htons(23);
|
||||
}
|
||||
else {
|
||||
|
||||
srv = getservbyname(args[1],"tcp");
|
||||
if (srv)
|
||||
destport = srv->s_port;
|
||||
else
|
||||
destport = htons(atoi(args[1]));
|
||||
}
|
||||
|
||||
desthost = ztrdup(args[0]);
|
||||
|
||||
zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno);
|
||||
if (!zthost || errflag) {
|
||||
zwarnnam(nam, "host resolution failure: %s", desthost, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);
|
||||
|
||||
if (!sess) {
|
||||
zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef SO_OOBINLINE
|
||||
len = 1;
|
||||
setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
|
||||
#endif
|
||||
|
||||
if (sess->fd < 0) {
|
||||
zwarnnam(nam, "socket creation failed: %e", NULL, errno);
|
||||
zsfree(desthost);
|
||||
zts_delete(sess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (addrp = zthost->h_addr_list; err && *addrp; addrp++) {
|
||||
if (zthost->h_length != 4)
|
||||
zwarnnam(nam, "address length mismatch", NULL, 0);
|
||||
do {
|
||||
err = tcp_connect(sess, *addrp, zthost, destport);
|
||||
} while (err && errno == EINTR && !errflag);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
zwarnnam(nam, "connection failed: %e", NULL, errno);
|
||||
tcp_close(sess);
|
||||
zsfree(desthost);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetfd) {
|
||||
redup(sess->fd, targetfd);
|
||||
sess->fd = targetfd;
|
||||
}
|
||||
|
||||
setiparam("REPLY", sess->fd);
|
||||
|
||||
if (verbose)
|
||||
printf("%s:%d is now on fd %d\n",
|
||||
desthost, destport, sess->fd);
|
||||
}
|
||||
|
||||
zsfree(desthost);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct builtin bintab[] = {
|
||||
BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acd:flLtv", NULL),
|
||||
};
|
||||
|
||||
/* The load/unload routines required by the zsh library interface */
|
||||
|
||||
/**/
|
||||
int
|
||||
setup_(UNUSED(Module m))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
boot_(Module m)
|
||||
{
|
||||
ztcp_sessions = znewlinklist();
|
||||
return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
|
||||
}
|
||||
|
||||
|
||||
/**/
|
||||
int
|
||||
cleanup_(Module m)
|
||||
{
|
||||
tcp_cleanup();
|
||||
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
|
||||
freelinklist(ztcp_sessions, (FreeFunc) ztcp_free_session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
finish_(UNUSED(Module m))
|
||||
{
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue