📄 ftp.c
字号:
#ifdef HAVE_SIGSETJMP
sj = sigsetjmp(gCancelConnectJmp, 1);
#else
sj = setjmp(gCancelConnectJmp);
#endif /* HAVE_SIGSETJMP */
if (sj != 0) {
/* Interrupted by a signal. */
(void) closesocket(sockfd);
(void) signal(SIGINT, (FTPSigProc) osigint);
if (vcip->connTimeout > 0) {
(void) alarm(0);
(void) signal(SIGALRM, (FTPSigProc) osigalrm);
}
if (gGotSig == SIGINT) {
result = vcip->errNo = kErrConnectMiscErr;
Error(vcip, kDontPerror, "Connection attempt canceled.\n");
(void) kill(getpid(), SIGINT);
} else if (gGotSig == SIGALRM) {
result = vcip->errNo = kErrConnectRetryableErr;
Error(vcip, kDontPerror, "Connection attempt timed-out.\n");
(void) kill(getpid(), SIGALRM);
} else {
result = vcip->errNo = kErrConnectMiscErr;
Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig);
}
return (result);
} else {
err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr,
(int) sizeof (cip->servCtlAddr));
if (cip->connTimeout > 0) {
(void) alarm(0);
(void) signal(SIGALRM, (FTPSigProc) osigalrm);
}
(void) signal(SIGINT, (FTPSigProc) osigint);
}
if (err < 0) {
oerrno = errno;
(void) closesocket(sockfd);
errno = oerrno;
sockfd = -1;
}
#endif /* NO_SIGNALS */
} else {
/* We can try each address in the list. We'll quit when we
* run out of addresses to try or get a successful connection.
*/
for (curaddr = hp->h_addr_list; *curaddr != NULL; curaddr++) {
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 could overwrite the address field in the structure,
* but this is okay because the structure has a junk field
* just for this purpose.
*/
(void) memcpy(&cip->servCtlAddr.sin_addr, *curaddr, (size_t) hp->h_length);
/* 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)
break;
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;
#ifdef HAVE_SIGSETJMP
sj = sigsetjmp(gCancelConnectJmp, 1);
#else
sj = setjmp(gCancelConnectJmp);
#endif /* HAVE_SIGSETJMP */
if (sj != 0) {
/* Interrupted by a signal. */
(void) closesocket(sockfd);
(void) signal(SIGINT, (FTPSigProc) osigint);
if (vcip->connTimeout > 0) {
(void) alarm(0);
(void) signal(SIGALRM, (FTPSigProc) osigalrm);
}
if (gGotSig == SIGINT) {
result = vcip->errNo = kErrConnectMiscErr;
Error(vcip, kDontPerror, "Connection attempt canceled.\n");
(void) kill(getpid(), SIGINT);
} else if (gGotSig == SIGALRM) {
result = vcip->errNo = kErrConnectRetryableErr;
Error(vcip, kDontPerror, "Connection attempt timed-out.\n");
(void) kill(getpid(), SIGALRM);
} else {
result = vcip->errNo = kErrConnectMiscErr;
Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig);
}
return (result);
} else {
err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr,
(int) sizeof (cip->servCtlAddr));
if (cip->connTimeout > 0) {
(void) alarm(0);
(void) signal(SIGALRM, (FTPSigProc) osigalrm);
}
(void) signal(SIGINT, (FTPSigProc) osigint);
}
if (err == 0)
break;
oerrno = errno;
(void) closesocket(sockfd);
errno = oerrno;
sockfd = -1;
#endif /* NO_SIGNALS */
}
}
if (err < 0) {
/* Could not connect. Close up shop and go home. */
/* If possible, tell the caller if they should bother
* calling back later.
*/
switch (errno) {
#ifdef ENETDOWN
case ENETDOWN:
#elif defined(WSAENETDOWN)
case WSAENETDOWN:
#endif
#ifdef ENETUNREACH
case ENETUNREACH:
#elif defined(WSAENETUNREACH)
case WSAENETUNREACH:
#endif
#ifdef ECONNABORTED
case ECONNABORTED:
#elif defined(WSAECONNABORTED)
case WSAECONNABORTED:
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT:
#elif defined(WSAETIMEDOUT)
case WSAETIMEDOUT:
#endif
#ifdef EHOSTDOWN
case EHOSTDOWN:
#elif defined(WSAEHOSTDOWN)
case WSAEHOSTDOWN:
#endif
#ifdef ECONNRESET
case ECONNRESET:
#elif defined(WSAECONNRESET)
case WSAECONNRESET:
#endif
Error(cip, kDoPerror, "Could not connect to %s -- try again later.\n", fhost);
result = cip->errNo = kErrConnectRetryableErr;
break;
#ifdef ECONNREFUSED
case ECONNREFUSED:
#elif defined(WSAECONNREFUSED)
case WSAECONNREFUSED:
#endif
Error(cip, kDoPerror, "Could not connect to %s.\n", fhost);
result = cip->errNo = kErrConnectRefused;
break;
default:
Error(cip, kDoPerror, "Could not connect to %s.\n", fhost);
result = cip->errNo = kErrConnectMiscErr;
}
goto fatal;
}
/* Get our end of the socket address for later use. */
if ((result = GetSocketAddress(cip, sockfd, &cip->ourCtlAddr)) < 0)
goto fatal;
#ifdef SO_OOBINLINE
/* We want Out-of-band data to appear in the regular stream,
* since we can handle TELNET.
*/
(void) SetInlineOutOfBandData(cip, sockfd);
#endif
(void) SetKeepAlive(cip, sockfd);
(void) SetLinger(cip, sockfd, 0); /* Don't need it for ctrl. */
#if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
/* Control connection is somewhat interactive, so quick response
* is desired.
*/
(void) SetTypeOfService(cip, sockfd, IPTOS_LOWDELAY);
#endif
#ifdef NO_SIGNALS
cip->ctrlSocketR = sockfd;
cip->ctrlSocketW = sockfd;
cip->cout = NULL;
cip->cin = NULL;
sock2fd = kClosedFileDescriptor;
if (InitSReadlineInfo(&cip->ctrlSrl, sockfd, cip->srlBuf, sizeof(cip->srlBuf), (int) cip->ctrlTimeout, 1) < 0) {
result = kErrFdopenW;
cip->errNo = kErrFdopenW;
Error(cip, kDoPerror, "Could not fdopen.\n");
goto fatal;
}
#else /* NO_SIGNALS */
if ((sock2fd = dup(sockfd)) < 0) {
result = kErrDupSocket;
cip->errNo = kErrDupSocket;
Error(cip, kDoPerror, "Could not duplicate a file descriptor.\n");
goto fatal;
}
/* Now setup the FILE pointers for use with the Std I/O library
* routines.
*/
if ((cip->cin = fdopen(sockfd, "r")) == NULL) {
result = kErrFdopenR;
cip->errNo = kErrFdopenR;
Error(cip, kDoPerror, "Could not fdopen.\n");
goto fatal;
}
if ((cip->cout = fdopen(sock2fd, "w")) == NULL) {
result = kErrFdopenW;
cip->errNo = kErrFdopenW;
Error(cip, kDoPerror, "Could not fdopen.\n");
CloseFile(&cip->cin);
sockfd = kClosedFileDescriptor;
goto fatal;
}
cip->ctrlSocketR = sockfd;
cip->ctrlSocketW = sockfd;
/* We'll be reading and writing lines, so use line buffering. This
* is necessary since the stdio library will use full buffering
* for all streams not associated with the tty.
*/
#ifdef HAVE_SETLINEBUF
setlinebuf(cip->cin);
setlinebuf(cip->cout);
#else
(void) SETVBUF(cip->cin, NULL, _IOLBF, (size_t) BUFSIZ);
(void) SETVBUF(cip->cout, NULL, _IOLBF, (size_t) BUFSIZ);
#endif
#endif /* NO_SIGNALS */
#ifdef HAVE_INET_NTOP /* Mostly to workaround bug in IRIX 6.5's inet_ntoa */
(void) memset(cip->ip, 0, sizeof(cip->ip));
(void) inet_ntop(AF_INET, &cip->servCtlAddr.sin_addr, cip->ip, sizeof(cip->ip) - 1);
#else
(void) STRNCPY(cip->ip, inet_ntoa(cip->servCtlAddr.sin_addr));
#endif
if ((hp == NULL) || (hp->h_name == NULL))
(void) STRNCPY(cip->actualHost, fhost);
else
(void) STRNCPY(cip->actualHost, (char *) hp->h_name);
/* Read the startup message from the server. */
rp = InitResponse();
if (rp == NULL) {
Error(cip, kDontPerror, "Malloc failed.\n");
cip->errNo = kErrMallocFailed;
result = cip->errNo;
goto fatal;
}
result = GetResponse(cip, rp);
if ((result < 0) && (rp->msg.first == NULL)) {
goto fatal;
}
if (rp->msg.first != NULL) {
cip->serverType = kServerTypeUnknown;
srvr = NULL;
firstLine = rp->msg.first->line;
secondLine = NULL;
if (rp->msg.first->next != NULL)
secondLine = rp->msg.first->next->line;
if (strstr(firstLine, "Version wu-") != NULL) {
cip->serverType = kServerTypeWuFTPd;
srvr = "wu-ftpd";
} else if (strstr(firstLine, "NcFTPd") != NULL) {
cip->serverType = kServerTypeNcFTPd;
srvr = "NcFTPd Server";
} else if (STRNEQ("ProFTPD", firstLine, 7)) {
cip->serverType = kServerTypeProFTPD;
srvr = "ProFTPD";
} else if (strstr(firstLine, "Microsoft FTP Service") != NULL) {
cip->serverType = kServerTypeMicrosoftFTP;
srvr = "Microsoft FTP Service";
} else if (strstr(firstLine, "(NetWare ") != NULL) {
cip->serverType = kServerTypeNetWareFTP;
srvr = "NetWare FTP Service";
} else if (STRNEQ("WFTPD", firstLine, 5)) {
cip->serverType = kServerTypeWFTPD;
srvr = "WFTPD";
} else if (STRNEQ("Serv-U FTP", firstLine, 10)) {
cip->serverType = kServerTypeServ_U;
srvr = "Serv-U FTP-Server";
} else if (strstr(firstLine, "VFTPD") != NULL) {
cip->serverType = kServerTypeVFTPD;
srvr = "VFTPD";
} else if (STRNEQ("FTP-Max", firstLine, 7)) {
cip->serverType = kServerTypeFTP_Max;
srvr = "FTP-Max";
} else if (strstr(firstLine, "Roxen") != NULL) {
cip->serverType = kServerTypeRoxen;
srvr = "Roxen";
} else if (strstr(firstLine, "WS_FTP") != NULL) {
cip->serverType = kServerTypeWS_FTP;
srvr = "WS_FTP Server";
} else if ((secondLine != NULL) && (strstr(secondLine, "WarFTP") != NULL)) {
cip->serverType = kServerTypeWarFTPd;
srvr = "WarFTPd";
}
if (srvr != NULL)
PrintF(cip, "Remote server is running %s.\n", srvr);
/* Do the application's connect message callback, if present. */
if ((cip->onConnectMsgProc != 0) && (rp->codeType < 4))
(*cip->onConnectMsgProc)(cip, rp);
}
if (rp->codeType >= 4) {
/* They probably hung up on us right away. That's too bad,
* but we can tell the caller that they can call back later
* and try again.
*/
DoneWithResponse(cip, rp);
result = kErrConnectRetryableErr;
Error(cip, kDontPerror, "Server hungup immediately after connect.\n");
cip->errNo = kErrConnectRetryableErr;
goto fatal;
}
if (result < 0) /* Some other error occurred during connect message */
goto fatal;
cip->connected = 1;
DoneWithResponse(cip, rp);
return (kNoErr);
fatal:
if (sockfd > 0)
(void) closesocket(sockfd);
if (sock2fd > 0)
(void) closesocket(sock2fd);
CloseFile(&cip->cin);
CloseFile(&cip->cout);
cip->ctrlSocketR = kClosedFileDescriptor;
cip->ctrlSocketW = kClosedFileDescriptor;
return (result);
} /* OpenControlConnection */
void
CloseDataConnection(const FTPCIPtr cip)
{
if (cip->dataSocket != kClosedFileDescriptor) {
#ifdef NO_SIGNALS
SClose(cip->dataSocket, 3);
#else /* NO_SIGNALS */
if (cip->xferTimeout > 0)
(void) alarm(cip->xferTimeout);
(void) closesocket(cip->dataSocket);
if (cip->xferTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
cip->dataSocket = kClosedFileDescriptor;
}
memset(&cip->ourDataAddr, 0, sizeof(cip->ourDataAddr));
memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr));
} /* CloseDataConnection */
int
SetStartOffset(const FTPCIPtr cip, longest_int restartPt)
{
ResponsePtr rp;
int result;
if (restartPt != (longest_int) 0) {
rp = InitResponse();
if (rp == NULL) {
Error(cip, kDontPerror, "Malloc failed.\n");
cip->errNo = kErrMallocFailed;
return (cip->errNo);
}
/* Force reset to offset zero. */
if (restartPt == (longest_int) -1)
restartPt = (longest_int) 0;
#ifdef PRINTF_LONG_LONG
result = RCmd(cip, rp,
"REST " PRINTF_LONG_LONG,
restartPt);
#else
result = RCmd(cip, rp, "REST %ld", (long) restartPt);
#endif
if (result < 0) {
return (result);
} else if (result == 3) {
cip->hasREST = kCommandAvailable;
DoneWithResponse(cip, rp);
} else if (UNIMPLEMENTED_CMD(rp->code)) {
cip->hasREST = kCommandNotAvailable;
DoneWithResponse(cip, rp);
cip->errNo = kErrSetStartPoint;
return (kErrSetStartPoint);
} else {
DoneWithResponse(cip, rp);
cip->errNo = kErrSetStartPoint;
return (kErrSetStartPoint);
}
}
return (0);
} /* SetStartOffset */
static int
SendPort(const FTPCIPtr cip, struct sockaddr_in *saddr)
{
char *a, *p;
int result;
ResponsePtr rp;
rp = InitResponse();
if (rp == NULL) {
Error(cip, kDontPerror, "Malloc failed.\n");
cip->errNo = kErrMallocFailed;
return (cip->errNo);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -