Using ReadFile in C code - c

I am trying to concurrently read a file at different offsets. I am able to do so using pread in posix systems, but I can't figure out how to do it using ReadFile for windows systems. I'm having difficulty understanding a lot of the Windows documentation. Can anyone show me an example of how I should be using ReadFile instead?
EDIT See working code here!
do {
#ifdef _WIN32
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = shard_meta->index*state->shard_size + total_read;
HANDLE file = (HANDLE)_get_osfhandle(fileno(state->original_file));
SetLastError(0);
bool RF = ReadFile(file, read_data, AES_BLOCK_SIZE * 256, NULL, &overlapped);
if ((RF==0) && GetLastError() == ERROR_IO_PENDING) {
printf ("Asynch readfile started. I can do other operations now\n");
while( !GetOverlappedResult(file, &overlapped, &read_bytes, TRUE)) {
if (GetLastError() == ERROR_IO_INCOMPLETE) {
printf("I/O pending: %d .\n",GetLastError());
} else if (GetLastError() == ERROR_HANDLE_EOF) {
printf("End of file reached.\n");
break;
} else {
printf("GetOverlappedResult failed with error:%d\n",GetLastError());
break;
}
}
} else if ((RF == 0) && GetLastError() != ERROR_IO_PENDING) {
printf ("Error reading file :%d\n",GetLastError());
goto clean_variables;
}
#else
read_bytes = pread(fileno(state->original_file),
read_data, AES_BLOCK_SIZE * 256,
shard_meta->index*state->shard_size + total_read);
#endif
total_read += read_bytes;
memset_zero(read_data, AES_BLOCK_SIZE * 256);
} while(total_read < state->shard_size && read_bytes > 0);

See working code below
#ifdef _WIN32
ssize_t pread(int fd, void *buf, size_t count, uint64_t offset)
{
long unsigned int read_bytes = 0;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
HANDLE file = (HANDLE)_get_osfhandle(fd);
SetLastError(0);
bool RF = ReadFile(file, buf, count, &read_bytes, &overlapped);
// For some reason it errors when it hits end of file so we don't want to check that
if ((RF == 0) && GetLastError() != ERROR_HANDLE_EOF) {
errno = GetLastError();
// printf ("Error reading file : %d\n", GetLastError());
return -1;
}
return read_bytes;
}
ssize_t pwrite(int fd, const void *buf, size_t count, uint64_t offset)
{
long unsigned int written_bytes = 0;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
HANDLE file = (HANDLE)_get_osfhandle(fd);
SetLastError(0);
bool RF = WriteFile(file, buf, count, &written_bytes, &overlapped);
if ((RF == 0)) {
errno = GetLastError();
// printf ("Error reading file :%d\n", GetLastError());
return -1;
}
return written_bytes;
}
#endif

Related

how to send image files through http?

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;
}
}

In c socket, why my server can't receive the whole content?

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);

Unable to decrypt: RSA_R_PADDING_CHECK_FAILED - OpenSSL 1.1.0‏

I'm creating a simple utility to encrypt and decrypt files using a key pair. I'm on Windows and coding against the 1.1.0 version of Openssl. I can load the key pair and encrypt the file fine, but when I try to decrypt EVP_PKEY_decrypt always returns -1. I traced this to the rsa padding check functions and they are returning -1 but I can't figure out why. I've tried changing the padding from RSA_PKCS1_OAEP_PADDING to RSA_PKCS1_PADDING and still have the same problem. Any insight would be appreciated, here are my encrypt and decrypt functions:
#define FILE_BUFFER_LENGTH 1
#define ENC_BUFFER_LENGTH 2048
int encryptfile(EVP_PKEY *key, FILE *srcfp, FILE *tgtfp) {
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
char *inbuf;
unsigned char *outbuf;
size_t in_len = 0;
size_t out_len = ENC_BUFFER_LENGTH;
int x;
inbuf = (char*)malloc(sizeof(char)*FILE_BUFFER_LENGTH+1);
outbuf = (char*)malloc(sizeof(char)*ENC_BUFFER_LENGTH+1);
if (ctx == NULL) {
fprintf(stderr, "Error while creating encryption context.\n");
return 0;
}
if (EVP_PKEY_encrypt_init(ctx) <= 0) {
fprintf(stderr, "Error while initializing encryption context.\n");
return 0;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
fprintf(stderr, "Error while setting encryption padding.\n");
return 0;
}
while (1) {
in_len = fread(inbuf, 1, FILE_BUFFER_LENGTH, srcfp);
if (in_len == 0) {break;}
if (EVP_PKEY_encrypt(ctx, outbuf, &out_len, inbuf, in_len) <= 0) {
fprintf(stderr, "Error while encrypting data.\n");
return 0;
}
x = fwrite(outbuf, sizeof(char), in_len, tgtfp);
if (x != in_len) {
fprintf(stderr, "Error while writing to target file.\n");
return 0;
}
}
return 1;
}
int decryptfile(EVP_PKEY *key, FILE *srcfp, FILE *tgtfp) {
ENGINE *e = ENGINE_new();
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
unsigned char *inbuf;
unsigned char *outbuf;
size_t in_len = 0;
size_t out_len = ENC_BUFFER_LENGTH;
int x;
inbuf = (char*)malloc(sizeof(char)*FILE_BUFFER_LENGTH + 1);
outbuf = (char*)malloc(sizeof(char)*ENC_BUFFER_LENGTH + 1);
if (ctx == NULL) {
fprintf(stderr, "Error while creating decryption context.\n");
return 0;
}
if (EVP_PKEY_decrypt_init(ctx) <= 0) {
fprintf(stderr, "Error while initializing decryption context.\n");
return 0;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
fprintf(stderr, "Error while setting decryption padding.\n");
return 0;
}
while (1) {
in_len = fread(inbuf, 1, FILE_BUFFER_LENGTH, srcfp);
if (in_len == 0) { break; }
if (EVP_PKEY_decrypt(ctx, outbuf, &out_len, inbuf, in_len) <= 0) {
fprintf(stderr, "Error while decrypting data.\n");
return 0;
}
x = fwrite(outbuf, sizeof(char), in_len, tgtfp);
if (x != in_len) {
fprintf(stderr, "Error while writing decrypted data to target file.\n");
return 0;
}
}
return 1;
}

What does it mean for ReadFile to be "completing asynchronously", and why is it an error?

I'm (synchronously) reading serial input in Windows using ReadFile(), but instead of waiting for the serial port to have input then returning that as I thought it should, ReadFile() instead returns immediately with a value of FALSE, and a GetLastError() of 0. (Yes, I'm certain I have the right error code and am not making syscalls in between).
The ReadFile() documentation says that when the function "is completing asynchronously, the return value is zero (FALSE)." How is it that a synchronous read can be completing asychronously? Why would this be an error? It's worth noting that the data read is garbage data, as one might expect.
More generally, how can I force ReadFile() to behave like a simple synchronous read of a serial port, or at least behave something like the UNIX read()?
Edit: Here is some source code:
HANDLE my_connect(char *port_name)
{
DCB dcb;
COMMTIMEOUTS timeouts;
HANDLE hdl = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
GetCommState(port_name, &dcb);
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if(SetCommState(hdl, &dcb) == 0)
{
fprintf(stderr, "SetCommState failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
/* TODO: Set a variable timeout. */
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 5000; /* wait 5s for input */
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 5000;
if(SetCommTimeouts(hdl, &timeouts) == 0)
{
fprintf(stderr, "SetCommTimeouts failed with error code %d.\n",
GetLastError());
return (HANDLE) -1;
}
return hdl;
}
int my_disconnect(HANDLE hdl)
{
return CloseHandle(hdl);
}
int my_send(HANDLE hdl, char *cmd)
{
DWORD nb = 0;
if(WriteFile(hdl, cmd, strlen(cmd), &nb, NULL) == 0)
{
fprintf(stderr, "WriteFile failed with error code %d.\n",
GetLastError());
return -1;
}
return (int) nb;
}
int my_receive(HANDLE hdl, char *dst, int dstlen)
{
int i;
DWORD r;
BOOL err;
char c = '\0';
for (i = 0; i < dstlen; err = ReadFile(hdl, &c, 1, &r, NULL))
{
if (err == 0)
{
fprintf(stderr, "ReadFile failed with error code %d.\n",
GetLastError());
return -1;
}
if (r > 0)
{
dst[i++] = c;
if (c == '\n') break;
}
}
if (i == dstlen)
{
fprintf(stderr, "Error: read destination buffer not large enough.\
Recommended size: 256B. Your size: %dB.\n", dstlen);
return -1;
}
else
{
dst[i] = '\0'; /* null-terminate the string. */
}
return i;
}
And my test code:
HANDLE hdl = my_connect("COM4");
char *cmd = "/home\n"; /* basic command */
char reply[256];
my_send(hdl, cmd);
my_receive(hdl, reply, 256);
puts(reply);
It's not completing asynchronously. If it were, GetLastError would return ERROR_IO_PENDING.
To do synchronous I/O, open the file without FILE_FLAG_OVERLAPPED.
It should not be possible for ReadFile to fail without a valid GetLastError code. ReadFile only returns false when the driver sets a non-success status code.

C- Socket : Programming a Client/Server-Application to send a file

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);
}

Resources