Blame tftpsubs.c

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