Search code examples
csocketsftpnetwork-programmingrecv

Sending file to distant FTP server


I have a task "Send file to distant FTP server". I have written code, but it's not working correctly. I create a socket for data transferring and try to upload my file. After uploading the file, I want to check the server answer using recv(), but my program hangs at this moment, but I can see my file on server. If I remove recv() from my code, the size of my file is 0 bytes. I have been trying to solve this problem for a couple of days. Can anyone help me?

I'm using this FTP server for testing: ftp://speedtest.tele2.net/

int upload_file(char *filename) {
    char str[256];
    char buff[1024];
    int getFile;
    int bytes_read;

    //ds - for data

    sprintf(str, "CWD %s\r\n", "upload");
    send(s, str, strlen(str), 0);
    get_server_answer();
    switch_to_passive_mode();
    sprintf(str, "TYPE I\r\n");
    send(s, str, strlen(str), 0);
    get_server_answer();
    sprintf(str, "STOR %s\r\n", filename);
    send(s, str, strlen(str), 0);
    get_server_answer();

    getFile = open(filename, O_RDONLY, 0644);
    while (1) {
        bytes_read = read(getFile, buff, 1024);
        if (bytes_read <= 0)
            break;
        send(ds, buff, bytes_read, 0);
    }
    char tmp[256];
    recv(s, tmp, 256, MSG_WAITALL); // program hangs here

    close(getFile);
    close(ds);
    close(s);
    return 0;
}

Solution

  • By default, FTP data transfers operate in STREAM transmission mode. In that mode, after sending the file data over your ds socket, you need to close the ds socket to signal End-Of-File to the server, before attempting to read the server's answer (why are you not using get_server_answer() instead?). Since you are not doing that, you are waiting for a final server answer that is never being sent.

    When you remove the recv(), you are closing both the ds and s sockets. By closing the s socket without sending a QUIT command first, the server thinks your client has vanished unexpectedly before receiving the server's answer, and so it aborts the transfer.

    So, you need to either:

    • close ds (but not s!) after your loop is finished, but before you read the answer.

    • use the MODE command to switch the data connection's transmission mode to BLOCK or COMPRESSED mode, which don't signal EOF by closing the data connection. See RFC 959 Section 3.4 for more details.

    Also, you are not validating that the initial answer to the STOR command is successful (has a reply code of 125 or 150) before sending the file data over ds