I am writing a small code to read ADS-B data from a Socket. The data is in following format
MSG,6,1,1,4242D7,1,2017/12/25,12:04:05.695,2017/12/25,12:04:05.695,,,,,,,,6142,0,0,0,
MSG,4,1,1,80068D,1,2017/12/25,12:04:05.695,2017/12/25,12:04:05.695,,,183,268,,,-576,,,,,0
MSG,2,1,1,800B6F,1,2017/12/25,12:04:05.695,2017/12/25,12:04:05.695,,,7,165,28.53949,77.10886,,,,,,-1
MSG,5,1,1,4242D7,1,2017/12/25,12:04:05.695,2017/12/25,12:04:05.696,KAR2440
,32025,,,,,,,0,,0
The strings are terminated by CRLF
I am presently using a readline function to read the data from the socket line by line
int readline(int fd, char ** out)
{
/* Keep reading till header "MSG" is received
* store it in buffer
* keep reading till newline is encountered
* exit function
*/
int buf_size = 512;
int bytesloaded = 0;
int ret;
char buf;
char * buffer = malloc(buf_size * sizeof(*buffer));
if (NULL == buffer)
{
free(buffer);
return -1;
}
//loop till header is received
while (1)
{
bzero(buffer,buf_size);
ret = read(fd, &buf, 1);
if (ret < 0)
{
free(buffer);
return -1;
}
if (buf=='M') //Got M; now wait for S
{
bytesloaded=0;
buffer[bytesloaded] = buf;
bytesloaded++;
ret = read(fd, &buf, 1);
if (ret < 1)
{
free(buffer);
return -1;
}
if (buf=='S') //Got S; now wait for G
{
buffer[bytesloaded] = buf;
bytesloaded++;
ret = read(fd, &buf, 1);
if (ret < 1)
{
free(buffer);
return -1;
}
if (buf=='G') //Got G; now wait for CR-LF
{
buffer[bytesloaded] = buf;
bytesloaded++;
while(1)
{
ret = read(fd, &buf, 1);
if (ret < 1)
{
free(buffer);
return -1;
}
if (buf=='\n')
break;
buffer[bytesloaded] = buf;
bytesloaded++;
}
buffer[bytesloaded] = '\0';
*out = buffer; // complete line
//free(buffer);
return bytesloaded;
}
}
}
}
}
The above function is called from main using the following routine
bytesread=readline(netfd, &netbuf);
The problem is the code footprint in the memory increases gradually indicating a memory leak. Valgrind also points to the readline function.
There is no memory leak if I uncomment the second last line (free(buffer)). But doing so gives me no data at output.
What am I missing here.
Your design indicates that the function readline allocates the memory required and returns a pointer to the calling function.
Using this design, the calling function MUST call free to avoid a memory leak.
I should point out that this design is often problematic and increases the chances for memory leaks.
A better design keeps memory management concerns together (the allocating function should free the memory. When this is impossible or impractical, the function name should clearly indicate the allocation and a destructor should be written (i.e., line_alloc and line_free), minimizing any confusion.
Related
I have to implement standard unix command "tail" without fopen, fclose, fread, fseek, printf. I am ready with everything else except handle of partial reads and writes.
And here is my print with handle of partial read and write of last 10 lines. It's happening after lseek to the right position for fd!
I test it several times with different files and it works like real tail, but i cant handle partial reads and writes like i said.
'''code'''
do
{
memset(buff, 0, SIZE);
read_value = read(fd, buff, SIZE);
ssize_t bytes_read_total = read_value;
int count=2;
char buff_copy[SIZE];
while (bytes_read_total < SIZE)
{
read_value = read(fd, buff + bytes_read_total, SIZE - bytes_read_total);
if(count%2==0)
strcpy(buff_copy, buff);
if (read_value == -1)
{
char *err;
err = (char *)malloc(sizeof(char)*(50+strlen(file)));
strcpy(err, "tail: error reading '");
strcat(err, file);
strcat(err, "'");
perror(err);
free(err);
return 2;
}
if(read_value==0)
{
strcpy(buff, buff_copy);
read_value = strlen(buff_copy);
break;
}
bytes_read_total+= read_value;
}
ssize_t bytes_written;
ssize_t bytes_written_total = 0;
while (read_value != bytes_written_total)
{
bytes_written = write(STDOUT_FILENO, buff+bytes_written_total, read_value - bytes_written_total);
if (bytes_written == -1)
{
perror("tail: error writing 'standard output'");
return 3;
}
bytes_written_total += bytes_written;
}
}while(read_value);
'''code'''
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);
}
I have the following function:
char *lsl(){
chdir("/Users/some/directory");
FILE *fp;
if ((fp = popen("ls -l", "r")) == NULL) {
perror("popen failed");
return (char *)EXIT_FAILURE;
}
size_t str_size = 1024;
char *stringts = malloc(str_size);
if (!stringts) {
perror("stringts allocation failed");
return (char *)EXIT_FAILURE;
}
stringts[0] = '\0';
char buf[128];
size_t n;
while ((n = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
buf[n] = '\0';
size_t capacity = str_size - strlen(stringts) - 1;
while (n > capacity) {
str_size *= 2;
stringts = realloc(stringts, str_size);
if (!stringts) {
perror("stringts realloation failed");
return (char *)EXIT_FAILURE;
}
capacity = str_size - strlen(stringts) - 1;
}
strcat(stringts, buf);
}
if (pclose(fp) != 0) {
perror("pclose failed");
return (char *)EXIT_FAILURE;
}
return stringts;
}
Related part in main:
char *out=lsl();
if(send(new_socket, out, 200, 0)<0){. //sending the string to the client to print it there
printf("Error in send! %s\n", strerror(errno));
return -1;
}
It returns a string to the main function, problem is I use malloc() to allocate memory for this function, if I use free(stringts) before return then obviously nothing will get returned, so how I my supposed to use free() while still returning it?
Note:
I found this link here: How do I free() after malloc() when the result of malloc() is returned by the function?
It is not in the same programming language hence why I am asking again.
If you want to return it, you must not free() stringts. You must later free() it in the calling function.
char *out=lsl();
int r = send(new_socket, out, 200, 0);
free(out);
if(r <0){. //sending the string to the client to print it there
printf("Error in send! %s\n", strerror(errno));
return -1;
}
Creating a tcp client <-> server program in c for my home exam. Been running into some problems with reciev and sending data between the server and client. I'm only able to receive one byte, feks if i send "abcd" i receive "a".
(This is happening both ways since i'm using same methods for server and client)
Dont know if it is the sending part thats the problem or receiving
This is my code:
#define BUFFER_SIZE 1024
char* recived_message;
int send_data(int socket, char* data){
int offset = 0, len = strlen(data);
while (offset != len) {
int nb = send(socket, data + offset, len - offset, 0);
if (nb < 0){
perror("send");
return -1;
}
offset += nb;
}
return 0;
}
int recive(int socket){
int offset = 0;
recived_message = malloc(BUFFER_SIZE);
memset(recived_message, 0, BUFFER_SIZE);
while (offset != BUFFER_SIZE) {
int nb = recv(socket, received_message + offset, BUFFER_SIZE - offset, 0);
if(nb == -1){
perror("read");
return -1;
}else if(nb == 0){
return -1;
}
offset += nb;
}
printf("%d\n", offset);
return 0;
}
char* get_data(){
return recived_message;
}
Server side
int recive_data(int socket){
char* buffer;
if(recive(socket) != 0){
return -1;
}
*buffer = *get_data();
printf("socket %d: %s\nlength: %lu%", fd, buffer, strlen(buffer));
return 0;
}
Part of client
char* test = "abcd";
for(i=0; i<10; i++) {
send_data(sock, test);
sleep(1);
}
The problem is here
*buffer = *get_data();
You dereferences the pointer returned by get_data() to get only the first element pointer to by the pointer.
And it's worse than that, because you dereference the uninitialized variable buffer to write that single character. This will lead to undefined behavior. Also, the later functions calls using this uninitialized variable also leads to undefined behavior.
The simple solution to (almost) all your problems: Assign to the actual variable:
buffer = get_data();
And I say that the above solves almost all your problems, because what if the terminating zero of the string isn't transmitted? That will also lead to UB (Undefined Behavior). If the data you receive is always a string, then you should make sure it's terminated, preferably in the receive function:
int recive(int socket){
...
received_message[offset] = '\0';
return 0;
}
I wrote function for read and write for a tcp program . I output in server side but I can't get read on client side . my code
read function :
int read_data (int sd , char **data_buf)
{
int in_length,length,size,bytesread;
char *temp_buf;
size = read(sd,&in_length,sizeof(in_length));/*send entire length of data*/
if( 0 > size )
{
printf("Error on reading from socket\n");
exit(1);
}
length = ntohl(in_length);
printf("Total length coming : %d\n",length);
*data_buf =(char *)malloc((length+1)*sizeof(char));
temp_buf =(char *)malloc((length+1)*sizeof(char));
while(length> 0)
{
bytesread = read(sd,temp_buf,4);
strcat(*data_buf,temp_buf);
temp_buf = temp_buf + bytesread;
length = length - bytesread;
}
return 1;
}
and my write functions as :
int write_data (int sd , char *buffer)
{
int length,len_buff,bytesread,size;
len_buff = strlen(buffer);/*total length of string*/
printf("string == %s\n",buffer);
length = htonl(len_buff);/*convert to host to n/w*/
printf("Total length send =%d\n",len_buff);
size = write(sd,&length,sizeof(length));/*write total size to server */
if( 0 > size)
{
printf("error\n");
exit(0);
}
while(length > 0)
{
bytesread = write(sd,buffer,4);/*write 4 bytes to server*/
buffer = buffer + bytesread;
length = length - bytesread;
}
return 1;
}
client program :
///.............code for socket and connections.................//
ret = write_data(sd,user_string);/*write entire datas to server*/
value_from_server = read_data(sd,&data_buf);
server side program :
value_from_client = read_data(connfd,&data_buf);
printf("the value from client : %s\n",data_buf);
index = string_function(data_buf,&store_buf);
printf("after string process : %s\n",store_buf);
write_data(connfd,store_buf);
printf("i am waiting for next string\n");
connfd is the new socket for communication with client . reading and writing function work perfectly on server side . writing function work on client side . but reading from server not work in client program . ant mistake on my code ?
bytesread = read(sd,temp_buf,4);
Why read 4 bytes always inside the loop? You should be reading the remaining number of bytes to be read. The socket is blocking and hence will be stuck if the server is done sending but client still tries reading 4 bytes to arrive in the last iteration.
Have print statements inside the loop to know the bytes read in each iteration and see if client is blocked with read
Your code has several logic errors.
size = read(sd,&in_length,sizeof(in_length));/*send entire length of data*/
if( 0 > size )
{
printf("Error on reading from socket\n");
exit(1);
}
length = ntohl(in_length);
Here you are assuming you read four bytes, rather than fewer, or end of stream. You must check for end of stream (zero return value), and you must loop until you get the four bytes.
while(length> 0)
{
bytesread = read(sd,temp_buf,4);
strcat(*data_buf,temp_buf);
temp_buf = temp_buf + bytesread;
length = length - bytesread;
}
Here again you are ignoring the possibility of end of stream or an error. It should be:
while ((bytesread = read(sd,temp_buf, length)) > 0)
{
temp_buf += bytes_read;
length -= bytesread;
}
if (bytesread < 0)
{
perror("read 2");
}
else if (length > 0)
{
// end of stream before all expected bytes were received ...
}
else
{
// The OK case
}
Your sending code is suboptimal:
while(length > 0)
{
bytesread = write(sd,buffer,4);/*write 4 bytes to server*/
buffer = buffer + bytesread;
length = length - bytesread;
}
There's no point in chunking into 4-byte writes. It should be:
while (length > 0)
{
bytesread = write(sd, buffer, length);
buffer = buffer + bytesread;
length = length - bytesread;
}
and of course the misnamed bytesread variable should be called byteswritten. In fact you can rely on this loop only executing once. Again it should be followed by a test of byteswritten == -1 to check for errors.
Your functions have logic errors in them.
The reading loop is reading exactly 4 bytes on each iteration. If the length of the data being read is not an even multiple of 4, read() will block on the last iteration waiting for data that does not arrive. The reading loop is also assuming that read() returns a null-terminated buffer, but that is not the case, so strcat() will attempt to copy data from surrounding memory and will either copy garbage or crash with a segfault. Also, the reading function is not null-terminating the data buffer it returns to the caller, but the caller assumes it is null-terminated.
The writing loop is writing exactly 4 bytes on each iteration. If the length of the data is not an even multiple of 4, write() will attempt to write data from surrounding memory on the last iteration, and will either send garbage or crash with a segfault.
You are also not doing adequate error handling in either function.
Try something more like this instead:
void read_raw_bytes (int sd, void *data, int length)
{
int bytes_read;
char *data_ptr;
data_ptr = (char*) data;
while( length > 0 )
{
bytes_read = read(sd, data_ptr, length);
if( bytes_read < 0 )
{
printf("Error on reading from socket\n");
exit(1);
}
if( bytes_read == 0 )
{
printf("Disconnected while reading from socket\n");
exit(1);
}
data_ptr += bytes_read;
length -= bytes_read;
}
}
void write_raw_bytes (int sd, void *data, int length)
{
int bytes_sent;
char *data_ptr;
data_ptr = (char*) data;
while( length > 0 )
{
bytes_sent = write(sd, data_ptr, length);
if( bytes_sent < 0 )
{
printf("Error on writing to socket\n");
exit(0);
}
data_ptr += bytes_sent;
length -= bytes_sent;
}
}
int read_data (int sd, char **data_buf)
{
int length;
read_raw_bytes (sd, &length, sizeof(length)); /*send entire length of data*/
length = ntohl(length);
printf("Total length coming : %d\n", length);
*data_buf = (char *) malloc((length+1)*sizeof(char));
if (*data_buf == NULL)
{
printf("Error on allocating memory\n");
exit(1);
}
read_raw_bytes (sd, *data_buf, length);
(*data_buf)[length] = 0;
return 1;
}
int write_data (int sd, char *buffer)
{
int length, len_buff;
len_buff = strlen(buffer); /*total length of string*/
printf("string == %s\n", buffer);
printf("Total length send =%d\n", len_buff);
length = htonl(len_buff); /*convert to host to n/w*/
write_raw_bytes (sd, &length, sizeof(length)); /*write total size to server */
write_raw_bytes (sd, buffer, len_buff);
return 1;
}