I'm trying to download a file from my server; both the client and the server are Linux, yet ssh_scp_read() returns an incorrect integer. According to the documentation the function writes up to 65536 bytes, yet is only reading 16384 when the file is 37980, but that's not my main concern; near the end of this 16384 bytes it starts to fill the buffer with NULL garbage, that will then be written to the file.
The creation of recursive directories works fine; the problem is downloading files larger than 16384 bytes. At this point I'll use sftp instead of scp, but I would like to know what I am doing wrong.
This is the function code:
int get(ssh_session gno_ses,ssh_scp scp)
{
int rc;
int size, permissions;
char *buff, *filename, path[PATH_MAX];
while(1)
{
rc = ssh_scp_pull_request(scp);
switch (rc)
{
// cases [...]
case SSH_SCP_REQUEST_NEWFILE:
size = ssh_scp_request_get_size(scp);
printf("Size is %d\n",size);
filename = strdup(ssh_scp_request_get_filename(scp));
permissions = ssh_scp_request_get_permissions(scp);
FILE *file;
file = fopen(filename, "w+");
if (!file)
{
ssh_scp_deny_request(scp,"Unable to open");
fprintf(stderr, " %s: %s\n", filename, strerror(errno));
fclose(file);
break;
}
buff = malloc(size);
printf("Size of buffer is %d\n", size);
if (!buff)
{
fprintf(stderr, "\nBuff memory allocation error.\n");
return SSH_ERROR;
}
if( ssh_scp_accept_request(scp) != SSH_OK)
{
fprintf(stderr, "Error accepting request: %s\n", ssh_get_error(gno_ses));
break;
}
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
break;
}
if (fwrite(buff, 1, size, file) != size)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
} while (rc != 0);
fclose(file);
free(filename);
free(buff);
break;
}
}
return SSH_OK;
}
And this is the output:
Size is 37980
Size of buffer is 37980
ssh_scp_read got 16384
ssh_scp_read got 16384
ssh_scp_read got 5212
Error receiving file data: ssh_scp_read called under invalid state
Any input would be appreciated.
The problem was that I was writing size bytes when indeed scp_scp_read() had reported that it had read less than that:
rc = ssh_scp_read(scp, buff, size);
fwrite(buff, 1, size, file)
The fix is to write only rc bytes:
int len_loop = size;
int len;
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR || rc < 0)
{
fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
break;
}
else if (!rc)
{
break;
}
len = fwrite(buff, 1, rc, file);
if (len != rc)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
len_loop -= rc;
} while(len_loop);
change your inner loop as
int len = size;
do
{
rc = ssh_scp_read(scp, buff, size);
if (rc == SSH_ERROR)
{
fprintf(stderr, "Error receiving file data: %s\n",
ssh_get_error(gno_ses));
break;
}
if (fwrite(buff, 1, rc, file) != size)
{
perror("Error at writting to file: ");
break;
}
printf("ssh_scp_read got %d\n",rc);
len-=rc;
} while (len);
Related
I'm on Windows. I have a server/client program that copies a file from client to server. Everthing works as expected until I add the code where I send the size of the file from client to server. When I remove the code it works fine again. The while() loop in my server normally loops 378 times the while() loop in my client also loops 378 times. After I add the code to send the file size the while() loop in my server loops 377 times, and that causes the failure. I don't get any errors but when I click on the copied file it doesn't show anything(because the server loops 377 instead of 378). I commented *** where the code is that I'm talking about. What is the cause of this and how can I solve it?
Edit: The server receives the size of the file successfully
functions:
int getSizeFile(FILE* file)
{
// get file size
FILE *f = file;
fseek(f, 0L, SEEK_END);
int sizeFile = ftell(f);
rewind(f);
return sizeFile;
}
static inline uint32_t ntohl_ch(char const* X)
{
uint32_t x; memcpy(&x, X, sizeof(x));
return ntohl(x);
}
server:
char ch[70];
printf("where do you want to save it(full path + name): ");
scanf_s("%s", ch, 70);
char c[70];
printf("which file you want to copy(full path + name): ");
scanf_s("%s", c, 70);
r = send(s, c, 70, 0); // B
if (r == SOCKET_ERROR)
{
printf("2 error: %d\n", WSAGetLastError);
}
FILE* copyFile;
fopen_s(©File, ch, "wb");
if (copyFile == NULL)
{
printf("Error opening file\n");
}
char buf[BUFSIZE];
size_t size = BUFSIZE;
int counter = 0;
// *** receiving file size. This is the code
char b[8192];
r = recv(s, b, 8192, 0); // C
if (r == SOCKET_ERROR)
{
printf("error recv\n");
}
uint32_t test = ntohl_ch(&b[0]);
printf("%d\n", (int)test);
// *** Until here
while (1)
{
int res = recv(s, buf, BUFSIZE, 0);
if (res == SOCKET_ERROR)
{
printf("3 error %d\n", WSAGetLastError);
break;
}
size = fwrite(buf, 1, res, copyFile);
printf("size: %d\n", size);
printf("res: %d\n", res);
counter++;
printf("counter: %d\n", counter);
}
fclose(copyFile);
client:
char c[70];
res = recv(ClientSocket, c, 70, 0); // B
if (res == SOCKET_ERROR)
{
printf("Server disconeccted\n");
break;
}
FILE* originalFile;
fopen_s(&originalFile, c, "rb");
if (originalFile == NULL)
{
printf("Error opening file\n");
}
char buf[BUFSIZE];
size_t size = BUFSIZE;
int counter = 0;
// getting file size
int sizeFile = getSizeFile(originalFile);
// *** sending file size. This is the code
uint32_t num = htonl(sizeFile);
char* converted_num = (char*)#
res = send(ClientSocket, converted_num, sizeof(num), 0); // C
if (res == SOCKET_ERROR)
{
printf("error send\n");
}
// *** Until here
while (size == BUFSIZE)
{
size = fread(buf, 1, BUFSIZE, originalFile);
int r = send(ClientSocket, buf, size, 0);
if (r == SOCKET_ERROR)
{
printf("1 error: %d\n", WSAGetLastError);
break;
}
printf("size: %d\n", size);
printf("r: %d\n", r);
counter++;
printf("counter: %d\n", counter);
}
printf("out of while loop\n");
fclose(originalFile);
In here I am sending file name first then sending the file in chunks, then trying to read the received message but it is just freezing. No respond. But after loop if I shutdown the WR shutdown(connfd,SHUT_WR); It is working fine. Though I should be able to send message again, if I do this I can not do that.
CLIENT.C
write(sockfd, fname,100);
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("File opern error");
exit(1);
}
int hi = 0;
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
/* If read was success, send data. */
if(nread > 0)
{
hi++;
//printf("Sending \n");
write(sockfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp))
{
printf("File transfer completed!\n");
}
if (ferror(fp))
printf("Error reading\n");
break;
}
}
char fname2[100];
// cant read
read(sockfd, fname2, 100);
printf("File Name: %s\n",fname2);
SERVER.C
FILE *fp;
int bytesReceived = 0;
char recvBuff[1024];
char fname[100];
char fname2[100];
read(newsockfd, fname, 100);
//strcat(fname,"AK");
printf("File Name: %s\n",fname);
printf("Receiving file...");
fp = fopen(fname, "ab");
if(NULL == fp)
{
printf("Error opening file");
}
long double sz=1;
/* Receive data in chunks of 256 bytes */
printf("\nCompleted.\n");
int hi = 0;
while((bytesReceived = read(newsockfd, recvBuff, 1024)) > 0)
{
hi++;
sz++;
fwrite(recvBuff, 1,bytesReceived,fp);
}
printf("Not pring this this!");
if(bytesReceived < 0)
{
printf("\n Read Error \n");
}
write(newsockfd, "SayGee",100);
I had to send the size of the file, then check from the other side inside loop. It was in deadlock.I found the solution. So thanks anyway!
I'm new with cryptography, so I decided to create simple program that would open a file encrypt data, put it in etest.txt, then open this file decrypt it and put it indetest.txt. I know it sounds really weired but its for educational purposes. so here is my code.
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
int main(void) {
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
char *pri_key; // Private key
char *pub_key; // Public key
char *msg = malloc(256); // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
RSA *keypair = RSA_generate_key(2048, 3, NULL, NULL);
FILE *in = fopen("test.txt", "rb");
FILE *out = fopen("etest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
encrypt = malloc(RSA_size(keypair));
for(;;)
{
//213 because of padding
memset(msg, '\0', 256);
memset(encrypt, '\0', 256);
fread(msg, 213, 1, in);
if((RSA_public_encrypt(strlen(msg), (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
if(fwrite(encrypt, 256, 1, out) != 1)
{
printf("fwrite Error is %d (%s).\n", errno, strerror(errno));
}
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
in = fopen("etest.txt", "rb");
out = fopen("dtest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
decrypt = malloc(RSA_size(keypair));
for(;;)
{
//I use malloc because if i didnt it would from file and if it filled the msg and if this function would execute second time it would not overwrite the whole buffer and would cause problem
memset(decrypt, '\0', 256);
memset(msg, '\0', 256);
fread(msg, 256, 1, in);
if(RSA_private_decrypt(256, (unsigned char*)msg, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
}
fwrite(decrypt, 256, 1, out);
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
RSA_free(keypair);
return 0;
}
When I run code it gives me back error saying:Error decrypting message: error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error but if i delete this codememset(msg, '\0', 256); it shows that everything works fine but it causes problems because msg buffer is overwritten with first few bytes that second fread() function overwrote.
Sorry if my questions sound silly. Hope you can help. thanks.
Your are using fwrite(decrypt, 256, 1, out); which is wrong.size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) Second parameter is the size in bytes of each element to be read And the third one is number of elements, each one with a size of size bytes.
I'm trying to send files using TCP from a windows client to a Linux server in C.
The size of the buffer I use to send the data is 65535. When the size of the file exceeds this value, I get an error saying 'connection reset by peer' or the error code 10054. When the size of the file is less than 65535 bytes, the server receives only a part of it (usually 2760 bytes).
I just want to send files with a maximum size of 50 MB.
This is the part of the windows client that I use to send data:
char *fileName; // pointer to filename
char buf[65535]; // buffer
int fileSize; // # bytes to send
for(i = 0; i < ARRAYSIZE; i++) {
if(selectList[i] != NULL) {
// select file
fileName= selectList[i]; // get path and filename from selectList
printf("=============================================\nSending: %s\n", fileName);
filefd = fopen(fileName, "rb"); // open file
if(filefd == NULL) {
printf("File %s not found\n", fileName);
exit(1);
}
// read and send file
memset(buf, '\0', 65535);
while((fileSize= fread(buf, sizeof(char), 65535, filefd)) > 0) { // read file
if((numberOfBytes = send(sockfd, buf, fileSize, 0)) < 0) { // send buffer
printf("send: %s (Error: %d)\n", filename, WSAGetLastError());
break;
}
printf("#bytes = %i \n", numberOfBytes);
memset(buf, '\0', 65535);
}
printf("File %s send!\n", filename);
// close file after sending it
if(fclose(filefd) < 0) {
printf("fclose: %i", WSAGetLastError());
}
} else if(selectList[0] == NULL) {
printf("no files selected");
}
}
The selectList contains multiple strings such as: C:\Windows\test.txt
The recieve part of the Linux server:
char* fr_name = "/home/MtFS/UploadedFiles/public/testFile.gif";
FILE *fr = fopen(fr_name, "wb");
if(fr == NULL)
printf("[Open_File]file %s cannot be created\n", fr_name);
else {
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) {
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz) {
error("[Write] error\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
}
if(fr_block_sz < 0) {
if (errno == EAGAIN) {
printf("[Receive] time out\n");
}
else {
printf("[Receive] error\n");
exit(1);
}
}
printf("[Receive] succesfull\n");
fclose(fr);
}
What am I doing wrong?
Your problem are those 3 lines of code. That's not the correct way to know that you're done:
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
Also you check against 512 instead of LENGTH. But only 0 means that you're done (assuming your connection is not NONBLOCKED.)
As a side note: you do not have to clear your buffers (bzero, memset) before using them with a read since the read/recv will overwrite the content of the buffers anyway.
I think the culprit is this line in your server
if (fr_block_sz == 0 || fr_block_sz != 512) {
fr_block_sz cab be anything between 1 to 65535 - the size block that you sent.
In your code, when its not 512 so your server is terminating the connection.
The below code works fine for smaller files where the last packet contains data less than maximum length, the function exit properly by displaying file received.
How ever if the last packet or buffer of file being transmitted contains exact number as the size of receiving buffer array 512 in my case. then th program keeps waiting for next packet.
All files with size multiple of 512 in my case stuck.
Below is the code:
CLIENT code for receiving:
void receiveFile() {
printf("inside receiveFile method\n");
char* fr_name = "final.txt";
int i;
FILE *fr = fopen(fr_name, "a");
int LENGTH = 512;
int fileLength=0;
char revbuf[LENGTH];
if (fr == NULL) {
printf("File %s Cannot be opened.\n", fr_name);
} else {
printf("starting to write the file\n");
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
i=0;
while ((fr_block_sz = recv(4, revbuf, LENGTH, 0)) > 0) {
fileLength+=fr_block_sz;
i++;
printf("Received buffer: %d, %d\n",fr_block_sz,i);
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if (write_sz < fr_block_sz) {
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
}
if (fr_block_sz < 0) {
if (errno == EAGAIN) {
printf("recv() timed out.\n");
} else {
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
}
}
printf("FILE RECEIVED....Total Bytes received:%d \n",fileLength);
}
fclose(fr);
}
Server for Receiving the file:
void sendFile() {
printf("inside sendFile method\n");
char* fs_name = "mb.txt";
int LENGTH = 512;
int sfileLength=0;
char sdbuf[LENGTH];
int i=0;
printf("[Client] Sending %s to the Server... \n", fs_name);
FILE *fs = fopen(fs_name , "r");
if (fs == NULL) {
perror("ERROR: File not found.\n");
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while ((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0) {
i++;
printf("Sent:%d , %d \n", fs_block_sz,i);
sfileLength+=fs_block_sz;
if (send(4, sdbuf, fs_block_sz, 0) < 0) {
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n",
fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("File sent.... Total Bytes:%d\n", sfileLength);
fclose(fs);
}
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
Remove this code. The first part of the test can never be true due to the 'while' condition, and the second part is unnecessary for the same reason.