/* *------------------------------------------------------------------ * * $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 */ #include #include #include #include #include #include #include #include "pdb.h" #include "network.h" #include "messages.h" TOSEND *firstrec = NULL; TOREC *first = NULL; extern CONN conntab[]; extern int ActiveJobs; char _sendbuf[BUFSIZ]; char *_sendbuf_pos = _sendbuf; extern char *msglist[]; extern void log_trans(char *str); extern int is_directory(int fd); extern int cur_sock; extern int debug; int dosend(char *str, char *buf, char **curpos); int dodeliver(char *buf, char **curpos, int sock); void nio_send_file(int sock, char *filename, long startpoint, long requested); void add_send(char *start, char *ptr, int size, int sock); void remove_send(TOSEND *ptr); void add_recv(int fd, char *file_name, int sock); void remove_rec(TOREC *ptr); int sendbuf(char *buf, int size, int sock); int send_more(TOSEND *ptr); void nio_rec_more(TOREC *ptr); void send_msg(char *str, int sock); void close_recfile(TOREC *ptr); /* macros and all that junk were too damn kludgy for me --lam */ void send_msg (char *str, int sock) { char *ptr; #define NOMSG "99:There is no error msg text assigned here" if (!str) { ptr = domalloc (sizeof(NOMSG) + EOLM_LEN); strcpy (ptr, NOMSG); } else { ptr = domalloc (strlen(str)+ 1 + EOLM_LEN); strcpy (ptr, str); } strcat (ptr, EOLM); sendbuf (ptr, strlen(ptr), sock); } 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; if (debug) printf("Starting blocked send to socket #%d.\n", sock); ActiveJobs++; rec = (TOSEND *) domalloc((unsigned int) sizeof(TOSEND)); rec->sock = sock; rec->ptr = ptr; rec->buf = start; rec->size = size; 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)); }