home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
ncftp-2.3.0-src.tgz
/
tar.out
/
contrib
/
ncftp
/
FTP.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
24KB
|
931 lines
/* FTP.c */
#include "Sys.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <netdb.h>
#include <errno.h>
#ifdef HAVE_NET_ERRNO_H
# include <net/errno.h>
#endif
#include <setjmp.h>
#include <ctype.h>
#include "Util.h"
#include "FTP.h"
#include "RCmd.h"
#ifdef HAVE_LIBTERMNET
# ifdef HAVE_TERMNET_H
# include <termnet.h>
# else
# ifdef HAVE_TERM_TERMNET_H
# include <term/termnet.h>
# endif
# endif
#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
/* The control stream we read responses to commands from. */
FILE *gControlIn = NULL;
/* The control stream we write our request to. */
FILE *gControlOut = NULL;
/* The actual socket for the data streams. */
int gDataSocket = kClosedFileDescriptor;
/* Port number we're FTP'ing to. */
unsigned int gFTPPort = kPortUnset;
/* Flag indicating whether we are connected to a remote host. */
int gConnected = 0;
/* Method we would rather to specify where to send data to our local
* host, either Passive (PASV) or SendPort (PORT). If you choose
* Passive FTP, you can attempt to use SendPort if the PASV command
* fails, since all FTP implementations must support PORT.
*/
#ifndef FTP_DATA_PORT_MODE
int gPreferredDataPortMode = kSendPortMode;
#else
int gPreferredDataPortMode = FTP_DATA_PORT_MODE;
#endif
/* Method we actually ended up using on the current data transfer,
* PORT or PASV.
*/
int gDataPortMode;
/* We keep track of whether we can even attempt to use Passive FTP.
* After we find out the remote server doesn't support it, we won't
* keep asking every time we want to do a transfer.
*/
int gHasPASV;
/* Need to special case if trying to read the startup message from the
* server, so our command handler won't jump to the wrong spot if
* the server hangs up at that point.
*/
int gReadingStartup = 0;
HangupProc gHangupProc;
/* Network addresses of the sockets we use. */
struct sockaddr_in gServerCtrlAddr;
struct sockaddr_in gServerDataAddr;
struct sockaddr_in gOurClientCtrlAddr;
struct sockaddr_in gOurClientDataAddr;
/* Real name (not alias) registered to the host we're connected to. */
string gActualHostName;
/* Internet Protocol address of host we're connected to, as a string. */
char gIPStr[32];
extern int gDoneApplication;
/*
* Some declare these with int's, others (hpux...) with size_t.
*
extern int gethostname(char *, int), getdomainname(char *, int);
*
*/
struct hostent *GetHostEntry(char *host, struct in_addr *ip_address);
void InitDefaultFTPPort(void)
{
#ifdef FTP_PORT
/* If FTP_PORT is defined, we use a different port number by default
* than the one supplied in the servent structure.
*/
gFTPPort = FTP_PORT;
#else
struct servent *ftp;
if ((ftp = getservbyname("ftp", "tcp")) == NULL)
gFTPPort = (unsigned int) kDefaultFTPPort;
else
gFTPPort = (unsigned int) ntohs(ftp->s_port);
#endif /* FTP_PORT */
#ifdef HAVE_LIBSOCKS
SOCKSinit("ncftp");
#endif
} /* InitDefaultFTPPort */
void MyInetAddr(char *dst, size_t siz, char **src, int i)
{
struct in_addr *ia;
char *cp;
Strncpy(dst, "???", siz);
if (src != (char **) 0) {
ia = (struct in_addr *) src[i];
cp = inet_ntoa(*ia);
if ((cp != (char *) 0) && (cp != (char *) -1))
Strncpy(dst, cp, siz);
}
} /* MyInetAddr */
/* 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.
*/
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 = gethostbyaddr((char *) &ip, (int) sizeof(ip), AF_INET);
} else {
/* No IP address, so it must be a hostname, like ftp.wustl.edu. */
hp = gethostbyname(host);
if (hp != NULL)
ip = * (struct in_addr *) hp->h_addr_list;
}
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);
#else
struct hostent *hp;
int result;
char **curAlias;
char nodeName[64], domain[64], tmpdomain[64];
char *cp;
size_t nodeNameLen;
host[0] = '\0';
result = gethostname(host, (int) siz);
if ((result < 0) || (host[0] == '\0')) {
(void) fprintf(stderr,
"Could not determine the hostname. Re-compile with HOSTNAME defined\n\
to be the full name of your hostname, i.e. -DHOSTNAME=\\\"cse.unl.edu\\\".\n");
Exit(kExitBadHostName);
}
if (strchr(host, '.') != NULL) {
/* gethostname returned full name (like "cse.unl.edu"), instead
* of just the node name (like "cse").
*/
return (1);
}
hp = GetHostEntry(host, NULL);
if (hp != NULL) {
/* Maybe the host entry has the full name. */
Strncpy(host, (char *) hp->h_name, siz);
if (strchr((char *) hp->h_name, '.') != NULL) {
/* The 'name' field for the host entry had full name. */
return (2);
}
/* Now try the list of aliases, to see if any of those look real. */
STRNCPY(nodeName, host);
nodeNameLen = strlen(nodeName);
for (curAlias = hp->h_aliases; *curAlias != NULL; curAlias++) {
/* See if this name is longer than the node name; we assume
* longer == more detailed.
*/
if (strlen(*curAlias) > nodeNameLen) {
/* We will use this one if it looks like this name is
* a superset of the nodename; so if it contains the
* nodename, assume that this will work.
*/
if (strstr(*curAlias, nodeName) != NULL)
Strncpy(host, *curAlias, siz);
}
}
/* See if the final thing we decided on in the host entry
* looks complete.
*/
if (strchr(host, '.') != NULL)
return (3);
}
/* Otherwise, we just have the node name. See if we can get the
* domain name ourselves.
*
* It'd be so much simpler if you would just define DOMAINNAME
* and get it over with!
*/
#ifdef DOMAINNAME
(void) STRNCPY(domain, DOMAINNAME);
#else
domain[0] = '\0';
# ifdef HAVE_GETDOMAINNAME
/* getdomainname() returns just the domain name, without a
* preceding period. For example, on "cse.unl.edu", it would
* return "unl.edu".
*
* SunOS note: getdomainname will return an empty string if
* this machine isn't on NIS.
*/
if (getdomainname(domain, (int) sizeof(domain)) < 0)
DebugMsg("getdomainname failed.\n");
if (domain[0] == '\0')
DebugMsg("getdomainname did not return anything.\n");
else {
/*
* local domain names
*
* These can now be determined from the domainname system call.
* The first component of the NIS domain name is stripped off unless
* it begins with a dot or a plus sign.
*/
if (domain[0] == '+')
domain[0] = '.';
# ifdef NIS_GETDOMAINNAME
if (domain[0] != '.') {
/* Strip off first component. */
cp = strchr(domain, '.');
if (cp != NULL) {
STRNCPY(tmpdomain, cp + 1);
STRNCPY(domain, tmpdomain);
}
}
# else
# ifdef DNS_GETDOMAINNAME
/* Don't do anything, since it should have reutrned the
* whole domain we want.
*/
# else
{
int dots;
for (dots = 0, cp = domain; *cp; cp++)
if (*cp == '.')
++dots;
/* You didn't say if you were running NIS, so only assume a
* NIS domain if there are three components or more (i.e.
* getdomainname returned something like aaa.bbb.ccc), which
* would have two dots or more. Otherwise, it would be an
* error to strip off "unl." from "unl.edu" if there were
* only two components returned.
*/
if ((dots > 1) && (domain[0] != '.')) {
/* Strip off first component. */
cp = strchr(domain, '.');
if (cp != NULL) {
STRNCPY(tmpdomain, cp + 1);
STRNCPY(domain, tmpdomain);
}
}
}
# endif /* DNS_GETDOMAINNAME */
# endif /* NIS_GETDOMAINNAME */
}
# endif /* HAVE_GETDOMAINNAME */
#endif /* DOMAINNAME */
if (domain[0] != '\0') {
/* Supposedly, it's legal for getdomainname() to return one 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);
return(4);
} else {
fprintf(stderr,
"WARNING: could not determine full host name (have: '%s').\n\
The program should be re-compiled with DOMAINNAME defined to be the\n\
domain name, i.e. -DDOMAINNAME=\\\"unl.edu\\\"\n\n",
host);
}
return(5);
#endif /* !HOSTNAME */
} /* GetOurHostName */
void CloseControlConnection(void)
{
/* This will close each file, if it was open. */
CloseFile(&gControlIn);
CloseFile(&gControlOut);
gConnected = 0;
} /* CloseControlConnection */
static
int GetSocketAddress(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(kDoPerror, "Could not get socket name.\n");
result = -1;
}
return (result);
} /* GetSocketAddress */
void SetLinger(int sockfd)
{
#ifdef SO_LINGER
struct linger li;
li.l_onoff = 1;
li.l_linger = 120; /* 2 minutes, but system ignores field. */
/* 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)
DebugMsg("Note: Linger mode could not be enabled.\n");
#endif /* SO_LINGER */
} /* SetLinger */
void SetTypeOfService(int sockfd, int tosType)
{
#ifdef IP_TOS
/* 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)
DebugMsg("Note: Type-of-service could not be set.\n");
#endif /* IP_TOS */
} /* SetTypeOfService */
void SetInlineOutOfBandData(int sockfd)
{
#ifdef SO_OOBINLINE
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, (int) sizeof(on)) < 0)
DebugMsg("Note: May not be able to handle out-of-band data.");
#endif /* SO_OOBINLINE */
} /* SetInlineOutOfBandData */
int OpenControlConnection(char *host, unsigned int port)
{
struct in_addr ip_address;
int err = 0;
int result;
int sockfd = -1, sock2fd = -1;
ResponsePtr rp;
char **curaddr;
struct hostent *hp;
/* Since we're the client, we just have to get a socket() and
* connect() it.
*/
ZERO(gServerCtrlAddr);
/* Assume it's a fatal error, unless we say otherwise. */
result = kConnectErrFatal;
/* Make sure we use network byte-order. */
port = (unsigned int) htons((unsigned short) port);
gServerCtrlAddr.sin_port = port;
hp = GetHostEntry(host, &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(kDontPerror, "%s: Unknown host.\n", host);
return (result);
}
gServerCtrlAddr.sin_family = AF_INET;
gServerCtrlAddr.sin_addr.s_addr = ip_address.s_addr;
} else {
gServerCtrlAddr.sin_family = hp->h_addrtype;
/* We'll fill in the rest of the structure below. */
}
if ((sockfd = socket(gServerCtrlAddr.sin_family, SOCK_STREAM, 0)) < 0) {
Error(kDoPerror, "Could not get a socket.\n");
return (result);
}
/* Okay, we have a socket, now 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.
*/
err = connect(sockfd, (struct sockaddr *) &gServerCtrlAddr,
(int) sizeof (gServerCtrlAddr));
} 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++) {
/* This could overwrite the address field in the structure,
* but this is okay because the structure has a junk field
* just for this purpose.
*/
memcpy(&gServerCtrlAddr.sin_addr, *curaddr, (size_t) hp->h_length);
err = connect(sockfd, (struct sockaddr *) &gServerCtrlAddr,
(int) sizeof (gServerCtrlAddr));
if (err == 0)
break;
}
}
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) {
case ENETDOWN:
case ENETUNREACH:
case ECONNABORTED:
case ETIMEDOUT:
case ECONNREFUSED:
case EHOSTDOWN:
result = kConnectErrReTryable;
/*FALLTHROUGH*/
default:
Error(kDoPerror, "Could not connect to %s.\n", host);
}
goto fatal;
}
/* Get our end of the socket address for later use. */
if (GetSocketAddress(sockfd, &gOurClientCtrlAddr) < 0)
goto fatal;
/* We want Out-of-band data to appear in the regular stream,
* since we can handle TELNET.
*/
SetInlineOutOfBandData(sockfd);
#if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
/* Control connection is somewhat interactive, so quick response
* is desired.
*/
SetTypeOfService(sockfd, IPTOS_LOWDELAY);
#endif
if ((sock2fd = dup(sockfd)) < 0) {
Error(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 ((gControlIn = fdopen(sockfd, "r")) == NULL) {
Error(kDoPerror, "Could not fdopen.\n");
goto fatal;
}
if ((gControlOut = fdopen(sock2fd, "w")) == NULL) {
Error(kDoPerror, "Could not fdopen.\n");
CloseFile(&gControlIn);
sockfd = kClosedFileDescriptor;
goto fatal;
}
/* 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(gControlIn);
setlinebuf(gControlOut);
#else
(void) SETVBUF(gControlIn, NULL, _IOLBF, (size_t) BUFSIZ);
(void) SETVBUF(gControlOut, NULL, _IOLBF, (size_t) BUFSIZ);
#endif
(void) STRNCPY(gIPStr, inet_ntoa(gServerCtrlAddr.sin_addr));
if ((hp == NULL) || (hp->h_name == NULL))
(void) STRNCPY(gActualHostName, host);
else
(void) STRNCPY(gActualHostName, (char *) hp->h_name);
/* Read the startup message from the server. */
rp = InitResponse();
gReadingStartup = 1;
if (GetResponse(rp) == 5) {
/* 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.
*/
gReadingStartup = 0;
result = kConnectErrReTryable;
CloseFile(&gControlIn);
CloseFile(&gControlOut);
sockfd = kClosedFileDescriptor;
sock2fd = kClosedFileDescriptor;
DoneWithResponse(rp);
goto fatal;
}
gReadingStartup = 0;
DoneWithResponse(rp);
gHasPASV = 1; /* Assume we have it, until proven otherwise. */
gConnected = 1;
return (kConnectNoErr);
fatal:
if (sockfd > 0)
close(sockfd);
if (sock2fd > 0)
close(sock2fd);
return (result);
} /* OpenControlConnection */
void CloseDataConnection(void)
{
if (gDataSocket != kClosedFileDescriptor) {
close(gDataSocket);
gDataSocket = kClosedFileDescriptor;
}
} /* CloseDataConnection */
int SetStartOffset(long restartPt)
{
if (restartPt != SZ(0)) {
if (RCmd(kDefaultResponse, "REST %lu", (unsigned long) restartPt) == 3) {
DebugMsg("Starting at %lu bytes.\n", (unsigned long) restartPt);
} else {
DebugMsg("Could not start at %lu bytes.\n", (unsigned long) restartPt);
return (-1);
}
}
return (0);
} /* SetStartOffset */
static
int SendPort(struct sockaddr_in *saddr)
{
char *a, *p;
int result;
ResponsePtr rp;
rp = InitResponse();
/* 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.
*/
RCmd(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]));
/* A 500'ish response code means the PORT command failed. */
result = ((rp->codeType == 5) ? (-1) : 0);
DoneWithResponse(rp);
return (result);
} /* SendPort */
static
int Passive(struct sockaddr_in *saddr, int *weird)
{
ResponsePtr rp;
int i[6], j;
unsigned char n[6];
char *cp;
int result;
result = -1;
rp = InitResponse();
RCmd(rp, "PASV");
if (rp->codeType != 2) {
/* Didn't understand or didn't want passive port selection. */
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') {
DebugMsg("Cannot parse PASV response: %s\n", rp->msg.first->line);
goto done;
}
if (isdigit(*cp))
break;
}
if (sscanf(cp, "%d,%d,%d,%d,%d,%d",
&i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6) {
DebugMsg("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);
}
memcpy(&saddr->sin_addr, &n[0], (size_t) 4);
memcpy(&saddr->sin_port, &n[4], (size_t) 2);
result = 0;
done:
DoneWithResponse(rp);
return (result);
} /* Passive */
int OpenDataConnection(int mode)
{
int dataSocket;
int weirdPort;
/* 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:
CloseDataConnection(); /* In case we didn't before... */
dataSocket = socket(AF_INET, SOCK_STREAM, 0);
if (dataSocket < 0) {
Error(kDoPerror, "Could not get a data socket.\n");
return (-1);
}
if ((gHasPASV == 0) || (mode == kSendPortMode)) {
tryPort:
gOurClientDataAddr.sin_family = AF_INET;
gOurClientDataAddr = gOurClientCtrlAddr;
/* bind will assign us an unused port, typically between 1024-5000. */
gOurClientDataAddr.sin_port = 0;
#ifdef HAVE_LIBSOCKS
if (Rbind(dataSocket, (struct sockaddr *) &gOurClientDataAddr,
(int) sizeof (gOurClientDataAddr),
gServerCtrlAddr.sin_addr.s_addr) < 0)
#else
if (bind(dataSocket, (struct sockaddr *) &gOurClientDataAddr,
(int) sizeof (gOurClientDataAddr)) < 0)
#endif
{
Error(kDoPerror, "Could not bind the data socket.\n");
goto bad;
}
/* Need to do this so we can figure out which port the system
* gave to us.
*/
if (GetSocketAddress(dataSocket, &gOurClientDataAddr) < 0)
goto bad;
if (listen(dataSocket, 1) < 0) {
Error(kDoPerror, "listen failed.\n");
goto bad;
}
if (SendPort(&gOurClientDataAddr) < 0)
goto bad;
gDataPortMode = kSendPortMode;
} else {
/* Passive mode. Let the other side decide where to send. */
gOurClientDataAddr.sin_family = AF_INET;
gOurClientDataAddr = gOurClientCtrlAddr;
if ((!gHasPASV) || (Passive(&gOurClientDataAddr, &weirdPort) < 0)) {
Error(kDontPerror, "Passive mode refused.\n");
gHasPASV = 0;
/* 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;
goto bad;
}
if (connect(dataSocket, (struct sockaddr *) &gOurClientDataAddr,
(int) sizeof(gOurClientDataAddr)) < 0 ) {
if ((weirdPort > 0) && (errno == ECONNREFUSED)) {
EPrintF("Server sent back a bogus port number.\nI will fall back to PORT instead of PASV mode.\n");
if (mode == kFallBackToSendPortMode) {
close(dataSocket);
gHasPASV = 0;
goto tryPort2;
}
goto bad;
}
Error(kDoPerror, "connect failed.\n");
goto bad;
}
gDataPortMode = kPassiveMode;
}
SetLinger(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.
*/
SetTypeOfService(dataSocket, IPTOS_THROUGHPUT);
#endif
gDataSocket = dataSocket;
return (0);
bad:
(void) close(dataSocket);
return (-1);
} /* OpenDataConnection */
int AcceptDataConnection(int mode)
{
int newSocket;
int len;
/* If we did a PORT, we have some things to finish up.
* If we did a PASV, we're ready to go.
*/
if (gDataPortMode == kSendPortMode) {
/* Accept will give us back the server's data address; at the
* moment we don't do anything with it though.
*/
len = (int) sizeof(gServerDataAddr);
newSocket = accept(gDataSocket, (struct sockaddr *) &gServerDataAddr, &len);
(void) close(gDataSocket);
if (newSocket < 0) {
Error(kDoPerror, "Could not accept a data connection.\n");
gDataSocket = kClosedFileDescriptor;
return (-1);
}
gDataSocket = newSocket;
}
return (0);
} /* AcceptDataConnection */
/* Kind of silly, but I wanted to keep this module as self-contained
* as possible.
*/
void SetPostHangupOnServerProc(HangupProc proc)
{
gHangupProc = proc;
} /* SetPostHangupOnServerProc */
void HangupOnServer(void)
{
int wasConn;
wasConn = gConnected;
/* 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().
*/
if (wasConn != 0) {
CloseControlConnection();
CloseDataConnection();
if (gHangupProc != (HangupProc)0)
(*gHangupProc)();
}
} /* HangupOnServer */
void SendTelnetInterrupt(void)
{
char msg[4];
/* 1. User system inserts the Telnet "Interrupt Process" (IP) signal
* in the Telnet stream.
*/
(void) fprintf(gControlOut, "%c%c", IAC, IP);
(void) fflush(gControlOut);
/* 2. User system sends the Telnet "Sync" signal. */
#if 1
msg[0] = IAC;
msg[1] = DM;
if (send(fileno(gControlOut), msg, 2, MSG_OOB) != 2)
Error(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] = IAC;
if (send(fileno(gControlOut), msg, 1, MSG_OOB) != 1)
Error(kDoPerror, "Could not send an urgent message.\n");
(void) fprintf(gControlOut, "%c", DM);
(void) fflush(gControlOut);
#endif
} /* SendTelnetInterrupt */
/* eof FTP.c */