⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftp.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:

	/* These will point to data in network byte order. */
	a = (char *) &saddr->sin_addr;
	p = (char *) &saddr->sin_port;
#define UC(x) (int) (((int) x) & 0xff)

	/* Need to tell the other side which host (the address) and
	 * which process (port) on that host to send data to.
	 */
	result = RCmd(cip, rp, "PORT %d,%d,%d,%d,%d,%d",
		UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));

	if (result < 0) {
		return (result);
	} else if (result != 2) {
		/* A 500'ish response code means the PORT command failed. */
		DoneWithResponse(cip, rp);
		cip->errNo = kErrPORTFailed;
		return (cip->errNo);
	}
	DoneWithResponse(cip, rp);
	return (kNoErr);
}	/* SendPort */




static int
Passive(const FTPCIPtr cip, struct sockaddr_in *saddr, int *weird)
{
	ResponsePtr rp;
	int i[6], j;
	unsigned char n[6];
	char *cp;
	int result;

	rp = InitResponse();
	if (rp == NULL) {
		Error(cip, kDontPerror, "Malloc failed.\n");
		cip->errNo = kErrMallocFailed;
		return (cip->errNo);
	}

	result = RCmd(cip, rp, "PASV");
	if (result < 0)
		goto done;

	if (rp->codeType != 2) {
		/* Didn't understand or didn't want passive port selection. */
		cip->errNo = result = kErrPASVFailed;
		goto done;
	}

	/* The other side returns a specification in the form of
	 * an internet address as the first four integers (each
	 * integer stands for 8-bits of the real 32-bit address),
	 * and two more integers for the port (16-bit port).
	 *
	 * It should give us something like:
	 * "Entering Passive Mode (129,93,33,1,10,187)", so look for
	 * digits with sscanf() starting 24 characters down the string.
	 */
	for (cp = rp->msg.first->line; ; cp++) {
		if (*cp == '\0') {
			Error(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line);
			goto done;
		}
		if (isdigit((int) *cp))
			break;
	}

	if (sscanf(cp, "%d,%d,%d,%d,%d,%d",
			&i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6) {
		Error(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line);
		goto done;
	}

	for (j=0, *weird = 0; j<6; j++) {
		/* Some ftp servers return bogus port octets, such as
		 * boombox.micro.umn.edu.  Let the caller know if we got a
		 * weird looking octet.
		 */
		if ((i[j] < 0) || (i[j] > 255))
			*weird = *weird + 1;
		n[j] = (unsigned char) (i[j] & 0xff);
	}

	(void) memcpy(&saddr->sin_addr, &n[0], (size_t) 4);
	(void) memcpy(&saddr->sin_port, &n[4], (size_t) 2);

	result = kNoErr;
done:
	DoneWithResponse(cip, rp);
	return (result);
}	/* Passive */




static int
BindToEphemeralPortNumber(int sockfd, struct sockaddr_in *addrp, int ephemLo, int ephemHi)
{
	int i;
	int result;
	int rangesize;
	unsigned short port;

	addrp->sin_family = AF_INET;
	if (((int) ephemLo == 0) || ((int) ephemLo >= (int) ephemHi)) {
		/* Do it the normal way.  System will
		 * pick one, typically in the range
		 * of 1024-4999.
		 */
		addrp->sin_port = 0;	/* Let system pick one. */

		result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in));
	} else {
		rangesize = (int) ((int) ephemHi - (int) ephemLo);
		result = 0;
		for (i=0; i<10; i++) {
			port = (unsigned short) (((int) rand() % rangesize) + (int) ephemLo);
			addrp->sin_port = port;

			result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in));
			if (result == 0)
				break;
			if ((errno != 999)
				/* This next line is just fodder to
				 * shut the compiler up about variable
				 * not being used.
				 */
				&& (gCopyright[0] != '\0'))
				break;
		}
	}
	return (result);
}	/* BindToEphemeralPortNumber */




int
OpenDataConnection(const FTPCIPtr cip, int mode)
{
	int dataSocket;
	int weirdPort;
	int result;

	/* Before we can transfer any data, and before we even ask the
	 * remote server to start transferring via RETR/NLST/etc, we have
	 * to setup the connection.
	 */

tryPort2:
	weirdPort = 0;
	result = 0;
	CloseDataConnection(cip);	/* In case we didn't before... */

	dataSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (dataSocket < 0) {
		Error(cip, kDoPerror, "Could not get a data socket.\n");
		result = kErrNewStreamSocket;
		cip->errNo = kErrNewStreamSocket;
		return result;
	}

	/* 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(dataSocket, cip->dataSocketRBufSize, cip->dataSocketSBufSize);

	if ((cip->hasPASV == kCommandNotAvailable) || (mode == kSendPortMode)) {
tryPort:
		cip->ourDataAddr = cip->ourCtlAddr;
		cip->ourDataAddr.sin_family = AF_INET;

#ifdef HAVE_LIBSOCKS
		cip->ourDataAddr.sin_port = 0;
		if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr,
			(int) sizeof (cip->ourDataAddr),
			cip->servCtlAddr.sin_addr.s_addr) < 0)
#else
		if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0)
#endif
		{
			Error(cip, kDoPerror, "Could not bind the data socket");
			result = kErrBindDataSocket;
			cip->errNo = kErrBindDataSocket;
			goto bad;
		}

		/* Need to do this so we can figure out which port the system
		 * gave to us.
		 */
		if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0)
			goto bad;

		if (listen(dataSocket, 1) < 0) {
			Error(cip, kDoPerror, "listen failed");
			result = kErrListenDataSocket;
			cip->errNo = kErrListenDataSocket;
			goto bad;
		}

		if ((result = SendPort(cip, &cip->ourDataAddr)) < 0)
			goto bad;

		cip->dataPortMode = kSendPortMode;
	} else {
		/* Passive mode.  Let the other side decide where to send. */

		cip->servDataAddr = cip->servCtlAddr;
		cip->servDataAddr.sin_family = AF_INET;
		cip->ourDataAddr = cip->ourCtlAddr;
		cip->ourDataAddr.sin_family = AF_INET;

		if (Passive(cip, &cip->servDataAddr, &weirdPort) < 0) {
			Error(cip, kDontPerror, "Passive mode refused.\n");
			cip->hasPASV = kCommandNotAvailable;

			/* We can try using regular PORT commands, which are required
			 * by all FTP protocol compliant programs, if you said so.
			 *
			 * We don't do this automatically, because if your host
			 * is running a firewall you (probably) do not want SendPort
			 * FTP for security reasons.
			 */
			if (mode == kFallBackToSendPortMode)
				goto tryPort;
			result = kErrPassiveModeFailed;
			cip->errNo = kErrPassiveModeFailed;
			goto bad;
		}

#ifdef HAVE_LIBSOCKS
		cip->ourDataAddr.sin_port = 0;
		if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr,
			(int) sizeof (cip->ourDataAddr),
			cip->servCtlAddr.sin_addr.s_addr) < 0)
#else
		if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0)
#endif
		{
			Error(cip, kDoPerror, "Could not bind the data socket");
			result = kErrBindDataSocket;
			cip->errNo = kErrBindDataSocket;
			goto bad;
		}

#ifdef NO_SIGNALS
		result = SConnect(dataSocket, &cip->servDataAddr, (int) cip->connTimeout);
#else	/* NO_SIGNALS */
		if (cip->connTimeout > 0)
			(void) alarm(cip->connTimeout);

		result = connect(dataSocket, (struct sockaddr *) &cip->servDataAddr, (int) sizeof(cip->servDataAddr));
		if (cip->connTimeout > 0)
			(void) alarm(0);
#endif	/* NO_SIGNALS */

#ifdef NO_SIGNALS
		if (result == kTimeoutErr) {
			if (mode == kFallBackToSendPortMode) {
				Error(cip, kDontPerror, "Data connection timed out.\n");
				Error(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n");
				(void) closesocket(dataSocket);
				cip->hasPASV = kCommandNotAvailable;
				goto tryPort2;
			}
			Error(cip, kDontPerror, "Data connection timed out.\n");
			result = kErrConnectDataSocket;
			cip->errNo = kErrConnectDataSocket;
		} else
#endif	/* NO_SIGNALS */

		if (result < 0) {
#ifdef ECONNREFUSED
			if ((weirdPort > 0) && (errno == ECONNREFUSED)) {
#elif defined(WSAECONNREFUSED)
			if ((weirdPort > 0) && (errno == WSAECONNREFUSED)) {
#endif
				Error(cip, kDontPerror, "Server sent back a bogus port number.\nI will fall back to PORT instead of PASV mode.\n");
				if (mode == kFallBackToSendPortMode) {
					(void) closesocket(dataSocket);
					cip->hasPASV = kCommandNotAvailable;
					goto tryPort2;
				}
				result = kErrServerSentBogusPortNumber;
				cip->errNo = kErrServerSentBogusPortNumber;
				goto bad;
			}
			if (mode == kFallBackToSendPortMode) {
				Error(cip, kDoPerror, "connect failed.\n");
				Error(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n");
				(void) closesocket(dataSocket);
				cip->hasPASV = kCommandNotAvailable;
				goto tryPort2;
			}
			Error(cip, kDoPerror, "connect failed.\n");
			result = kErrConnectDataSocket;
			cip->errNo = kErrConnectDataSocket;
			goto bad;
		}

		/* Need to do this so we can figure out which port the system
		 * gave to us.
		 */
		if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0)
			goto bad;

		cip->dataPortMode = kPassiveMode;
		cip->hasPASV = kCommandAvailable;
	}

	(void) SetLinger(cip, dataSocket, 1);
	(void) SetKeepAlive(cip, dataSocket);

#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
	/* Data connection is a non-interactive data stream, so
	 * high throughput is desired, at the expense of low
	 * response time.
	 */
	(void) SetTypeOfService(cip, dataSocket, IPTOS_THROUGHPUT);
#endif

	cip->dataSocket = dataSocket;
	return (0);
bad:
	(void) closesocket(dataSocket);
	return (result);
}	/* OpenDataConnection */




int
AcceptDataConnection(const FTPCIPtr cip)
{
	int newSocket;
#ifndef NO_SIGNALS
	int len;
#endif
	unsigned short remoteDataPort;
	unsigned short remoteCtrlPort;

	/* If we did a PORT, we have some things to finish up.
	 * If we did a PASV, we're ready to go.
	 */
	if (cip->dataPortMode == kSendPortMode) {
		/* Accept will give us back the server's data address;  at the
		 * moment we don't do anything with it though.
		 */
		memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr));

#ifdef NO_SIGNALS
		newSocket = SAccept(cip->dataSocket, &cip->servDataAddr, (int) cip->connTimeout);
#else	/* NO_SIGNALS */
		len = (int) sizeof(cip->servDataAddr);
		if (cip->connTimeout > 0)
			(void) alarm(cip->connTimeout);
		newSocket = accept(cip->dataSocket, (struct sockaddr *) &cip->servDataAddr, &len);
		if (cip->connTimeout > 0)
			(void) alarm(0);
#endif	/* NO_SIGNALS */

		(void) closesocket(cip->dataSocket);
		if (newSocket < 0) {
			Error(cip, kDoPerror, "Could not accept a data connection.\n");
			cip->dataSocket = kClosedFileDescriptor;
			cip->errNo = kErrAcceptDataSocket;
			return (kErrAcceptDataSocket);
		}

		if (cip->require20 != 0) {
			remoteDataPort = ntohs(cip->servDataAddr.sin_port);
			remoteCtrlPort = ntohs(cip->servCtlAddr.sin_port);
			if ((int) remoteDataPort != ((int) remoteCtrlPort - 1)) {
				Error(cip, kDontPerror, "Data connection did not originate on correct port!\n");
				(void) closesocket(newSocket);
				cip->dataSocket = kClosedFileDescriptor;
				cip->errNo = kErrAcceptDataSocket;
				return (kErrAcceptDataSocket);
			} else if (memcmp(&cip->servDataAddr.sin_addr.s_addr, &cip->servCtlAddr.sin_addr.s_addr, sizeof(cip->servDataAddr.sin_addr.s_addr)) != 0) {
				Error(cip, kDontPerror, "Data connection did not originate from remote server!\n");
				(void) closesocket(newSocket);
				cip->dataSocket = kClosedFileDescriptor;
				cip->errNo = kErrAcceptDataSocket;
				return (kErrAcceptDataSocket);
			}
		}

		cip->dataSocket = newSocket;
	}

	return (0);
}	/* AcceptDataConnection */




void
HangupOnServer(const FTPCIPtr cip)
{
	/* Since we want to close both sides of the connection for each
	 * socket, we can just have them closed with close() instead of
	 * using shutdown().
	 */
	CloseControlConnection(cip);
	CloseDataConnection(cip);
}	/* HangupOnServer */




void
SendTelnetInterrupt(const FTPCIPtr cip)
{
	char msg[4];

	/* 1. User system inserts the Telnet "Interrupt Process" (IP) signal
	 *    in the Telnet stream.
	 */

	if (cip->cout != NULL)
		(void) fflush(cip->cout);

	msg[0] = (char) (unsigned char) IAC;
	msg[1] = (char) (unsigned char) IP;
	(void) send(cip->ctrlSocketW, msg, 2, 0);

	/* 2. User system sends the Telnet "Sync" signal. */
#if 1
	msg[0] = (char) (unsigned char) IAC;
	msg[1] = (char) (unsigned char) DM;
	if (send(cip->ctrlSocketW, msg, 2, MSG_OOB) != 2)
		Error(cip, kDoPerror, "Could not send an urgent message.\n");
#else
	/* "Send IAC in urgent mode instead of DM because UNIX places oob mark
	 * after urgent byte rather than before as now is protocol," says
	 * the BSD ftp code.
	 */
	msg[0] = (char) (unsigned char) IAC;
	if (send(cip->ctrlSocketW, msg, 1, MSG_OOB) != 1)
		Error(cip, kDoPerror, "Could not send an urgent message.\n");
	(void) fprintf(cip->cout, "%c", DM);
	(void) fflush(cip->cout);
#endif
}	/* SendTelnetInterrupt */

/* eof FTP.c */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -