Ejemplo n.º 1
0
void *listen_for_ack(void* data) {
	printf("listening thread is started ...\n");
	receive_socket = establish_receive_connection();
	struct sockaddr_storage their_addr;
	socklen_t addr_len = sizeof their_addr;
	while (1) {
		unsigned char buf[INT_SIZE];
		int akc_seq;
		if ((recvfrom(receive_socket, buf, INT_SIZE, 0,
				(struct sockaddr *) &their_addr, &addr_len)) == -1) {
			perror("ack recv");
			exit(1);
		}
		memcpy(&akc_seq, buf, INT_SIZE);
		ack_packet(akc_seq);
	}
}
Ejemplo n.º 2
0
/*
 * Get a fresh packet if the buffer is drained, and we haven't hit
 * EOF yet.  The buffer should be filled immediately after draining!
 */
static void tftp_get_packet(struct inode *inode)
{
    uint16_t last_pkt;
    const uint8_t *timeout_ptr;
    uint8_t timeout;
    uint16_t buffersize;
    uint16_t serial;
    jiffies_t oldtime;
    struct tftp_packet *pkt = NULL;
    uint16_t buf_len;
    struct pxe_pvt_inode *socket = PVT(inode);
    uint16_t src_port;
    uint32_t src_ip;
    int err;

    /*
     * Start by ACKing the previous packet; this should cause
     * the next packet to be sent.
     */
    timeout_ptr = TimeoutTable;
    timeout = *timeout_ptr++;
    oldtime = jiffies();

ack_again:
    ack_packet(inode, socket->tftp_lastpkt);

    while (timeout) {
        buf_len = socket->tftp_blksize + 4;
        err = core_udp_recv(socket, socket->tftp_pktbuf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();

            if (now-oldtime >= timeout) {
                oldtime = now;
                timeout = *timeout_ptr++;
                if (!timeout)
                    break;
                goto ack_again;
            }
            continue;
        }

        if (buf_len < 4)	/* Bad size for a DATA packet */
            continue;

        pkt = (struct tftp_packet *)(socket->tftp_pktbuf);
        if (pkt->opcode != TFTP_DATA)    /* Not a data packet */
            continue;

        /* If goes here, recevie OK, break */
        break;
    }

    /* time runs out */
    if (timeout == 0)
        kaboom();

    last_pkt = socket->tftp_lastpkt;
    last_pkt++;
    serial = ntohs(pkt->serial);
    if (serial != last_pkt) {
        /*
         * Wrong packet, ACK the packet and try again.
         * This is presumably because the ACK got lost,
         * so the server just resent the previous packet.
         */
#if 0
        printf("Wrong packet, wanted %04x, got %04x\n", \
               htons(last_pkt), htons(*(uint16_t *)(data+2)));
#endif
        goto ack_again;
    }

    /* It's the packet we want.  We're also EOF if the size < blocksize */
    socket->tftp_lastpkt = last_pkt;    /* Update last packet number */
    buffersize = buf_len - 4;		/* Skip TFTP header */
    socket->tftp_dataptr = socket->tftp_pktbuf + 4;
    socket->tftp_filepos += buffersize;
    socket->tftp_bytesleft = buffersize;
    if (buffersize < socket->tftp_blksize) {
        /* it's the last block, ACK packet immediately */
        ack_packet(inode, serial);

        /* Make sure we know we are at end of file */
        inode->size 		= socket->tftp_filepos;
        socket->tftp_goteof	= 1;
        tftp_close_file(inode);
    }
}
Ejemplo n.º 3
0
/**
 * Open a TFTP connection to the server
 *
 * @param:inode, the inode to store our state in
 * @param:ip, the ip to contact to get the file
 * @param:filename, the file we wanna open
 *
 * @out: open_file_t structure, stores in file->open_file
 * @out: the lenght of this file, stores in file->file_len
 *
 */
void tftp_open(struct url_info *url, int flags, struct inode *inode,
               const char **redir)
{
    struct pxe_pvt_inode *socket = PVT(inode);
    char *buf;
    uint16_t buf_len;
    char *p;
    char *options;
    char *data;
    static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
    char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
    char reply_packet_buf[PKTBUF_SIZE];
    int err;
    int buffersize;
    int rrq_len;
    const uint8_t  *timeout_ptr;
    jiffies_t timeout;
    jiffies_t oldtime;
    uint16_t opcode;
    uint16_t blk_num;
    uint64_t opdata;
    uint16_t src_port;
    uint32_t src_ip;

    (void)redir;		/* TFTP does not redirect */
    (void)flags;

    if (url->type != URL_OLD_TFTP) {
        /*
         * The TFTP URL specification allows the TFTP to end with a
         * ;mode= which we just ignore.
         */
        url_unescape(url->path, ';');
    }

    if (!url->port)
        url->port = TFTP_PORT;

    socket->ops = &tftp_conn_ops;
    if (core_udp_open(socket))
        return;

    buf = rrq_packet_buf;
    *(uint16_t *)buf = TFTP_RRQ;  /* TFTP opcode */
    buf += 2;

    buf = stpcpy(buf, url->path);

    buf++;			/* Point *past* the final NULL */
    memcpy(buf, rrq_tail, sizeof rrq_tail);
    buf += sizeof rrq_tail;

    rrq_len = buf - rrq_packet_buf;

    timeout_ptr = TimeoutTable;   /* Reset timeout */
sendreq:
    timeout = *timeout_ptr++;
    if (!timeout)
        return;			/* No file available... */
    oldtime = jiffies();

    core_udp_sendto(socket, rrq_packet_buf, rrq_len, url->ip, url->port);

    /* If the WRITE call fails, we let the timeout take care of it... */
wait_pkt:
    for (;;) {
        buf_len = sizeof(reply_packet_buf);

        err = core_udp_recv(socket, reply_packet_buf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();
            if (now - oldtime >= timeout)
                goto sendreq;
        } else {
            /* Make sure the packet actually came from the server and
               is long enough for a TFTP opcode */
            dprintf("tftp_open: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n",
                    buf_len,
                    ((uint8_t *)&src_ip)[0],
                    ((uint8_t *)&src_ip)[1],
                    ((uint8_t *)&src_ip)[2],
                    ((uint8_t *)&src_ip)[3],
                    ((uint8_t *)&url->ip)[0],
                    ((uint8_t *)&url->ip)[1],
                    ((uint8_t *)&url->ip)[2],
                    ((uint8_t *)&url->ip)[3]);
            if ((src_ip == url->ip) && (buf_len >= 2))
                break;
        }
    }

    core_udp_disconnect(socket);
    core_udp_connect(socket, src_ip, src_port);

    /* filesize <- -1 == unknown */
    inode->size = -1;
    socket->tftp_blksize = TFTP_BLOCKSIZE;
    buffersize = buf_len - 2;	  /* bytes after opcode */

    /*
     * Get the opcode type, and parse it
     */
    opcode = *(uint16_t *)reply_packet_buf;
    switch (opcode) {
    case TFTP_ERROR:
        inode->size = 0;
        goto done;        /* ERROR reply; don't try again */

    case TFTP_DATA:
        /*
         * If the server doesn't support any options, we'll get a
         * DATA reply instead of OACK. Stash the data in the file
         * buffer and go with the default value for all options...
         *
         * We got a DATA packet, meaning no options are
         * suported. Save the data away and consider the
         * length undefined, *unless* this is the only
         * data packet...
         */
        buffersize -= 2;
        if (buffersize < 0)
            goto wait_pkt;
        data = reply_packet_buf + 2;
        blk_num = ntohs(*(uint16_t *)data);
        data += 2;
        if (blk_num != 1)
            goto wait_pkt;
        socket->tftp_lastpkt = blk_num;
        if (buffersize > TFTP_BLOCKSIZE)
            goto err_reply;	/* Corrupt */

        socket->tftp_pktbuf = malloc(TFTP_BLOCKSIZE + 4);
        if (!socket->tftp_pktbuf)
            goto err_reply;	/* Internal error */

        if (buffersize < TFTP_BLOCKSIZE) {
            /*
             * This is the final EOF packet, already...
             * We know the filesize, but we also want to
             * ack the packet and set the EOF flag.
             */
            inode->size = buffersize;
            socket->tftp_goteof = 1;
            ack_packet(inode, blk_num);
        }

        socket->tftp_bytesleft = buffersize;
        socket->tftp_dataptr = socket->tftp_pktbuf;
        memcpy(socket->tftp_pktbuf, data, buffersize);
        goto done;

    case TFTP_OACK:
        /*
         * Now we need to parse the OACK packet to get the transfer
         * and packet sizes.
         */

        options = reply_packet_buf + 2;
        p = options;

        while (buffersize) {
            const char *opt = p;

            /*
             * If we find an option which starts with a NUL byte,
             * (a null option), we're either seeing garbage that some
             * TFTP servers add to the end of the packet, or we have
             * no clue how to parse the rest of the packet (what is
             * an option name and what is a value?)  In either case,
             * discard the rest.
             */
            if (!*opt)
                goto done;

            while (buffersize) {
                if (!*p)
                    break;	/* Found a final null */
                *p++ |= 0x20;
                buffersize--;
            }
            if (!buffersize)
                break;		/* Unterminated option */

            /* Consume the terminal null */
            p++;
            buffersize--;

            if (!buffersize)
                break;		/* No option data */

            opdata = 0;

            /* do convert a number-string to decimal number, just like atoi */
            while (buffersize--) {
                uint8_t d = *p++;
                if (d == '\0')
                    break;              /* found a final null */
                d -= '0';
                if (d > 9)
                    goto err_reply;     /* Not a decimal digit */
                opdata = opdata*10 + d;
            }

            if (!strcmp(opt, "tsize"))
                inode->size = opdata;
            else if (!strcmp(opt, "blksize"))
                socket->tftp_blksize = opdata;
            else
                goto err_reply; /* Non-negotitated option returned,
				   no idea what it means ...*/


        }

        if (socket->tftp_blksize < 64 || socket->tftp_blksize > PKTBUF_SIZE)
            goto err_reply;

        /* Parsing successful, allocate buffer */
        socket->tftp_pktbuf = malloc(socket->tftp_blksize + 4);
        if (!socket->tftp_pktbuf)
            goto err_reply;
        else
            goto done;

    default:
        printf("TFTP unknown opcode %d\n", ntohs(opcode));
        goto err_reply;
    }

err_reply:
    /* Build the TFTP error packet */
    tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
    inode->size = 0;

done:
    if (!inode->size)
        core_udp_close(socket);

    return;
}
Ejemplo n.º 4
0
int tftp_rcv(char* file, int socketFd)
{
	/* create file with given name */
	/* send first request */
	/* get tid and change port number as per tid 
	 * if it is first run then store it is some variable otherwise compare with it
	 * and it they are not equal then crate error */
	/* subsequent packet might be data/error packet
	 * start timer and wait for data packet until timeout 
	 * extract data and block number from that
	 * using block number create ack request
	 * send that ack and write data into file
	 * if data packet is less then 512 then it means it is last packet */

	/* local variables */
	int server_len, opcode, tid = 0;
	int i, j, n;
	unsigned short int count = 0, rcount = 0;
	unsigned char filebuf[DATA_SIZE + 1];
	unsigned char packetbuf[DATA_SIZE + 12];
	extern int errno;
	char filename[128], mode[12];
	char *bufptr;
	struct sockaddr_in data;
	FILE *fp;			/* pointer to the file we will be getting */

	strcpy (mode, "netascii");
	fp = fopen (file, "w");	/* open the file for writing */
	if (fp == NULL)
	{				//if the pointer is null then the file can't be opened - Bad perms 
		printf ("Client requested bad file: cannot open for writing (%s)\n",
					file);
		return -1;
	}
	
	printf ("Getting file... (destination: %s) \n", file);
	rw_req_packet(socketFd, READ, file, "netascii");
	
	memset (filebuf, 0, sizeof (filebuf));
	n = DATA_SIZE + 4;
	
	do
	{
		memset (packetbuf, 0, sizeof (packetbuf));
		
		if (n != (DATA_SIZE + 4))
		{
			printf("Last chunk detected (file chunk size: %d). exiting while loop\n",n - 4);
			printf("Last packet recieved");
			ack_packet(socketFd, count, buf);
			//fclose (fp);
			printf ("The Client has sent an ACK for packet\n");
			goto done;
		}

		count++;

		for (j = 0; j < RTCOUNT; j++)
		{
			server_len = sizeof (data);
			errno = EAGAIN;
			n = -1;
			for (i = 0; errno == EAGAIN && i <= TIMEOUT && n < 0; i++)
			{
				n = recvfrom (socketFd, packetbuf, sizeof (packetbuf) - 1,
							MSG_DONTWAIT, (struct sockaddr *) &data,
							(socklen_t *) & server_len);
				usleep (1000);
			}

			if (!tid)
			{
				tid = ntohs (data.sin_port);
				server.sin_port = htons (tid);
			}

			if (n < 0 && errno == EAGAIN)	/* If timeout occurs */
			{
				printf("Client packet got lost");
				printf ("Timeout waiting for data");
			}
			else
			{
				
				bufptr = (char *) packetbuf;	/*start our pointer going*/
				if (bufptr++[0] != 0x00)
					printf ("bad first nullbyte!\n");
				opcode = *bufptr++;
				rcount = *bufptr++ << 8;
				rcount &= 0xff00;
				rcount += (*bufptr++ & 0x00ff);
				memcpy ((char *) filebuf, bufptr, n - 4);
				if (opcode != 3)
				{
					printf("Badly ordered/invalid data packet (Got OP: %d Block: %d) (Wanted Op: 3 Block: %d)\n",
							 opcode, rcount, count);
					if (opcode > 5)
					{
						error_code = 0x04;
						//error_packet(socketFd, error_code, err_msg[error_code]);
					}
				}
				else
				{
					ack_packet(socketFd, count, buf);
					break;
				}		//end of else
			}
		}
		if (j == RTCOUNT)
		{
			printf ("Data recieve Timeout. Aborting transfer\n");
			fclose (fp);
			return -1;
		}
	}
	while (fwrite (filebuf, 1, n - 4, fp) == n - 4);

done:

	fclose (fp);
	sync ();
	printf ("fclose and sync successful. File received successfully\n");
	return 0;

}
/* Create an ACK packet */
LSP_Packet MessageProcessor::create_ack_packet(LSP_Packet& packet) const
{
	LSP_Packet ack_packet(packet.getConnId(), packet.getSeqNo(), 0, NULL);
	return ack_packet;
}