0

My current application involves a C client sending a file to a Python server using TCP. It will produce a hash of the file and send the information back. I can get it to work with a python client but I am having issues migrating the client into C. The python server is still unfinished (it needs to convert the file size string to int, error checking, etc).

My biggest issue right now is after the server calls hash_type = connbuff.get_utf8(), it gives me the first user input of the hash type, then closes the connection. I know it is an issue with get_utf8(), but I am stumped on how to fix this. Should I just send arbitrary amounts of data from the client every time? Please help me learn from the error of my ways! Any advice/suggestions are much appreciated! Thanks =)

Server.py

import socket
import os
import hashlib
import buffer

HOST = '127.0.0.1'
PORT = 2345

def getHash(fileName, hashType):
    ... hash algorithms ....

try:
    os.mkdir('uploads')
except FileExistsError:
    pass

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")

while True:
    conn, addr = s.accept()
    print("Got a connection from ", addr)
    connbuf = buffer.Buffer(conn)

while True:
    hash_type = connbuf.get_utf8()
        if not hash_type:
            break
        print('Hash Type: ', hash_type)

        file_name = connbuf.get_utf8()
        if not file_name:
            break
        print('File Name: ', file_name)
        file_name = os.path.join('uploads', file_name)

        file_size = connbuf.get_utf8()
        file_size = int(file_size)
        print('File Size: ', file_size)

        with open(file_name, 'wb') as f:
            remaining = file_size
            while remaining:
                if remaining >= 4096:
                    chunk_size = 4096
                else:
                    chunk_size = remaining
                chunk = connbuf.get_bytes(chunk_size)
                if not chunk:
                    break
                f.write(chunk)
                remaining -= len(chunk)

            if remaining:
                print('File incomplete: MISSING', remaining, 'BYTES.')
            else:
                print('File received successfully.')

        file_hash = getHash(file_name, hash_type)
        response = file_name + ' ' + file_hash
        connbuf.put_utf8(response)

print('Connection closed.')
conn.close()

My Buffer class get_utf8() and get_bytes() look like this...

def __init__(self,s):
    self.sock = s
    self.buffer = b''

def get_bytes(self,n):
    while len(self.buffer) < n:
        data = self.sock.recv(1024)
        if not data:
            data = self.buffer
            self.buffer = b''
            return data
        self.buffer += data

    data,self.buffer = self.buffer[:n],self.buffer[n:]
    return data

def get_utf8(self):
    while b'\x00' not in self.buffer:
        data = self.sock.recv(1024)
        if not data:
            return ''
        self.buffer += data

    data,_,self.buffer = self.buffer.partition(b'\x00')
    return data.decode()

Client.c

#include <sys/socket.h>
  ... more includes ...

#define PORT_NUMBER 2345
#define SERVER_ADDRESS "127.0.0.1"

char *inputString(FILE* fp, size_t size){
    ... string input code ...
}

int main () {
    int server_socket, connection_status;
    struct sockaddr_in serverAddress;
    char *hashType;
    char *fileName;
    char send_buffer[4000];
    FILE * file_to_send;
    int file_size;

/* Connect to Server */
    ... connect to server code ...

/* Get Hash an File User Input */
printf("Enter hash type: ");
hashType = inputString(stdin, 10);
printf("Hash type: %s\n", hashType);

printf("Enter file name: ");
fileName = inputString(stdin, 10);
printf("File Name: %s\n");

/* Send User Input */
send(server_socket, hashType, sizeof(hashType), 0);
send(server_socket, fileName, sizeof(fileName), 0);

/* Open File, Get Size, Convert to String */
file_to_send = fopen(fileName, "rb");
fseek(file_to_send, 0, SEEK_END);
file_size = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);

int l = snprintf(NULL, 0, "%d", file_size);
char *str_file_size;
asprintf(&str_file_size, "%i", file_size);
printf("%s\n", str_file_size);

/* Send File Size and File */
send(server_socket, str_file_size, sizeof(str_file_size), 0);

while(!feof(file_to_send)) {
    fread(send_buffer, 1, sizeof(send_buffer) - 1, file_to_send);
}
send(server_socket, send_buffer, sizeof(send_buffer), 0);

return 0;

}

1

1 Answer 1

1

get_utf8 expects to read a null-terminated UTF-8-encoded string from the socket. In the C code, you send sizeof(hashType). hashType is a pointer, so you are sending exactly 4 or 8 bytes (depending on 32- or 64-bit architecture). You probably need strlen(hashType)+1 (+1 for the NULL). Ditto for filename.

get_utf8 also reads until it sees a null. If it never sees one, it returns empty string, which then causes the receive code to break and closes the connection.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.