I managed to compile ncat. I am using -k option to keep server open. Instead of accepting data to STDOUT, my goal is to write to files instead. So far I was able to write to a file instead of STDOUT but my goal is to loop through new files on each new connection. Right now it is appending to the same filename_0 and f++ is not incrementing. Here is what I have so far. The original code will be below. The difference is in the else clause, basically if n is actually greater than 0. On each loop, n is 512 bytes until the last chunk. I just want to be able to have new files from each new connection. filename_0, filename_1, filename_3, etc.
MODIFIED CODE:
/* Read from a client socket and write to stdout. Return the number of bytes
read from the socket, or -1 on error. */
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
int f = 0;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n, s;
n = ncat_recv(fdn, buf, 512, &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
char filename[20];
snprintf(filename, sizeof(char) * 20, "filename_%i", f);
FILE *fp = fopen(filename, "a");
if (fp == NULL)
{
printf("Could not open file");
return 0;
}
//Write(STDOUT_FILENO, buf, n);
s = fwrite(buf, 1, n, fp);
fclose(fp);
f++;
nbytes += n;
}
} while (pending);
return nbytes;
}
ORIGINAL CODE:
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n;
n = ncat_recv(fdn, buf, sizeof(buf), &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
Write(STDOUT_FILENO, buf, n);
nbytes += n;
}
} while (pending);
return nbytes;
}
I was able to figure out using the other functions involved. i passed a pointer into this function to write to it. the handler is a function i added the open() file pointer to.
Related
I am currently trying to work out Downloading / Uploading Files via socket (SOCK_STREAM). The following two functions are what I use to send and receive the data.
I am currently running into the following Issue(s):
The result File sometimes is not the same size as the source File
This Problem is more sever, the larger the file.
I am pretty sure that I am missing something obvious, in my loops maybe or determining the end of the data stream. I spent the past week trying a bunch of different approaches / solutions and this is the closest to a working version i got...
I am thankfull for any advice and review, if i need to provide further information please tell me
Function Sending Data from Server to Client:
void send_file(char *filename, int sock)
{
char data[1024] = {0};
FILE *fp = fopen(filename, "rb");
while (fread(data, sizeof(char), sizeof(data), fp) == 1024) {
if (send(sock, data, sizeof(data), 0) == -1) {
printf("%s%s[-] Error Transmitting File\n\n", KRED, BGHT);
break;
}
bzero(data, sizeof(data));
}
bzero(data, sizeof(data));
strcpy(data, "!EOF!");
send(sock, data, sizeof(data), 0);
bzero(data, sizeof(data));
printf("%s%s[+] Upload Successful\n\n", KGRN, BGHT);
fclose(fp);
}
Function of Client Receiving Data from Server:
void write_file(int sock, char *filepath)
{
FILE *fp;
int n;
char *lastSlash = strrchr(filepath, '\\');
char *filename = lastSlash ? lastSlash +1 : filepath;
char data[1024] = {0};
fp = fopen(filename, "wb");
while (1) {
n = recv(sock, data, sizeof(data), 0);
if (strncmp("!EOF!", data, 5) == 0) {
break;
}
if (n <= 0) {
break;
return;
}
fwrite(data, sizeof(char), sizeof(data), fp);
bzero(data, sizeof(data));
}
fclose(fp);
return;
}
i finally figured it out with the help of the following Post:
Sending files over TCP sockets C++ | Windows
I rewrote the example code to fit my needs. Works like a charm so far.
Thanks to all for giving me some more insight on the topic and helping me figure our the necessary checks on the way!
Here the new Code with a brief explanation:
First thing that needs to be recognized, ist that functions like send() recv() fread() fwrite() are likely to not fill their buffer entirely before passing it on. Meaning if you have a buffer specified with size 100, they might only fill it up to 89 95 or whatever. As a result files are likely to be corrupted. To solve this every call of the send() recv() fread() fwrite() functions needs to be checked.
First you need those two functions both on server and client side. These make sure the entire buffer is being sent / received.
Its basically just looping over send() / recv() until the buffer is filled up.
int RecvBuffer(int sock, char* buffer, int bufferSize, int chunkSize) {
int i = 0;
while (i < bufferSize) {
const int l = recv(sock, &buffer[i], __min(chunkSize, bufferSize - i), 0);
if (l < 0) { return l; }
i += l;
}
return i;
}
int SendBuffer(int sock, char* buffer, int bufferSize, int chunkSize) {
int i = 0;
while (i < bufferSize) {
const int l = send(sock, &buffer[i], __min(chunkSize, bufferSize - i), 0);
if (l < 0) { return l; }
i += l;
}
return i;
}
Next we need to apply the same check in the functions that are being called to Download / Upload a file. Here I loop over the above functions that fill our Buffer and over the fread() fwrite() until all bytes (fileSize) have been sent. The chunkSize parameter defines the size of each package being sent. I used 65.536 (64kb) so far without any issues.
int RecvFile(int sock, char *filePath, int chunkSize, int fileSize) {
char *lastSlash = strrchr(filePath, '\\');
char *filename = lastSlash ? lastSlash +1 : filePath;
FILE *fp = fopen(filename, "wb");
char buffer[chunkSize];
int i = fileSize;
while (i != 0) {
const int r = RecvBuffer(sock, buffer, (int)__min(i, (int)chunkSize), chunkSize);
if ((r < 0) || !fwrite(buffer, sizeof(char), r, fp)) { break; }
i -= r;
}
bzero(buffer, sizeof(buffer));
fclose(fp);
printf("\n%s%s[+] Download Successful\n\n", KGRN, BGHT);
return -3;
}
int SendFile(int sock, char *fileName, int chunkSize, int fileSize) {
FILE *fp = fopen(fileName, "rb");
char buffer[chunkSize];
int i = fileSize;
while (i != 0) {
const int ssize = __min(i, (int)chunkSize);
if (!fread(buffer, sizeof(char), ssize, fp)) { break; }
const int l = SendBuffer(sock, buffer, (int)ssize, (int)chunkSize);
if (l < 0) { break; }
i -= l;
}
bzero(buffer, sizeof(buffer));
fclose(fp);
printf("\n%s%s[+] Upload Successful\n\n", KGRN, BGHT);
return -3;
}
I'm learning the socket programming and trying to write a simple http server with c. My program can load html/css/javascript files correctly, but the image files can't be loaded. For example, the website icon favicon.ico and <img> of the html file always failed to load. I'm using the code as below to build my simple server:
server.c:
#define CYAN(format, ...) \
printf("\033[1;36m" format "\33[0m\n", ## __VA_ARGS__)
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
socklen_t c_addr_size;
int s_sock;// server socket
int c_sock;// clinet socket
char buf[4096];// user agent
char msg[4096];// file content
char head[1024];// http header
char file[128];// which file requested
void init_server();
void read_request();
void send_file();
int main()
{
init_server();
while (1) {
c_sock = accept(s_sock, NULL, NULL);
if (c_sock != -1) {
int nread = recv(c_sock, buf, sizeof(buf), 0);
read_request();// TODO
CYAN("%d", nread);
CYAN("%s", buf);
send_file();
close(c_sock);
}
}
close(s_sock);
return 0;
}
void init_server()
{
s_sock = socket(AF_INET, SOCK_STREAM, 0);
assert(s_sock != -1);
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
s_addr.sin_port = htons(8000);
int res = bind(s_sock, (struct sockaddr*)&s_addr, sizeof(s_addr));
if (res == -1) { perror("cannot bind"); exit(-1); }
listen(s_sock, 10);// TODO
c_addr_size = sizeof(c_addr);
}
void read_request()
{
int buf_len = strlen(buf);
int i = 0, j = 0;
for (i = 0; i < buf_len - 10; i ++) {
if (buf[i] == 'G' && buf[i + 1] == 'E' && buf[i + 2] == 'T') {// `GET` keyword
i = i + 4;// skip space
while (buf[i] != ' ') {
file[j] = buf[i];
j ++, i ++;
}
file[j] = '\0';
CYAN("%s", file);
return;
}
}
}
void send_file()
{
if (strcmp(file, "/") == 0) {
sprintf(file, "index.html");
is_html = 1;
} else {
sprintf(file, "%s", file + 1);// skip `/`
}
FILE *fp = fopen(file, "r");
// count file length
int file_len = 0;
while (fgets(msg, 1000, fp)) {// read by lines
file_len += strlen(msg);
}
// send http header
sprintf(head,
"HTTP/1.1 200 OK\n"
// "Content-Type: text/html\n"
"Content-Length: %d\n"
"\n", file_len
);
// send file content
CYAN("%d", fseek(fp, 0, SEEK_SET));
memset(msg, 0, sizeof(msg));
send(c_sock, head, strlen(head), 0);
while (fgets(msg, 1000, fp)) {// read by lines
send(c_sock, msg, strlen(msg), 0);
}
fclose(fp);
}
I'm not familiar with http, and I don't know whether I should change the content of the http header when sending images files. How to correct my code, can anyone help me?
FILE *fp = fopen(file, "r");
// count file length
int file_len = 0;
while (fgets(msg, 1000, fp)) {// read by lines
file_len += strlen(msg);
}
No. No. No. No. Never use text processing on binary data.
File length is easy.
FILE *fp = fopen(file, "rb");
fseek(fp, 0, SEEK_END);
long file_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
Now to send it:
send_helper(c_sock, head, strlen(head), 0); /* send header */
while (file_len > 4096) {
int delta = fread(msg, 4096, 1, fp);
if (delta == 0) {
/* handle error */
fclose(fp);
/* need to refactor here; c_sock is useless and needs to be closed */
return;
}
send_helper(c_sock, msg, delta);
file_len -= delta;
}
if (file_len > 0) {
/* last chunk; fread only returns a short count on an actual error so no loop here */
int delta = fread(msg, 4096, 1, fp);
if (delta == 0) {
/* handle error */
fclose(fp);
/* need to refactor here; c_sock is useless and needs to be closed */
return;
}
send_helper(c_sock, msg, delta);
}
fclose(fp);
Unlike fread, send needs a loop to ensure all bytes are sent.
void send_helper(int c_sock, char *msg, size_t size)
{
while (size > 0)
{
ssize_t delta = sendto(c_sock, msg, size, 0);
/*
* not bothering to handle error well--
* we'll just error a few more times and drop out of loop anyway.
* You probably should come back and fix this later though
*/
if (delta <= 0) return;
size -= (size_t)delta;
msg += (size_t)delta;
}
}
I am new in this field, and writing one server and client, but it really confusing that I can't get all the content, but some small clip.
My server code:
read(connfd, name, 20);
//recv(connfd,name,1024,0);
char* a=name;
while(a[0]!='\n'){
a++;
}
a[0]='\0';
printf("name:%s\n", name);
read(connfd, size, 20);
printf("size:%s\n", size);
recv(connfd,buf,8192,0);
printf("buf:%s\n", buf);
if((stream = fopen(name,"w+t"))==NULL){
printf("The file was not opened! \n");
}
int write_length = fwrite(buf,sizeof(char),8192,stream);
bzero(buf,8192);
if(put){
char *res="OK\n";
write(connfd, res, 1024);
}
fclose(stream);
and my client code is:
char buffer[8192];
bzero(buffer,8192);
char * put="PUT\n";
if ((write(fd, put, 8192)) <= 0) {
if (errno != EINTR) {
fprintf(stderr, "Write error: %s\n", strerror(errno));
exit(0);
}
}
struct stat st ;
stat( put_name, &st );
char str[100];
sprintf(str, "%d", st.st_size);
int len;
char *current=NULL;
len=strlen(put_name);
char sendname[1024];
strcpy(sendname,put_name);
strcat(sendname,"\n");
write(fd, sendname, 10);
strcat(str,"\n");
write(fd, str, 10);
FILE *stream;
if((stream = fopen(put_name,"r"))==NULL)
{
printf("The file was not opened! \n");
exit(1);
}
int lengsize = 0;
while((lengsize = fread(buffer,1,8192,stream)) > 0){
if(send(fd,buffer,8192,0)<0){
printf("Send File is Failed\n");
break;
}
bzero(buffer, 8192);
}
Now, I can send all content, but can receive part of them. for example, on my mac, server can receive name but the str is neglected, when I printf the str in the server, it shows the content of file. and the content of file is not the whole file content. Some content disappear. Could you tell me why?
The read and write functions are not guaranteed to send or receive the entire message with a single call. Instead, you're expected to sit in a loop, writing the message incrementally until everything has been sent and reading everything incrementally until everything has been read. For example, if you know exactly how much has been sent, you can do this:
char recvBuffer[BUFFER_SIZE];
int bytesRead = 0;
while (bytesRead < BUFFER_SIZE) {
int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
if (readThisTime == -1) {
// handle error...
}
bytesRead += readThisTime;
}
If you don't know exactly how much has been sent, try this:
char recvBuffer[BUFFER_SIZE];
int bytesRead = 0;
while (bytesRead < BUFFER_SIZE) {
int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
if (readThisTime == -1) {
// handle error...
}
if (readThisTime == 0) break; // Done!
bytesRead += readThisTime;
}
You are ignoring the return values of send() and recv(). You MUST check return values!
When sending the file, lengsize receives how many bytes were actually read from the file. Your client is sending too many bytes when lengsize is < 8192 (typically the last block of the file if the file size is not an even multiple of 8192).
But more importantly, although the client is telling the server the file size, the server is ignoring it to know when to stop reading. The server is also ignoring the return value of recv() to know how many bytes were actually received so it knows how many bytes can safely be written to the output file.
Try something more like this instead:
common:
int readData(int s, void *buf, int buflen)
{
int total = 0;
char *pbuf = (char*) buf;
while (buflen > 0) {
int numread = recv(s, pbuf, buflen, 0);
if (numread <= 0) return numread;
pbuf += numread;
buflen -= numread;
total += numread;
}
return total;
}
int sendData(int s, void *buf, int buflen)
{
int total = 0;
char *pbuf = (char*) buf;
while (buflen > 0) {
int numsent = send(s, pbuf, buflen, 0);
if (numsent <= 0) return numsent;
pbuf += numsent;
buflen -= numsent;
total += numsent;
}
return total;
}
int readInt32(int s, int32_t *value)
{
int res = readData(s, value, sizeof(*value));
if (res > 0) *value = ntohl(*value);
return res;
}
int sendInt32(int s, int32_t value)
{
value = htonl(value);
return sendData(s, &value, sizeof(value));
}
char* readStr(int s)
{
int32_t size;
if (readInt32(s, &size) <= 0)
return NULL;
char *str = malloc(size+1);
if (!str)
return NULL;
if (readData(s, str, size) <= 0) {
free(str);
return NULL;
}
str[size] = '\0';
return str;
}
int sendStr(int s, const char *str)
{
int len = strlen(str);
int res = sendInt32(s, len);
if (res > 0)
res = sendData(s, str, len);
return res;
}
server:
char buffer[8192];
char *name = readStr(connfd);
if (!name) {
// error handling ...
sendStr(connfd, "Socket read error");
return;
}
printf("name:%s\n", name);
int32_t filesize;
if (readInt32(connfd, &filesize) <= 0) {
// error handling ...
free(name);
sendStr(connfd, "Socket read error");
return;
}
printf("size:%d\n", filesize);
if ((stream = fopen(name, "wb")) == NULL) {
// error handling ...
printf("The file was not opened!\n");
free(name);
sendStr(connfd, "File not opened");
return;
}
while (filesize > 0) {
int numread = readData(connfd, buf, min(filesize, sizeof(buffer)));
if (numread <= 0) {
// error handling ...
close(stream);
free(name);
sendStr(connfd, "Socket read error");
return;
}
printf("buf:%.*s\n", numread, buf);
if (fwrite(buf, 1, numread, stream) != numread) {
// error handling ...
close(stream);
free(name);
sendStr(connfd, "File write error");
return;
}
filesize -= numread;
}
fclose(stream);
free(name);
sendStr(connfd, "OK");
client:
char buffer[8192];
struct stat st;
if (stat( put_name, &st ) != 0) {
// error handling ...
exit(0);
}
if ((stream = fopen(put_name, "rb")) == NULL) {
// error handling ...
printf("The file was not opened!\n");
exit(0);
}
if (sendStr(fd, put_name) <= 0) {
// error handling ...
close(stream);
exit(0);
}
int32_t filesize = st.st_size;
if (sendInt32(fd, filesize) <= 0) {
// error handling ...
close(stream);
exit(0);
}
int lengsize;
while (filesize > 0) {
lengsize = fread(buffer, 1, min(filesize , sizeof(buffer)), stream);
if (lengsize <= 0) {
printf("Read File Failed\n");
// error handling ...
close(stream);
exit(0);
}
if (sendData(fd, buffer, lengsize) <= 0) {
printf("Send File Failed\n");
// error handling ...
close(stream);
exit(0);
}
filesize -= lengsize;
}
close(stream);
char *resp = readStr(fd);
if (!resp) {
// error handling ...
exit(0);
}
if (strcmp(resp, "OK") == 0)
printf("Send File OK\n");
else
printf("Send File Failed: %s\n", resp);
free(resp);
I have a file, partitioned in fixed sized blocks. I am copying a test_file.txt into the 3rd block of the file. I read and copied 18 bytes.
Then I am trying to copy from the file that very same .txt file I just imported to a newly created .txt, but I am writing 256 bytes to the new file. Moreover, when I try to read it, it is full of garbage.
The first function is used to import the .txt and the second one to export it.
void copy_file(int mfs_desc, char* filename, Superblock* s, MDS mds) {
if(mds.size == 0)
return;
char buffer[s->block_size];
int i = 0;
for (; i < s->block_size; ++i) {
buffer[i] = '\0';
}
int source_desc = open(filename, O_RDONLY);
// error handling
if (source_desc == -1) {
perror("opening file in copy file");
exit(1);
}
ssize_t nread;
int total = 0;
off_t seek = lseek(mfs_desc,
sizeof(Superblock) + mds.datablocks[0] * s->block_size,
SEEK_SET);
printf("offset = %d\n", mds.datablocks[0]);
if (seek < 0) {
perror("seek");
exit(1);
}
total = 0;
while ((nread = read(source_desc, buffer, s->block_size)) > 0) {
total += nread;
write(mfs_desc, buffer, s->block_size);
}
printf("read and copied: %d bytes\n", total);
if (close(source_desc) == -1) {
perror("closing file in copy file");
exit(1);
}
}
int copy_file_export(int mfs_desc, char* filename, Superblock s, MDS mds) {
if(mds.size == 0) {
printf("File is empty, abort\n");
return 0;
}
char buffer[s.block_size];
int i = 0;
for (; i < s.block_size; ++i) {
buffer[i] = '\0';
}
int destination_desc = open(filename, O_CREAT | O_WRONLY);
// error handling
if (destination_desc == -1) {
printf("filename = |%s|\n", filename);
perror("opening file in copy file export");
exit(1);
}
ssize_t nread;
int total = 0;
off_t seek = lseek(mfs_desc,
sizeof(Superblock) + mds.datablocks[0] * s.block_size,
SEEK_SET);
printf("offset = %d\n", mds.datablocks[0]);
if (seek < 0) {
perror("seek");
exit(1);
}
for(i = 0; i < mds.size; ++i) {
nread = read(mfs_desc, buffer, s.block_size);
total += nread;
write(destination_desc, buffer, nread);
}
printf("wrote: %d bytes\n", total);
if (close(destination_desc) == -1) {
perror("closing file in copy file");
exit(1);
}
return 1;
}
Output:
import test_file.txt ... / <-- just a command
offset = 2
read and copied: 18 bytes
export test_file.txt ... ../../ <-- just a command
offset = 2
wrote: 256 bytes
What I am doing wrong?
I would replace
write(mfs_desc, buffer, s->block_size);
with
write(mfs_desc, buffer, nread);
In this chunk of code:
while ((nread = read(source_desc, buffer, s->block_size)) > 0) {
total += nread;
write(mfs_desc, buffer, s->block_size);
}
You're very likely handling the last write() incorrectly. You need to write only the bytes you read.
write(mfs_desc, buffer, nread);
Also, these lines are most likely bogus:
char buffer[s->block_size];
char buffer[s.block_size];
You're trying to use a variable sized allocation for an array on the stack. You Can't Do That™. Those allocations have to be fixed (compile time constant) sized.
I want to program an application to send a file with sockets:
Here my Server:
void str_server(int sock)
{
char buf[1025];
const char* filename="test.text";
FILE *file = fopen(filename, "rb");
err_abort("Test");
while (!feof(file))
{
int rval = fread(buf, 1, sizeof(buf), file);
send(sock, buf, rval, 0);
}
}
and here my client:
void RecvFile(int sock, const char* filename)
{
int rval;
char buf[0x1000];
FILE *file = fopen(filename, "wb");
while ((rval = recv(sock, buf, sizeof(buf), 0)) > 0)
{
fwrite(buf, 1, rval, file);
}
close(sock);
}
My problem is that my client create a file....but dont write the content in the file!
Add some error handling to your code, that should help you track down the problem. Also note that send(), recv(), fread() and fwrite() are not guaranteed to write/read the entire buffer you specify, so you should take that into account as well.
Also, since TCP is a byte stream, the server needs to indicate when the file ends so the client knows when to stop reading. If you don't send the file size before sending the actual file, the only option is to close the socket when the transfer is done.
Try something like this:
int send_all(int sock, const void *buf, int len)
{
const char *pbuf = (const char *) buf;
while (len > 0)
{
int sent = send(sock, pbuf, len, 0);
if (sent < 1)
{
// if the socket is non-blocking, then check
// the socket error for WSAEWOULDBLOCK/EAGAIN
// (depending on platform) and if true then
// use select() to wait for a small period of
// time to see if the socket becomes writable
// again before failing the transfer...
printf("Can't write to socket");
return -1;
}
pbuf += sent;
len -= sent;
}
return 0;
}
void str_server(int sock)
{
char buf[0x1000];
const char* filename = "test.text";
struct stat s;
if (stat(filename, &s) == -1)
{
printf("Can't get file info");
return;
}
FILE *file = fopen(filename, "rb");
if (!file)
{
printf("Can't open file for reading");
return;
}
// if you need to handle files > 2GB,
// be sure to use a 64bit integer, and
// a host-to-network function that can
// handle 64bit integers...
long size = s.st_size;
long tmp_size = htonl(size);
if (send_all(sock, &tmp_size, sizeof(tmp_size)) == 0)
{
while (size > 0)
{
int rval = fread(buf, 1, min(sizeof(buf), size), file);
if (rval < 1)
{
printf("Can't read from file");
break;
}
if (send_all(sock, buf, rval) == -1)
break;
size -= rval;
}
}
fclose(file);
}
int write_all(FILE *file, const void *buf, int len)
{
const char *pbuf = (const char *) buf;
while (len > 0)
{
int written = fwrite(pbuf, 1, len, file);
if (written < 1)
{
printf("Can't write to file");
return -1;
}
pbuf += written;
len -= written;
}
return 0;
}
int read_all(int sock, void *buf, int len)
{
char *pbuf = (char *) buf;
int total = 0;
while (len > 0)
{
int rval = recv(sock, pbuf, len, 0);
if (rval < 0)
{
// if the socket is non-blocking, then check
// the socket error for WSAEWOULDBLOCK/EAGAIN
// (depending on platform) and if true then
// use select() to wait for a small period of
// time to see if the socket becomes readable
// again before failing the transfer...
printf("Can't read from socket");
return -1;
}
if (rval == 0)
{
printf("Socket disconnected")
return 0;
}
pbuf += rval;
len -= rval;
total += rval;
}
return total;
}
void RecvFile(int sock, const char* filename)
{
int rval;
char buf[0x1000];
FILE *file = fopen(filename, "wb");
if (!file)
{
printf("Can't open file for writing");
return;
}
// if you need to handle files > 2GB,
// be sure to use a 64bit integer, and
// a network-to-host function that can
// handle 64bit integers...
long size = 0;
if (read_all(sock, &size, sizeof(size)) == 1)
{
size = ntohl(size);
while (size > 0)
{
rval = read_all(sock, buf, min(sizeof(buf), size));
if (rval < 1)
break;
if (write_all(file, buf, rval) == -1)
break;
}
}
fclose(file);
}