[ale] sendto: Invalid Argument
chrisf at computone.com
chrisf at computone.com
Wed Jan 17 18:15:26 EST 2001
Help,
I hacked up tftp.c from NetKit to allow me to retrieve only a file and do it by command line options.
It seems to compile fine but each time I run it, I get an EINVAL in sendto of recvfile().
I can;t seem to see the problems with my own eyse but maybe someone here might be able to see it.
2 files:
main.c - Majorally hacked
tftp.c - Minor hack
Any help would be appreciated,
Chris
----- Main.c
/* SYS */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
/* NET */
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
/* SYSTEM */
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Function Prototypes */
int main(int argc, char *argv[]);
void setpeer(int argc, char *argv[]);
void get(char *filename);
/* Public Declerations */
#define TIMEOUT 5
struct sockaddr_in s_inn;
static short port;
static char mode[32];
static struct servent *sp;
static char hostname[100];
int f;
int rexmtval = TIMEOUT;
int maxtimeout = 5 * TIMEOUT ;
int
main(int argc, char *argv[])
{
struct sockaddr_in s_in;
if ( argc != 4 )
{
fprintf(stderr, "usage: %s [hostname or IP] [port] [filename to restore]\n", argv[0]);
fprintf(stderr, " All options are required\n");
exit(1);
}
sp = getservbyname("tftp", "udp");
if ( sp == 0)
{
fprintf(stderr, "tftp: tftp/udp unknown service.\n");
exit(1);
}
f = socket(AF_INET, SOCK_DGRAM, 0);
if ( f < 0 )
{
perror("tftp: socket");
exit(1);
}
memset(&s_in, 0, sizeof(s_in));
s_in.sin_family = AF_INET;
if (bind(f, (struct sockaddr *)&s_in, sizeof(s_in)) < 0 )
{
perror("tftp: bind");
exit(1);
}
strcpy(mode, "netascii");
printf("filename: %s\n", argv[3]);
strcpy(mode, "netoctet");
get(argv[3]);
return 0;
}
void
setpeer(int argc, char *argv[])
{
struct hostent *host;
if ( argc != 4 )
{
fprintf(stderr, "usage: %s [hostname or IP] [port] [filename to restore]\n", argv[0]);
fprintf(stderr, " All options are required\n");
exit(1);
}
host = gethostbyname(argv[1]);
if (host)
{
s_inn.sin_family = host->h_addrtype;
if ( host->h_length > (int)sizeof(s_inn.sin_addr))
{
host->h_length = sizeof(s_inn.sin_addr);
}
memcpy(&s_inn.sin_addr, host->h_addr, host->h_length);
strncpy(hostname, host->h_name, sizeof(hostname));
hostname[sizeof(hostname) - 1 ] = 0;
}
else
{
s_inn.sin_family = AF_INET;
if(!inet_aton(argv[1], &s_inn.sin_addr))
{
fprintf(stderr, "unknown host: %s\n", argv[1]);
exit(1);
}
strcpy(hostname, argv[1]);
}
port = sp->s_port;
port = atoi(argv[2]);
if ( port < 0 )
{
fprintf(stderr, "bad port number %s\n", argv[2]);
exit(1);
}
port = htons(port);
}
void
get(char *filename)
{
int fd;
fd = creat(filename, 0644);
if ( fd < 0 )
{
fprintf(stderr, "tftp: ");
perror(filename);
}
s_inn.sin_port = port;
recvfile(fd, filename, mode);
}
---- Tftp.c
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* From: @(#)tftp.c 5.10 (Berkeley) 3/1/91
*/
char tftp_rcsid[] =
"$Id: tftp.c,v 1.6 1996/08/29 22:25:27 dholland Exp $";
/* Many bug fixes are from Jim Guyton <guyton at rand-unix> */
/*
* TFTP User Program -- Protocol Machines
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/tftp.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <setjmp.h>
#include <unistd.h>
#include <string.h>
#include "tftpsubs.h"
extern struct sockaddr_in s_inn; /* filled in by main */
extern int f; /* the opened socket */
extern int rexmtval;
extern int maxtimeout;
void recvfile(int fd, char *name, char *modestr);
#define PKTSIZE SEGSIZE+4
static char ackbuf[PKTSIZE];
static int timeout;
static sigjmp_buf timeoutbuf;
static int makerequest(int request, char *name,
struct tftphdr *tp, char *mode);
static void nak(int errnor);
static void tpacket(const char *s, struct tftphdr *tp, int n);
static void startclock(void);
static void stopclock(void);
static void printstats(const char *direction, unsigned long amount);
static
void
timer(int signum)
{
(void)signum;
timeout += rexmtval;
if (timeout >= maxtimeout) {
printf("Transfer timed out.\n");
exit(1);
}
siglongjmp(timeoutbuf, 1);
}
/*
* Receive a file.
*/
void
recvfile(int fd, char *name, char *mode)
{
register struct tftphdr *ap;
struct tftphdr *dp;
volatile int block = 1, size = 0;
int n;
volatile unsigned long amount = 0;
struct sockaddr_in from;
size_t fromlen;
volatile int firsttrip = 1;
FILE *file;
volatile int convert; /* true if converting crlf -> lf */
startclock();
dp = w_init();
ap = (struct tftphdr *)ackbuf;
file = fdopen(fd, "w");
convert = !strcmp(mode, "netascii");
signal(SIGALRM, timer);
do {
if (firsttrip) {
size = makerequest(RRQ, name, ap, mode);
firsttrip = 0;
} else {
ap->th_opcode = htons((u_short)ACK);
ap->th_block = htons((u_short)(block));
size = 4;
block++;
}
timeout = 0;
send_ack:
printf("%d\n", f);
if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&s_inn,
sizeof (s_inn)) != size) {
alarm(0);
perror("tftp: sendto");
goto abort;
}
write_behind(file, convert);
for ( ; ; ) {
alarm(rexmtval);
do {
fromlen = sizeof (from);
n = recvfrom(f, dp, PKTSIZE, 0,
(struct sockaddr *)&from, &fromlen);
} while (n <= 0);
alarm(0);
if (n < 0) {
perror("tftp: recvfrom");
goto abort;
}
s_inn.sin_port = from.sin_port; /* added */
/* should verify client address */
dp->th_opcode = ntohs(dp->th_opcode);
dp->th_block = ntohs(dp->th_block);
if (dp->th_opcode == ERROR) {
printf("Error code %d: %s\n", dp->th_code,
dp->th_msg);
goto abort;
}
if (dp->th_opcode == DATA) {
volatile int j = 0;
if (dp->th_block == block) {
break; /* have next packet */
}
/* On an error, try to synchronize
* both sides.
*/
j = synchnet(f);
if (dp->th_block == (block-1)) {
goto send_ack; /* resend ack */
}
}
}
/* size = write(fd, dp->th_data, n - 4); */
size = writeit(file, &dp, n - 4, convert);
if (size < 0) {
nak(errno + 100);
break;
}
amount += size;
} while (size == SEGSIZE);
abort: /* ok to ack, since user */
ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
ap->th_block = htons((u_short)block);
(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&s_inn, sizeof(s_inn));
write_behind(file, convert); /* flush last buffer */
fclose(file);
stopclock();
if (amount > 0)
printstats("Received", amount);
}
int
makerequest(int request, char *name, struct tftphdr *tp, char *mode)
{
register char *cp;
tp->th_opcode = htons((u_short)request);
cp = tp->th_stuff;
strcpy(cp, name);
cp += strlen(name);
*cp++ = '\0';
strcpy(cp, mode);
cp += strlen(mode);
*cp++ = '\0';
return (cp - (char *)tp);
}
struct errmsg {
int e_code;
const char *e_msg;
} errmsgs[] = {
{ EUNDEF, "Undefined error code" },
{ ENOTFOUND, "File not found" },
{ EACCESS, "Access violation" },
{ ENOSPACE, "Disk full or allocation exceeded" },
{ EBADOP, "Illegal TFTP operation" },
{ EBADID, "Unknown transfer ID" },
{ EEXISTS, "File already exists" },
{ ENOUSER, "No such user" },
{ -1, 0 }
};
/*
* Send a nak packet (error message).
* Error code passed in is one of the
* standard TFTP codes, or a UNIX errno
* offset by 100.
*/
void
nak(int error)
{
register struct errmsg *pe;
register struct tftphdr *tp;
int length;
tp = (struct tftphdr *)ackbuf;
tp->th_opcode = htons((u_short)ERROR);
tp->th_code = htons((u_short)error);
for (pe = errmsgs; pe->e_code >= 0; pe++)
if (pe->e_code == error)
break;
if (pe->e_code < 0) {
pe->e_msg = strerror(error - 100);
tp->th_code = EUNDEF;
}
strcpy(tp->th_msg, pe->e_msg);
length = strlen(pe->e_msg) + 4;
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&s_inn,
sizeof (s_inn)) != length)
perror("nak");
}
static
void
tpacket(const char *s, struct tftphdr *tp, int n)
{
static const char *opcodes[] =
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
register char *cp, *file;
u_short op = ntohs(tp->th_opcode);
if (op < RRQ || op > ERROR)
printf("%s opcode=%x ", s, op);
else
printf("%s %s ", s, opcodes[op]);
switch (op) {
case RRQ:
case WRQ:
n -= 2;
file = cp = tp->th_stuff;
cp = cp + strlen(cp);
printf("<file=%s, mode=%s>\n", file, cp + 1);
break;
case DATA:
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
break;
case ACK:
printf("<block=%d>\n", ntohs(tp->th_block));
break;
case ERROR:
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
break;
}
}
struct timeval tstart;
struct timeval tstop;
struct timezone zone;
void
startclock(void) {
gettimeofday(&tstart, &zone);
}
void
stopclock(void) {
gettimeofday(&tstop, &zone);
}
void
printstats(const char *direction, unsigned long amount)
{
double delta;
/* compute delta in 1/10's second units */
delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
delta = delta/10.; /* back to seconds */
printf("%s %ld bytes in %.1f seconds", direction, amount, delta);
putchar('\n');
}
--
To unsubscribe: mail majordomo at ale.org with "unsubscribe ale" in message body.
More information about the Ale
mailing list