2001-06-06 20:53:56 +02:00
/*
2001-09-08 23:09:55 +02:00
* tcp . c - TCP module
2001-06-06 20:53:56 +02:00
*
* 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"
/* it's a TELNET based protocol, but don't think I like doing this */
# include <arpa/telnet.h>
/*
* 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 )
{
2001-09-09 11:39:24 +02:00
if ( af ! = AF_INET ) {
2001-09-08 23:09:55 +02:00
errno = EAFNOSUPPORT ;
return NULL ;
}
2001-09-09 11:39:24 +02:00
if ( len < INET_ADDRSTRLEN ) {
2001-09-08 23:09:55 +02:00
errno = ENOSPC ;
return NULL ;
}
strcpy ( buf , inet_ntoa ( * ( struct in_addr * ) cp ) ) ;
return buf ;
2001-06-06 20:53:56 +02:00
}
/**/
# else /* !HAVE_INET_NTOP */
/**/
# define zsh_inet_ntop inet_ntop
/**/
# endif /* !HAVE_INET_NTOP */
/**/
2001-09-09 11:39:24 +02:00
# ifndef HAVE_INET_ATON
2001-06-06 20:53:56 +02:00
2001-09-09 11:39:24 +02:00
# ifndef INADDR_NONE
# define INADDR_NONE 0xffffffffUL
# endif
2001-06-06 20:53:56 +02:00
/**/
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
/**/
2001-09-09 11:39:24 +02:00
# endif /* !HAVE_INET_ATON */
/**/
# ifndef HAVE_INET_PTON
2001-06-06 20:53:56 +02:00
/**/
mod_export int
zsh_inet_pton ( int af , char const * src , void * dst )
{
2001-09-09 11:39:24 +02:00
if ( af ! = AF_INET ) {
2001-09-08 23:09:55 +02:00
errno = EAFNOSUPPORT ;
return - 1 ;
}
return ! ! zsh_inet_aton ( src , dst ) ;
2001-06-06 20:53:56 +02:00
}
# 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 )
{
2001-09-09 11:39:24 +02:00
if ( af ! = AF_INET ) {
2001-09-08 23:09:55 +02:00
h_errno = NO_RECOVERY ;
return NULL ;
}
return gethostbyname ( name ) ;
2001-06-06 20:53:56 +02:00
}
/**/
# 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 , int flags , int * errorp )
{
2001-09-08 23:09:55 +02:00
static struct hostent ahe ;
static char nbuf [ 16 ] ;
static char * addrlist [ ] = { nbuf , NULL } ;
2001-06-06 20:53:56 +02:00
# ifdef SUPPORT_IPV6
2001-09-08 23:09:55 +02:00
static char pbuf [ INET6_ADDRSTRLEN ] ;
2001-06-06 20:53:56 +02:00
# else
2001-09-08 23:09:55 +02:00
static char pbuf [ INET_ADDRSTRLEN ] ;
2001-06-06 20:53:56 +02:00
# endif
2001-09-08 23:09:55 +02:00
struct hostent * he ;
2001-09-09 11:39:24 +02:00
if ( zsh_inet_pton ( af , name , nbuf ) = = 1 ) {
2001-09-08 23:09:55 +02:00
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 ) ;
2001-09-09 11:39:24 +02:00
if ( ! he )
2001-09-08 23:09:55 +02:00
* errorp = h_errno ;
return he ;
2001-06-06 20:53:56 +02:00
}
/**/
mod_export void
freehostent ( struct hostent * ptr )
{
}
/**/
# else /* !HAVE_GETIPNODEBYNAME */
/**/
# define zsh_getipnodebyname getipnodebyname
/**/
# endif /* !HAVE_GETIPNODEBYNAME */
2001-10-02 04:35:00 +02:00
LinkList ztcp_sessions ;
2001-09-08 23:09:55 +02:00
/* "allocate" a tcp_session */
static Tcp_session
zts_alloc ( int ztflags )
{
Tcp_session sess ;
sess = ( Tcp_session ) zcalloc ( sizeof ( struct tcp_session ) ) ;
2001-09-09 11:39:24 +02:00
if ( ! sess ) return NULL ;
2001-09-08 23:09:55 +02:00
sess - > fd = - 1 ;
sess - > flags = ztflags ;
2001-10-02 04:35:00 +02:00
zinsertlinknode ( ztcp_sessions , lastnode ( ztcp_sessions ) , ( void * ) sess ) ;
2001-09-08 23:09:55 +02:00
return sess ;
}
2001-06-06 20:53:56 +02:00
/**/
2001-09-08 23:09:55 +02:00
mod_export Tcp_session
tcp_socket ( int domain , int type , int protocol , int ztflags )
2001-06-06 20:53:56 +02:00
{
2001-09-08 23:09:55 +02:00
Tcp_session sess ;
sess = zts_alloc ( ztflags ) ;
2001-09-09 11:39:24 +02:00
if ( ! sess ) return NULL ;
2001-09-08 23:09:55 +02:00
2001-06-11 16:21:57 +02:00
sess - > fd = socket ( domain , type , protocol ) ;
2001-09-08 23:09:55 +02:00
return sess ;
}
static int
2001-10-02 04:35:00 +02:00
ztcp_free_session ( Tcp_session sess )
2001-09-08 23:09:55 +02:00
{
2001-10-02 04:35:00 +02:00
zfree ( sess , sizeof ( struct tcp_session ) ) ;
2001-09-08 23:09:55 +02:00
2001-10-02 04:35:00 +02:00
return 0 ;
}
2001-09-08 23:09:55 +02:00
2001-10-02 04:35:00 +02:00
static int
zts_delete ( Tcp_session sess )
{
LinkNode node ;
2001-09-10 14:37:21 +02:00
2001-10-02 04:35:00 +02:00
node = linknodebydatum ( ztcp_sessions , ( void * ) sess ) ;
2001-09-08 23:09:55 +02:00
2001-10-02 04:35:00 +02:00
if ( ! node )
{
return 1 ;
2001-09-08 23:09:55 +02:00
}
2001-10-02 04:35:00 +02:00
ztcp_free_session ( getdata ( node ) ) ;
remnode ( ztcp_sessions , node ) ;
2001-09-08 23:09:55 +02:00
return 0 ;
}
static Tcp_session
zts_byfd ( int fd )
{
2001-10-02 04:35:00 +02:00
LinkNode node ;
for ( node = firstnode ( ztcp_sessions ) ; node ; incnode ( node ) )
if ( ( ( Tcp_session ) getdata ( node ) ) - > fd = = fd )
return ( Tcp_session ) node ;
2001-09-08 23:09:55 +02:00
return NULL ;
2001-06-06 20:53:56 +02:00
}
static void
tcp_cleanup ( void )
{
2001-10-02 04:35:00 +02:00
LinkNode node ;
for ( node = firstnode ( ztcp_sessions ) ; node ; incnode ( node ) )
tcp_close ( ( Tcp_session ) getdata ( node ) ) ;
2001-06-06 20:53:56 +02:00
}
2001-06-11 16:21:57 +02:00
/**/
mod_export int
tcp_close ( Tcp_session sess )
{
2001-09-08 23:09:55 +02:00
int err ;
2001-09-10 01:33:06 +02:00
if ( sess & & sess - > fd ! = - 1 )
2001-09-08 23:09:55 +02:00
{
err = close ( sess - > fd ) ;
2001-09-09 11:39:24 +02:00
if ( err )
2001-09-08 23:09:55 +02:00
{
zwarn ( " connection close failed: %e " , NULL , errno ) ;
return - 1 ;
}
2001-09-10 01:33:06 +02:00
zts_delete ( sess ) ;
2001-06-12 17:57:25 +02:00
return 0 ;
}
2001-09-08 23:09:55 +02:00
2001-09-10 01:33:06 +02:00
zts_delete ( sess ) ;
2001-09-08 23:09:55 +02:00
return - 1 ;
2001-06-12 17:57:25 +02:00
}
/**/
mod_export int
tcp_connect ( Tcp_session sess , char * addrp , struct hostent * zhost , int d_port )
{
2001-06-15 15:01:42 +02:00
int salen ;
2001-06-12 17:57:25 +02:00
# ifdef SUPPORT_IPV6
2001-09-09 11:39:24 +02:00
if ( zhost - > h_addrtype = = AF_INET6 ) {
2001-06-12 17:57:25 +02:00
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
2001-06-15 15:01:42 +02:00
salen = sizeof ( struct sockaddr_in6 ) ;
2001-06-12 17:57:25 +02:00
} else
# endif /* SUPPORT_IPV6 */
{
memcpy ( & ( sess - > peer . in . sin_addr ) , addrp , zhost - > h_length ) ;
sess - > peer . in . sin_port = d_port ;
2001-09-08 23:09:55 +02:00
sess - > peer . a . sa_family = zhost - > h_addrtype ;
2001-06-15 15:01:42 +02:00
salen = sizeof ( struct sockaddr_in ) ;
2001-06-12 17:57:25 +02:00
}
2001-06-15 15:01:42 +02:00
return connect ( sess - > fd , ( struct sockaddr * ) & ( sess - > peer ) , salen ) ;
2001-06-11 16:21:57 +02:00
}
2001-09-08 23:09:55 +02:00
static int
bin_ztcp ( char * nam , char * * args , char * ops , int func )
{
2001-10-08 09:19:35 +02:00
int herrno , err = 1 , destport , force = 0 , verbose = 0 , test = 0 , targetfd = 0 ;
SOCKLEN_T len ;
2001-09-10 21:19:15 +02:00
char * * addrp , * desthost , * localname , * remotename , * * dargs ;
2001-09-09 11:39:24 +02:00
struct hostent * zthost = NULL , * ztpeer = NULL ;
2001-09-10 00:08:55 +02:00
struct servent * srv ;
2001-09-10 04:41:20 +02:00
Tcp_session sess = NULL ;
2001-09-08 23:09:55 +02:00
if ( ops [ ' f ' ] )
2001-09-10 04:17:55 +02:00
force = 1 ;
2001-09-09 00:08:04 +02:00
if ( ops [ ' v ' ] )
2001-09-10 04:17:55 +02:00
verbose = 1 ;
if ( ops [ ' t ' ] )
test = 1 ;
2001-09-10 17:23:37 +02:00
if ( ops [ ' d ' ] ) {
2001-09-10 21:19:15 +02:00
targetfd = atoi ( args [ 0 ] ) ;
dargs = args + 1 ;
2001-09-10 17:23:37 +02:00
if ( ! targetfd ) {
zwarnnam ( nam , " %s is an invalid argument to -d " , args [ 0 ] , 0 ) ;
return 1 ;
}
}
2001-09-10 21:19:15 +02:00
else
dargs = args ;
2001-09-10 17:23:37 +02:00
2001-09-08 23:09:55 +02:00
if ( ops [ ' c ' ] ) {
2001-09-10 21:19:15 +02:00
if ( ! dargs [ 0 ] ) {
2001-09-08 23:09:55 +02:00
tcp_cleanup ( ) ;
}
else {
2001-09-10 21:19:15 +02:00
targetfd = atoi ( dargs [ 0 ] ) ;
2001-09-08 23:09:55 +02:00
sess = zts_byfd ( targetfd ) ;
2001-09-10 17:23:37 +02:00
if ( ! targetfd ) {
2001-09-10 21:19:15 +02:00
zwarnnam ( nam , " %s is an invalid argument to -c " , dargs [ 0 ] , 0 ) ;
2001-09-10 17:23:37 +02:00
return 1 ;
}
2001-09-08 23:09:55 +02:00
2001-09-09 11:39:24 +02:00
if ( sess )
2001-09-08 23:09:55 +02:00
{
2001-09-09 11:39:24 +02:00
if ( ( sess - > flags & ZTCP_ZFTP ) & & ! force )
2001-09-08 23:09:55 +02:00
{
zwarnnam ( nam , " use -f to force closure of a zftp control connection " , NULL , 0 ) ;
return 1 ;
}
tcp_close ( sess ) ;
return 0 ;
}
else
{
2001-09-10 21:19:15 +02:00
zwarnnam ( nam , " fd %s not found in tcp table " , dargs [ 0 ] , 0 ) ;
2001-09-08 23:09:55 +02:00
return 1 ;
}
}
}
2001-09-09 11:39:24 +02:00
else if ( ops [ ' l ' ] ) {
2001-09-10 00:08:55 +02:00
int lport = 0 ;
2001-09-09 11:39:24 +02:00
2001-09-10 21:19:15 +02:00
if ( ! dargs [ 0 ] ) {
2001-09-09 11:39:24 +02:00
zwarnnam ( nam , " -l requires an argument " , NULL , 0 ) ;
return 1 ;
}
2001-09-10 00:08:55 +02:00
2001-09-10 21:19:15 +02:00
srv = getservbyname ( dargs [ 0 ] , " tcp " ) ;
2001-09-10 00:08:55 +02:00
if ( srv )
lport = srv - > s_port ;
else
2001-09-10 21:19:15 +02:00
lport = htons ( atoi ( dargs [ 0 ] ) ) ;
2001-09-10 00:08:55 +02:00
if ( ! lport ) { zwarnnam ( nam , " bad service name or port number " , NULL , 0 ) ;
return 1 ;
2001-09-09 11:39:24 +02:00
}
2001-09-10 01:33:06 +02:00
sess = tcp_socket ( PF_INET , SOCK_STREAM , 0 , ZTCP_LISTEN ) ;
2001-09-09 11:39:24 +02:00
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 ;
2001-09-10 00:08:55 +02:00
sess - > sock . in . sin_port = lport ;
2001-09-09 11:39:24 +02:00
if ( bind ( sess - > fd , ( struct sockaddr * ) & sess - > sock . in , sizeof ( struct sockaddr_in ) ) )
{
zwarnnam ( nam , " could not bind to %s: %e " , " 0.0.0.0 " , 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 ;
}
2001-09-10 17:23:37 +02:00
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 ) ;
}
2001-09-10 01:33:06 +02:00
setiparam ( " REPLY " , sess - > fd ) ;
if ( verbose )
fprintf ( shout , " %d listener is on fd %d \n " , ntohs ( sess - > sock . in . sin_port ) , sess - > fd ) ;
return 0 ;
}
else if ( ops [ ' a ' ] )
{
int lfd , rfd ;
2001-09-10 21:19:15 +02:00
if ( ! dargs [ 0 ] ) {
2001-09-10 01:33:06 +02:00
zwarnnam ( nam , " -a requires an argument " , NULL , 0 ) ;
return 1 ;
}
2001-09-10 21:19:15 +02:00
lfd = atoi ( dargs [ 0 ] ) ;
2001-09-10 01:33:06 +02:00
if ( ! lfd ) {
zwarnnam ( nam , " invalid numerical argument " , NULL , 0 ) ;
return 1 ;
}
sess = zts_byfd ( lfd ) ;
if ( ! sess ) {
2001-09-10 21:19:15 +02:00
zwarnnam ( nam , " fd %s is not registered as a tcp connection " , dargs [ 0 ] , 0 ) ;
2001-09-10 01:33:06 +02:00
return 1 ;
}
if ( ! ( sess - > flags & ZTCP_LISTEN ) )
2001-09-09 11:39:24 +02:00
{
2001-09-10 01:33:06 +02:00
zwarnnam ( nam , " tcp connection not a listener " , NULL , 0 ) ;
2001-09-09 11:39:24 +02:00
return 1 ;
}
2001-09-10 04:17:55 +02:00
if ( test ) {
2001-09-27 17:36:41 +02:00
# if defined(HAVE_POLL) || defined(HAVE_SELECT)
# ifdef HAVE_POLL
2001-09-10 04:17:55 +02:00
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 ;
}
2001-09-27 17:36:41 +02:00
# 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
2001-09-10 04:17:55 +02:00
}
2001-09-10 01:33:06 +02:00
sess = zts_alloc ( ZTCP_INBOUND ) ;
2001-09-09 11:39:24 +02:00
2001-09-10 01:33:06 +02:00
if ( ( rfd = accept ( lfd , ( struct sockaddr * ) & sess - > peer . in , & len ) ) = = - 1 )
2001-09-09 11:39:24 +02:00
{
2001-09-10 01:33:06 +02:00
zwarnnam ( nam , " could not accept connection: %e " , NULL , errno ) ;
tcp_close ( sess ) ;
return 1 ;
2001-09-09 11:39:24 +02:00
}
2001-09-10 17:23:37 +02:00
if ( targetfd ) {
redup ( rfd , targetfd ) ;
sess - > fd = targetfd ;
}
else {
sess - > fd = rfd ;
}
2001-09-09 11:39:24 +02:00
2001-09-10 00:08:55 +02:00
setiparam ( " REPLY " , sess - > fd ) ;
if ( verbose )
fprintf ( shout , " %d is on fd %d \n " , ntohs ( sess - > peer . in . sin_port ) , sess - > fd ) ;
2001-09-09 11:39:24 +02:00
}
2001-09-10 01:33:06 +02:00
else
{
2001-09-08 23:09:55 +02:00
2001-09-10 21:19:15 +02:00
if ( ! dargs [ 0 ] ) {
2001-10-02 04:35:00 +02:00
LinkNode node ;
for ( node = firstnode ( ztcp_sessions ) ; node ; incnode ( node ) )
2001-09-08 23:09:55 +02:00
{
2001-10-02 04:35:00 +02:00
sess = ( Tcp_session ) getdata ( node ) ;
2001-09-09 11:39:24 +02:00
if ( sess - > fd ! = - 1 )
2001-09-08 23:09:55 +02:00
{
2001-09-09 11:39:24 +02:00
zthost = gethostbyaddr ( & ( sess - > sock . in . sin_addr ) , sizeof ( struct sockaddr_in ) , AF_INET ) ;
if ( zthost )
localname = zthost - > h_name ;
else
localname = ztrdup ( inet_ntoa ( sess - > sock . in . sin_addr ) ) ;
ztpeer = gethostbyaddr ( & ( sess - > peer . in . sin_addr ) , sizeof ( struct sockaddr_in ) , AF_INET ) ;
if ( ztpeer )
remotename = ztpeer - > h_name ;
else
remotename = ztrdup ( inet_ntoa ( sess - > sock . in . sin_addr ) ) ;
2001-09-10 01:33:06 +02:00
fprintf ( shout , " %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 " : " " ) ;
2001-09-08 23:09:55 +02:00
}
}
return 0 ;
}
2001-09-10 21:19:15 +02:00
else if ( ! dargs [ 1 ] ) {
2001-09-10 00:08:55 +02:00
destport = htons ( 23 ) ;
2001-09-08 23:09:55 +02:00
}
else {
2001-09-10 00:08:55 +02:00
2001-09-10 21:19:15 +02:00
srv = getservbyname ( dargs [ 1 ] , " tcp " ) ;
2001-09-10 00:08:55 +02:00
if ( srv )
destport = srv - > s_port ;
else
2001-09-10 21:19:15 +02:00
destport = htons ( atoi ( dargs [ 1 ] ) ) ;
2001-09-08 23:09:55 +02:00
}
2001-09-10 21:19:15 +02:00
desthost = ztrdup ( dargs [ 0 ] ) ;
2001-09-08 23:09:55 +02:00
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 ) ;
2001-09-09 11:39:24 +02:00
if ( ! sess ) {
zwarnnam ( nam , " unable to allocate a TCP session slot " , NULL , 0 ) ;
return 1 ;
}
2001-09-08 23:09:55 +02:00
# 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 + + ) {
2001-09-09 11:39:24 +02:00
if ( zthost - > h_length ! = 4 )
2001-09-08 23:09:55 +02:00
zwarnnam ( nam , " address length mismatch " , NULL , 0 ) ;
do {
2001-09-10 00:08:55 +02:00
err = tcp_connect ( sess , * addrp , zthost , destport ) ;
2001-09-08 23:09:55 +02:00
} while ( err & & errno = = EINTR & & ! errflag ) ;
}
2001-09-10 17:23:37 +02:00
if ( err ) {
2001-09-08 23:09:55 +02:00
zwarnnam ( nam , " connection failed: %e " , NULL , errno ) ;
2001-09-10 17:23:37 +02:00
tcp_close ( sess ) ;
}
2001-09-08 23:09:55 +02:00
else
{
2001-09-10 17:23:37 +02:00
if ( targetfd ) {
redup ( sess - > fd , targetfd ) ;
sess - > fd = targetfd ;
}
2001-09-10 00:08:55 +02:00
setiparam ( " REPLY " , sess - > fd ) ;
2001-09-09 11:39:24 +02:00
if ( verbose )
2001-09-09 00:08:04 +02:00
fprintf ( shout , " %s:%d is now on fd %d \n " , desthost , destport , sess - > fd ) ;
2001-09-08 23:09:55 +02:00
}
zsfree ( desthost ) ;
}
return 0 ;
}
static struct builtin bintab [ ] = {
2001-09-10 17:23:37 +02:00
BUILTIN ( " ztcp " , 0 , bin_ztcp , 0 , 3 , 0 , " acdfltv " , NULL ) ,
2001-09-08 23:09:55 +02:00
} ;
2001-06-06 20:53:56 +02:00
/* The load/unload routines required by the zsh library interface */
/**/
int
setup_ ( Module m )
{
return 0 ;
}
/**/
int
boot_ ( Module m )
{
2001-10-02 04:35:00 +02:00
ztcp_sessions = znewlinklist ( ) ;
2001-09-08 23:09:55 +02:00
return ! addbuiltins ( m - > nam , bintab , sizeof ( bintab ) / sizeof ( * bintab ) ) ;
2001-06-06 20:53:56 +02:00
}
2001-09-08 23:09:55 +02:00
2001-06-06 20:53:56 +02:00
/**/
int
cleanup_ ( Module m )
{
tcp_cleanup ( ) ;
2001-10-02 04:35:00 +02:00
freelinklist ( ztcp_sessions , ( FreeFunc ) ztcp_free_session ) ;
2001-06-06 20:53:56 +02:00
return 0 ;
}
/**/
int
finish_ ( Module m )
{
return 0 ;
}