?? ftp.c
字號:
/* ftp.c
*
* Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
* All rights reserved.
*
*/
#define _libncftp_ftp_c_
#include "syshdrs.h"
char gLibNcFTPVersion[64] = kLibraryVersion;
#ifdef NO_SIGNALS
static char gNoSignalsMarker[] = "@(#) LibNcFTP - NO_SIGNALS";
#else
static int gGotSig = 0;
#ifdef HAVE_SIGSETJMP
static sigjmp_buf gCancelConnectJmp;
#else
static jmp_buf gCancelConnectJmp;
#endif /* HAVE_SIGSETJMP */
#endif /* NO_SIGNALS */
#ifndef lint
static char gCopyright[] = "@(#) LibNcFTP Copyright 1995-2000, by Mike Gleason. All rights reserved.";
#endif
#ifdef HAVE_LIBSOCKS5
# define SOCKS 5
# include <socks.h>
#else
# ifdef HAVE_LIBSOCKS
# define accept Raccept
# define connect Rconnect
# define getsockname Rgetsockname
# define listen Rlisten
# endif
#endif
/* On entry, you should have 'host' be set to a symbolic name (like
* cse.unl.edu), or set to a numeric address (like 129.93.3.1).
* If the function fails, it will return NULL, but if the host was
* a numeric style address, you'll have the ip_address to fall back on.
*/
static struct hostent *
GetHostEntry(char *host, struct in_addr *ip_address)
{
struct in_addr ip;
struct hostent *hp;
/* See if the host was given in the dotted IP format, like "36.44.0.2."
* If it was, inet_addr will convert that to a 32-bit binary value;
* it not, inet_addr will return (-1L).
*/
ip.s_addr = inet_addr(host);
if (ip.s_addr != INADDR_NONE) {
hp = NULL;
} else {
/* No IP address, so it must be a hostname, like ftp.wustl.edu. */
hp = gethostbyname(host);
if (hp != NULL)
(void) memcpy(&ip.s_addr, hp->h_addr_list[0], (size_t) hp->h_length);
}
if (ip_address != NULL)
*ip_address = ip;
return (hp);
} /* GetHostEntry */
/* Makes every effort to return a fully qualified domain name. */
int
GetOurHostName(char *host, size_t siz)
{
#ifdef HOSTNAME
/* You can hardcode in the name if this routine doesn't work
* the way you want it to.
*/
Strncpy(host, HOSTNAME, siz);
return (1); /* Success */
#else
struct hostent *hp;
int result;
char **curAlias;
char domain[64];
char *cp;
int rc;
host[0] = '\0';
result = gethostname(host, (int) siz);
if ((result < 0) || (host[0] == '\0')) {
return (-1);
}
if (strchr(host, '.') != NULL) {
/* gethostname returned full name (like "cse.unl.edu"), instead
* of just the node name (like "cse").
*/
return (2); /* Success */
}
hp = gethostbyname(host);
if (hp != NULL) {
/* Maybe the host entry has the full name. */
cp = strchr((char *) hp->h_name, '.');
if ((cp != NULL) && (cp[1] != '\0')) {
/* The 'name' field for the host entry had full name. */
(void) Strncpy(host, (char *) hp->h_name, siz);
return (3); /* Success */
}
/* Now try the list of aliases, to see if any of those look real. */
for (curAlias = hp->h_aliases; *curAlias != NULL; curAlias++) {
cp = strchr(*curAlias, '.');
if ((cp != NULL) && (cp[1] != '\0')) {
(void) Strncpy(host, *curAlias, siz);
return (4); /* Success */
}
}
}
/* Otherwise, we just have the node name. See if we can get the
* domain name ourselves.
*/
#ifdef DOMAINNAME
(void) STRNCPY(domain, DOMAINNAME);
rc = 5;
#else
rc = -1;
domain[0] = '\0';
# if defined(HAVE_RES_INIT) && defined(HAVE__RES_DEFDNAME)
if (domain[0] == '\0') {
(void) res_init();
if ((_res.defdname != NULL) && (_res.defdname[0] != '\0')) {
(void) STRNCPY(domain, _res.defdname);
rc = 6;
}
}
# endif /* HAVE_RES_INIT && HAVE__RES_DEFDNAME */
if (domain[0] == '\0') {
FILE *fp;
char line[256];
char *tok;
fp = fopen("/etc/resolv.conf", "r");
if (fp != NULL) {
(void) memset(line, 0, sizeof(line));
while (fgets(line, sizeof(line) - 1, fp) != NULL) {
if (!isalpha((int) line[0]))
continue; /* Skip comment lines. */
tok = strtok(line, " \t\n\r");
if (tok == NULL)
continue; /* Impossible */
if (strcmp(tok, "domain") == 0) {
tok = strtok(NULL, " \t\n\r");
if (tok == NULL)
continue; /* syntax error */
(void) STRNCPY(domain, tok);
rc = 7;
break; /* Done. */
}
}
(void) fclose(fp);
}
}
#endif /* DOMAINNAME */
if (domain[0] != '\0') {
/* Supposedly, it's legal for a domain name with
* a period at the end.
*/
cp = domain + strlen(domain) - 1;
if (*cp == '.')
*cp = '\0';
if (domain[0] != '.')
(void) Strncat(host, ".", siz);
(void) Strncat(host, domain, siz);
}
if (rc < 0)
host[0] = '\0';
return(rc); /* Success */
#endif /* !HOSTNAME */
} /* GetOurHostName */
void
CloseControlConnection(const FTPCIPtr cip)
{
/* This will close each file, if it was open. */
#ifdef NO_SIGNALS
SClose(cip->ctrlSocketR, 3);
cip->ctrlSocketR = kClosedFileDescriptor;
cip->ctrlSocketW = kClosedFileDescriptor;
DisposeSReadlineInfo(&cip->ctrlSrl);
#else /* NO_SIGNALS */
if (cip->ctrlTimeout > 0)
(void) alarm(cip->ctrlTimeout);
CloseFile(&cip->cin);
CloseFile(&cip->cout);
cip->ctrlSocketR = kClosedFileDescriptor;
cip->ctrlSocketW = kClosedFileDescriptor;
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
cip->connected = 0;
cip->loggedIn = 0;
} /* CloseControlConnection */
static int
GetSocketAddress(const FTPCIPtr cip, int sockfd, struct sockaddr_in *saddr)
{
int len = (int) sizeof (struct sockaddr_in);
int result = 0;
if (getsockname(sockfd, (struct sockaddr *)saddr, &len) < 0) {
Error(cip, kDoPerror, "Could not get socket name.\n");
cip->errNo = kErrGetSockName;
result = kErrGetSockName;
}
return (result);
} /* GetSocketAddress */
int
SetKeepAlive(const FTPCIPtr cip, int sockfd)
{
#ifndef SO_KEEPALIVE
cip->errNo = kErrSetKeepAlive;
return (kErrSetKeepAlive);
#else
int opt;
opt = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, (int) sizeof(opt)) < 0) {
/* Error(cip, kDoPerror, "Could not set keep-alive mode.\n"); */
cip->errNo = kErrSetKeepAlive;
return (kErrSetKeepAlive);
}
return (kNoErr);
#endif /* SO_KEEPALIVE */
} /* SetKeepAlive */
int
SetLinger(const FTPCIPtr cip, int sockfd, int onoff)
{
#ifndef SO_LINGER
cip->errNo = kErrSetLinger;
return (kErrSetLinger);
#else
struct linger li;
if (onoff != 0) {
li.l_onoff = 1;
li.l_linger = 120; /* 2 minutes, but system ignores field. */
} else {
li.l_onoff = 0;
li.l_linger = 0;
}
/* Have the system make an effort to deliver any unsent data,
* even after we close the connection.
*/
if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *) &li, (int) sizeof(li)) < 0) {
/* Error(cip, kDoPerror, "Could not set linger mode.\n"); */
cip->errNo = kErrSetLinger;
return (kErrSetLinger);
}
return (kNoErr);
#endif /* SO_LINGER */
} /* SetLinger */
#ifdef IP_TOS
int
SetTypeOfService(const FTPCIPtr cip, int sockfd, int tosType)
{
/* Specify to the router what type of connection this is, so it
* can prioritize packets.
*/
if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, (char *) &tosType, (int) sizeof(tosType)) < 0) {
/* Error(cip, kDoPerror, "Could not set type of service.\n"); */
cip->errNo = kErrSetTypeOfService;
return (kErrSetTypeOfService);
}
return (kNoErr);
} /* SetTypeOfService */
#endif /* IP_TOS */
#ifdef SO_OOBINLINE
int
SetInlineOutOfBandData(const FTPCIPtr cip, int sockfd)
{
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, (int) sizeof(on)) < 0) {
Error(cip, kDoPerror, "Could not set out of band inline mode.\n");
cip->errNo = kErrSetOutOfBandInline;
return (kErrSetOutOfBandInline);
}
return (kNoErr);
} /* SetInlineOutOfBandData */
#endif /* SO_OOBINLINE */
#ifndef NO_SIGNALS
static void
CancelConnect(int signum)
{
gGotSig = signum;
#ifdef HAVE_SIGSETJMP
siglongjmp(gCancelConnectJmp, 1);
#else
longjmp(gCancelConnectJmp, 1);
#endif /* HAVE_SIGSETJMP */
} /* CancelConnect */
#endif /* NO_SIGNALS */
int
OpenControlConnection(const FTPCIPtr cip, char *host, unsigned int port)
{
struct in_addr ip_address;
int err = 0;
int result;
int oerrno;
volatile int sockfd = -1;
volatile int sock2fd = -1;
ResponsePtr rp;
char **volatile curaddr;
struct hostent *hp;
char *volatile fhost;
unsigned int fport;
#ifndef NO_SIGNALS
volatile FTPSigProc osigint;
volatile FTPSigProc osigalrm;
volatile FTPCIPtr vcip;
int sj;
#endif /* NO_SIGNALS */
const char *firstLine, *secondLine, *srvr;
LIBNCFTP_USE_VAR(gLibNcFTPVersion);
LIBNCFTP_USE_VAR(gCopyright);
#ifdef NO_SIGNALS
LIBNCFTP_USE_VAR(gNoSignalsMarker);
#endif /* NO_SIGNALS */
if (cip->firewallType == kFirewallNotInUse) {
fhost = host;
fport = port;
} else {
fhost = cip->firewallHost;
fport = cip->firewallPort;
}
if (fport == 0)
fport = cip->lip->defaultPort;
/* Since we're the client, we just have to get a socket() and
* connect() it.
*/
(void) ZERO(cip->servCtlAddr);
cip->cin = NULL;
cip->cout = NULL;
/* Make sure we use network byte-order. */
fport = (unsigned int) htons((unsigned short) fport);
cip->servCtlAddr.sin_port = (unsigned short) fport;
hp = GetHostEntry(fhost, &ip_address);
if (hp == NULL) {
/* Okay, no Host entry, but maybe we have a numeric address
* in ip_address we can try.
*/
if (ip_address.s_addr == INADDR_NONE) {
Error(cip, kDontPerror, "%s: unknown host.\n", fhost);
cip->errNo = kErrHostUnknown;
return (kErrHostUnknown);
}
cip->servCtlAddr.sin_family = AF_INET;
cip->servCtlAddr.sin_addr.s_addr = ip_address.s_addr;
} else {
cip->servCtlAddr.sin_family = hp->h_addrtype;
/* We'll fill in the rest of the structure below. */
}
/* After obtaining a socket, try to connect it to a remote
* address. If we didn't get a host entry, we will only have
* one thing to try (ip_address); if we do have one, we can try
* every address in the list from the host entry.
*/
if (hp == NULL) {
/* Since we're given a single raw address, and not a host entry,
* we can only try this one address and not any other addresses
* that could be present for a site with a host entry.
*/
if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) {
Error(cip, kDoPerror, "Could not get a socket.\n");
cip->errNo = kErrNewStreamSocket;
return (kErrNewStreamSocket);
}
/* This doesn't do anything if you left these
* at their defaults (zero). Otherwise it
* tries to set the buffer size to the
* size specified.
*/
(void) SetSockBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize);
#ifdef NO_SIGNALS
err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout);
if (err < 0) {
oerrno = errno;
(void) SClose(sockfd, 3);
errno = oerrno;
sockfd = -1;
}
#else /* NO_SIGNALS */
osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect);
if (cip->connTimeout > 0) {
osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect);
(void) alarm(cip->connTimeout);
}
vcip = cip;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -