Blame tftpsubs.c

Packit 1034e0
/*
Packit 1034e0
 * Copyright (c) 1983 Regents of the University of California.
Packit 1034e0
 * All rights reserved.
Packit 1034e0
 *
Packit 1034e0
 * Redistribution and use in source and binary forms, with or without
Packit 1034e0
 * modification, are permitted provided that the following conditions
Packit 1034e0
 * are met:
Packit 1034e0
 * 1. Redistributions of source code must retain the above copyright
Packit 1034e0
 *    notice, this list of conditions and the following disclaimer.
Packit 1034e0
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 1034e0
 *    notice, this list of conditions and the following disclaimer in the
Packit 1034e0
 *    documentation and/or other materials provided with the distribution.
Packit 1034e0
 * 3. Neither the name of the University nor the names of its contributors
Packit 1034e0
 *    may be used to endorse or promote products derived from this software
Packit 1034e0
 *    without specific prior written permission.
Packit 1034e0
 *
Packit 1034e0
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit 1034e0
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 1034e0
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 1034e0
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit 1034e0
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 1034e0
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 1034e0
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 1034e0
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 1034e0
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 1034e0
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 1034e0
 * SUCH DAMAGE.
Packit 1034e0
 */
Packit 1034e0
/* Simple minded read-ahead/write-behind subroutines for tftp user and
Packit 1034e0
   server.  Written originally with multiple buffers in mind, but current
Packit 1034e0
   implementation has two buffer logic wired in.
Packit 1034e0
Packit 1034e0
   Todo:  add some sort of final error check so when the write-buffer
Packit 1034e0
   is finally flushed, the caller can detect if the disk filled up
Packit 1034e0
   (or had an i/o error) and return a nak to the other side.
Packit 1034e0
Packit 1034e0
			Jim Guyton 10/85
Packit 1034e0
 */
Packit 1034e0
Packit 1034e0
#include <sys/types.h>
Packit 1034e0
#include <sys/socket.h>
Packit 1034e0
#include <sys/ioctl.h>
Packit 1034e0
#include <netinet/in.h>
Packit 1034e0
#include <unistd.h>
Packit 1034e0
#include <stdio.h>
Packit 1034e0
Packit 1034e0
#include "tftp.h"
Packit 1034e0
Packit 1034e0
struct bf {
Packit 1034e0
	int counter;            /* size of data in buffer, or flag */
Packit 1034e0
	char buf[PKTSIZE];      /* room for data packet */
Packit 1034e0
} bfs[2];
Packit 1034e0
Packit 1034e0
				/* Values for bf.counter  */
Packit 1034e0
#define BF_ALLOC -3             /* alloc'd but not yet filled */
Packit 1034e0
#define BF_FREE  -2             /* free */
Packit 1034e0
/* [-1 .. SEGSIZE] = size of data in the data buffer */
Packit 1034e0
Packit 1034e0
static int nextone;     /* index of next buffer to use */
Packit 1034e0
static int current;     /* index of buffer in use */
Packit 1034e0
Packit 1034e0
			/* control flags for crlf conversions */
Packit 1034e0
int newline = 0;        /* fillbuf: in middle of newline expansion */
Packit 1034e0
int prevchar = -1;      /* putbuf: previous char (cr check) */
Packit 1034e0
Packit 1034e0
struct tftphdr *rw_init(int);
Packit 1034e0
Packit 1034e0
struct tftphdr *w_init() { return rw_init(0); }         /* write-behind */
Packit 1034e0
struct tftphdr *r_init() { return rw_init(1); }         /* read-ahead */
Packit 1034e0
Packit 1034e0
/* init for either read-ahead or write-behind */
Packit 1034e0
/* x is zero for write-behind, one for read-head */
Packit 1034e0
struct tftphdr *rw_init(int x)
Packit 1034e0
{
Packit 1034e0
	newline = 0;            /* init crlf flag */
Packit 1034e0
	prevchar = -1;
Packit 1034e0
	bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */
Packit 1034e0
	current = 0;
Packit 1034e0
	bfs[1].counter = BF_FREE;
Packit 1034e0
	nextone = x;                    /* ahead or behind? */
Packit 1034e0
	return (struct tftphdr *)bfs[0].buf;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
Packit 1034e0
/* Have emptied current buffer by sending to net and getting ack.
Packit 1034e0
   Free it and return next buffer filled with data.
Packit 1034e0
 */
Packit 1034e0
int readit(FILE * file, struct tftphdr **dpp, int convert)
Packit 1034e0
{
Packit 1034e0
	struct bf *b;
Packit 1034e0
Packit 1034e0
	bfs[current].counter = BF_FREE; /* free old one */
Packit 1034e0
	current = !current;             /* "incr" current */
Packit 1034e0
Packit 1034e0
	b = &bfs[current];              /* look at new buffer */
Packit 1034e0
	if (b->counter == BF_FREE)      /* if it's empty */
Packit 1034e0
		read_ahead(file, convert);      /* fill it */
Packit 1034e0
#if 0
Packit 1034e0
	assert(b->counter != BF_FREE);  /* check */
Packit 1034e0
#endif
Packit 1034e0
	*dpp = (struct tftphdr *)b->buf;        /* set caller's ptr */
Packit 1034e0
	return b->counter;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/*
Packit 1034e0
 * fill the input buffer, doing ascii conversions if requested
Packit 1034e0
 * conversions are  lf -> cr,lf  and cr -> cr, nul
Packit 1034e0
 */
Packit 1034e0
void read_ahead(FILE *file, int convert)
Packit 1034e0
{
Packit 1034e0
	register int i;
Packit 1034e0
	register char *p;
Packit 1034e0
	register int c;
Packit 1034e0
	struct bf *b;
Packit 1034e0
	struct tftphdr *dp;
Packit 1034e0
Packit 1034e0
	b = &bfs[nextone];              /* look at "next" buffer */
Packit 1034e0
	if (b->counter != BF_FREE)      /* nop if not free */
Packit 1034e0
		return;
Packit 1034e0
	nextone = !nextone;             /* "incr" next buffer ptr */
Packit 1034e0
Packit 1034e0
	dp = (struct tftphdr *)b->buf;
Packit 1034e0
Packit 1034e0
	if (convert == 0) {
Packit 1034e0
		b->counter = read(fileno(file), dp->th_data, SEGSIZE);
Packit 1034e0
		return;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	p = dp->th_data;
Packit 1034e0
	for (i = 0 ; i < SEGSIZE; i++) {
Packit 1034e0
		if (newline) {
Packit 1034e0
			if (prevchar == '\n')
Packit 1034e0
				c = '\n';       /* lf to cr,lf */
Packit 1034e0
			else    c = '\0';       /* cr to cr,nul */
Packit 1034e0
			newline = 0;
Packit 1034e0
		}
Packit 1034e0
		else {
Packit 1034e0
			c = getc(file);
Packit 1034e0
			if (c == EOF) break;
Packit 1034e0
			if (c == '\n' || c == '\r') {
Packit 1034e0
				prevchar = c;
Packit 1034e0
				c = '\r';
Packit 1034e0
				newline = 1;
Packit 1034e0
			}
Packit 1034e0
		}
Packit 1034e0
	       *p++ = c;
Packit 1034e0
	}
Packit 1034e0
	b->counter = (int)(p - dp->th_data);
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/* Update count associated with the buffer, get new buffer
Packit 1034e0
   from the queue.  Calls write_behind only if next buffer not
Packit 1034e0
   available.
Packit 1034e0
 */
Packit 1034e0
int writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
Packit 1034e0
{
Packit 1034e0
	bfs[current].counter = ct;      /* set size of data to write */
Packit 1034e0
	current = !current;             /* switch to other buffer */
Packit 1034e0
	if (bfs[current].counter != BF_FREE)     /* if not free */
Packit 1034e0
		write_behind(file, convert);     /* flush it */
Packit 1034e0
	bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
Packit 1034e0
	*dpp =  (struct tftphdr *)bfs[current].buf;
Packit 1034e0
	return ct;                      /* this is a lie of course */
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/*
Packit 1034e0
 * Output a buffer to a file, converting from netascii if requested.
Packit 1034e0
 * CR,NUL -> CR  and CR,LF => LF.
Packit 1034e0
 * Note spec is undefined if we get CR as last byte of file or a
Packit 1034e0
 * CR followed by anything else.  In this case we leave it alone.
Packit 1034e0
 */
Packit 1034e0
int write_behind(FILE *file, int convert)
Packit 1034e0
{
Packit 1034e0
	char *buf;
Packit 1034e0
	int count;
Packit 1034e0
	register int ct;
Packit 1034e0
	register char *p;
Packit 1034e0
	register int c;                 /* current character */
Packit 1034e0
	struct bf *b;
Packit 1034e0
	struct tftphdr *dp;
Packit 1034e0
Packit 1034e0
	b = &bfs[nextone];
Packit 1034e0
	if (b->counter < -1)            /* anything to flush? */
Packit 1034e0
		return 0;               /* just nop if nothing to do */
Packit 1034e0
Packit 1034e0
	count = b->counter;             /* remember byte count */
Packit 1034e0
	b->counter = BF_FREE;           /* reset flag */
Packit 1034e0
	dp = (struct tftphdr *)b->buf;
Packit 1034e0
	nextone = !nextone;             /* incr for next time */
Packit 1034e0
	buf = dp->th_data;
Packit 1034e0
Packit 1034e0
	if (count <= 0) return -1;      /* nak logic? */
Packit 1034e0
Packit 1034e0
	if (convert == 0)
Packit 1034e0
		return write(fileno(file), buf, count);
Packit 1034e0
Packit 1034e0
	p = buf;
Packit 1034e0
	ct = count;
Packit 1034e0
	while (ct--) {                  /* loop over the buffer */
Packit 1034e0
	    c = *p++;                   /* pick up a character */
Packit 1034e0
	    if (prevchar == '\r') {     /* if prev char was cr */
Packit 1034e0
		if (c == '\n')          /* if have cr,lf then just */
Packit 1034e0
		   fseek(file, -1, 1);  /* smash lf on top of the cr */
Packit 1034e0
		else
Packit 1034e0
		   if (c == '\0')       /* if have cr,nul then */
Packit 1034e0
			goto skipit;    /* just skip over the putc */
Packit 1034e0
		/* else just fall through and allow it */
Packit 1034e0
	    }
Packit 1034e0
	    putc(c, file);
Packit 1034e0
skipit:
Packit 1034e0
	    prevchar = c;
Packit 1034e0
	}
Packit 1034e0
	return count;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
Packit 1034e0
/* When an error has occurred, it is possible that the two sides
Packit 1034e0
 * are out of synch.  Ie: that what I think is the other side's
Packit 1034e0
 * response to packet N is really their response to packet N-1.
Packit 1034e0
 *
Packit 1034e0
 * So, to try to prevent that, we flush all the input queued up
Packit 1034e0
 * for us on the network connection on our host.
Packit 1034e0
 *
Packit 1034e0
 * We return the number of packets we flushed (mostly for reporting
Packit 1034e0
 * when trace is active).
Packit 1034e0
 */
Packit 1034e0
Packit 1034e0
int synchnet(int f)
Packit 1034e0
{
Packit 1034e0
	int j = 0;
Packit 1034e0
	char dummy;
Packit 1034e0
Packit 1034e0
	while (1) {
Packit 1034e0
		if (recv(f, &dummy, 1, MSG_DONTWAIT) < 0)
Packit 1034e0
			break;
Packit 1034e0
		j++;
Packit 1034e0
	}
Packit 1034e0
	return j;
Packit 1034e0
}