0

Implementing the TFTP client over UDP socket. First I create the UDP non blocking socket and perform the PUT/GET operation it works fine. But when again I try to perform the GET/PUT it does not work. The RRQ/WRQ request itself is not reaching to the server but from the client side it has been sent successfully. Below is my tftp client code.

=========================================================

int sockfd;
struct sockaddr_in serv_addr;


//called when we retrieve a file from the server
void getFile(int port, char *filename)
{
    printf("enter to get file\n");
    FILE * file;

    if (strchr(filename,'/') != NULL )
    {
        printf("We do not support file transfer out of the current working directory\n");
        return;
    }

    file = fopen(filename, "wb");

    if(file == NULL)
    {
        perror(filename);
        return;
    }

    if(sockfd < 0)
    {
        printf("Couldn't open socket\n");
        return;
    }

    if(!send_RRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
    {
        printf("Error: couldn't send RRQ\n");
        return;
    }
    if(!recvFile(sockfd, (struct sockaddr *) &serv_addr, file,filename))
    {
        printf("Error: didn't receive file\n");
        return;
    }
    fclose(file);
    return;
}


//used to upload files to the server
void putFile(int port, char *filename)
{
    printf("filenemae is: %s \t",filename);

    PACKET packet;
    int result;
    FILE * fileh;
    int timeout_counter = 0;

    if (strchr(filename,'/') != NULL )
    {
        printf("We do not support file transfer out of the current working directory\n");
        return;
    }


    fileh = fopen(filename, "rb");

    if(fileh == NULL)
    {
        perror(filename);
        return;
    }

    if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
    {
        printf("Error: couldn't send WRQ to server\n");
        return;
    }

    while (timeout_counter < MAX_TFTP_TIMEOUTS)
    {
        result = waitForPacket(sockfd, (struct sockaddr *) &serv_addr, TFTP_OPTCODE_ACK, &packet);
        if (result < 0)
        {
            printf("Error: Timeout sending packet to server\n");
            if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE))
            {
                printf("Error: couldn't send WRQ to server\n");
                return;
            }
            timeout_counter++;
        }else
        {
            break;
        }
    }
    if (result < 0)
    {
        //we still timed out
        printf("Timed out after %d tries, is the server running\n",MAX_TFTP_TIMEOUTS);
        fclose(fileh);
        return;
    }
    if (packet.optcode == TFTP_OPTCODE_ERR)
    {
        //we recieved an error, print it
        printError(&packet);
    }else
    {
        if (!sendFile(sockfd, (struct sockaddr *) &serv_addr, fileh))
        {
            printf("Unable to send file to server\n");
        }
    }
    fclose(fileh);
    return;
}

int createUDPSocketAndBind(int port)
{
    //create a socket
    sockfd = socket(PF_INET, SOCK_DGRAM, 0);

    //return -1 on error
    if (sockfd == -1)
    {
    return -1;
    }

    //zero out the struct
    bzero((char*) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(port);

    return 0;
}


//main client, checks for args and starts an operation if no errors detected
int main(int argc, char *argv[])
{
    int port = 59;
    int argOffset = 1;
    char* filename;
    char fme[] = "test.txt";

    createUDPSocketAndBind(port);

    printf("for put file\n");
    putFile(port,fme);   //=====> this operation is successful.


    //createUDPSocketAndBind(port); //=====> If I uncomment this function, next   operation works.

    printf("for getfile\n");
    getFile(port,fme); //=======> It is failing.

    printf("Usage: %s [-p port] (-w putfile || -r getFile)\n",argv[0]);
}

=========================================================================
Rathore
  • 1
  • 2

1 Answers1

0

I have investigated more and found the problem with my code and solution as well.

When you send the first RD/WR request to the Server it will create a separate process or thread to handle your request and at the same time it will create the new socket and will use the different port number as well to handle the RD/WR request.

Client side when you will receive the response from the Server using below UDP socket API.

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

In the "struct sockaddr *src_addr" instance port number will be updated as server is responding using different port number which server has created to handle your request and your RD/WR operation will complete successfully using this port number.

Once RD/WR is done successfully server will close the socket which has been created to handle you request and start listening to your new request on the Original port. But client side "struct sockaddr *src_addr" instance will still have the modified port number and when you try to send the new RD/WR request it will not reach to the server. And that is the reason second RD/WR request will not reach to the server and it will fail.

To fix this on the client side in the "struct sockaddr *src_addr" instance you have to reset the port to the initial value which you have used initially to configure the server instance of the "struct sockaddr *src_addr". So after each RD/WR operation you have to reset the port number to the original value.

I am quite new to the UDP socket and it was good learning for me. I think this will be helpful for the beginners like me.

Thanks

Rathore
  • 1
  • 2