source: trunk/minix/commands/ftp/net.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 8.3 KB
Line 
1/* net.c
2 *
3 * This file is part of ftp.
4 *
5 *
6 * 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.com>
7 */
8
9#include <sys/types.h>
10#include <sys/ioctl.h>
11#include <sys/wait.h>
12#include <stdio.h>
13#include <unistd.h>
14#include <string.h>
15#include <unistd.h>
16#include <stdlib.h>
17#include <fcntl.h>
18#include <signal.h>
19#include <errno.h>
20#include <net/netlib.h>
21#include <net/hton.h>
22#include <net/gen/netdb.h>
23#include <net/gen/in.h>
24#include <net/gen/inet.h>
25#include <net/gen/tcp.h>
26#include <net/gen/tcp_io.h>
27
28#include "ftp.h"
29#include "file.h"
30#include "net.h"
31
32_PROTOTYPE(void donothing, (int sig));
33
34static int ftpcomm_fd;
35static ipaddr_t myip;
36static ipaddr_t hostip;
37static char host[256];
38static int lpid;
39
40void NETinit()
41{
42int s;
43char *tcp_device;
44int tcp_fd;
45nwio_tcpconf_t nwio_tcpconf;
46
47 /* All this just to get our ip address */
48
49 if((tcp_device = getenv("TCP_DEVICE")) == (char *)NULL)
50 tcp_device = TCP_DEVICE;
51
52 tcp_fd = open(tcp_device, O_RDWR);
53 if(tcp_fd < 0) {
54 perror("ftp: Could not open tcp_device");
55 exit(-1);
56 }
57 s = ioctl(tcp_fd, NWIOGTCPCONF, &nwio_tcpconf);
58 if(s < 0) {
59 perror("ftp: Could not get tcp configuration");
60 exit(-1);
61 }
62
63 myip = nwio_tcpconf.nwtc_locaddr;
64
65 close(tcp_fd);
66}
67
68int DOopen()
69{
70nwio_tcpconf_t tcpconf;
71nwio_tcpcl_t tcpcopt;
72char *tcp_device;
73tcpport_t port;
74int s;
75struct hostent *hp;
76struct servent *servent;
77
78 if(linkopen) {
79 printf("Use \"CLOSE\" to close the connection first.\n");
80 return(0);
81 }
82
83 if(cmdargc < 2)
84 readline("Host: ", host, sizeof(host));
85 else
86 strncpy(host, cmdargv[1], sizeof(host));
87
88 if((servent = getservbyname("ftp", "tcp")) == (struct servent *)NULL) {
89 fprintf(stderr, "ftp: Could not find ftp tcp service\n");
90 return(-1);
91 }
92 port = (tcpport_t)servent->s_port;
93
94 hp = gethostbyname(host);
95 if (hp == (struct hostent *)NULL) {
96 hostip = (ipaddr_t)0;
97 printf("Unresolved host %s\n", host);
98 return(0);
99 } else
100 memcpy((char *) &hostip, (char *) hp->h_addr, hp->h_length);
101
102 /* This HACK allows the server to establish data connections correctly */
103 /* when using the loopback device to talk to ourselves */
104 if(hostip == inet_addr("127.0.0.1"))
105 hostip = myip;
106
107 if((tcp_device = getenv("TCP_DEVICE")) == NULL)
108 tcp_device = "/dev/tcp";
109
110 if((ftpcomm_fd = open(tcp_device, O_RDWR)) < 0) {
111 perror("ftp: open error on tcp device");
112 return(-1);
113 }
114
115 tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
116 tcpconf.nwtc_remaddr = hostip;
117 tcpconf.nwtc_remport = port;
118
119 s = ioctl(ftpcomm_fd, NWIOSTCPCONF, &tcpconf);
120 if(s < 0) {
121 perror("ftp: ioctl error on NWIOSTCPCONF");
122 close(ftpcomm_fd);
123 return(s);
124 }
125
126 tcpcopt.nwtcl_flags = 0;
127
128 s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
129 if(s < 0) {
130 perror("ftp: ioctl error on NWIOTCPCONN");
131 close(ftpcomm_fd);
132 return(s);
133 }
134
135 s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
136 if(s < 0) {
137 perror("ftp: ioctl error on NWIOGTCPCONF");
138 close(ftpcomm_fd);
139 return(s);
140 }
141
142 fpcommin = fdopen(ftpcomm_fd, "r");
143 fpcommout = fdopen(ftpcomm_fd, "w");
144
145 s = DOgetreply();
146
147 if(s < 0) {
148 fclose(fpcommin);
149 fclose(fpcommout);
150 close(ftpcomm_fd);
151 return(s);
152 }
153
154 if(s != 220) {
155 fclose(fpcommin);
156 fclose(fpcommout);
157 close(ftpcomm_fd);
158 return(0);
159 }
160
161 linkopen = 1;
162
163 return(s);
164}
165
166int DOclose()
167{
168 if(!linkopen) {
169 printf("You can't close a connection that isn't open.\n");
170 return(0);
171 }
172
173 fclose(fpcommin);
174 fclose(fpcommout);
175 close(ftpcomm_fd);
176
177 linkopen = 0;
178 loggedin = 0;
179
180 return(0);
181}
182
183int DOquit()
184{
185int s;
186
187 if(linkopen) {
188 s = DOcommand("QUIT", "");
189 s = DOclose();
190 }
191
192 printf("FTP done.\n");
193
194 exit(0);
195}
196
197void donothing(sig)
198int sig;
199{
200}
201
202int DOdata(datacom, file, direction, fd)
203char *datacom;
204char *file;
205int direction; /* RETR or STOR */
206int fd;
207{
208nwio_tcpconf_t tcpconf;
209nwio_tcpcl_t tcplopt, tcpcopt;
210char *tcp_device;
211int ftpdata_fd;
212char *buff;
213ipaddr_t ripaddr;
214tcpport_t rport;
215static tcpport_t lport = HTONS(0xF000);
216int s;
217int i;
218int cs;
219int pfd[2];
220char dummy;
221char port[32];
222
223 ripaddr = hostip;
224 rport = HTONS(20);
225
226 /* here we set up a connection to listen on if not passive mode */
227 /* otherwise we use this to connect for passive mode */
228
229 if((tcp_device = getenv("TCP_DEVICE")) == NULL)
230 tcp_device = "/dev/tcp";
231
232 if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
233 perror("ftp: open error on tcp device");
234 return(-1);
235 }
236
237 if(passive) {
238 s = DOcommand("PASV", "");
239 if(s != 227) {
240 close(ftpdata_fd);
241 return(s);
242 }
243 /* decode host and port */
244 buff = reply;
245 while(*buff && (*buff != '(')) buff++;
246 buff++;
247 ripaddr = (ipaddr_t)0;
248 for(i = 0; i < 4; i++) {
249 ripaddr = (ripaddr << 8) + (ipaddr_t)atoi(buff);
250 if((buff = strchr(buff, ',')) == (char *)0) {
251 printf("Could not parse PASV reply\n");
252 return(-1);
253 }
254 buff++;
255 }
256 rport = (tcpport_t)atoi(buff);
257 if((buff = strchr(buff, ',')) == (char *)0) {
258 printf("Could not parse PASV reply\n");
259 return(-1);
260 }
261 buff++;
262 rport = (rport << 8) + (tcpport_t)atoi(buff);
263 ripaddr = ntohl(ripaddr);
264 rport = ntohs(rport);
265 }
266
267 for (;;) {
268 tcpconf.nwtc_flags = NWTC_SET_RA | NWTC_SET_RP;
269 if (passive || ntohs(lport) >= 0xF000) {
270 tcpconf.nwtc_flags |= NWTC_LP_SEL;
271 } else {
272 /* For no good reason Sun hosts don't like it if they have to
273 * connect to the same port twice in a short time...
274 */
275 lport = htons(ntohs(lport) + 1);
276 tcpconf.nwtc_flags |= NWTC_LP_SET;
277 tcpconf.nwtc_locport = lport;
278 }
279
280 tcpconf.nwtc_remaddr = ripaddr;
281 tcpconf.nwtc_remport = rport;
282
283 s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
284 if(s < 0) {
285 if (errno == EADDRINUSE) continue;
286 perror("ftp: ioctl error on NWIOSTCPCONF");
287 close(ftpdata_fd);
288 return(s);
289 }
290 break;
291 }
292
293 s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
294 if(s < 0) {
295 perror("ftp: ioctl error on NWIOGTCPCONF");
296 close(ftpdata_fd);
297 return(s);
298 }
299 lport = tcpconf.nwtc_locport;
300
301 if(passive) {
302 tcplopt.nwtcl_flags = 0;
303 s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
304 if(s < 0) {
305 perror("ftp: error on ioctl NWIOTCPCONN");
306 close(ftpdata_fd);
307 return(0);
308 }
309 s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
310 if(s < 0) {
311 perror("ftp: error on ioctl NWIOGTCPCONF");
312 close(ftpdata_fd);
313 return(0);
314 }
315 } else {
316 tcplopt.nwtcl_flags = 0;
317
318 if (pipe(pfd) < 0) {
319 perror("ftp: could not create a pipe");
320 return(s);
321 }
322 lpid = fork();
323 if(lpid < 0) {
324 perror("ftp: could not fork listener");
325 close(ftpdata_fd);
326 close(pfd[0]);
327 close(pfd[1]);
328 return(s);
329 } else if(lpid == 0) {
330 close(pfd[0]);
331 signal(SIGALRM, donothing);
332 alarm(15);
333 close(pfd[1]);
334 s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
335 alarm(0);
336 if(s < 0)
337 if(errno == EINTR)
338 exit(1); /* timed out */
339 else
340 exit(-1); /* error */
341 else
342 exit(0); /* connection made */
343 }
344 /* Wait for the pipe to close, then the listener is ready (almost). */
345 close(pfd[1]);
346 (void) read(pfd[0], &dummy, 1);
347 close(pfd[0]);
348 while(1) {
349 signal(SIGALRM, donothing);
350 alarm(1);
351 s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
352 alarm(0);
353 if(s == -1) break;
354 }
355 }
356
357#define hiword(x) ((u16_t)((x) >> 16))
358#define loword(x) ((u16_t)(x & 0xffff))
359#define hibyte(x) (((x) >> 8) & 0xff)
360#define lobyte(x) ((x) & 0xff)
361
362 if(!passive) {
363 sprintf(port, "%u,%u,%u,%u,%u,%u",
364 hibyte(hiword(ntohl(myip))), lobyte(hiword(ntohl(myip))),
365 hibyte(loword(ntohl(myip))), lobyte(loword(ntohl(myip))),
366 hibyte(ntohs(lport)), lobyte(ntohs(lport)));
367 s = DOcommand("PORT", port);
368 if(s != 200) {
369 close(ftpdata_fd);
370 kill(lpid, SIGKILL);
371 return(s);
372 }
373 }
374
375 s = DOcommand(datacom, file);
376 if(s == 125 || s == 150) {
377 if(!passive) {
378 while(1) {
379 s = wait(&cs);
380 if(s < 0 || s == lpid)
381 break;
382 }
383 if(s < 0) {
384 perror("wait error:");
385 close(ftpdata_fd);
386 kill(lpid, SIGKILL);
387 return(s);
388 }
389 if((cs & 0x00ff)) {
390 printf("Child listener failed %04x\n", cs);
391 close(ftpdata_fd);
392 return(-1);
393 }
394 cs = (cs >> 8) & 0x00ff;
395 if(cs == 1) {
396 printf("Child listener timed out\n");
397 return(DOgetreply());
398 } else if(cs) {
399 printf("Child listener returned %02x\n", cs);
400 close(ftpdata_fd);
401 return(-1);
402 }
403 }
404 switch(direction) {
405 case RETR:
406 s = recvfile(fd, ftpdata_fd);
407 break;
408 case STOR:
409 s = sendfile(fd, ftpdata_fd);
410 break;
411 }
412 close(ftpdata_fd);
413 s = DOgetreply();
414 } else {
415 if(!passive)
416 kill(lpid, SIGKILL);
417 close(ftpdata_fd);
418 }
419
420 return(s);
421}
Note: See TracBrowser for help on using the repository browser.