Initial revision
CVS patchset: 429 CVS date: 1996/02/27 17:37:03
This commit is contained in:
parent
fbb56975fb
commit
f9c1e8d728
|
@ -0,0 +1,311 @@
|
|||
#include <alloca.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/protocols.h>
|
||||
#include <pwd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TIMEOUT_SECS 20
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
#include "ftp.h"
|
||||
|
||||
static int ftpCheckResponse(int sock);
|
||||
static int ftpCommand(int sock, char * command, ...);
|
||||
static int ftpReadData(int sock, int out);
|
||||
static int getHostAddress(const char * host, struct in_addr * address);
|
||||
|
||||
static int ftpCheckResponse(int sock) {
|
||||
char buf[BUFFER_SIZE + 1];
|
||||
int bufLength = 0;
|
||||
fd_set emptySet, readSet;
|
||||
char * chptr, * start;
|
||||
struct timeval timeout;
|
||||
int bytesRead, rc;
|
||||
int doesContinue = 1;
|
||||
|
||||
while (doesContinue) {
|
||||
FD_ZERO(&emptySet);
|
||||
FD_ZERO(&readSet);
|
||||
FD_SET(sock, &readSet);
|
||||
|
||||
timeout.tv_sec = TIMEOUT_SECS;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout);
|
||||
if (rc < 1) return 1;
|
||||
|
||||
/* We got a response - make sure none of the response codes are in the
|
||||
400's or 500's. That would indicate a problem */
|
||||
|
||||
bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength);
|
||||
|
||||
bufLength += bytesRead;
|
||||
|
||||
buf[bufLength] = '\0';
|
||||
|
||||
start = chptr = buf;
|
||||
if (start[3] == '-')
|
||||
doesContinue = 1;
|
||||
else
|
||||
doesContinue = 0;
|
||||
|
||||
if (*start == '4' || *start == '5') return 1;
|
||||
while (chptr < (bufLength + buf)) {
|
||||
if (*chptr == '\n') {
|
||||
start = chptr + 1;
|
||||
if ((start - buf) < bufLength) {
|
||||
if (start[3] == '-')
|
||||
doesContinue = 1;
|
||||
else
|
||||
doesContinue = 0;
|
||||
if (*start == '4' || *start == '5') return 1;
|
||||
}
|
||||
}
|
||||
chptr++;
|
||||
}
|
||||
|
||||
if (*(chptr - 1) != '\n') {
|
||||
memcpy(buf, start, chptr - start);
|
||||
bufLength = chptr - start;
|
||||
} else {
|
||||
bufLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftpCommand(int sock, char * command, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char * s;
|
||||
char * buf;
|
||||
|
||||
va_start(ap, command);
|
||||
len = strlen(command) + 1;
|
||||
s = va_arg(ap, char *);
|
||||
while (s) {
|
||||
len += strlen(s) + 1;
|
||||
s = va_arg(ap, char *);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
buf = alloca(len + 1);
|
||||
|
||||
va_start(ap, command);
|
||||
strcpy(buf, command);
|
||||
strcat(buf, " ");
|
||||
s = va_arg(ap, char *);
|
||||
while (s) {
|
||||
strcat(buf, s);
|
||||
strcat(buf, " ");
|
||||
s = va_arg(ap, char *);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
buf[len - 1] = '\n';
|
||||
buf[len] = '\0';
|
||||
|
||||
if (write(sock, buf, len) != len)
|
||||
return 1;
|
||||
|
||||
if (ftpCheckResponse(sock))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getHostAddress(const char * host, struct in_addr * address) {
|
||||
struct hostent * hostinfo;
|
||||
|
||||
if (isdigit(host[0])) {
|
||||
if (inet_aton(host, address))
|
||||
return 1;
|
||||
} else {
|
||||
hostinfo = gethostbyname(host);
|
||||
if (!hostinfo) {
|
||||
errno = h_errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(address, hostinfo->h_addr_list[0], hostinfo->h_length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns -1 on error, error code in errno */
|
||||
int ftpOpen(char * host, char * name, char * password) {
|
||||
static int sock;
|
||||
/*static char * lastHost = NULL;*/
|
||||
struct in_addr serverAddress;
|
||||
struct sockaddr_in destPort;
|
||||
struct passwd * pw;
|
||||
|
||||
if (getHostAddress(host, &serverAddress)) return -1;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (sock < 0) return -1;
|
||||
|
||||
destPort.sin_family = AF_INET;
|
||||
destPort.sin_port = htons(IPPORT_FTP);
|
||||
destPort.sin_addr = serverAddress;
|
||||
|
||||
if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ftpCheckResponse() assumes the socket is nonblocking */
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ftpCheckResponse(sock);
|
||||
|
||||
if (!name)
|
||||
name = "anonymous";
|
||||
|
||||
if (!password) {
|
||||
pw = getpwuid(getuid());
|
||||
password = alloca(strlen(pw->pw_name) + 2);
|
||||
strcpy(password, pw->pw_name);
|
||||
strcat(password, "@");
|
||||
}
|
||||
|
||||
if (ftpCommand(sock, "USER", name, NULL)) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ftpCommand(sock, "PASS", password, NULL)) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ftpCommand(sock, "TYPE", "I", NULL)) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int ftpReadData(int sock, int out) {
|
||||
char buf[BUFFER_SIZE];
|
||||
fd_set emptySet, readSet;
|
||||
struct timeval timeout;
|
||||
int bytesRead, rc;
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&emptySet);
|
||||
FD_ZERO(&readSet);
|
||||
FD_SET(sock, &readSet);
|
||||
|
||||
timeout.tv_sec = TIMEOUT_SECS;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout);
|
||||
if (rc == 0) {
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
if (rc < 0) {
|
||||
close(sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytesRead = read(sock, buf, sizeof(buf));
|
||||
if (bytesRead == 0) {
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (write(out, buf, bytesRead) != bytesRead) {
|
||||
close(sock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ftpGetFile(int sock, char * remotename, int dest) {
|
||||
int dataSocket, trSocket;
|
||||
struct sockaddr_in myAddress, dataAddress;
|
||||
int i;
|
||||
char portbuf[64];
|
||||
char numbuf[20];
|
||||
char * dotAddress;
|
||||
char * chptr;
|
||||
unsigned short dataPort;
|
||||
|
||||
i = sizeof(myAddress);
|
||||
if (getsockname(sock, (struct sockaddr *) &myAddress, &i))
|
||||
return 1;
|
||||
|
||||
dataAddress.sin_family = AF_INET;
|
||||
dataAddress.sin_port = 0;
|
||||
dataAddress.sin_addr = myAddress.sin_addr;
|
||||
|
||||
dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (dataSocket < 0)
|
||||
return 1;
|
||||
|
||||
if (bind(dataSocket, (struct sockaddr *) &dataAddress,
|
||||
sizeof(dataAddress))) {
|
||||
close(dataSocket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(dataSocket, 1)) {
|
||||
close(dataSocket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getsockname(dataSocket, (struct sockaddr *) &dataAddress, &i)) {
|
||||
close(dataSocket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dotAddress = inet_ntoa(dataAddress.sin_addr);
|
||||
dataPort = ntohs(dataAddress.sin_port);
|
||||
|
||||
strcpy(portbuf, dotAddress);
|
||||
for (chptr = portbuf; *chptr; chptr++)
|
||||
if (*chptr == '.') *chptr = ',';
|
||||
|
||||
sprintf(numbuf, ",%d,%d", dataPort >> 8, dataPort & 0xFF);
|
||||
strcat(portbuf, numbuf);
|
||||
|
||||
if (ftpCommand(sock, "PORT", portbuf, NULL)) {
|
||||
close(dataSocket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ftpCommand(sock, "RETR", remotename, NULL)) {
|
||||
close(dataSocket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i = sizeof(dataAddress);
|
||||
trSocket = accept(dataSocket, (struct sockaddr *) &dataAddress, &i);
|
||||
close(dataSocket);
|
||||
|
||||
return ftpReadData(trSocket, dest);
|
||||
}
|
||||
|
||||
void ftpClose(int sock) {
|
||||
close(sock);
|
||||
}
|
||||
|
Loading…
Reference in New Issue