openenvutils/commandshell/shell/src/modules/tcp.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // tcp.c - TCP module
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1998-2001 Peter Stephenson
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Peter Stephenson or the Zsh Development
       
    18  * Group be liable to any party for direct, indirect, special, incidental,
       
    19  * or consequential damages arising out of the use of this software and
       
    20  * its documentation, even if Peter Stephenson, and the Zsh
       
    21  * Development Group have been advised of the possibility of such damage.
       
    22  *
       
    23  * Peter Stephenson and the Zsh Development Group specifically
       
    24  * disclaim any warranties, including, but not limited to, the implied
       
    25  * warranties of merchantability and fitness for a particular purpose.  The
       
    26  * software provided hereunder is on an "as is" basis, and Peter Stephenson
       
    27  * and the Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 
       
    32 /*
       
    33  * We need to include the zsh headers later to avoid clashes with
       
    34  * the definitions on some systems, however we need the configuration
       
    35  * file to decide whether we can include netinet/in_systm.h, which
       
    36  * doesn't exist on cygwin.
       
    37  */
       
    38 
       
    39 #include "tcp.h"
       
    40 #include "tcp.mdh"
       
    41 
       
    42 #ifdef __SYMBIAN32__
       
    43 #ifdef __WINSCW__
       
    44 #pragma warn_unusedarg off
       
    45 #endif//__WINSCW__
       
    46 #endif//__SYMBIAN32__
       
    47 
       
    48 #ifdef __SYMBIAN32__
       
    49 #include "dummy.h"
       
    50 #endif //__SYMBIAN32__
       
    51 /*
       
    52  * We use poll() in preference to select because some subset of manuals says
       
    53  * that's the thing to do, plus it's a bit less fiddly.  I don't actually
       
    54  * have access to a system with poll but not select, however, though
       
    55  * both bits of the code have been tested on a machine with both.
       
    56  */
       
    57 #ifdef HAVE_POLL_H
       
    58 #ifndef __SYMBIAN32__
       
    59 # include <sys/poll.h>
       
    60 #else
       
    61 # include "poll.h"
       
    62 #endif
       
    63 #endif
       
    64 #if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM)
       
    65 # undef HAVE_POLL
       
    66 #endif
       
    67 
       
    68 #ifdef USE_LOCAL_H_ERRNO
       
    69 int h_errno;
       
    70 #endif
       
    71 
       
    72 /* We use the RFC 2553 interfaces.  If the functions don't exist in the
       
    73  * library, simulate them. */
       
    74 
       
    75 #ifndef INET_ADDRSTRLEN
       
    76 # define INET_ADDRSTRLEN 16
       
    77 #endif
       
    78 
       
    79 #ifndef INET6_ADDRSTRLEN
       
    80 # define INET6_ADDRSTRLEN 46
       
    81 #endif
       
    82 
       
    83 /**/
       
    84 #ifndef HAVE_INET_NTOP
       
    85 
       
    86 /**/
       
    87 mod_export char const *
       
    88 zsh_inet_ntop(int af, void const *cp, char *buf, size_t len)
       
    89 {       
       
    90     if (af != AF_INET) {
       
    91 	errno = EAFNOSUPPORT;
       
    92 	return NULL;
       
    93     } 
       
    94     if (len < INET_ADDRSTRLEN) {
       
    95 	errno = ENOSPC;
       
    96 	return NULL;
       
    97     }
       
    98     strcpy(buf, inet_ntoa(*(struct in_addr *)cp));
       
    99     return buf;
       
   100 }
       
   101 
       
   102 /**/
       
   103 #else /* !HAVE_INET_NTOP */
       
   104 
       
   105 /**/
       
   106 # define zsh_inet_ntop inet_ntop
       
   107 
       
   108 /**/
       
   109 #endif /* !HAVE_INET_NTOP */
       
   110 
       
   111 /**/
       
   112 #ifndef HAVE_INET_ATON
       
   113 
       
   114 # ifndef INADDR_NONE
       
   115 #  define INADDR_NONE 0xffffffffUL
       
   116 # endif
       
   117 
       
   118 /**/
       
   119 mod_export int zsh_inet_aton(char const *src, struct in_addr *dst)
       
   120 {
       
   121     return (dst->s_addr = inet_addr(src)) != INADDR_NONE;
       
   122 }
       
   123 
       
   124 /**/
       
   125 #else /* !HAVE_INET_ATON */
       
   126 
       
   127 /**/
       
   128 # define zsh_inet_aton inet_aton
       
   129 
       
   130 /**/
       
   131 #endif /* !HAVE_INET_ATON */
       
   132 
       
   133 /**/
       
   134 #ifndef HAVE_INET_PTON
       
   135 
       
   136 /**/
       
   137 mod_export int
       
   138 zsh_inet_pton(int af, char const *src, void *dst)
       
   139 {
       
   140     if (af != AF_INET) {
       
   141 	errno = EAFNOSUPPORT;
       
   142 	return -1;
       
   143     }
       
   144     return !!zsh_inet_aton(src, dst);
       
   145 }
       
   146 
       
   147 #else /* !HAVE_INET_PTON */
       
   148 
       
   149 # define zsh_inet_pton inet_pton
       
   150 
       
   151 /**/
       
   152 #endif /* !HAVE_INET_PTON */
       
   153 
       
   154 /**/
       
   155 #ifndef HAVE_GETIPNODEBYNAME
       
   156 
       
   157 /**/
       
   158 # ifndef HAVE_GETHOSTBYNAME2
       
   159 
       
   160 /**/
       
   161 mod_export struct hostent *
       
   162 zsh_gethostbyname2(char const *name, int af)
       
   163 {
       
   164     if (af != AF_INET) {
       
   165 	h_errno = NO_RECOVERY;
       
   166 	return NULL;
       
   167     }
       
   168     return gethostbyname(name);
       
   169 }
       
   170 
       
   171 /**/
       
   172 #else /* !HAVE_GETHOSTBYNAME2 */
       
   173 
       
   174 /**/
       
   175 # define zsh_gethostbyname2 gethostbyname2
       
   176 
       
   177 /**/
       
   178 # endif /* !HAVE_GETHOSTBYNAME2 */
       
   179 
       
   180 /* note: this is not a complete implementation.  If ignores the flags,
       
   181    and does not provide the memory allocation of the standard interface.
       
   182    Each returned structure will overwrite the previous one. */
       
   183 
       
   184 /**/
       
   185 mod_export struct hostent *
       
   186 zsh_getipnodebyname(char const *name, int af, UNUSED(int flags), int *errorp)
       
   187 {
       
   188     static struct hostent ahe;
       
   189     static char nbuf[16];
       
   190     static char *addrlist[] = { nbuf, NULL };
       
   191 # ifdef SUPPORT_IPV6
       
   192     static char pbuf[INET6_ADDRSTRLEN];
       
   193 # else
       
   194     static char pbuf[INET_ADDRSTRLEN];
       
   195 # endif
       
   196     struct hostent *he;
       
   197     if (zsh_inet_pton(af, name, nbuf) == 1) {
       
   198 	zsh_inet_ntop(af, nbuf, pbuf, sizeof(pbuf));
       
   199 	ahe.h_name = pbuf;
       
   200 	ahe.h_aliases = addrlist+1;
       
   201 	ahe.h_addrtype = af;
       
   202 	ahe.h_length = (af == AF_INET) ? 4 : 16;
       
   203 	ahe.h_addr_list = addrlist;
       
   204 	return &ahe;
       
   205     }
       
   206     he = (struct hostent *)zsh_gethostbyname2(name, af);
       
   207     if (!he)
       
   208 	*errorp = h_errno;
       
   209     return he;
       
   210 }
       
   211 
       
   212 /**/
       
   213 mod_export void
       
   214 freehostent(UNUSED(struct hostent *ptr))
       
   215 {
       
   216 }
       
   217 
       
   218 /**/
       
   219 #else /* !HAVE_GETIPNODEBYNAME */
       
   220 
       
   221 /**/
       
   222 # define zsh_getipnodebyname getipnodebyname
       
   223 
       
   224 /**/
       
   225 #endif /* !HAVE_GETIPNODEBYNAME */
       
   226 
       
   227 LinkList ztcp_sessions;
       
   228 
       
   229 /* "allocate" a tcp_session */
       
   230 static Tcp_session
       
   231 zts_alloc(int ztflags)
       
   232 {
       
   233     Tcp_session sess;
       
   234 
       
   235     sess = (Tcp_session)zshcalloc(sizeof(struct tcp_session));
       
   236     if (!sess) return NULL;
       
   237     sess->fd=-1;
       
   238     sess->flags=ztflags;
       
   239 
       
   240     zinsertlinknode(ztcp_sessions, lastnode(ztcp_sessions), (void *)sess);
       
   241 
       
   242     return sess;
       
   243 }
       
   244 
       
   245 /**/
       
   246 mod_export Tcp_session
       
   247 tcp_socket(int domain, int type, int protocol, int ztflags)
       
   248 {
       
   249     Tcp_session sess;
       
   250 
       
   251     sess = zts_alloc(ztflags);
       
   252     if (!sess) return NULL;
       
   253 
       
   254     sess->fd = socket(domain, type, protocol);
       
   255     return sess;
       
   256 }
       
   257 
       
   258 static int
       
   259 ztcp_free_session(Tcp_session sess)
       
   260 {
       
   261     zfree(sess, sizeof(struct tcp_session));
       
   262 
       
   263     return 0;
       
   264 }
       
   265 
       
   266 static int
       
   267 zts_delete(Tcp_session sess)
       
   268 {
       
   269     LinkNode node;
       
   270 
       
   271     node = linknodebydatum(ztcp_sessions, (void *)sess);
       
   272 
       
   273     if (!node)
       
   274     {
       
   275 	return 1;
       
   276     }
       
   277 
       
   278     ztcp_free_session(getdata(node));
       
   279     remnode(ztcp_sessions, node);
       
   280 
       
   281     return 0;
       
   282 }
       
   283 
       
   284 static Tcp_session
       
   285 zts_byfd(int fd)
       
   286 {
       
   287     LinkNode node;
       
   288     
       
   289     for (node = firstnode(ztcp_sessions); node; incnode(node))
       
   290 	if (((Tcp_session)getdata(node))->fd == fd)
       
   291 	    return (Tcp_session)getdata(node);
       
   292     
       
   293     return NULL;
       
   294 }
       
   295 
       
   296 static void
       
   297 tcp_cleanup(void)
       
   298 {
       
   299     LinkNode node, next;
       
   300 
       
   301     for (node = firstnode(ztcp_sessions); node; node = next) {
       
   302 	next = node->next;
       
   303 	tcp_close((Tcp_session)getdata(node));
       
   304     }
       
   305 }
       
   306 
       
   307 /**/
       
   308 mod_export int
       
   309 tcp_close(Tcp_session sess)
       
   310 {
       
   311     int err;
       
   312     
       
   313     if (sess)
       
   314     {  
       
   315 	if (sess->fd != -1)
       
   316 	{
       
   317 	    err = close(sess->fd);
       
   318 	    if (err)
       
   319 		zwarn("connection close failed: %e", NULL, errno);
       
   320 	}
       
   321 	zts_delete(sess);
       
   322 	return 0;
       
   323     }
       
   324 
       
   325     return -1;
       
   326 }
       
   327 
       
   328 /**/
       
   329 mod_export int
       
   330 tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port)
       
   331 {
       
   332     int salen;
       
   333 #ifdef SUPPORT_IPV6
       
   334     if (zhost->h_addrtype==AF_INET6) {
       
   335 	memcpy(&(sess->peer.in6.sin6_addr), addrp, zhost->h_length);
       
   336 	sess->peer.in6.sin6_port = d_port;
       
   337 	sess->peer.in6.sin6_flowinfo = 0;
       
   338 # ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
       
   339 	sess->peer.in6.sin6_scope_id = 0;
       
   340 # endif
       
   341 	sess->peer.in6.sin6_family = zhost->h_addrtype;
       
   342 	salen = sizeof(struct sockaddr_in6);
       
   343     } else
       
   344 #endif /* SUPPORT_IPV6 */
       
   345     {
       
   346 	memcpy(&(sess->peer.in.sin_addr), addrp, zhost->h_length);
       
   347 	sess->peer.in.sin_port = d_port;
       
   348 	sess->peer.in.sin_family = zhost->h_addrtype;
       
   349 	salen = sizeof(struct sockaddr_in);
       
   350     }
       
   351 
       
   352     return connect(sess->fd, (struct sockaddr *)&(sess->peer), salen);
       
   353 }
       
   354 
       
   355 static int
       
   356 bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
       
   357 {
       
   358     int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0;
       
   359     ZSOCKLEN_T  len;
       
   360     char **addrp, *desthost, *localname, *remotename;
       
   361     struct hostent *zthost = NULL, *ztpeer = NULL;
       
   362     struct servent *srv;
       
   363     Tcp_session sess = NULL;
       
   364 
       
   365     if (OPT_ISSET(ops,'f'))
       
   366 	force = 1;
       
   367 
       
   368     if (OPT_ISSET(ops,'v'))
       
   369 	verbose = 1;
       
   370 
       
   371     if (OPT_ISSET(ops,'t'))
       
   372         test = 1;
       
   373 
       
   374     if (OPT_ISSET(ops,'d')) {
       
   375 	targetfd = atoi(OPT_ARG(ops,'d'));
       
   376 	if (!targetfd) {
       
   377 	    zwarnnam(nam, "%s is an invalid argument to -d",
       
   378 		     OPT_ARG(ops,'d'), 0);
       
   379 	    return 1;
       
   380 	}
       
   381     }
       
   382 
       
   383 
       
   384     if (OPT_ISSET(ops,'c')) {
       
   385 	if (!args[0]) {
       
   386 	    tcp_cleanup();
       
   387 	}
       
   388 	else {
       
   389 	    targetfd = atoi(args[0]);
       
   390 	    sess = zts_byfd(targetfd);
       
   391 	    if(!targetfd) {
       
   392 		zwarnnam(nam, "%s is an invalid argument to -c", args[0], 0);
       
   393 		return 1;
       
   394 	    }
       
   395 
       
   396 	    if (sess)
       
   397 	    {
       
   398 		if ((sess->flags & ZTCP_ZFTP) && !force)
       
   399 		{
       
   400 		    zwarnnam(nam, "use -f to force closure of a zftp control connection", NULL, 0);
       
   401 		    return 1;
       
   402 		}
       
   403 		tcp_close(sess);
       
   404 		return 0;
       
   405 	    }
       
   406 	    else
       
   407 	    {
       
   408 		zwarnnam(nam, "fd %s not found in tcp table", args[0], 0);
       
   409 		return 1;
       
   410 	    }
       
   411 	}
       
   412     }
       
   413     else if (OPT_ISSET(ops,'l')) {
       
   414 	int lport = 0;
       
   415 
       
   416 	if (!args[0]) {
       
   417 	    zwarnnam(nam, "-l requires an argument", NULL, 0);
       
   418 	    return 1;
       
   419 	}
       
   420 
       
   421 	srv = getservbyname(args[0], "tcp");
       
   422 	if (srv)
       
   423 	    lport = srv->s_port;
       
   424 	else
       
   425 	    lport = htons(atoi(args[0]));
       
   426 	if (!lport) { zwarnnam(nam, "bad service name or port number", NULL, 0);
       
   427 	return 1;
       
   428 	}
       
   429 	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN);
       
   430 
       
   431 	if (!sess) {
       
   432 	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
       
   433 	    return 1;
       
   434 	}
       
   435 #ifdef SO_OOBINLINE
       
   436 	len = 1;
       
   437 	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
       
   438 #endif
       
   439 
       
   440 #ifndef __SYMBIAN32__
       
   441 	if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr)))
       
   442 	{
       
   443 	    zwarnnam(nam, "bad address: %s", "0.0.0.0", 0);
       
   444 	    return 1;
       
   445 	}
       
   446 
       
   447 #endif//__SYMBIAN32__
       
   448 
       
   449 	sess->sock.in.sin_family = AF_INET;
       
   450 	sess->sock.in.sin_port = lport;
       
   451 
       
   452 
       
   453 	if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in)))
       
   454 	{
       
   455 	    char buf[DIGBUFSIZE];
       
   456 	    convbase(buf, (zlong)lport, 10);
       
   457 	    zwarnnam(nam, "could not bind to port %s: %e", buf, errno);
       
   458 	    tcp_close(sess);
       
   459 	    return 1;
       
   460 	}
       
   461 
       
   462 	if (listen(sess->fd, 1))
       
   463 	{
       
   464 	    zwarnnam(nam, "could not listen on socket: %e", NULL, errno);
       
   465 	    tcp_close(sess);
       
   466 	    return 1;
       
   467 	}
       
   468 
       
   469 	if (targetfd) {
       
   470 	    redup(sess->fd,targetfd);
       
   471 	    sess->fd = targetfd;
       
   472 	}
       
   473 	else {
       
   474 	    /* move the fd since no one will want to read from it */
       
   475 	    sess->fd = movefd(sess->fd);
       
   476 	}
       
   477 
       
   478 	setiparam("REPLY", sess->fd);
       
   479 
       
   480 	if (verbose)
       
   481 	    printf("%d listener is on fd %d\n", ntohs(sess->sock.in.sin_port), sess->fd);
       
   482 
       
   483 	return 0;
       
   484 
       
   485     }
       
   486     else if (OPT_ISSET(ops,'a'))
       
   487     {
       
   488 	int lfd, rfd;
       
   489 
       
   490 	if (!args[0]) {
       
   491 	    zwarnnam(nam, "-a requires an argument", NULL, 0);
       
   492 	    return 1;
       
   493 	}
       
   494 
       
   495 	lfd = atoi(args[0]);
       
   496 
       
   497 	if (!lfd) {
       
   498 	    zwarnnam(nam, "invalid numerical argument", NULL, 0);
       
   499 	    return 1;
       
   500 	}
       
   501 
       
   502 	sess = zts_byfd(lfd);
       
   503 	if (!sess) {
       
   504 	    zwarnnam(nam, "fd %s is not registered as a tcp connection", args[0], 0);
       
   505 	    return 1;
       
   506 	}
       
   507 
       
   508 	if (!(sess->flags & ZTCP_LISTEN))
       
   509 	{
       
   510 	    zwarnnam(nam, "tcp connection not a listener", NULL, 0);
       
   511 	    return 1;
       
   512 	}
       
   513 
       
   514 	if (test) {
       
   515 #if defined(HAVE_POLL) || defined(HAVE_SELECT)
       
   516 # ifdef HAVE_POLL
       
   517 	    struct pollfd pfd;
       
   518 	    int ret;
       
   519 
       
   520 	    pfd.fd = lfd;
       
   521 	    pfd.events = POLLIN;
       
   522 	    if ((ret = poll(&pfd, 1, 0)) == 0) return 1;
       
   523 	    else if (ret == -1)
       
   524 	    {
       
   525 		zwarnnam(nam, "poll error: %e", NULL, errno);
       
   526 		return 1;
       
   527 	    }
       
   528 # else
       
   529 	    fd_set rfds;
       
   530 	    struct timeval tv;
       
   531 	    int ret;
       
   532 	    
       
   533 	    FD_ZERO(&rfds);
       
   534 	    FD_SET(lfd, &rfds);
       
   535 	    tv.tv_sec = 0;
       
   536 	    tv.tv_usec = 0;
       
   537 	    
       
   538 	    if ((ret = select(lfd+1, &rfds, NULL, NULL, &tv))) return 1;
       
   539 	    else if (ret == -1)
       
   540 	    {
       
   541 		zwarnnam(nam, "select error: %e", NULL, errno);
       
   542 		return 1;
       
   543 	    }
       
   544 	    
       
   545 # endif
       
   546 	    
       
   547 #else
       
   548 	    zwarnnam(nam, "not currently supported", NULL, 0);
       
   549 	    return 1;
       
   550 #endif
       
   551 	}
       
   552 	sess = zts_alloc(ZTCP_INBOUND);
       
   553 
       
   554 	len = sizeof(sess->peer.in);
       
   555 	if ((rfd = accept(lfd, (struct sockaddr *)&sess->peer.in, &len)) == -1)
       
   556 	{
       
   557 	    zwarnnam(nam, "could not accept connection: %e", NULL, errno);
       
   558 	    tcp_close(sess);
       
   559 	    return 1;
       
   560 	}
       
   561 
       
   562 	if (targetfd) {
       
   563 	    redup(rfd, targetfd);
       
   564 	    sess->fd = targetfd;
       
   565 	}
       
   566 	else {
       
   567 	    sess->fd = rfd;
       
   568 	}
       
   569 
       
   570 	setiparam("REPLY", sess->fd);
       
   571 
       
   572 	if (verbose)
       
   573 	    printf("%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd);
       
   574     }
       
   575     else
       
   576     {
       
   577 	if (!args[0]) {
       
   578 	    LinkNode node;
       
   579 	    for(node = firstnode(ztcp_sessions); node; incnode(node))
       
   580 	    {
       
   581 		sess = (Tcp_session)getdata(node);
       
   582 
       
   583 		if (sess->fd != -1)
       
   584 		{
       
   585 		    zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET);
       
   586 		    if (zthost)
       
   587 			localname = zthost->h_name;
       
   588 		    else
       
   589 			localname = ztrdup(inet_ntoa(sess->sock.in.sin_addr));
       
   590 		    ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET);
       
   591 		    if (ztpeer)
       
   592 			remotename = ztpeer->h_name;
       
   593 		    else
       
   594 			remotename = ztrdup(inet_ntoa(sess->peer.in.sin_addr));
       
   595 		    if (OPT_ISSET(ops,'L')) {
       
   596 			int schar;
       
   597 			if (sess->flags & ZTCP_ZFTP)
       
   598 			    schar = 'Z';
       
   599 			else if (sess->flags & ZTCP_LISTEN)
       
   600 			    schar = 'L';
       
   601 			else if (sess->flags & ZTCP_INBOUND)
       
   602 			    schar = 'I';
       
   603 			else
       
   604 			    schar = 'O';
       
   605 			printf("%d %c %s %d %s %d\n",
       
   606 			       sess->fd, schar,
       
   607 			       localname, ntohs(sess->sock.in.sin_port),
       
   608 			       remotename, ntohs(sess->peer.in.sin_port));
       
   609 		    } else {
       
   610 			printf("%s:%d %s %s:%d is on fd %d%s\n",
       
   611 			       localname, ntohs(sess->sock.in.sin_port),
       
   612 			       ((sess->flags & ZTCP_LISTEN) ? "-<" :
       
   613 				((sess->flags & ZTCP_INBOUND) ? "<-" : "->")),
       
   614 			       remotename, ntohs(sess->peer.in.sin_port),
       
   615 			       sess->fd,
       
   616 			       (sess->flags & ZTCP_ZFTP) ? " ZFTP" : "");
       
   617 		    }
       
   618 		}
       
   619 	    }
       
   620 	    return 0;
       
   621 	}
       
   622 	else if (!args[1]) {
       
   623 	    destport = htons(23);
       
   624 	}
       
   625 	else {
       
   626 
       
   627 	    srv = getservbyname(args[1],"tcp");
       
   628 	    if (srv)
       
   629 		destport = srv->s_port;
       
   630 	    else
       
   631 		destport = htons(atoi(args[1]));
       
   632 	}
       
   633 	
       
   634 	desthost = ztrdup(args[0]);
       
   635 	
       
   636 	zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno);
       
   637 	if (!zthost || errflag) {
       
   638 	    zwarnnam(nam, "host resolution failure: %s", desthost, 0);
       
   639 	    return 1;
       
   640 	}
       
   641 	
       
   642 	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);
       
   643 
       
   644 	if (!sess) {
       
   645 	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
       
   646 	    return 1;
       
   647 	}
       
   648 
       
   649 #ifdef SO_OOBINLINE
       
   650 	len = 1;
       
   651 	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
       
   652 #endif
       
   653 
       
   654 	if (sess->fd < 0) {
       
   655 	    zwarnnam(nam, "socket creation failed: %e", NULL, errno);
       
   656 	    zsfree(desthost);
       
   657 	    zts_delete(sess);
       
   658 	    return 1;
       
   659 	}
       
   660 	
       
   661 	for (addrp = zthost->h_addr_list; err && *addrp; addrp++) {
       
   662 	    if (zthost->h_length != 4)
       
   663 		zwarnnam(nam, "address length mismatch", NULL, 0);
       
   664 	    do {
       
   665 		err = tcp_connect(sess, *addrp, zthost, destport);
       
   666 	    } while (err && errno == EINTR && !errflag);
       
   667 	}
       
   668 	
       
   669 	if (err) {
       
   670 	    zwarnnam(nam, "connection failed: %e", NULL, errno);
       
   671 	    tcp_close(sess);
       
   672 	    zsfree(desthost);
       
   673 	    return 1;
       
   674 	}
       
   675 	else
       
   676 	{
       
   677 	    if (targetfd) {
       
   678 		redup(sess->fd, targetfd);
       
   679 		sess->fd = targetfd;
       
   680 	    }
       
   681 
       
   682 	    setiparam("REPLY", sess->fd);
       
   683 
       
   684 	    if (verbose)
       
   685 		printf("%s:%d is now on fd %d\n",
       
   686 			desthost, destport, sess->fd);
       
   687 	}
       
   688 	
       
   689 	zsfree(desthost);
       
   690     }
       
   691 
       
   692     return 0;
       
   693 }
       
   694 
       
   695 static struct builtin bintab[] = {
       
   696     BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acd:flLtv", NULL),
       
   697 };
       
   698 
       
   699 /* The load/unload routines required by the zsh library interface */
       
   700 
       
   701 /**/
       
   702 int
       
   703 setup_(UNUSED(Module m))
       
   704 {
       
   705     return 0;
       
   706 }
       
   707 
       
   708 /**/
       
   709 int
       
   710 boot_(Module m)
       
   711 {
       
   712     ztcp_sessions = znewlinklist();
       
   713     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   714 }
       
   715 
       
   716 
       
   717 /**/
       
   718 int
       
   719 cleanup_(Module m)
       
   720 {
       
   721     tcp_cleanup();
       
   722     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   723     freelinklist(ztcp_sessions, (FreeFunc) ztcp_free_session);
       
   724     return 0;
       
   725 }
       
   726 
       
   727 /**/
       
   728 int
       
   729 finish_(UNUSED(Module m))
       
   730 {
       
   731     return 0;
       
   732 }