код ошибки 1024 tftp сервер

Я пишу tftp-сервер на C и тестирую его с помощью команды 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, для упрощения кода я удалил часть кода обработки ошибок Спасибо всем, кто может помочь

            #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;
}

person AllenLiiu574    schedule 13.02.2018    source источник
comment
Пожалуйста, включите образец кода, а не ссылку на его изображение.   -  person Dragonthoughts    schedule 13.02.2018


Ответы (1)


Я прочитал ваш код, но не проверял его выполнением.

Сравнивая с RFC 1350, я обнаружил следующее:

  • Поле данных имеет размер до 512 байт, поэтому 512 байт buffer недостаточно, поскольку нет места для заголовка (код операции и номер блока). Вам нужно как минимум еще 4 байта.
  • Вы записываете данные из buffer + 2 через memcpy(). Это должно уничтожить номер блока. Кажется, вместо этого следует использовать buffer + 4.
  • buffer[datalen + 2] = '\0'; не нужно. Я думаю, вы должны удалить его, потому что он уничтожит данные или вызовет переполнение буфера.
  • Вы должны закрыть файл, открытый после обработки запроса на чтение.
person MikeCAT    schedule 13.02.2018
comment
Благодарю. вот код. буфер + 4 уменьшил шанс получить код ошибки, но он все еще существует. Я обновлю свой полный код. - person AllenLiiu574; 14.02.2018
comment
@ AllenLiiu574 buffer[datalen + 4] = '\0'; может вызвать переполнение буфера, например buffer[datalen + 2] = '\0';. Убери это. - person MikeCAT; 15.02.2018