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