Code:
int tftp_receive_ext(struct sockaddr_in *to1,char *name,char *mode,int innum,
char (*TFTPwrite)(char *,long ,char,void *),
void *argu,int vPKTSIZE)
{
char *buf, *ackbuf, *dat, *cp;
struct tftphdr *datapacket, *ackpacket;
int i, size, n, nto, ptp;
struct timeval tv;
u_short nextsegnum;
fd_set fdfileset;
struct sockaddr_in from,to=*to1;
size_t fromlen=sizeof(from),tolen=fromlen;
buf = (char*)malloc(vPKTSIZE);
if (buf==NULL) {
fprintf(stderr,"TFTP: out of memory.\n");
return 255;
}
ackbuf=(char*)malloc(vPKTSIZE);
if (ackbuf==NULL) {
fprintf(stderr,"TFTP: out of memory.\n");
free(buf);
return 255;
}
datapacket = (struct tftphdr *)buf;
ackpacket = (struct tftphdr *)ackbuf;
dat = (char*)&datapacket->th_data[0];
cp = (char*)&ackpacket->th_stuff[0];
i=0;
if ((ptp=create_socket(SOCK_DGRAM, &i, NULL))<0) {
syslog(1,"creation socket client: %m\n");
free(buf); free(ackbuf);
return 255;
}
if (innum) {
ackpacket->th_opcode=htons((u_short)RRQ);
strcpy(cp, name);
cp += strlen(name);
*cp++ = '\0';
strcpy(cp, mode);
cp += strlen(mode);
*cp++ = '\0';
size=(DWORD)cp-(DWORD)ackbuf;
}
else {
ackpacket->th_opcode=htons((u_short)ACK);
ackpacket->th_block=0;
size=4;
}
nextsegnum=1;
do {
nto=0;
do {
if (nto==numTimeOut) {
close(ptp);
free(buf);
free(ackbuf);
return 255;
}
if (sendto(ptp,ackpacket,size,0,(struct sockaddr *)&to,tolen)!=size)
{
syslog(1, "tftp is writing: %m\n");
close(ptp);
free(buf);
free(ackbuf);
return 255;
}
do {
n=-1;
FD_ZERO(&fdfileset);
FD_SET(ptp,&fdfileset);
tv.tv_sec=TimeOut; tv.tv_usec=0;
if ((i=select(ptp+1, &fdfileset, NULL, NULL, &tv))==-1) {
syslog(1,"select error.\n");
close(ptp);
free(buf);
free(ackbuf);
return 255;
}
if (i>0)
n=recvfrom(ptp, datapacket, vPKTSIZE, 0,(struct sockaddr *)&from, &fromlen);
} while ((n<0)&&(i>0));
if (i>0) {
to.sin_port=from.sin_port;
datapacket->th_opcode = ntohs((u_short)datapacket->th_opcode);
datapacket->th_block = ntohs((u_short)datapacket->th_block);
if (datapacket->th_opcode != DATA) {
close(ptp); free(buf); free(ackbuf);
return 255;
}
if (datapacket->th_block != nextsegnum) {
ioctl(ptp, FIONREAD, &i);
while (i)
{
recv(ptp, datapacket, vPKTSIZE, 0);
ioctl(ptp, FIONREAD, &i);
};
datapacket->th_block=nextsegnum+1;
}
}
nto++;
} while (datapacket->th_block!=nextsegnum);
ackpacket->th_block=htons(nextsegnum);
nextsegnum++;
if (nextsegnum==2) {
ackpacket->th_opcode=htons((u_short)ACK);
size=4;
}
if (n-4>0)
{
if (nextsegnum==2)
i=(*TFTPwrite)(dat,n-4,1,argu);
else
i=(*TFTPwrite)(dat,n-4,0,argu);
if (i) {
close(ptp); free(buf); free(ackbuf);
return i;
}
}
} while (n == vPKTSIZE);
sendto(ptp, ackpacket, 4, 0,(struct sockaddr *)&to,tolen);
close(ptp);
free(buf);
free(ackbuf);
return 0;
}