1 /*
2   tcp.c - tcp handling for lrzsz
3   Copyright (C) 1997 Uwe Ohse
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2, or (at your option)
8   any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18   02111-1307, USA.
19 
20   originally written by Uwe Ohse
21 */
22 
23 #include "config.h"
24 
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netdb.h>
29 #ifdef HAVE_ARPA_INET_H
30 #include <arpa/inet.h>
31 #endif
32 #include <errno.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <signal.h>
36 
37 #include "zglobal.h"
38 #include <stdlib.h>
39 #include "error.h"
40 
41 static RETSIGTYPE
tcp_alarm_handler(int dummy LRZSZ_ATTRIB_UNUSED)42 tcp_alarm_handler(int dummy LRZSZ_ATTRIB_UNUSED)
43 {
44     /* doesn't need to do anything */
45 }
46 
47 
48 /* server/lsz:
49  * Get a TCP socket, bind it, listen, figure out the port,
50  * and build the magic string for lrz in "buf".
51  */
52 int
tcp_server(char * buf)53 tcp_server (char *buf)
54 {
55 	int sock;
56 	struct sockaddr_in s;
57 	struct sockaddr_in t;
58 	int on=1;
59 	size_t len;
60 
61 	if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
62 		error(1,errno,"socket");
63 	}
64 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
65 		error(1,errno,"setsockopt (reuse address)");
66 	}
67 	memset (&s, 0, sizeof (s));
68 	s.sin_family = AF_INET;
69 	s.sin_port=0; /* let system fill it in */
70 	s.sin_addr.s_addr=htonl(INADDR_ANY);
71 	if (bind(sock, (struct sockaddr *)&s, sizeof (s)) < 0) {
72 		error(1,errno,"bind");
73 	}
74 	len=sizeof(t);
75 	if (getsockname (sock, (struct sockaddr *) &t, &len)) {
76 		error(1,errno,"getsockname");
77 	}
78 	sprintf(buf,"[%s] <%d>\n",inet_ntoa(t.sin_addr),ntohs(t.sin_port));
79 
80 	if (listen(sock, 1) < 0) {
81 		error(1,errno,"listen");
82 	}
83 	getsockname (sock, (struct sockaddr *) &t, &len);
84 
85 	return (sock);
86 }
87 
88 /* server/lsz: accept a connection */
89 int
tcp_accept(int d)90 tcp_accept (int d)
91 {
92 	int so;
93 	struct  sockaddr_in s;
94 	size_t namelen;
95 	int num=0;
96 
97 	namelen = sizeof(s);
98 	memset((char*)&s,0, namelen);
99 
100 retry:
101 	signal(SIGALRM, tcp_alarm_handler);
102 	alarm(30);
103 	if ((so = accept(d, (struct sockaddr*)&s, &namelen)) < 0) {
104 		if (errno == EINTR) {
105 			if (++num<=5)
106 				goto retry;
107 		}
108 		error(1,errno,"accept");
109 	}
110 	alarm(0);
111 	return so;
112 }
113 
114 /* client/lrz:
115  * "Connect" to the TCP socket decribed in "buf" and
116  * return the connected socket.
117  */
118 int
tcp_connect(char * buf)119 tcp_connect (char *buf)
120 {
121 	int sock;
122 	struct sockaddr_in s_in;
123 	char *p;
124 	char *q;
125 
126 	memset(&s_in,0,sizeof(s_in));
127 	s_in.sin_family = AF_INET;
128 
129 	/* i _really_ distrust scanf & co. Or maybe i distrust bad input */
130 	if (*buf!='[') {
131 		error(1,0,_("tcp_connect: illegal format1\n"));
132 	}
133 	p=strchr(buf+1,']');
134 	if (!p) {
135 		error(1,0,_("tcp_connect: illegal format2\n"));
136 	}
137 	*p++=0;
138 	s_in.sin_addr.s_addr=inet_addr(buf+1);
139 #ifndef INADDR_NONE
140 #define INADDR_NONE (-1)
141 #endif
142 	if (s_in.sin_addr.s_addr== (unsigned long) INADDR_NONE) {
143 		struct hostent *h=gethostbyname(buf+1);
144 		if (!h)
145 			error(1,0,_("tcp_connect: illegal format3\n"));
146 		memcpy(& s_in.sin_addr.s_addr,h->h_addr,h->h_length);
147 	}
148 	while (isspace((unsigned char)(*p)))
149 		p++;
150 	if (*p!='<') {
151 		error(1,0,_("tcp_connect: illegal format4\n"));
152 	}
153 	q=strchr(p+1,'>');
154 	if (!q)
155 		error(1,0,_("tcp_connect: illegal format5\n"));
156 	s_in.sin_port = htons(strtol(p+1,NULL,10));
157 
158 	if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
159 		error(1,errno,"socket");
160 	}
161 
162 	signal(SIGALRM, tcp_alarm_handler);
163 	alarm(30);
164 	if (connect (sock, (struct sockaddr *) &s_in, sizeof (s_in)) < 0) {
165 		error(1,errno,"connect");
166 	}
167 	alarm(0);
168 	return (sock);
169 }
170