0

I wrote a simple tftp server that only handles read requests (RRQ) from clients. The problem is that the server seems not to be sending DATA packets to the client. I made sure that the server is not sending the DATA packet through checking the length of the sent bytes against the data packet size.

Note: I use the standard tftp client that comes with linux.

Here's the code I've written so far...

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

void sendFile (char *Filename, char *mode, struct sockaddr_in client)
{
    char path[70] = "tmp/";
    char filebuf [1024];
    int acked = 0; // Number of acked data portions
    int count = 0; // Number of data portions we sent
    unsigned char packetbuf[1024];
    char recvbuf[1024];
    socklen_t recv_size;

    int sock = socket(PF_INET, SOCK_DGRAM, 0);

    FILE *fp;
    char fullpath[200];
    strcpy(fullpath, path);
    strncat(fullpath, Filename, sizeof(fullpath) -1);
    fp = fopen(fullpath, "r");
    if (fp == NULL)
        perror("");

    memset(filebuf, 0, sizeof(filebuf));
    while (1)
    {   
        int ssize = fread(filebuf, 1 , 512, fp);
        count++;        
        sprintf((char *) packetbuf, "%c%c%c%c", 0x00, 0x03, 0x00, 0x00);
        memcpy((char *) packetbuf + 4, filebuf, ssize);
        packetbuf[2] = (count & 0xFF00) >> 8;
        packetbuf[3] = (count & 0x00FF);

        int len = 4 + ssize;        

        if (sendto(sock, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client)) != len)
            puts("SENDING FAILED!");

        memset(recvbuf, 0, 1024);
        recvfrom(sock, recvbuf, 1024, 0, (struct sockaddr *) &client, &recv_size);
        if (recvbuf[1] == 4)
            puts("Acked");

        if (ssize != 512)
            break;
    }   
}


int main()
{
    int udpSocket, nBytes;
    char buffer[1024], filename[200], mode[20], *bufindex, opcode;
    struct sockaddr_in serverAddr, client;
    struct sockaddr_storage serverStorage;
    socklen_t addr_size;

    udpSocket = socket(AF_INET, SOCK_DGRAM, 0);

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(69);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 

    bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
    memset(buffer,0,1024);

    while(1)
    {
        nBytes = recvfrom(udpSocket,buffer,1024,0,(struct sockaddr *)&client, &addr_size);

        bufindex = buffer;
        bufindex++;

        // Extracting the opcode from the packet...     
        opcode = *bufindex++;

        // Extracting the filename from the packet...
        strncpy(filename, bufindex, sizeof(filename)-1);

        bufindex += strlen(filename) + 1;

        // Extracting the mode from the packet...       
        strncpy(mode, bufindex, sizeof(mode)-1);

        // If we received an RRQ...
        if (opcode == 1)
            sendFile(filename, mode, client);
    }   
    return 0;
}

Thanks in advance :)

user3490561
  • 446
  • 3
  • 8
  • 20
  • Did you check the packet trace b/w server and client? Is file going out from server? – Prabhu Apr 14 '15 at 12:38
  • @Prabhu I just checked a packet trace and it seems that the file is not going out from the server. – user3490561 Apr 14 '15 at 12:45
  • @Prabhu I also checked the socket in `sendFile()` and it seems to be created successfully. – user3490561 Apr 14 '15 at 12:48
  • 1
    amongst other problems in the posted code, when a file fails to open; more needs to be done than just report the problem. Usually the error needs to be handled. Probably, in this case, by telling the client that the file is not available. Definitely not by continuing with the execution of the file transfer,. – user3629249 Apr 14 '15 at 21:29
  • 1
    the assignments to packetBuf[2] and packetBuf[3] are overlaying data that the code already placed into the packetBuf buffer. Is that what you really want to do? – user3629249 Apr 14 '15 at 21:32
  • 1
    The code is using UDP for communications, but has not implemented any feedback to assure a packet was successfully transfered. – user3629249 Apr 14 '15 at 21:33
  • 1
    part of the UDP/tftp protocol is the initial handshake where each side of the communication tells the other side what port they wish to continue using for the communication. This is almost always a port number above 1024, Only the initial handshake uses the tftp port. Note: both ends of the communication need to have the appropriate port 'open' through their firewall. – user3629249 Apr 14 '15 at 21:36
  • 1
    in this line: 'void sendFile (char *Filename, char *mode, struct sockaddr_in client)' and this line: 'sendFile(filename, mode, client);' The third parameter should be a pointer to the 'client' struct, not trying to pass the whole struct – user3629249 Apr 14 '15 at 21:46
  • 1
    the list of #includes is missing – user3629249 Apr 14 '15 at 21:58
  • 1
    the socket has not been set to 'non-blocking' and the recvfrom() is requesting 1024 bytes. The execution will hang until 1024 bytes are received. This is probably not what is wanted when the expected received message will consist of little more than the 'ack' command. – user3629249 Apr 14 '15 at 22:02
  • @user3629249 thanks for all these informative and valuable comments. – user3490561 Apr 14 '15 at 23:11

1 Answers1

1

Your opcode check appears to be incorrect.

Try:

bufindex++;
 opcode = *bufindex++;

Also, why 1024 bytes in sendto. Shouldn't it be size of file? You are just passing on the size of the packetbuf instead of actual size of file.

Change to :

sendto((sock, packetbuf, len, 0, (struct sockaddr *) &client, sizeof (client)) );

Prabhu
  • 3,443
  • 15
  • 26