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; }
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); /* We'll check failure and tidy up in caller */ addmodulefd(sess->fd, FDT_MODULE); return sess; }
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; const char *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')); 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]); return 1; } if (sess) { if ((sess->flags & ZTCP_ZFTP) && !force) { zwarnnam(nam, "use -f to force closure of a zftp control connection"); return 1; } tcp_close(sess); return 0; } else { zwarnnam(nam, "fd %s not found in tcp table", args[0]); return 1; } } } else if (OPT_ISSET(ops,'l')) { int lport = 0; if (!args[0]) { zwarnnam(nam, "-l requires an argument"); 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"); return 1; } sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN); if (!sess) { zwarnnam(nam, "unable to allocate a TCP session slot"); 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"); 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", errno); tcp_close(sess); return 1; } if (targetfd) { sess->fd = redup(sess->fd, targetfd); } else { /* move the fd since no one will want to read from it */ sess->fd = movefd(sess->fd); } if (sess->fd == -1) { zwarnnam(nam, "cannot duplicate fd %d: %e", sess->fd, errno); tcp_close(sess); return 1; } setiparam_no_convert("REPLY", (zlong)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"); return 1; } lfd = atoi(args[0]); if (!lfd) { zwarnnam(nam, "invalid numerical argument"); return 1; } sess = zts_byfd(lfd); if (!sess) { zwarnnam(nam, "fd %s is not registered as a tcp connection", args[0]); return 1; } if (!(sess->flags & ZTCP_LISTEN)) { zwarnnam(nam, "tcp connection not a listener"); 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", 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)) == 0) return 1; else if (ret == -1) { zwarnnam(nam, "select error: %e", errno); return 1; } # endif #else zwarnnam(nam, "not currently supported"); return 1; #endif } sess = zts_alloc(ZTCP_INBOUND); len = sizeof(sess->peer.in); do { rfd = accept(lfd, (struct sockaddr *)&sess->peer.in, &len); } while (rfd < 0 && errno == EINTR && !errflag); if (rfd == -1) { zwarnnam(nam, "could not accept connection: %e", errno); tcp_close(sess); return 1; } /* redup expects fd is already registered */ addmodulefd(rfd, FDT_MODULE); if (targetfd) { sess->fd = redup(rfd, targetfd); if (sess->fd < 0) { zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); return 1; } } else { sess->fd = rfd; } setiparam_no_convert("REPLY", (zlong)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 = 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 = 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); zsfree(desthost); return 1; } sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0); if (!sess) { zwarnnam(nam, "unable to allocate a TCP session slot"); zsfree(desthost); 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", 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"); do { err = tcp_connect(sess, *addrp, zthost, destport); } while (err && errno == EINTR && !errflag); } if (err) { zwarnnam(nam, "connection failed: %e", errno); tcp_close(sess); zsfree(desthost); return 1; } else { if (targetfd) { sess->fd = redup(sess->fd, targetfd); if (sess->fd < 0) { zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); zsfree(desthost); tcp_close(sess); return 1; } } setiparam_no_convert("REPLY", (zlong)sess->fd); if (verbose) printf("%s:%d is now on fd %d\n", desthost, destport, sess->fd); } zsfree(desthost); } return 0; }