/*
*------------------------------------------------------------------
*
* $Source: /afs/net.mit.edu/dapps/project/techinfodev/src/srv_ti/RCS/netio.c,v $
* $Revision: 1.5 $
* $Date: 92/08/28 16:09:26 $
* $State: Exp $
* $Author: ark $
* $Locker: ark $
*
* $Log: netio.c,v $
* Revision 1.5 92/08/28 16:09:26 ark
* Summer 1992 final version
*
* Revision 1.4 92/08/27 17:11:11 ark
* Retropatched error message file to allow old clients to work
*
* Revision 1.3 92/08/06 18:43:47 ark
* Admin command "B" no longer crashes when there are many connections.
*
* Revision 1.2 92/08/04 16:27:31 ark
* Test production version 8/4/92
*
* Revision 1.1 92/07/22 11:09:18 ark
* Saber loads quietly; ANSI use standardized; command line options; no behavioral changes
*
* Revision 1.0 92/07/10 12:32:28 ark
* Initial revision
*
* Revision 1.1 91/07/15 10:40:20 thorne
* Initial revision
*
*------------------------------------------------------------------
*/
#ifndef lint
#ifndef SABER
static char *rcsid_foo_c = "$Header: /afs/net.mit.edu/dapps/project/techinfodev/src/srv_ti/RCS/netio.c,v 1.5 92/08/28 16:09:26 ark Exp Locker: ark $";
#endif SABER
#endif lint
/*
Copyright (C) 1989 by the Massachusetts Institute of Technology
Export of this software from the United States of America is assumed
to require a specific license from the United States Government.
It is the responsibility of any person or organization contemplating
export to obtain such a license before exporting.
WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
distribute this software and its documentation for any purpose and
without fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation, and that
the name of M.I.T. not be used in advertising or publicity pertaining
to distribution of the software without specific, written prior
permission. M.I.T. makes no representations about the suitability of
this software for any purpose. It is provided "as is" without express
or implied warranty.
*/
/* These routines handle most of the non-blocking IO for the server. This does
not use the LWP package. Its pupose is to allow the server to go ahead and
do something else if a connection blocks.
S. Thorne 3/28/91 */
void
nio_send_file(int sock, char *filename, long startpoint, long requested)
{
long fd, red,len, should_send;
char *iobuf, *cp;
struct stat st;
if ((fd = open(filename, O_RDONLY, 0644)) < 0) {
/*
* This error message has no code because of the format of the
* header returned below; in order to be backward compatible with
* old clients, atoi() on this error message must return 0.
*/
send_msg(msglist[ SENDFILE_CANT_ACCESS ], sock);
return;
}
fstat(fd, &st);
if (st.st_mode & S_IFDIR)
{
send_msg(msglist[ SENDFILE_IS_DIRECTORY ], sock);
close(fd);
return;
}
lseek(fd, startpoint, L_SET);
should_send = min(st.st_size - startpoint + EOLM_LEN,requested + EOLM_LEN);
if (should_send < 0)
should_send = EOLM_LEN;
iobuf = domalloc((unsigned int) should_send + 200);
bzero(iobuf,should_send +200);
sprintf(iobuf,"%ld Total Characters :%ld sent:This document was last modified on %s\n",
st.st_size, should_send, ctime(&st.st_mtime));
len = strlen(iobuf);
cp = index(iobuf,'\0');
red = read(fd,cp,should_send - EOLM_LEN);
if (red < 0)
{
send_msg(msglist[ SENDFILE_CANT_ACCESS ], sock);
close(fd);
return;
}
cp = cp + red;
bcopy(EOLM,cp,EOLM_LEN);
sendbuf(iobuf,len + red + EOLM_LEN, sock);
close(fd);
return;
}
/* If a write would have blocked, save it away so that we can send the
remaining text later */
void
add_send(char *start, char *ptr, int size, int sock)
{
TOSEND *rec;
int i;
for (i = 0; i < FD_SETSIZE; i++) {
if (conntab[i].c_socket == sock) {
conntab[i].c_ptr = rec;
break;
}
}
return;
}
/* remove a pending send */
void
remove_send(TOSEND *ptr)
{
int i;
ActiveJobs--;
for (i = 0; i < FD_SETSIZE; i++) {
if (conntab[i].c_ptr == ptr) {
if (debug)
printf("Finished blocked send to socket #%d.\n", conntab[i].c_socket);
break;
}
}
if (ptr->buf != _sendbuf)
do_free(ptr->buf); /* do_free the text buffer */
do_free(ptr);
conntab[i].c_ptr = NULL;
return;
}
/* add a pending receive */
void
add_recv(int fd, char *file_name, int sock)
{
TOREC *rec;
int i;
ActiveJobs++;
rec = (TOREC *) domalloc((unsigned int) sizeof(TOREC));
rec->sock = sock;
rec->the_fd = fd;
rec->filename = file_name;
for (i = 0; i < FD_SETSIZE; i++) {
if (conntab[i].c_socket == sock) {
conntab[i].c_recptr = rec;
break;
}
}
return;
}
void
remove_rec(TOREC *ptr) /* remove a pending receive from the list */
{
int i;
ActiveJobs--;
for (i = 0; i < FD_SETSIZE; i++)
if (conntab[i].c_recptr == ptr)
break;
do_free(ptr->filename);
do_free(ptr);
conntab[i].c_recptr = NULL;
return;
}
int
sendbuf(char *buf, int size, int sock)
{
int len = BUFSIZ,rc;
char *startbuf;
startbuf = buf;
while (size)
{
if (size <= BUFSIZ)
len = size;
rc = write(sock,buf,len);
if (rc < 0)
{
if (errno == EWOULDBLOCK) /* would block, so save info, and leave it
will be done later */
{
if (debug)
printf("Write blocked on socket #%d.\n", sock);
add_send(startbuf,buf,size,sock);
return 1;
}
if (startbuf != _sendbuf)
do_free(startbuf);
return -1;
}
size = size - rc;
buf = buf + rc;
}
if (startbuf != _sendbuf)
do_free(startbuf);
return 0;
}
int
send_more(TOSEND *ptr)
{
int size,len = BUFSIZ,rc,sock;
char *buf;
if (ptr == NULL) {
return 0;
}
size = ptr->size;
buf = ptr->ptr;
sock = ptr->sock;
if (debug)
printf("Continuing send to socket #%d.\n",sock);
while (size)
{
if (size <= BUFSIZ)
len = size;
rc = write(sock,buf,len);
if (rc <= 0){
ptr->size = size; /* update the TOSEND record */
ptr->ptr = buf;
if (errno == EWOULDBLOCK) /* would block, so save info, and leave it
will be done later */
{
if (debug)
printf("Write blocked again on socket #%d.\n", sock);
return 1;
}
return -1;
}
size = size - rc;
buf = buf + rc;
}
remove_send(ptr);
return 0; /* Added for consistency 7/15/92 ark */
}
/* does the work of receiving a file */
void
nio_rec_more(TOREC *ptr)
{
int red, done;
char in_buff[BUFSIZ];
errno = 0;
done = FALSE;
for (;;) {
red = read(ptr->sock, in_buff, BUFSIZ);
if (debug)
printf("Received %d bytes from socket #%d.\n", red, ptr->sock);
while (red > 0)
{
if (!strncmp(&in_buff[red - EOM_LEN], EOM, EOM_LEN))
{
write(ptr->the_fd, in_buff, red - EOM_LEN);
done = TRUE;
break;
}
else
write(ptr->the_fd, in_buff, red);
red = read(ptr->sock, in_buff, BUFSIZ);
} /* end of while */
if (done) {
close_recfile(ptr);
remove_rec(ptr);
break;
}
else /* EWOULDBLOCK */
return; /* no settings to update, so just leave */
} /* end of forever */
}
/* Try to back up destination file with a ~ on the end of its
filename. Then move our temporary file, ending with .tmp, to the
destination file. */
void
close_recfile(TOREC *ptr)
{
char tempfile[MAXPATHLEN],backup_fname[MAXPATHLEN],in_buff[BUFSIZ];
int rc;
sprintf(tempfile,"%s.tmp",ptr->filename);
sprintf(backup_fname,"%s~",ptr->filename);
if (close(ptr->the_fd))
printf("Couldn't close file descriptor %d on receipt of file!\n",
ptr->the_fd);
/* We really shouldn't try to do this rename if the file doesn't exist! */
rc = rename(ptr->filename, backup_fname);
if (rc == 0)
if (debug)
printf("Backed up existing file %s to %s.\n",
ptr->filename, backup_fname);
rc = rename(tempfile,ptr->filename);
if (rc)
printf("Temporary file %s couldn't be renamed!\n", tempfile);
else
printf("Wrote file %s.\n", ptr->filename);
chmod(ptr->filename,0644);
/* Tell client if final rename worked */
if (rc)
sprintf(in_buff, "%s\n%s", msglist[ CANT_OPEN ], EOM);
else
sprintf(in_buff, "%s\n%s", msglist[ OK ], EOM);
write(ptr->sock, in_buff,strlen(in_buff));
}