错误代码1024 tftp服务器

时间:2018-02-13 20:33:28

标签: c++ c tftp

我在C中编写一个tftp服务器,并在终端上使用tftp命令对其进行测试。但是,在大多数情况下,当我尝试发送RRQ时,我会收到以下内容:

tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received ERROR <code=4, msg=>
Error code 1024: 

其他重大事件包括:

tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received DATA <block=20334, 512 bytes>
discarded 4 packets

和这一个:这看起来可能正确,但它几乎没有发生。我用来测试它的文本文件是857字节。

sent ACK <block=1>
received DATA <block=1, 512 bytes>
sent ACK <block=1>
received DATA <block=2, 345 bytes>
Received 857 bytes in 0.0 seconds

这是我的代码的一部分 这里缓冲区是一个大小为512的char数组,为了简化代码,我删除了一些错误处理代码 感谢任何可能提供帮助的人

            #include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/select.h> 
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <cerrno>


//define opcode for later use
enum opcode {
     RRQ = 1,
     WRQ,
     DATA,
     ACK,
     ERROR
};


void handle_write(struct sockaddr_in * sock_info, char* filename, int BUF_LEN){
    //printf("Received write request + %d\n", WRQ);
    return;
}

void handle_error(unsigned short int * opcode_ptr, char* buffer, socklen_t sockaddr_len, int server_socket, struct sockaddr_in * sock_info, const char* errormsg){
     ssize_t n;
     *opcode_ptr = htons(ERROR);
     *(opcode_ptr + 1) = htons(1);
     *(buffer + 4) = 0;
     //memcpy(buffer+4, errormsg, strlen(errormsg));
 intr_send:
     n = sendto(server_socket, buffer, 5, 0,
                (struct sockaddr *)sock_info, sockaddr_len);
     if(n < 0) {
         if(errno == EINTR) goto intr_send;
         perror(errormsg);
         exit(-1);
     }
    return;
}

int main() {
    int BUF_LEN = 516;
    ssize_t n;
    char buffer[BUF_LEN];
    socklen_t sockaddr_len;
    int server_socket;
    struct sigaction act;
    unsigned short int opcode;
    unsigned short int * opcode_ptr;
    struct sockaddr_in sock_info;
    memset(&sock_info, 0, sockaddr_len);

    //----------setup the server----------------//
    sock_info.sin_addr.s_addr = htonl(INADDR_ANY);
    sock_info.sin_port = htons(5743);
    sock_info.sin_family = PF_INET;

    if((server_socket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket");
        exit(-1);
    }

    sockaddr_len = sizeof(sock_info);
    if(bind(server_socket, (struct sockaddr *)&sock_info, sockaddr_len) < 0) {
        perror("bind");
        exit(-1);
    }

    getsockname(server_socket, (struct sockaddr *)&sock_info, &sockaddr_len);
    printf("UDP server listening on port: %d\n", ntohs(sock_info.sin_port));
    //----------setup the server----------------//

    while(1){
    intr_recv:
         n = recvfrom(server_socket, buffer, BUF_LEN, 0, (struct sockaddr *)&sock_info, &sockaddr_len);

         if(n < 0) {
            if(errno == EINTR) goto intr_recv;
            perror("recvfrom()");
            exit(-1);
        }
        opcode_ptr = (unsigned short int *)buffer;
        opcode = ntohs(*opcode_ptr);    //the opcode will be either RRQ or WRQ according to the test
        if(opcode != RRQ && opcode != WRQ) {
            /* Illegal TFTP Operation */
            handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid command");
        }
        else {
            if(fork() == 0) {
                /* Child - handle the request */
                FILE* fd;
                char* filename;
                filename = strdup(buffer+2);  //this is the filename to be read (i.e. a.txt)

                printf("request received\n");
                char data[512];
                //----------------------------------handle read request-------------------------------------//
                if(opcode == RRQ){
                    int blocknumber = 0;
                    int i = 0; //counter for loop
                    fd = fopen(filename, "r");
                    free(filename);
                    //uint8_t data[512];
                    ssize_t datalen, n;
                    int done = 0;   //this is a boolean indicator that indicates whether the packet transfering process is done or not.
                    while(!done){
                        datalen = fread(data, 1, 512, fd);
                        blocknumber++;
                        if(datalen < 512){
                            done = 1;       //according to rfc 1350, the last packet will have a data length less than 512 bytes.
                        }
                        //for(i = 5; i > 0; i--){
                        *opcode_ptr = htons(DATA);
                        opcode = ntohs(*opcode_ptr);
                        *(opcode_ptr + 1) = htons(blocknumber);
                        memcpy(buffer + 4, data, datalen);
                        buffer[datalen + 4] = '\0';
                        //*(buffer + 4) = 0;
                        //printf("%d  %s\n", datalen, buffer+2);
                        n = sendto(server_socket, buffer, 4 + datalen, 0, (struct sockaddr *)&sock_info, sockaddr_len);
                        if(n < 0){
                            perror("sendto() failed");
                            exit(-1);
                        }
                        //printf("done %d\n", done);
                        //char buffer[512];
                        n = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&sock_info, &sockaddr_len);
                        opcode_ptr = (unsigned short int *)buffer;
                        opcode = ntohs(*opcode_ptr);
                        if(n >= 0 && n < 4){
                            //handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid request size");
                        }
                         if(n > 4){
                             break;
                         }
                         //}
                        //if(i != 0){
                        //    printf("Transfer timeout!\n");
                        //    exit(1);
                        //}
                        //printf("opcode is %d\n", opcode);
                        if(opcode == ERROR){
                            printf("Error received\n");
                            exit(1);
                        }

                        if(opcode != ACK){
                            printf("Invalid message received\n");
                            exit(1);
                        }
                    }
                }
                //----------------------------------handle read request-------------------------------------//



                //----------------------------------handle write request------------------------------------//

                //----------------------------------handle write request------------------------------------//

                close(server_socket);
                break;
            }
            else {
                /* Parent - continue to wait */
            }
        }
    }






    return EXIT_SUCCESS;
}

1 个答案:

答案 0 :(得分:0)

我读了你的代码但没有通过执行来测试。

RFC 1350比较,我找到的是

  • 数据字段最多为512字节,因此512字节buffer是不够的,因为标题没有空间(操作码和块#)。您至少需要4个字节。
  • 您通过buffer + 2memcpy()撰写数据。这应该破坏块号。似乎应该使用buffer + 4
  • buffer[datalen + 2] = '\0';不应该被需要。我认为你应该删除它,因为它会破坏数据或导致缓冲区溢出。
  • 您应该在处理读取请求后关闭打开的文件。