Use rio_readlineb to read image,but not work - c

I am trying to make a small proxy service.
Now the problem is that I can not show the image from web service.
I use Rio_readlineb to read image data back.But it could not show up.
while ((Rio_readlineb(&rio_client, buf, MAXLINE)) !=0){
Rio_writen(fd, buf, strlen(buf));
}
But when I use Rio_readnb to read.The problem is solved.
while ((size = Rio_readnb(&rio_client, body, MAXLINE)) != 0)
Rio_writen(fd, body, size);
I do not know where is the problem.
readnb
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = rio_read(rp, bufp, nleft)) < 0)
return -1; /* errno set by read() */
else if (nread == 0)
break; /* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft); /* return >= 0 */
}
rio_readlineb
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0; /* EOF, no data read */
else
break; /* EOF, some data was read */
} else
return -1; /* Error */
}
*bufp = 0;
return n-1;
}
Is the rio_readlineb cut off the data? But If MAXLINE is too small,rio_readnb also will cut off the data.So where is the problem?

I assume that you are trying to implement a HTTP 1.0 proxy.
rio_readlineb is looking for the newline character (\n, hex value 0x0A, decimal value 10) in the data is is reading. When it has read that character, it returns successfully, indicating the number of characters read. This works fine for reading textual data, like HTTP headers, where each header line is terminated by the newline character.
However, image data is not terminated by a newline character. In fact, images can contain this character anywhere within their data. The moment rio_readlineb finds \n in the image data, it returns, but the buffer likely does not contain the entire image yet. So, you're sending a corrupt image (too short) to the proxy client.
In HTTP 1.0, the server writes the response headers and then data to the socket. After it has written all the data, it closes the socket. You need to read until end-of-file to get all the image data. This is what your Rio_readnb & Rio_writen loop is doing.

Related

System-call read() blocked

I have a client that need to read on a socket a sequence of char sent by server.
Client read with system-call read() a socket SOCK_DGRAM.
Here the complete function with system-call read(..) inside.
ssize_t readLine(int sockd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *buffer;
buffer = vptr;
for ( n = 1; n < maxlen; n++ )
{
rc = read(sockd, &c, 1);
if ( rc == 1 )
{
*buffer++ = c;
if (c == '\0') break;
}
else
{
if (errno == EINTR) continue;
return -1;
}
}
*buffer = 0;
return n;
}
The problem is that if Server send a sequence of char like this ABCDEF'\0', this client read only A and then the system-call read() go in blocking mode.
I have used Wireshark to see if server work well and it send correctly ABCDEF'\0' in a UDP packet. All ok from this point of view.
Thanks to all in advance.
With datagram sockets, you need to read and write the whole datagram at once.
If you don't give read enough space to read the entire datagram, the rest of the datagram simply disappears.
int datagram_length = read(sockd, vptr, maxlen - 1);
if (datagram_length < 0) {
// complain about the error
} else {
vptr[datagram_length] = 0;
}

Is there any way to know the amount of bytes send from the client to the server and process the recv() in networks

I am trying to build a chat application between the server and the client. My doubt is for sending information from the client or from the server I was able to handle the partial send with the help of the loop, but I am unable to find out the length of the send data bytes from the client to the server or from the server to the client, thereby having problem in creating the memory for the received bytes and printing.
My chat function code for the client:
int chat_function(int sockfd)
{
char ch;
char *buf;
char *newp;
int ret_send = 0;
int ret_recv = 0;
int buf_size = 0;
while(1) {
printf("From client, enter the message : ");
buf = (char *)malloc(sizeof(char));
if (buf == NULL)
return -1;
while ((ch = getchar()) != '\n') {
buf[buf_size++] = ch;
newp = (char *)realloc(buf, (buf_size + 1) * sizeof(char));
if ( newp == NULL) {
free(buf);
return -1;
}
buf = newp;
}
buf[buf_size] = '\0';
ret_send = send_all(sockfd, buf, buf_size);
if (ret_send == -1)
error(1, errno, "error in send() function call\n");
memset(buf, 0, buf_size);
ret_recv = recv_all(sockfd, buf, buf_size);
if (ret_recv == -1) {
error(1, errno, "error in recv() function call\n");
} else if (ret_recv == -2) {
printf("Oops the server has closed the connection\n");
free(buf);
break;
}
printf("From Server : %s", buf);
if ((strncmp(buf, "exit", 4)) == 0) {
printf("Client Exit...\n");
free(buf);
break;
}
free(buf);
}
}
For handling partial send:
int send_all(int sockfd, char *buf, int buf_size)
{
int bytes_left = 0;
size_t send_bytes = 0;
bytes_left = buf_size
while (1) {
send_bytes = send(fd, buf, bytes_left, 0);
if (send_bytes == -1)
return -1;
buf = buf + send_bytes;
bytes_left = bytes_left - send_bytes;
if (bytes_left == 0)
break;
}
return 0;
}
TCP is a stream protocol, meaning there are no message boundaries: it is just a full-duplex (meaning data flows in both directions at the same time, as if there were two separate lanes) more or less continuous stream of data.
UDP is a datagram protocol, and does have message boundaries. There is an ioctl (FIONREAD/SIOCINQ) that provides the length of the next datagram, but because it involves a syscall, doing that for every message you receive is going to be slow and inefficient. Instead, you normally use a buffer large enough to hold the largest acceptable message, and copy it if/when necessary. However, UDP also has no reliability guarantees, and often UDP datagrams are completely lost without any trace or discernible reason; that's just what happens.
For a chat client-server connection, you'll want to use TCP.
Since the underlying connection is just a stream of data, you need to design a protocol for the communications, so that the stream can be split into messages, with each message processed separately.
The simplest case would be to use the nul character, \0, as a message separator.
The "send" function would then look something like this:
/* Returns 0 if message successfully sent,
nonzero errno code otherwise. */
int send_message(int descriptor, const char *message)
{
/* If message is NULL, we cannot use strlen(); use zero for that. */
const size_t message_len = (message) ? strlen(message) : 0;
/* Temporary variables for the sending part. */
const char *ptr = message;
const char *const end = message + message_len + 1; /* Include '\0' at end */
ssize_t bytes;
/* Check valid descriptor and message length. */
if (descriptor == -1 || message_len < 1)
return errno = EINVAL;
/* Write loop for sending the entire message. */
while (ptr < end) {
bytes = write(descriptor, ptr, (size_t)(end - ptr));
if (bytes > 0) {
ptr += bytes;
} else
if (bytes != -1) {
/* This should never happen. */
return errno = EIO;
} else
if (errno != EINTR) {
/* We do not consider EINTR an actual error; others we do. */
return errno;
}
}
return 0;
}
The above send_message() function writes the specified string, including the string terminating nul character \0, to the specified descriptor.
On the read end, we need a buffer large enough to hold at least one full message. Instead of always waiting for incoming data, we need to check if the buffer already contains a full message, and if it does, return that. Also, you do not necessarily want to always wait for an incoming message, because that would mean you cannot send two messages in a row.
So, here's my suggestion:
static int incoming_desc = -1;
static char *incoming_data = NULL;
static size_t incoming_size = 0;
static char *incoming_next = NULL; /* First received but not handled */
static char *incoming_ends = NULL; /* Last received but not handled */
#define INCOMING_CHUNK 4096
/* Receive a new message into dynamically allocated buffer,
and return the length. Returns 0 when no message, with errno set.
Waits at most ms milliseconds for a new message to arrive.
errno == EAGAIN: no message, timeout elapsed.
errno == ECONNABORTED: other end closed the connection.
*/
size_t get_message(char **message, size_t *size, long ms)
{
struct timeval timeout;
/* Make sure the parameters are sane. */
if (!message || !size || ms < 0) {
errno = EINVAL;
return 0;
}
/* For this function to work like getline() and getdelim() do,
we need to treat *message as NULL if *size == 0. */
if (!*size)
*message = NULL;
timeout.tv_sec = ms / 1000;
timeout.tv_usec = (ms % 1000) * 1000;
/* Timeout loop. */
while (1) {
fd_set readfds;
ssize_t bytes;
size_t used;
int result;
/* Is there a pending complete message in the buffer? */
if (incoming_ends > incoming_next) {
char *endmark = memchr(incoming_next, '\0', (size_t)(incoming_ends - incoming_next));
if (endmark) {
const size_t len = (size_t)(endmark - incoming_next) + 1;
/* Reallocate the message buffer, if necessary. */
if (len > *size) {
char *temp = realloc(*message, len);
if (!temp) {
errno = ENOMEM;
return 0;
}
*message = temp;
*size = len;
}
/* Copy message, */
memcpy(*message, incoming_next, len);
/* and remove it from the buffer. */
incoming_next += len;
/* In case the other end sent just the separator, clear errno. */
errno = 0;
/* We return the length sans the separator. */
return len - 1;
}
}
/* Do we have time left to check for input? */
if (timeout.tv_sec <= 0 && timeout.tv_usec <= 0)
break; /* Nope. */
/* Is incoming_desc one we can select() for? */
if (incoming_desc < 0 || incoming_desc >= FD_SETSIZE)
break; /* Nope. */
FD_ZERO(&readfds);
FD_SET(incoming_desc, &readfds);
result = select(incoming_desc + 1, &readfds, NULL, NULL, &timeout);
if (result < 1)
break; /* Nothing interesting happened (we ignore error here). */
if (!FD_ISSET(incoming_fd, &readfds))
break;
/* Number of bytes used in the buffer right now. */
used = (size_t)(incoming_ends - incoming_data);
/* Do we have at least INCOMING_CHUNK bytes available? */
if (used + INCOMING_CHUNK >= incoming_size) {
/* Nope. Repack the incoming buffer first. */
if (incoming_next > incoming_data) {
const size_t len = (size_t)(incoming_ends - incoming_next);
if (len > 0)
memmove(incoming_data, incoming_next, len);
incoming_next = incoming_data;
incoming_ends = incoming_data + len;
}
/* Recalculate the number of bytes we have free now. Enough? */
used = (size_t)(incoming_ends - incoming_data);
if (used + INCOMING_CHUNK > incoming_size) {
/* Grow incoming buffer. */
const size_t newsize = used + INCOMING_CHUNK;
char *temp = realloc(incoming_data, newsize);
if (!temp) {
errno = ENOMEM;
return 0;
}
incoming_next = temp + (size_t)(incoming_next - incoming_data);
incoming_ends = temp + used;
incoming_data = temp;
incoming_size = newsize;
}
}
/* Read more data into the buffer; up to a full buffer. */
bytes = read(incoming_fd, incoming_ends, incoming_size - used);
if (bytes > 0) {
incoming_ends += bytes;
} else
if (bytes == 0) {
/* Other end closed the connection. We may have a partial message
in the buffer, and should handle that too, but for now, we
just error out. */
errno = ECONNABORTED;
return 0;
} else
if (bytes != -1) {
/* Should never happen. */
errno = EIO;
return 0;
} else
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
/* No data yet, interrupted by signal delivery, etc. */
continue;
} else {
/* errno is set to indicate which error happened. */
return 0;
}
}
/* Timeout. */
errno = EAGAIN;
return 0;
}
Note that get_message() works like getline(): you do e.g.
char *msg = NULL;
size_t size = 0;
size_t len;
len = get_message(&msg, &size, 100); /* 100 ms = 0.1 seconds */
if (len) {
/* msg contains a full message of len characters */
} else
if (errno == ECONNABORTED) {
/* Other end closed the connection */
} else
if (errno != EAGAIN) {
fprintf(stderr, "Error receiving data: %s.\n", strerror(errno));
}
Then, you can reuse the same dynamically allocated buffer by just calling e.g.
len = get_message(&msg, &size, 100); /* 100 ms = 0.1 seconds */
again.
There is no such mechanism built into TCP or UDP. You need to implement your own protocol on top of it. One of the possible solutions is:
If the content delivered is static.
If the sending end knows the size of the data that is being delivered prior, your client and server can agree on specific terms. For example, the first four bytes sent by the server is the size of the remaining message represented in network byte order.
Server code
uint32_t n_size = htonl(size); // Convert the data size into network byte order.
write(sockfd, &n_size, sizeof(n_size)); // Send to the client.
Client code
uint32_t n_size;
int n_read = 0;
for ( ; ; ) {
int rd_status = read(sockfd, (void*) &n_size + n_read, sizeof(n_size) - n_read);
if (rd_status <= 0)
goto handle_this_case;
n_read = n_read + rd_status;
if (n_read == sizeof(n_size))
break;
}
uint32_t size = ntohl(n_size);
If the content delivered is generated on the fly.
In this case, even the server is not aware of the size of the message. You need to build your functions for handling this case. Below I have shown a bare minimal implementation:
Client-Side:
struct data_unit
{
void* data;
int size;
};
struct data_storage
{
struct data_unit unit;
struct data_storage* next;
};
void append_data(struct data_storage* storage, struct data_unit* unit);
struct data_unit* dump_data(struct data_storage* storage);
int main()
{
struct data_storage storage;
struct data_unit unit;
unit.data = malloc(MAX_SIZE);
for ( ; ; ) {
int rd_status = read(sockfd, unit.data, MAX_SIZE);
if (rd_status < 0)
goto handle_this_case;
else if (rd_status == 0)
break;
unit.size = rd_status;
append_data(&storage, &unit);
}
struct data_unit* t_data = dump_data(&storage);
}

how to send string, one char at a time through sock_stream

I am having trouble sending a string, one char at a time through sock_stream connection. The reason for this is that I am attempting to send multiple strings which are nearly 70000 characters at a time. It seems that the write function I was attempting to use requires a string.
for(i=0;i<BUF_SIZE;i++)
{
write(sockfd,plaintext[i],1);
if(plaintext[i]=='0')
break;
}
write(sockfd,'^',sizeof(char));
Also, how would I read this? Here is how I was attempting it.
int read_line(int fd,char message[])
{
size_t message_len=0;
while (message_len<BUF_SIZE)
{
char c;
int ret = read(fd, &c, 1);
if (ret < 0)
{
message[message_len] = 0;
return len; // EOF reached
}
if (c == '^')
{
read(fd,&c,1);
message[message_len] = 0;
return message_len; // EOF reached
}
data[len++] = c;
}
}
How would I implement this? Thank you.
The signature of write api is:
int write(int fd, const void *buf, size_t nbyte);
So what you can do something like:
#define BUF_SIZE 70000
char *buf = (char*)malloc(BUF_SIZE);
int written = 0;
int wrote;
if (buf)
memset(buf, 1, BUF_SIZE);
else
return written;//some error code
while (written < BUF_SIZE)
{
wrote = write(fd, buf, BUF_SIZE);
if (wrote < 0)
return written;
written += wrote;
}
Similarly you should try to do bulk read, as reading one char at a time is too slow unless you have a very valid reason. Each time you do write or read, its system call and they are costly.
So for read you can try something like
int read_bytes = read(fd, buf, BUF_SIZE);
and read_bytes will have the exact value of how much you have read.
Then do parse_buf(buf) in which you can find the tag you are looking for and then save the rest for the future in case you get more data, else if you get less data, then call read again.
You need change line
write(sockfd,plaintext[i],1);
to
write(sockfd,&plaintext[i],1);
Additionally, you can use
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
to enable TCP_NODELAY option.

Send/Read using a TCP socket, anomalies in the byte sizes

I'm trying to implement a working HTTP Client-Server application just to make practice with network programming.
The 2 programs have to follow this basic algorithm:
CLIENT - send a GET request
SERVER - send "+OK\r\n"
SERVER - send file size in bytes
SERVER - send file
CLIENT - send ACK
I'm having a lot of troubles in the reading part, probably because i perform some dirty read on the stream.
These are the 2 reading function that i'm using:
/* Reads a line from stream socket s to buffer ptr
The line is stored in ptr including the final '\n'
At most maxlen chasracters are read*/
int readline (SOCKET s, char *ptr, size_t maxlen)
{
size_t n;
ssize_t nread;
char c;
for (n=1; n<maxlen; n++)
{
nread=recv(s, &c, 1, 0);
if (nread == 1)
{
*ptr++ = c;
if (c == '\n')
break;
}
else if (nread == 0) /* connection closed by party */
{
*ptr = 0;
return (n-1);
}
else /* error */
return (-1);
}
*ptr = 0;
return (n);
}
and:
int readNumber(SOCKET s, long *num, int maxRead)
{
size_t n;
ssize_t nread;
int totRead;
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
if (nread == sizeof(number))
{
totRead+=nread;
*num = number;
}
else if (nread == 0) /* connection closed by party */
{
*num = 0;
return (n-1);
}
else /* error */
{
printf("nread = %d\n", nread);
return (-1);
}
}
return (totRead);
}
this is the snippet of the main where i receive the +OK message and then the file size:
memset(rbuf,0,sizeof(rbuf)); //rbuf is the buffer where is store the read
printf("waiting for response...\n");
result = readline(s, rbuf, sizeof(rbuf)); //reading function is above
printf("Byte read(okMsg) = %d\n", result);
if (result <= 0)
//ERROR MANAGEMENT
{
printf("Read error/Connection closed\n");
closesocket(s);
SockCleanup();
exit(1);
}
else
{
long fileLength=0;
unsigned char *fBuf;
//RECEIVE OK
if(!strcmp(rbuf,"+OK\r\n"))
{
puts("+OK\n");
//RECEIVE FILE LEN
int nw = readNumber(s, &fileLength, 1); //reading function is above
printf("Byte read(fDim) = %d\n", nw);
printf("File is %ld bytes long\n", fileLength);
if(nw >0)
{
// RECEIVE FILE
}
}
}
When i send the "+OK\r\n" string the server tells me that it sends 8 bytes, but when i read i find the '\0' char only after 6 bytes.
By the way it reads correctly the message, but when i try to read the file size (that is a long) it gives me back a wrong number.
My opinion is that the stream buffer is dirty, and that i'm reading 2 bytes that are not part of the file size, but i'm not understanding why this happens.
Please ask me more info if i'm not clear enough.
SOLVED:
Thank you all for your answers!!!
You put me in the right mindset to understand what was wrong.
Look like the problem was this declaration in the server:
char *okMsg = "+OK\r\n";
instead of
char okMsg[] = "+OK\r\n";
that lead me to an undefined behavior.
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
You forgot to design and implement a protocol to carry the data between your server and your client. Because TCP provides a stream of bytes, your protocol should be defined as a stream of bytes.
How many bytes convey this number? Is "however many bytes a 'long' happens to occupy on my platform" a good answer? What's the semantic meaning of the first byte? Is "whatever the first byte of a 'long' happens to mean on my platform" a good answer?
A good answer would be, "The size shall be conveyed as a 4-byte unsigned integer in little-endian byte order". Then make absolutely sure your code sends and receives in that format.

Socket programming problem in C

From the below piece of code, why I am getting Reading Socket for response
int Read(int sock, char *p, int size)
{
int remain, read=0;
remain = size;
while (remain > 0 ) {
if ((read = recv(sock, p, remain, 0)) < 0) {
/* Error */
return(read);
} else if (read == 0 || *p == 0x0a) {
/* EOF */
break;
}
remain -= read;
p += read;
}
return(size - remain);
}
while (!done)
{
printf("***Reading Socket for response***");
rsplen= Read(myVsHandle.sock,(char *)encXMLResponse,MAX_RSP_LEN);
if (rsplen < 0 )
{
printf("Internal Communication Error");
return -1;
}
else if (rsplen >0)
printf("Revieved response");
done++;
return 0;
else if (rsplen == 0)
{
printf("Reading socket");
}
You are waiting for MAX_RSP_LEN bytes to be read - is there that many bytes to be read? Maybe your process is stuck in a blocking read().
Also depending on the sort of socket you are recv()ing from, there is no guarantee on the amount of data you will read, so specifically looking for a value 0x0a may not work.
Your problem could be that you are not ending your output with a newline. Try ending your outputs with a newline (\n). stdout is line buffered, so you may not see anything for a long time if you don't output a newline.
Another possibility is that you don't return from Read() unless you read the specified number of bytes. Depending upon the value of MAX_RSP_LEN, and the amount of data available, Read() may wait forever.
Also, your test: *p == 0x0a looks suspicious. What are you testing here?
Edit: There is another "bug":
else if (rsplen >0)
printf("Revieved response");
done++;
return 0;
else...
You are missing curly braces. In the current form, the code shouldn't compile. Please post actual code.
This:
if ((read = recv(sock, p, remain, 0)) < 0) {
Should be
if ((read = recv(sock, p, remain, 0)) > 0) { // Greater then 0, because recv returns the number of bytes received if successful, if it fails -1.
You're missing curly braces around the:
else if(rsplen > 0)
... statements
It should be:
...
}else if (rsplen >0){
printf("Revieved response");
done++;
return 0;
} ...

Resources