/***************************************************************************/
/***************************************************************************/
/* */
/* (c) 1995-1999. The Regents of the University of California. All */
/* rights reserved. */
/* */
/* This work was produced at the University of California, Lawrence */
/* Livermore National Laboratory (UC LLNL) under contract no. */
/* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */
/* (DOE) and The Regents of the University of California (University) */
/* for the operation of UC LLNL. Copyright is reserved to the */
/* University for purposes of controlled dissemination, */
/* commercialization through formal licensing, or other disposition */
/* under terms of Contract 48; DOE policies, regulations and orders; */
/* and U.S. statutes. The rights of the Federal Government are */
/* reserved under Contract 48 subject to the restrictions agreed upon */
/* by the DOE and University. */
/* */
/* */
/* DISCLAIMER */
/* */
/* This software was prepared as an account of work sponsored by an */
/* agency of the United States Government. Neither the United States */
/* Government nor the University of California nor any of their */
/* employees, makes any warranty, express or implied, or assumes any */
/* liability or responsibility for the accuracy, completeness, or */
/* usefulness of any information, apparatus, product, or process */
/* disclosed, or represents that its specific commercial products, */
/* process, or service by trade name, trademark, manufacturer, or */
/* otherwise, does not necessarily constitute or imply its */
/* endorsement, recommendation, or favoring by the United States */
/* Government or the University of California. The views and opinions */
/* of the authors expressed herein do not necessarily state or reflect */
/* those of the United States Government or the University of */
/* California, and shall not be used for advertising or product */
/* endorsement purposes. */
/* */
/* Permission to use, copy, modify and distribute this software and its */
/* documentation for any non-commercial purpose, without fee, is */
/* hereby granted, provided that the above copyright notice and this */
/* permission notice appear in all copies of the software and */
/* supporting documentation, and that all UC LLNL identification in */
/* the user interface remain unchanged. The title to copyright LLNL */
/* XDIR shall at all times remain with The Regents of the University */
/* of California and users agree to preserve same. Users seeking the */
/* right to make derivative works with LLNL XDIR for commercial */
/* purposes may obtain a license from the Lawrence Livermore National */
/* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */
/* Livermore, CA 94550. */
/* */
/***************************************************************************/
/***************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#ifdef HIPPI
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <Xm/Xm.h>
#include "xdir.h"
#include "xfer.h"
static char *tcpbuf = NULL;
static char *filebuf = NULL;
extern struct xfer_ctrl_block xc;
extern int max_ftp_retries;
extern int diagnostics;
extern int store_unique;
extern int maxt;
extern int passive_mode;
extern struct st_host_info hinfo[];
/*
* init_put - Initialize transfer of file from local host to remote host.
* "xc" is used for input and output. Returns 0 if successful,
* -4 for lost sink connection, -6 for stop button pushed, and
* -1 for other errors.
*/
init_put()
{
char *src_path;
char *snk_dir;
char *snk_file;
int file_fd;
int data_fd;
long file_len;
long flen;
struct stat status;
int code;
char reply[MAXFTPREPLY];
int sock;
char cmd[MAXPATHLEN+5];
int retval;
char msg[MAXPATHLEN+30];
int retries = 0;
int scode;
int errval;
int sys_tcpbuflen = XFER_SYS_TCPBUFLEN;
char *snk_path;
#ifdef HIPPI
int winshift = XFER_TCPWINSHIFT;
#endif
retry:
/* Open source file and verify that it is a "real" file */
src_paths_of_xfer_node(xc.current_node, NULL, &src_path);
if ((file_fd = iopen2(src_path, O_RDONLY)) < 0) {
report_perror(src_path);
XtFree(src_path);
return -1;
}
if (fstat(file_fd, &status) < 0 || !S_ISREG(status.st_mode)) {
sprintf(msg, "%s is not a \"real\" file", src_path);
XtFree(src_path);
record_warning(msg);
close(file_fd);
return -1;
}
XtFree(src_path);
/* Get length of file */
file_len = status.st_size;
/* "cd" into sink directory */
snk_paths_of_xfer_node(xc.current_node, NULL, &snk_path);
parse_path(xc.snk_host_system, snk_path, &snk_dir,
&snk_file);
XtFree(snk_path);
retval = remote_cd(xc.snk_dirwin->host, snk_dir, True);
XtFree(snk_dir);
switch (retval) {
case 0:
break;
case -3:
XtFree(snk_file);
close(file_fd);
return -4;
case -6:
XtFree(snk_file);
close(file_fd);
return -6;
default:
XtFree(snk_file);
close(file_fd);
return -1;
}
/* Initialize data connection */
if (passive_mode) {
if ((data_fd = passive_data_conn(xc.snk_dirwin->host)) < 0) {
close(file_fd);
return data_fd;
}
} else if ((sock = init_data_conn(xc.snk_dirwin->host)) < 0) {
XtFree(snk_file);
close(file_fd);
if (sock == -3)
return -4;
else
return sock;
}
/* Preallocate storage for UniTree and HPSS FTP servers */
if (hinfo[xc.snk_dirwin->host].server == SERVER_UNIX_HPSS) {
if (file_len < 10) /* HPSS bug workaround */
flen = 10;
else
flen = file_len;
if ((retval = ftp_allocate(xc.snk_dirwin->host, flen)) < 0) {
if (retval == -3)
errval = -4;
else
errval = retval;
goto error;
}
} else if (((hinfo[xc.snk_dirwin->host].server == SERVER_UNIX_UNITREE) ||
(hinfo[xc.snk_dirwin->host].server == SERVER_UNIX_NSL_UNITREE)) &&
(xc.mode == BINARY)) {
if ((retval = ftp_allocate(xc.snk_dirwin->host, file_len)) < 0) {
if (retval == -3)
errval = -4;
else
errval = retval;
goto error;
}
}
/* Send STOR command to FTP server */
if (store_unique)
sprintf(cmd, "STOU %s", snk_file);
else
sprintf(cmd, "STOR %s", snk_file);
XtFree(snk_file);
if ((retval = send_ftp_cmd(xc.snk_dirwin->host, cmd)) < 0) {
switch (retval) {
case -6:
errval = -6;
goto error;
case -3:
errval = -4;
goto error;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
errval = -1;
goto error;
}
}
/* Get initial response from FTP server */
scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 1:
break;
case 4:
close(file_fd);
if (passive_mode)
close(data_fd);
else
close(sock);
if (code >= 450 && code < 460 && retries++ < max_ftp_retries) {
if (diagnostics >= VERBOSE)
write_log("*** Unable to initialize put. Will retry.\n");
goto retry;
}
if (diagnostics < VERBOSE)
report_ftp_reply(xc.snk_dirwin->host, reply);
return -1;
case -3:
errval = -4;
goto error;
case -6:
abort_ftp_cmd(xc.snk_dirwin->host);
errval = -6;
goto error;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(xc.snk_dirwin->host, reply);
errval = -1;
goto error;
}
/* Establish data connection */
if (!passive_mode) {
data_fd = accept_data_conn(sock);
close(sock);
if (data_fd < 0) {
close(file_fd);
return -1;
}
}
/* Attempt to increase TCP send buffer size to improve performance */
#if defined(SOL_SOCKET) && defined(SO_SNDBUF)
setsockopt(data_fd, SOL_SOCKET, SO_SNDBUF, (char *)&sys_tcpbuflen,
sizeof(sys_tcpbuflen));
#endif
/* Optimize tranfer rate for HIPPI channel on UNICOS Cray */
#ifdef HIPPI
setsockopt(data_fd, IPPROTO_TCP, TCP_WINSHIFT, (char *)&winshift,
sizeof(winshift));
#endif
/* Allocate user buffers (but first perform sanity check) */
if (tcpbuf)
fatal_error("Programming bug in init_put() involving tcpbuf");
tcpbuf = XtMalloc(XFER_USER_TCPBUFLEN);
if (filebuf)
fatal_error("Programming bug in init_put() involving filebuf");
filebuf = XtMalloc(XFER_FILEBUFLEN);
xc.data_fd = data_fd;
xc.src_file_fd = file_fd;
xc.file_len = file_len;
xc.file_index = 0;
return 0;
error:
close(file_fd);
if (passive_mode)
close(data_fd);
else
close(sock);
return errval;
}
/*
* do_put - Transfer next part of file from local host to remote host.
* "xc" is used for input and output. Returns 0 if file
* transfer complete, 1 if file transfer not complete,
* -4 for lost sink connection, -7 for a "552" reply (for
* UniTree retry mechanism), -6 for stop button pressed,
* and -1 for other errors.
*/
do_put()
{
int tcp_index = 0;
int nbytes;
int code;
char reply[MAXFTPREPLY];
int i;
int retval;
int scode;
char *src_path;
if (xc.mode == ASCII) {
if (xc.file_index < xc.file_len) {
nbytes = MIN(xc.file_len-xc.file_index, XFER_FILEBUFLEN);
if (iread(xc.src_file_fd, filebuf, nbytes) != nbytes) {
src_paths_of_xfer_node(xc.current_node, NULL, &src_path);
report_perror(src_path);
XtFree(src_path);
return abort_put();
}
for (i=0; i<nbytes; i++)
if (filebuf[i] == '\n') {
if (tcp_index+2 >= XFER_USER_TCPBUFLEN) {
retval = write_tcp(xc.snk_dirwin->host, xc.data_fd,
tcpbuf, tcp_index, maxt);
if (retval != tcp_index) {
switch (retval) {
case -3:
close(xc.src_file_fd);
close(xc.data_fd);
XtFree(tcpbuf);
tcpbuf = NULL;
XtFree(filebuf);
filebuf = NULL;
return -4;
case -6:
abort_put();
return -6;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
return abort_put();
}
}
tcp_index = 0;
}
tcpbuf[tcp_index++] = '\r';
tcpbuf[tcp_index++] = '\n';
} else {
if (tcp_index+1 >= XFER_USER_TCPBUFLEN) {
retval = write_tcp(xc.snk_dirwin->host, xc.data_fd,
tcpbuf, tcp_index, maxt);
if (retval != tcp_index) {
switch (retval) {
case -3:
close(xc.src_file_fd);
close(xc.data_fd);
XtFree(tcpbuf);
tcpbuf = NULL;
XtFree(filebuf);
filebuf = NULL;
return -4;
case -6:
abort_put();
return -6;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
return abort_put();
}
}
tcp_index = 0;
}
tcpbuf[tcp_index++] = filebuf[i];
}
xc.file_index += nbytes;
}
if (tcp_index) {
retval = write_tcp(xc.snk_dirwin->host, xc.data_fd, tcpbuf,
tcp_index, maxt);
if (retval != tcp_index) {
switch (retval) {
case -3:
close(xc.src_file_fd);
close(xc.data_fd);
XtFree(tcpbuf);
tcpbuf = NULL;
XtFree(filebuf);
filebuf = NULL;
return -4;
case -6:
abort_put();
return -6;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
return abort_put();
}
}
}
} else /* Send binary file to FTP server */
if (xc.file_index < xc.file_len) {
nbytes = MIN(xc.file_len-xc.file_index, XFER_FILEBUFLEN);
if (iread(xc.src_file_fd, filebuf, nbytes) != nbytes) {
src_paths_of_xfer_node(xc.current_node, NULL, &src_path);
report_perror(src_path);
XtFree(src_path);
return abort_put();
}
retval = write_tcp(xc.snk_dirwin->host, xc.data_fd, filebuf,
nbytes, maxt);
if (retval != nbytes) {
switch (retval) {
case -3:
close(xc.src_file_fd);
close(xc.data_fd);
XtFree(tcpbuf);
tcpbuf = NULL;
XtFree(filebuf);
filebuf = NULL;
return -4;
case -6:
abort_put();
return -6;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
return abort_put();
}
}
xc.file_index += nbytes;
}
/* Have all the bytes been transferred? */
if (xc.file_index < xc.file_len)
return 1;
/* Close source file */
close(xc.src_file_fd);
/* Close data connection */
close(xc.data_fd);
/* Free up user buffers */
XtFree(tcpbuf);
tcpbuf = NULL;
XtFree(filebuf);
filebuf = NULL;
/* Get final response from FTP server */
scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case -3:
return -4;
case -6:
abort_ftp_cmd(xc.snk_dirwin->host);
return -6;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(xc.snk_dirwin->host, reply);
if (code == 552) /* UniTree retry logic */
return -7;
else
return -1;
}
}
/*
* abort_put - Abort transfer of file from local host to remote host.
* "xc" is used for input and output. Returns -4 for lost
* sink connection, -6 for stop button pushed, else -1.
*/
abort_put()
{
int code;
char reply[MAXFTPREPLY];
int retval;
/* Pop up abort dialog */
show_abort_dialog();
/* Close source file */
close(xc.src_file_fd);
/* Close data connection */
close(xc.data_fd);
/* Make sure that user buffers have been freed */
XtFree(tcpbuf);
tcpbuf = NULL;
XtFree(filebuf);
filebuf = NULL;
/* Get final response from FTP server */
retval = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY, &code,
maxt);
/* Hide abort dialog */
hide_abort_dialog();
/* Finish up */
switch (retval) {
case -3:
return -4;
case -6:
abort_ftp_cmd(xc.snk_dirwin->host);
return -6;
case -2:
report_client_timeout(xc.snk_dirwin->host);
default:
return -1;
}
}
syntax highlighted by Code2HTML, v. 0.9.1