C socket read all function possible wrong? - c

I'm trying to do a client/server program using sockets, with protobuf messages, for school.
However one of the commands is(put) isn't working properly. It works with size, and returns 0, as it should but when I try put, it doesn't seem to work properly. I wrote some printf's in the code to try and check what's happening, and read_all doesn't seem right.
Here's the code.
int read_all (int socket, char *buf, int len){
int left;
int used;
char *prov;
prov = buf;
left = len;
printf("read all len: %d\n",len);
while (left > 0) {
printf("left : %d\n",left);
used = read(socket, prov, left);
printf("used: %d\n",used);
if ( used < 0) {
perror("readall err\n");
printf("errno here %d \n",errno);
return -1;
} else if (used == 0) break;
left -= used;
printf("left 2 : %d\n",left);
prov += used;
}
printf("read_all %d\n",len-left);
return (len - left);
}
When I use put , on the server terminal it shows :
read all len: 6
left: 6
and then it stops, that makes me think that read_all isn't working well, but I don't understand why. While on the client terminal it just shows that put wasn't successful.
Is read_all right or is something wrong.
Edit, read calls.
read_all for the size of msg buff:
read_all(client_socket, &rec, sizeof(rec) )
read_all for msg buff:
read_all(client_socket,(char *) rbuf, len )
rec is an int
len is an unsigned = ntohl(rec)
rbuf is a uint8_t = malloc(len)
edit 3:
write_all code:
int write_all(int socket, char *buf, int len){
int bufsize = len;
char *prov = buf;
while(bufsize > 0){
int res = write(socket, prov, bufsize);
if(res < 0){
perror("writeall err");
return -1;
}
prov += res;
bufsize -= res;
}
return len;
}
write calls:
sends size:
write_all(descr, &sen , sizeof(len))) != len)
send msg buf:
write_all(descritor,(char *) buf, len)) != len)
variable:
unsigned len = message_t__get_packed_size(msg)
uint8_t *buf = malloc(len)
unsigned sen = htoml(len)

Related

How to read all of STDOUT produced by system() call into a socket written in C?

The following is a code snippet from the server socket that reads a linux command sent by the client, executes it and sends the output back to the client :
while(1){
char command[200];
message_read = read(sock, command, sizeof(command));
if(message_read > 0){
command[message_read] = '\0';
dup2(sock, STDOUT_FILENO);
dup2(sock, STDERR_FILENO);
system(command);
}
}
The following is a code snippet of the client that sends a command to the server and receives back the output:
char output[10240];
send(sock, command, strlen(command), MSG_NOSIGNAL);
if((message_read = read(sock, output, sizeof(output)))>0){
output[message_read] = '\0';
//print the output somewhere
}
While the commands like "ls -al", "pwd", or "whoami" give the output in one go, the client fails to read whole of the output produced by commands like "ping", "ps" or "du". However when I call the above snippet multiple times, it gets me the rest of the output produced by the above commands(in chunks.)
I tried to modify the client function as follows:
send(sock, command, strlen(command), MSG_NOSIGNAL);
do{
if((message_read = read(sock, output, sizeof(output))) > 0){
output[message_read] = '\0';
//print the output somewhere
}
}while(message_read);
The above solution hanged the client program. However, after I killed the server, the outputs did show up in the client's window!
Also, this time the output was all scattered and poorly indented.
Q1. What's happening?
Q2. How to solve it?
The way your code is sending and reading strings is not sufficient.
TCP is a byte stream. There is no 1-to-1 relationship between sends and reads. As such, the sender MUST either:
send the string length before sending the string's data.
send a unique terminator after the string data.
And the receiver MUST either:
read the length then read the specified amount of data.
read until the terminator is reached.
Also, send()/write() and recv()/read() can return fewer bytes than requested, so they need to be called in loops (or, in the case of recv(), you can use the MSG_WAITALL flag).
Try something more like this instead:
// common functions ...
bool sendRaw(int sock, void *data, size_t len)
{
char *ptr = (char*) data;
while (len > 0) {
int sent = send(sock, ptr, len, MSG_NOSIGNAL);
if (sent < 0) return false;
ptr += sent;
len -= sent;
}
return true;
}
int recvRaw(int sock, void *data, size_t len)
{
char *ptr = (char*) data;
while (len > 0) {
int recvd = recv(sock, ptr, len, MSG_NOSIGNAL);
if (recvd <= 0) return recvd;
ptr += recvd;
len -= recvd;
}
return 1;
}
bool sendUInt32(int sock, uint32_t value)
{
value = htonl(value);
return sendRaw(sock, &value, sizeof(value));
}
uint32_t recvUInt32(int sock)
{
uint32_t value;
if (recvRaw(sock, &value, sizeof(value)) <= 0) return -1;
return ntohl(value);
}
bool sendString(int sock, const char *str)
{
uint32_t len = strlen(str);
if (!sendUInt32(sock, len)) return false;
return sendRaw(sock, str, len);
/* alternatively:
return sendRaw(sock, str, strlen(len) + 1);
*/
}
/*
bool grow(char **str, size_t *cap, size_t stepBy)
{
size_t newcap = cap + stepBy;
char *newstr = (char*) realloc(*str, newcap);
if (!newstr) return false;
*str = newstr;
*cap = newcap;
return true;
}
*/
char* recvString(int sock)
{
uint32_t len = recvUInt32(sock);
if (len == -1) return NULL;
char *str = (char*) malloc(len+1);
if (!str) return NULL;
if (recvRaw(sock, str, len) <= 0){
free(str);
return NULL;
}
str[len] = '\0';
return str;
/* alternatively:
char ch, *str = NULL;
size_t len = 0, cap = 0;
do{
if (recvRaw(sock, &ch, 1) <= 0){
free(str);
return NULL;
}
if (ch == '\0') break;
if (len == cap){
if (!grow(&str, &cap, 256)){
free(str);
return NULL;
}
}
str[len++] = ch;
}
while (1);
if (len == cap){
if (!grow(&str, &cap, 1)){
free(str);
return NULL;
}
}
str[len] = '\0';
return str;
*/
}
// server ...
char *command;
while ((command = recvString(sock)) != NULL){
// ...
system(command);
free(command);
// read from command's stdout until finished ...
if (!sendString(sock, output, outputLength)) break;
}
// client ...
if (sendString(sock, command)){
char *output = recvString(sock);
if (output){
//print the output somewhere
free(output);
}
}
Alternatively, if you don't know the length of the command's response ahead of time, and/or don't want to buffer it all in a single memory buffer, then you can read it in chunks, sending each chunk as you go, eg:
// common functions, see above ...
typedef struct _chunk
{
uint8_t size;
char data[256];
} chunk;
bool sendChunk(int sock, const chunk *chk)
{
uint8_t size = chk ? chk->size : 0;
if (!sendRaw(sock, &size, 1)) return false;
if (chk) return sendRaw(sock, chk->data, size);
return true;
}
bool recvChunk(int sock, chunk *chk)
{
if (recvRaw(sock, &(chk->size), 1) <= 0) return false;
if (chk->size) return recvRaw(sock, chk->data, chk->size);
return true;
}
// server ...
bool sendOutput(int sock)
{
chunk chk;
int size;
do{
// read from command's stdout ...
size = read(..., chk.data, sizeof(chk.data));
if (size <= 0) break;
chk.size = (uint8_t) size;
if (!sendChunk(sock, &chk)) return false;
}
while(1);
// tell client the data is finished ...
return sendChunk(sock, NULL);
}
char *command;
while ((command = recvString(sock)) != NULL){
// ...
system(command);
free(command);
if (!sendOutput(sock)) break;
}
// client ...
if (sendString(sock, command)){
chunk chk;
do{
if (!recvChunk(sock, &chk)) break;
if (chk.size == 0) break;
//print the chk.data somewhere
}
while (1);
}

How do I grow a dynamic buffer with read()?

So I'm having a bit of trouble wrapping my head around growing a buffer, from what I'm seeing I'm definitely reading all of the bytes from the file descriptor, but it seems I'm not storing them in the buffer properly. Can someone help point me in the right direction?
char *read_all(int fd, int *nread){ //nread tracks total bytes read
int max_size = 1;
*nread = 0;
char *buf = malloc(max_size*sizeof(char));
int bytes_read = read(fd, buf, max_size*sizeof(char));
while(bytes_read > 0){
*nread+=bytes_read;
if(*nread >= max_size*sizeof(char)){
max_size*=2;
buf = realloc(buf, max_size*sizeof(char));
}
bytes_read = read(fd, buf, max_size*sizeof(char));
}
return buf;
}
==== EXPECT ==== ==== ACTUAL ====
{ {
// Tests the read_all() function to ensure that // Tests the read_all() function to ensure that
// it properly accumulates all data from an // it properly accumulates all data from an
// arbitrary input FD including allocating memory // arbitrary input FD including allocating memory
// for the data. // for the data.
int fd = open("test-data/quote.txt", O_RDONLY); int fd = open("test-data/quote.txt", O_RDONLY);
int bytes_read = -1; int bytes_read = -1;
char *actual_read = read_all(fd, &bytes_read); char *actual_read = read_all(fd, &bytes_read);
int result = close(fd); int result = close(fd);
printf("result: %d\n", result); printf("result: %d\n", result);
printf("bytes_read: %d\n", bytes_read); printf("bytes_read: %d\n", bytes_read);
actual_read[bytes_read] = '\0'; actual_read[bytes_read] = '\0';
printf("actual_read:\n" ); printf("actual_read:\n" );
printf("--------------------\n" ); printf("--------------------\n" );
printf("%s",actual_read); printf("%s",actual_read);
printf("--------------------\n" ); printf("--------------------\n" );
free(actual_read); free(actual_read);
} }
result: 0 result: 0
bytes_read: 125 bytes_read: 125
actual_read: actual_read:
-------------------- --------------------
Object-oriented programming is an exceptionally bad idea which could | could
only have originated in California. only have originated in California.
-- Edsger Dijkstra -- Edsger Dijkstra
-------------------- --------------------
ALERTS: ALERTS:
(
Somewhat bizzare...
I changed read_all() so it works more like expected: (full here)
char *read_all2(int fd, int *nread){ //nread tracks total bytes read
int max_size = 1;
*nread = 0;
char *buf = malloc(max_size*sizeof(char));
char *ptr = buf;
int bytes_read = 0;
//while(bytes_read > 0)
do
{
fprintf(stderr, "bytes_read=%d\n", bytes_read);
*nread += bytes_read;
ptr += bytes_read;
if(*nread >= max_size*1){
max_size *= 2;
fprintf(stderr, "realloc(buf=%08x, max_size=%d)\n", buf, max_size);
buf = realloc(buf, max_size*1);
}
} while((bytes_read = read(fd, ptr, max_size*1)) > 0);
return buf;
}
but when it realloc(buf, 16); it crashes.
$ gcc -o readynbuf2 readynbuf2.c ; ./readynbuf2
bytes_read=0
bytes_read=1
realloc(buf=016ba008, max_size=2)
bytes_read=2
realloc(buf=016ba008, max_size=4)
bytes_read=4
realloc(buf=016ba008, max_size=8)
bytes_read=8
realloc(buf=016ba008, max_size=16)
*** Error in `./readynbuf2': realloc(): invalid next size: 0x016ba008 ***
I'm out of ideas why would it happen.
Thanks guys, I managed to solve it, the key was passing &buf[*nread] into read().
char *read_all(int fd, int *nread){
int bytes_read = 0, size_mult = 1;
*nread = 0;
char * buf = malloc(1024);
bytes_read = read(fd, &buf[*nread], 256);
while(bytes_read > 0){
*nread += bytes_read;
if(*nread > size_mult*512){
size_mult*=2;
buf = realloc(buf, size_mult*1024);
}
bytes_read = read(fd, &buf[*nread], 256);
}
return buf;
}

recv() on socket by dynamically allocating space

I'm trying to get the source code of my website using c, I'm able to connect and everything but when I implement the recv() code, it only receives the last few bytes of the source code. I'd like to dynamically allocate space for the buffer to receive more using the C functions malloc and realloc.
This is the code I have so far:
char *buffer = NULL;
unsigned int i = 0;
unsigned long LEN = 200;
unsigned long cur_size = 0;
buffer = (char*)malloc(sizeof(char)*LEN);
do
{
if( status >= LEN )
{
cur_size += status;
buffer = (char*)realloc(buffer, cur_size);
}
status = recv(cSocket, buffer, LEN, 0);
if( status == 0 )
{
printf("Bye\n");
}
else if( status > 0 )
{
printf("%d\n", status);
}
else
{
printf("socket error=%d\n", WSAGetLastError());
break;
}
}while( status > 0 );
printf("%s\n", buffer);
It still doesn't print the whole source code. How should I go about this?
Pseudocode:
buffer = 'len chars';
loop:
if( status >= buffer ) buffer = 'resize to status chars';
status = recv(sock, buffer, len, 0);
end loop
As you resize the buffer in advance this needs to be reflected by its size. Which currently is not the case.
To fix this you could, for example, initialise cur_size with LEN by changing
unsigned long cur_size = 0;
to
unsigned long cur_size = LEN;
Assuming the fix above, you want to append to the buffer and not overwrite it with every call to recv().
To do so change this line
status = recv(cSocket, buffer, LEN, 0);
to be
status = recv(cSocket, buffer + cur_size - LEN, LEN, 0);
A more straight forward approach would be to not track the size of the buffer, but the number of bytes received and just always increase the buffer by a constant size.
Also the two calls to allocate memory can be replaced by one:
char *buffer = NULL;
unsigned long LEN = 200;
unsigned long bytes_received = 0;
unsigned long cur_size = 0;
int status = 0;
do
{
if (bytes_received >= cur_size)
{
char * tmp;
cur_size += LEN;
tmp = realloc(buffer, cur_size);
if (NULL == tmp)
{
fprintf(stderr, "realloc error=%d\n", WSAGetLastError());
break;
}
buffer = tmp;
}
status = recv(cSocket, buffer + bytes_received, LEN, 0);
if (status == 0)
{
printf("Bye\n");
}
else if (status > 0)
{
bytes_received += status;
printf("%d\n", status);
}
else /* < 0 */
{
fprintf(stderr, "socket error=%d\n", WSAGetLastError());
}
} while (status > 0);
printf("%s\n", buffer);
Well, after a bit of research, I came across this website and finally found what I was looking for.
Binary tides
Although it uses linux's fcntl, the windows equivalent is ioctlsocket which is used to set the socket's non-blocking mode.
To see the exact function, visit the website. I modified the version and set my socket to blocking mode.
int total_recv(SOCKET s)
{
int size_recv = 0, total_size = 0, block = 00;
char chunk[BUFLEN];
ioctlsocket(s, FIONBIO, (unsigned long*)&block); // set mode to block
// not necessary but clarification of function, mode is block by
// default
while( 1 )
{
memset(chunk, 0, BUFLEN);
if( ( size_recv = recv(s, chunk, BUFLEN, 0) ) == SOCKET_ERROR )
{
printf("Error receiving\n");
}
else if( size_recv == 0 )
{
break;
}
else
{
total_size += size_recv;
// i used file since console wouldn't show full source code
FILE *fp = NULL;
fp = fopen("source.txt", "a");
fprintf(fp, chunk);
fclose(fp);
}
}
return total_size;
}

Read line by line from a socket buffer

I want to write a function that read line by line from a socket buffer obtained from third parameter from read() function from unistd.h header.
I have wrote this:
int sgetline(int fd, char ** out)
{
int buf_size = 128;
int bytesloaded = 0;
char buf[2];
char * buffer = malloc(buf_size);
char * newbuf;
int size = 0;
assert(NULL != buffer);
while( read(fd, buf, 1) > 0 )
{
strcat(buffer, buf);
buf[1] = '\0';
bytesloaded += strlen(buf);
size = size + buf_size;
if(buf[0] == '\n')
{
*out = buffer;
return bytesloaded;
}
if(bytesloaded >= size)
{
size = size + buf_size;
newbuf = realloc(buffer, size);
if(NULL != newbuf)
{
buffer = newbuf;
}
else
{
printf("sgetline() allocation failed!\n");
exit(1);
}
}
}
*out = buffer;
return bytesloaded;
}
but I have some problems with this function, for example, if the input is something like:
HTTP/1.1 301 Moved Permanently\r\n
Cache-Control:no-cache\r\n
Content-Length:0\r\n
Location\r\nhttp://bing.com/\r\n
\r\n\r\n
and I do
int sockfd = socket( ... );
//....
char* tbuf;
while(sgetline(sockfd, &tbuf) > 0)
{
if(strcmp(tbuf,"\r\n\r\n") == 0)
{
printf("End of Headers detected.\n");
}
}
the above C application does not output "End of Header detected.". Why is this, and how can I fix this?
It's not OK to read one byte at a time, because you are making too many system calls - better is to use a buffer, read a chunk and check if you got \n. After getting a line, the rest of the bytes read remains in the buffer, so you cannot mix read/recv with read_line. Another version of read n bytes using this kind of buffer can be write...
My version to read a line, and a little example to use it.
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#define CBSIZE 2048
typedef struct cbuf {
char buf[CBSIZE];
int fd;
unsigned int rpos, wpos;
} cbuf_t;
int read_line(cbuf_t *cbuf, char *dst, unsigned int size)
{
unsigned int i = 0;
ssize_t n;
while (i < size) {
if (cbuf->rpos == cbuf->wpos) {
size_t wpos = cbuf->wpos % CBSIZE;
//if ((n = read(cbuf->fd, cbuf->buf + wpos, (CBSIZE - wpos))) < 0) {
if((n = recv(cbuf->fd, cbuf->buf + wpos, (CBSIZE - wpos), 0)) < 0) {
if (errno == EINTR)
continue;
return -1;
} else if (n == 0)
return 0;
cbuf->wpos += n;
}
dst[i++] = cbuf->buf[cbuf->rpos++ % CBSIZE];
if (dst[i - 1] == '\n')
break;
}
if(i == size) {
fprintf(stderr, "line too large: %d %d\n", i, size);
return -1;
}
dst[i] = 0;
return i;
}
int main()
{
cbuf_t *cbuf;
char buf[512];
struct sockaddr_in saddr;
struct hostent *h;
char *ip;
char host[] = "www.google.com";
if(!(h = gethostbyname(host))) {
perror("gethostbyname");
return NULL;
}
ip = inet_ntoa(*(struct in_addr*)h->h_addr);
cbuf = calloc(1, sizeof(*cbuf));
fprintf(stdout, "Connecting to ip: %s\n", ip);
if((cbuf->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(80);
inet_aton(ip, &saddr.sin_addr);
if(connect(cbuf->fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
perror("connect");
return 1;
}
snprintf(buf, sizeof(buf), "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", host);
write(cbuf->fd, buf, strlen(buf));
while(read_line(cbuf, buf, sizeof(buf)) > 0) {
// if it's an empty \r\n on a line, header ends //
if(buf[0]=='\r' && buf[1] == '\n') {
printf("------------------------\n");
}
printf("[%s]", buf);
}
close(cbuf->fd);
free(cbuf);
return 0;
}
Try this implementation instead:
int sgetline(int fd, char ** out)
{
int buf_size = 0;
int in_buf = 0;
int ret;
char ch;
char * buffer = NULL;
char * new_buffer;
do
{
// read a single byte
ret = read(fd, &ch, 1);
if (ret < 1)
{
// error or disconnect
free(buffer);
return -1;
}
// has end of line been reached?
if (ch == '\n')
break; // yes
// is more memory needed?
if ((buf_size == 0) || (in_buf == buf_size))
{
buf_size += 128;
new_buffer = realloc(buffer, buf_size);
if (!new_buffer)
{
free(buffer);
return -1;
}
buffer = new_buffer;
}
buffer[in_buf] = ch;
++in_buf;
}
while (true);
// if the line was terminated by "\r\n", ignore the
// "\r". the "\n" is not in the buffer
if ((in_buf > 0) && (buffer[in_buf-1] == '\r'))
--in_buf;
// is more memory needed?
if ((buf_size == 0) || (in_buf == buf_size))
{
++buf_size;
new_buffer = realloc(buffer, buf_size);
if (!new_buffer)
{
free(buffer);
return -1;
}
buffer = new_buffer;
}
// add a null terminator
buffer[in_buf] = '\0';
*out = buffer; // complete line
return in_buf; // number of chars in the line, not counting the line break and null terminator
}
int sockfd = socket( ... );
//....
char* tbuf;
int ret;
// keep reading until end of headers is detected.
// headers are terminated by a 0-length line
do
{
// read a single line
ret = sgetline(sockfd, &tbuf);
if (ret < 0)
break; // error/disconnect
// is it a 0-length line?
if (ret == 0)
{
printf("End of Headers detected.\n");
free(tbuf);
break;
}
// tbuf contains a header line, use as needed...
free(tbuf);
}
while (true);
You are making things more difficult for yourself than they need to be. You really don't need to do strcats to get the single character you read on each read added at the current position.
But your bug is that the routine returns as soon as it sees a \n, so the string it returns can never contain anything following the first \n.

Unable to send whole file over TCP connection! (UNIX C)

So I programmed a multi threaded web server, here is one function from the program. This function takes output file descriptor (fd), content type, pointer to data to be served (*buf) and size of the data (numbytes). It always gets stuck at 5775 bytes! I've tried using write() instead of send(), but no avail! I tried to send whole buf at a time, and even tried to transfer it in chunks, but wget shows that it gets stck at 5775 bytes! Here is the code:
int return_result(int fd, char *content_type, char *buf, int numbytes)
{
char out_buf[BUF_SIZE], numb[6];
int buf_len, total = 0, buf_size;
long int i = 0;
sprintf(numb, "%d", numbytes);
strcpy(out_buf, "HTTP/1.1 200 OK \nContent-Type: ");
strcat(out_buf, content_type);
strcat(out_buf, "\nContent-Length: ");
strcat(out_buf, numb);
strcat(out_buf, "\nConnection: Close\n \n");
printf("\nSending HTTP Header\n %d bytes sent!",
send(fd, out_buf, strlen(out_buf), 0));
char *start = NULL, *str = NULL, *temp = NULL;
start = buf;
printf("\n Start Pointer Val = %ld", &start);
while (start != NULL) {
printf("\n While Loop");
if (i + 2048 * sizeof(char) < numbytes) {
printf("\n If 1");
str = (char *)malloc(sizeof(char) * 2048);
memcpy(str, start, sizeof(char) * 2048);
i = i + 2048 * sizeof(char);
buf_size = send(fd, str, 2048, 0);
free(str);
printf("\n Sent %d bytes total : %d", buf_size, total =
total + buf_size);
temp = start + sizeof(char) * 2048;
start = temp;
} else {
i = numbytes - i * sizeof(char);
if (i > 0) {
printf("\n If 2");
printf("\n Value of i %d", i);
str = (char *)malloc(sizeof(char) * i);
memcpy(str, start, sizeof(char) * i);
printf("Total bytes finally sent:%d", total =
total + send(fd, str, i, 0));
if (total == numbytes) {
printf("\nTransfer Complete!");
}
free(str);
}
start = NULL;
}
}
printf("out of loop!");
return 0;
}
I'd like to suggest replacing your code with the following writen() function from Advanced Programming in the Unix Environment, 2nd edition:
ssize_t /* Write "n" bytes to a descriptor */
writen(int fd, const void *ptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) < 0) {
if (nleft == n)
return(-1); /* error, return -1 */
else
break; /* error, return amount written so far */
} else if (nwritten == 0) {
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft); /* return >= 0 */
}
This code is already debugged and known working, and further allows write(2) to write PIPE_BUF bytes at a go for better speed when things are working well.
send(2) should block if it cannot send all the data you have requested, though. I think more interesting would be debugging the version with plain send(2) without any of the surrounding efforts to break things into blocks.
Better than both write(2) and send(2) would be sendfile(2) -- open the file, pass the descriptor and socket to sendfile(2), and let the kernel handle it all for you, using zero-copy mechanisms if possible.
One last point: HTTP uses CRLF, not plain carriage returns. Each \n should be replaced with \r\n.
Try something like this (printf() statements omitted for clarity):
int send_buf(in fd, void *buf, int numbytes)
{
char *start = (char*) buf;
while (numbytes > 0)
{
int sent = send(fd, start, numbytes, 0);
if (sent <= 0)
{
if ((sent == -1) && (errno == EAGAIN))
{
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
if (select(fd + 1, NULL, &wfds, NULL, NULL) == 1)
continue;
}
return -1;
}
start += sent;
numbytes -= sent;
}
return 0;
}
int return_result(int fd, char *content_type, void *buf, int numbytes)
{
char out_buf[BUF_SIZE],
int len = sprintf(out_buf,
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"Connection: Close\r\n"
"\r\n",
content_type,
numb);
if (send_buf(fd, out_buf, len) != 0)
return -1;
if (send_buf(fd, buf, numbytes) != 0)
return -1;
return 0;
}

Resources