| /* |
| tcp.c - tcp handling for lrzsz |
| Copyright (C) 1997 Uwe Ohse |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| originally written by Uwe Ohse |
| */ |
| |
| #include "config.h" |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <netdb.h> |
| #ifdef HAVE_ARPA_INET_H |
| #include <arpa/inet.h> |
| #endif |
| #include <errno.h> |
| #include <ctype.h> |
| #include <stdio.h> |
| #include <signal.h> |
| |
| #include "zglobal.h" |
| #include <stdlib.h> |
| #include "error.h" |
| |
| static RETSIGTYPE |
| tcp_alarm_handler(int dummy) |
| { |
| dummy++; /* doesn't need to do anything */ |
| } |
| |
| typedef union { |
| struct sockaddr sa; |
| struct sockaddr_in in; |
| } sock_addr; |
| |
| /* server/lsz: |
| * Get a TCP socket, bind it, listen, figure out the port, |
| * and build the magic string for lrz in "buf". |
| */ |
| int |
| tcp_server (char *buf) |
| { |
| int sock; |
| sock_addr s; |
| sock_addr t; |
| int on=1; |
| socklen_t len; |
| |
| if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { |
| error(1,errno,"socket"); |
| } |
| if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { |
| error(1,errno,"setsockopt (reuse address)"); |
| } |
| memset (&s, 0, sizeof (s)); |
| s.in.sin_family = AF_INET; |
| s.in.sin_port=0; /* let system fill it in */ |
| s.in.sin_addr.s_addr=htonl(INADDR_ANY); |
| if (bind(sock, &s.sa, sizeof (s)) < 0) { |
| error(1,errno,"bind"); |
| } |
| len=sizeof(t); |
| if (getsockname (sock, &t.sa, &len)) { |
| error(1,errno,"getsockname"); |
| } |
| sprintf(buf,"[%s] <%d>\n",inet_ntoa(t.in.sin_addr),ntohs(t.in.sin_port)); |
| |
| if (listen(sock, 1) < 0) { |
| error(1,errno,"listen"); |
| } |
| getsockname (sock, &t.sa, &len); |
| |
| return (sock); |
| } |
| |
| /* server/lsz: accept a connection */ |
| int |
| tcp_accept (int d) |
| { |
| int so; |
| sock_addr s; |
| socklen_t namelen; |
| int num=0; |
| |
| namelen = sizeof(s); |
| memset((char*)&s,0, namelen); |
| |
| retry: |
| signal(SIGALRM, tcp_alarm_handler); |
| alarm(30); |
| if ((so = accept(d, &s.sa, &namelen)) < 0) { |
| if (errno == EINTR) { |
| if (++num<=5) |
| goto retry; |
| } |
| error(1,errno,"accept"); |
| } |
| alarm(0); |
| return so; |
| } |
| |
| /* client/lrz: |
| * "Connect" to the TCP socket decribed in "buf" and |
| * return the connected socket. |
| */ |
| int |
| tcp_connect (char *buf) |
| { |
| int sock; |
| sock_addr s_in; |
| char *p; |
| char *q; |
| |
| memset(&s_in,0,sizeof(s_in)); |
| s_in.in.sin_family = AF_INET; |
| |
| /* i _really_ distrust scanf & co. Or maybe i distrust bad input */ |
| if (*buf!='[') { |
| error(1,0,_("tcp_connect: illegal format1\n")); |
| } |
| p=strchr(buf+1,']'); |
| if (!p) { |
| error(1,0,_("tcp_connect: illegal format2\n")); |
| } |
| *p++=0; |
| s_in.in.sin_addr.s_addr=inet_addr(buf+1); |
| #ifndef INADDR_NONE |
| #define INADDR_NONE (-1) |
| #endif |
| if (s_in.in.sin_addr.s_addr== (unsigned long) INADDR_NONE) { |
| struct hostent *h=gethostbyname(buf+1); |
| if (!h) |
| error(1,0,_("tcp_connect: illegal format3\n")); |
| memcpy(& s_in.in.sin_addr.s_addr,h->h_addr,h->h_length); |
| } |
| while (isspace((unsigned char)(*p))) |
| p++; |
| if (*p!='<') { |
| error(1,0,_("tcp_connect: illegal format4\n")); |
| } |
| q=strchr(p+1,'>'); |
| if (!q) |
| error(1,0,_("tcp_connect: illegal format5\n")); |
| s_in.in.sin_port = htons(strtol(p+1,NULL,10)); |
| |
| if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { |
| error(1,errno,"socket"); |
| } |
| |
| signal(SIGALRM, tcp_alarm_handler); |
| alarm(30); |
| if (connect (sock, &s_in.sa, sizeof (s_in)) < 0) { |
| error(1,errno,"connect"); |
| } |
| alarm(0); |
| return (sock); |
| } |