c++ - 错误代码 1024 tftp 服务器

标签 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

这是我的代码的一部分 这里的 buffer 是一个大小为 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;
}

最佳答案

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

RFC 1350 比较,我发现的是

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

关于c++ - 错误代码 1024 tftp 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48775159/

相关文章:

c++ - 由于许多进程,pthread_create 的错误返回代码是 35 错误,我使用了 pthread_exit,它应该终止线程,不是吗?

c - 从函数中获取数组的计数

实现TFTP、FTP、SFTP服务器的Python包

c++ - 如何禁止赋值

c++ - 类定义和函数签名中的宏有什么用?

c++ - 更改非 Windows 应用商店应用程序的磁贴颜色?

c - 是什么造就了这个建筑?

c++ - 在 C++ 中使用文件时出现段错误

java - 基于java NIO的TFTP客户端