tz database is in /usr/share/zoneinfo.
[minix3.git] / commands / ftp101 / net.c
blobb2c9e87dc01dabcabc6fa82c09e95d3c8f5ed741
1 /* net.c Copyright 1992-2000 by Michael Temari All Rights Reserved
3 * This file is part of ftp.
6 * 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
7 */
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>
28 #include "ftp.h"
29 #include "xfer.h"
30 #include "net.h"
32 _PROTOTYPE(void donothing, (int sig));
34 int ftpcomm_fd;
35 static ipaddr_t myip;
36 static ipaddr_t hostip;
37 static char host[256];
38 static int lpid;
40 int NETinit()
42 int s;
43 char *tcp_device;
44 int tcp_fd;
45 nwio_tcpconf_t nwio_tcpconf;
47 /* All this just to get our ip address */
49 if((tcp_device = getenv("TCP_DEVICE")) == (char *)NULL)
50 tcp_device = TCP_DEVICE;
52 tcp_fd = open(tcp_device, O_RDWR);
53 if(tcp_fd < 0) {
54 perror("ftp: Could not open tcp_device");
55 return(-1);
57 s = ioctl(tcp_fd, NWIOGTCPCONF, &nwio_tcpconf);
58 if(s < 0) {
59 perror("ftp: Could not get tcp configuration");
60 return(-1);
63 myip = nwio_tcpconf.nwtc_locaddr;
65 close(tcp_fd);
67 return(0);
70 int DOopen()
72 nwio_tcpconf_t tcpconf;
73 nwio_tcpcl_t tcpcopt;
74 char *tcp_device;
75 tcpport_t port;
76 int s;
77 struct hostent *hp;
78 struct servent *servent;
80 if(linkopen) {
81 printf("Use \"CLOSE\" to close the connection first.\n");
82 return(0);
85 if(cmdargc < 2) {
86 if(readline("Host: ", host, sizeof(host)) < 0)
87 return(-1);
88 } else
89 strncpy(host, cmdargv[1], sizeof(host));
91 if((servent = getservbyname("ftp", "tcp")) == (struct servent *)NULL) {
92 fprintf(stderr, "ftp: Could not find ftp tcp service\n");
93 port = htons(21);
94 } else
95 port = (tcpport_t)servent->s_port;
97 hp = gethostbyname(host);
98 if(hp == (struct hostent *)NULL) {
99 hostip = (ipaddr_t)0;
100 printf("Unresolved host %s\n", host);
101 return(0);
102 } else
103 memcpy((char *) &hostip, (char *) hp->h_addr, hp->h_length);
105 /* This HACK allows the server to establish data connections correctly */
106 /* when using the loopback device to talk to ourselves */
107 if((hostip & NTOHL(0xFF000000)) == inet_addr("127.0.0.0"))
108 hostip = myip;
110 if((tcp_device = getenv("TCP_DEVICE")) == NULL)
111 tcp_device = "/dev/tcp";
113 if((ftpcomm_fd = open(tcp_device, O_RDWR)) < 0) {
114 perror("ftp: open error on tcp device");
115 return(-1);
118 tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
119 tcpconf.nwtc_remaddr = hostip;
120 tcpconf.nwtc_remport = port;
122 s = ioctl(ftpcomm_fd, NWIOSTCPCONF, &tcpconf);
123 if(s < 0) {
124 perror("ftp: ioctl error on NWIOSTCPCONF");
125 close(ftpcomm_fd);
126 return(-1);
129 tcpcopt.nwtcl_flags = 0;
131 s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
132 if(s < 0) {
133 perror("ftp: ioctl error on NWIOTCPCONN");
134 close(ftpcomm_fd);
135 return(-1);
138 s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
139 if(s < 0) {
140 perror("ftp: ioctl error on NWIOGTCPCONF");
141 close(ftpcomm_fd);
142 return(-1);
145 s = DOgetreply();
147 if(s < 0) {
148 close(ftpcomm_fd);
149 return(s);
152 if(s != 220) {
153 close(ftpcomm_fd);
154 return(0);
157 linkopen = 1;
159 return(s);
162 int DOclose()
164 if(!linkopen) {
165 printf("You can't close a connection that isn't open.\n");
166 return(0);
169 close(ftpcomm_fd);
171 linkopen = 0;
172 loggedin = 0;
174 return(0);
177 int DOquit()
179 int s;
181 if(linkopen) {
182 s = DOcommand("QUIT", "");
183 s = DOclose();
186 printf("FTP done.\n");
188 exit(0);
191 void donothing(sig)
192 int sig;
196 int DOdata(datacom, file, direction, fd)
197 char *datacom;
198 char *file;
199 int direction; /* RETR or STOR */
200 int fd;
202 nwio_tcpconf_t tcpconf;
203 nwio_tcpcl_t tcplopt, tcpcopt;
204 char *tcp_device;
205 static int ftpdata_fd = -1;
206 char *buff;
207 ipaddr_t ripaddr;
208 tcpport_t rport;
209 static tcpport_t lport = HTONS(0xF000);
210 int s;
211 int i;
212 int wpid;
213 int cs;
214 int pfd[2];
215 char dummy;
216 char port[32];
217 int wasopen;
219 #ifdef DEBUG
220 printf("DOdata %s %s %d %d\n", datacom, file, direction, fd);
221 #endif
223 ripaddr = hostip;
224 rport = HTONS(20);
226 /* here we set up a connection to listen on if not passive mode */
227 /* otherwise we use this to connect for passive mode */
229 if((tcp_device = getenv("TCP_DEVICE")) == NULL)
230 tcp_device = "/dev/tcp";
232 if(ftpdata_fd >= 0 && mode != MODE_B) {
233 close(ftpdata_fd);
234 ftpdata_fd = -1;
237 wasopen = (ftpdata_fd >= 0);
239 #ifdef DEBUG
240 printf("wasopen = %d\n", wasopen);
241 #endif
243 if(wasopen)
244 goto WASOPEN;
246 #ifdef DEBUG
247 printf("b4 open = %d\n", ftpdata_fd);
248 #endif
250 if(ftpdata_fd == -1)
251 if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
252 perror("ftp: open error on tcp device");
253 return(0);
256 #ifdef DEBUG
257 printf("at open = %d\n", ftpdata_fd);
258 #endif
260 if(passive) {
261 #ifdef DEBUG
262 printf("b4 PASV command\n");
263 #endif
264 s = DOcommand("PASV", "");
265 #ifdef DEBUG
266 printf("PASV command returned %d\n", s);
267 #endif
268 if(s != 227) {
269 close(ftpdata_fd);
270 ftpdata_fd = -1;
271 return(s);
273 /* decode host and port */
274 buff = reply;
275 while(*buff && (*buff != '(')) buff++;
276 buff++;
277 ripaddr = (ipaddr_t)0;
278 for(i = 0; i < 4; i++) {
279 ripaddr = (ripaddr << 8) + (ipaddr_t)atoi(buff);
280 if((buff = strchr(buff, ',')) == (char *)0) {
281 printf("Could not parse PASV reply\n");
282 return(0);
284 buff++;
286 rport = (tcpport_t)atoi(buff);
287 if((buff = strchr(buff, ',')) == (char *)0) {
288 printf("Could not parse PASV reply\n");
289 return(0);
291 buff++;
292 rport = (rport << 8) + (tcpport_t)atoi(buff);
293 ripaddr = ntohl(ripaddr);
294 rport = ntohs(rport);
295 #ifdef DEBUG
296 printf("PASV %08x %04x\n", ripaddr, rport);
297 #endif
300 while(1) {
301 tcpconf.nwtc_flags = NWTC_SET_RA | NWTC_SET_RP;
302 if(passive || ntohs(lport) >= 0xF000) {
303 tcpconf.nwtc_flags |= NWTC_LP_SEL;
304 } else {
305 /* For no good reason Sun hosts don't like it if they have to
306 * connect to the same port twice in a short time...
308 lport = htons(ntohs(lport) + 1);
309 tcpconf.nwtc_flags |= NWTC_LP_SET;
310 tcpconf.nwtc_locport = lport;
313 tcpconf.nwtc_remaddr = ripaddr;
314 tcpconf.nwtc_remport = rport;
316 #ifdef DEBUG
317 printf("b4 STCPCONF locport = %d\n", lport);
318 #endif
320 s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
321 #ifdef DEBUG
322 printf("at STCPCONF %d %d\n", s, errno);
323 #endif
324 if(s < 0) {
325 if(errno == EADDRINUSE) continue;
326 perror("ftp: ioctl error on NWIOSTCPCONF");
327 close(ftpdata_fd);
328 ftpdata_fd = -1;
329 return(0);
331 break;
334 #ifdef DEBUG
335 printf("b4 GTCPCONF\n");
336 #endif
337 s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
338 #ifdef DEBUG
339 printf("at GTCPCONF %d %d\n", s, errno);
340 #endif
341 if(s < 0) {
342 perror("ftp: ioctl error on NWIOGTCPCONF");
343 close(ftpdata_fd);
344 ftpdata_fd = -1;
345 return(0);
347 lport = tcpconf.nwtc_locport;
349 #ifdef DEBUG
350 printf("lport = %04x\n", lport);
351 #endif
353 if(passive) {
354 /* passive mode we connect to them */
355 tcplopt.nwtcl_flags = 0;
356 #ifdef DEBUG
357 printf("Doing TCPCONN\n");
358 #endif
359 s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
360 #ifdef DEBUG
361 printf("TCPCONN %d %d\n", s, errno);
362 #endif
363 if(s < 0) {
364 perror("ftp: error on ioctl NWIOTCPCONN");
365 close(ftpdata_fd);
366 ftpdata_fd = -1;
367 return(0);
369 #ifdef DEBUG
370 printf("GTCPCONF\n");
371 #endif
372 s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
373 #ifdef DEBUG
374 printf("GTCPCONF %d %d\n", s, errno);
375 #endif
376 if(s < 0) {
377 perror("ftp: error on ioctl NWIOGTCPCONF");
378 close(ftpdata_fd);
379 ftpdata_fd = -1;
380 return(0);
382 } else {
383 /* we listen for them */
384 tcplopt.nwtcl_flags = 0;
385 #ifdef DEBUG
386 printf("Listen\n");
387 #endif
389 if (pipe(pfd) < 0) {
390 perror("ftp: could not create a pipe");
391 close(ftpdata_fd);
392 ftpdata_fd = -1;
393 return(0);
395 lpid = fork();
396 if(lpid < 0) {
397 perror("ftp: could not fork listener");
398 close(ftpdata_fd);
399 ftpdata_fd = -1;
400 close(pfd[0]);
401 close(pfd[1]);
402 return(0);
403 } else if(lpid == 0) {
404 #ifdef DEBUG
405 printf("Child here\n");
406 #endif
407 close(pfd[0]);
408 signal(SIGALRM, donothing);
409 alarm(15);
410 close(pfd[1]);
411 #ifdef DEBUG
412 printf("child TCPLISTEN\n");
413 #endif
414 s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
415 alarm(0);
416 #ifdef DEBUG
417 printf("listen %d %d\n", s, errno);
418 #endif
419 if(s < 0)
420 exit(errno); /* error */
421 else
422 exit(0); /* connection made */
424 #ifdef DEBUG
425 printf("Fork = %d\n", lpid);
426 #endif
427 /* Wait for the pipe to close, then the listener is ready (almost). */
428 close(pfd[1]);
429 (void) read(pfd[0], &dummy, 1);
430 close(pfd[0]);
431 while(1) {
432 wpid = waitpid(lpid, &cs, WNOHANG);
433 #ifdef DEBUG
434 printf("waitpid %d %d\n", wpid, cs);
435 printf("GTCPCONF loop\n");
436 #endif
437 if(wpid != 0) break;
438 signal(SIGALRM, donothing);
439 alarm(1);
440 s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
441 alarm(0);
442 #ifdef DEBUG
443 printf("GTCPCONF loop %d %d\n", s, errno);
444 #endif
445 if(s == -1) break;
446 sleep(1);
448 #ifdef DEBUG
449 printf("GTCPCONF = %d\n", s);
450 #endif
453 #define hiword(x) ((u16_t)((x) >> 16))
454 #define loword(x) ((u16_t)(x & 0xffff))
455 #define hibyte(x) (((x) >> 8) & 0xff)
456 #define lobyte(x) ((x) & 0xff)
458 if(!passive) {
459 if(wpid != 0) {
460 close(ftpdata_fd);
461 ftpdata_fd = -1;
462 cs = (cs >> 8) & 0x00ff;
463 printf("Child listener error %s\n", strerror(cs));
464 return(0);
466 sprintf(port, "%u,%u,%u,%u,%u,%u",
467 hibyte(hiword(ntohl(myip))), lobyte(hiword(ntohl(myip))),
468 hibyte(loword(ntohl(myip))), lobyte(loword(ntohl(myip))),
469 hibyte(ntohs(lport)), lobyte(ntohs(lport)));
470 #ifdef DEBUG
471 printf("sending port command %s\n", port);
472 #endif
473 s = DOcommand("PORT", port);
474 #ifdef DEBUG
475 printf("port command = %d\n", s);
476 #endif
477 if(s != 200) {
478 close(ftpdata_fd);
479 ftpdata_fd = -1;
480 kill(lpid, SIGKILL);
481 (void) wait(&cs);
482 return(s);
486 WASOPEN:
488 #ifdef DEBUG
489 printf("doing data command %s %s\n", datacom, file);
490 #endif
491 s = DOcommand(datacom, file);
492 #ifdef DEBUG
493 printf("do command reply %d\n", s);
494 #endif
495 if(s == 125 || s == 150) {
496 if(!passive && !wasopen) {
497 while(1) {
498 #ifdef DEBUG
499 printf("Waiting for child %d\n", lpid);
500 #endif
501 s = wait(&cs);
502 #ifdef DEBUG
503 printf("Wait returned %d cs=%d errno=%d\n", s, cs, errno);
504 #endif
505 if(s < 0 || s == lpid)
506 break;
508 if(s < 0) {
509 perror("wait error:");
510 close(ftpdata_fd);
511 ftpdata_fd = -1;
512 kill(lpid, SIGKILL);
513 (void) wait(&cs);
514 return(s);
516 if((cs & 0x00ff)) {
517 printf("Child listener failed %04x\n", cs);
518 close(ftpdata_fd);
519 ftpdata_fd = -1;
520 return(-1);
522 cs = (cs >> 8) & 0x00ff;
523 if(cs) {
524 printf("Child listener error %s\n", strerror(cs));
525 close(ftpdata_fd);
526 ftpdata_fd = -1;
527 return(DOgetreply());
530 #ifdef DEBUG
531 printf("Before recvfile/sendfile call\n");
532 #endif
533 switch(direction) {
534 case RETR:
535 s = recvfile(fd, ftpdata_fd);
536 break;
537 case STOR:
538 s = sendfile(fd, ftpdata_fd);
539 break;
541 #ifdef DEBUG
542 printf("send/recieve %d\n", s);
543 #endif
544 if(mode != MODE_B) {
545 close(ftpdata_fd);
546 ftpdata_fd = -1;
549 s = DOgetreply();
550 #ifdef DEBUG
551 printf("send/recieve reply %d\n", s);
552 #endif
553 if(mode == MODE_B && s == 226) {
554 close(ftpdata_fd);
555 ftpdata_fd = -1;
557 } else {
558 if(!passive) {
559 kill(lpid, SIGKILL);
560 (void) wait(&cs);
562 close(ftpdata_fd);
563 ftpdata_fd = -1;
566 return(s);