I'm writing a client application in C++ to receive binary data via UDP broadcast, however I'm unable to receive anything beyond the first 4 bytes, regardless of the buffer size. I've checked the packets in Wireshark, and I can see that my machine is receiving roughly 1200 bytes of data. When I compare this to what my client is receiving, I can see that I'm getting the packets, however the remaining data is lost. Here's my code:
#define BUFFERSIZE 4096
int main()
{
struct addrinfo hints, *servinfo, *p;
int sockfd, i, nbyt;
int *buf = (int*) malloc(BUFFERSIZE);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, "9011", &hints, &servinfo);
sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen);
FILE *file;
file = fopen("file.txt", "w+");
for (i=0;i<=45;i++)
{
nbyt = recv(sockfd, buf, BUFFERSIZE, 0);
fprintf(file, "%s %d; %s %x\n", "Bytes received:", nbyt, "Message:", *buf);
}
fclose(file);
close(sockfd);
free(buf);
printf("%s\n", "Execution ended.");
return 0;
}
An example of some of the data I'm receiving:
Bytes received: 1131; Message: 5b0
Bytes received: 1131; Message: 5b3
Bytes received: 1131; Message: 5b6
Bytes received: 1092; Message: 4e0
I've tried setting the socket to non-blocking with the MSG_DONTWAIT flag, as this fixed the problem for a similar Python application, however this only returns errors:
Bytes received: -1; Message: 0
I'm relatively new to C++ and sockets, so it's possible there's something I'm just not seeing. Hopefully somebody can help me figure out what's wrong? I can provide additional information if necessary.
You're receiving it just fine. Your debug code just doesn't do what you think it does.
The x specifier to printf prints the unsigned int argument in hex. Integers on your platform are probably 32-bits. So you're only printing the first 4 bytes.
If you want to print the entire buffer in hex, you need to write the loop to do that yourself (or use a library, of course).
For example, and I warn you my C is a little rusty (and this is by far not the best performing way to do this) ... Also, this assumes your buffer is always a multiple of sizeof(int), or it'll lose some data:
nbyt = recv(sockfd, buf, BUFFERSIZE, 0);
fprintf(file, "%s %d; %s\n", "Bytes received:", nbyt, "Message:");
for (offset = 0; offset < nbyt/sizeof(int); ++offset) {
fprintf(file, "%x ", buf[offset]);
}
fprintf(file, "\n");
*buf in your code means the first integer from the array of the received data, so you are printing just four first bytes of the received UDP payload.
Despite the already mentioned format error, if you receive a '\0' char, a formatted print with %s will cut the string there, regardless of the actual number of chars received.
For debugging plaintext, I used below code:
char escaped_char(char c)
{
char escapable[12] = {'\a','\b','\f','\n','\r','\t','\v','\\','\'','\"','\?','\0'};
char escaped[12] = { 'a', 'b', 'f', 'n', 'r', 't', 'v','\\','\'','\"', '?', '0'};
const char* escapable_end = escapable + 12;
const char* ec;
for(ec = escapable;ec != escapable_end;++ec)
{
if(c == *ec) return escaped[ec-escapable];
}
return 0;
}
/**
* #param buf input buffer to escape
* #param len length of contents in buf
* #param outlen pointer to an integer, which receives the length of the returned string
* #return A newly allocated, C style escaped string, NULL on error
* #warning A returned string must be freed with free()
*/
char* aescape(const char* buf,size_t len,size_t* outlen)
{
const char* buf_end = buf + len;
const char* c;
char ec;
char* result;
assert(buf && outlen);
(*outlen) = len;
for(c = buf;c != buf_end;++c)
{
if(escaped_char(*c))
{
++*outlen;
}
}
result = malloc((*outlen)+1);
assert(result != NULL);
if(result)
{
if((*outlen) > len)
{
char* out = result;
for(c = buf;c != buf_end;++c)
{
ec = escaped_char(*c);
if(ec)
{
*out++ = '\\';
*out++ = ec;
}
else
{
*out++ = *c;
}
}
}
else
{
memcpy(result,buf,len);
}
result[(*outlen)] = '\0';
}
else
{
(*outlen) = 0;
}
return result;
}
Related
I'm doing an exercise about UDP sockets in C. When the client sends a specific message (e.g hi) the server has to send "Nice to meet you". If no standard reply is found the server sends "No suitable reply". My problem is that memset fails if I try to return the reply like this:
return "No suitable reply";
and it doesn't if I return the reply in this way:
char* foo = malloc(sizeof(char*));
memset(foo, 0, strlen(ses));
memcpy(foo, "No suitable reply", 17);
return foo;
I tried to google a solution to this and I found this and this, but they don't seem to address my problem (I first thought that memset doesn't work on a string declared like char string[] = "something" but in the second example they use memset on a static string).
Here is the whole code (the memset I'm talking about is right at the end):
/*
Alessandro Dussin 5AI
2018-17-11
Write a program to handle a single UDP "connection"
*/
//Standard libraries
#include <stdio.h>
#include <stdlib.h>
//Sockets libraries and connection ahndling
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
//Read/write ops on file descriptors
#include <unistd.h>
//String ops
#include <string.h>
#include <assert.h>
void chopN(char *str, size_t n)
{
assert(n != 0 && str != 0);
size_t len = strlen(str);
if (n > len)
return; // Or: n = len;
memmove(str, str+n, len - n + 1);
}
//Required by the exercise. Given a certain word or phrase, reply with a specific string
char* switchreply(char* str){
//Extracts the word or phrase (Basically removes the "/command " word)
chopN(str, strlen("/stdreply "));
int i = 0;
for(; i < strlen(str); i++){
if(str[i] == '\n'){
str[i] = '\0';
break;
}
}
if(strcmp(str, "ciao") == 0){
return "ciao anche a te!";
}
else if(strcmp(str, "I hate you") == 0){
return "I hate you too!";
}
return "";
}
char* stdreply(char *str){
char* tmp = malloc(sizeof(char)*128);
int i = 0;
//printf("Entered stdreply... str at the start of the func: %s\n", str);
for(; i < strlen(str); i++){
tmp[i] = str[i];
//printf("tmp: %s\n", tmp); //DEBUG
if(strcmp(tmp, "/echo ") == 0){ // if(strcmp() == 0) is necessary because
//otherwise 0 would be interpreted as FALSE
//printf("Echo detected\n"); //DEBUG
chopN(str, strlen("/echo "));
str[strlen(str)] = '\0';
return str;
}
else if(strcmp(tmp, "/stdreply ") == 0){
//printf("I got into the else if\n"); //DEBUG
char* tmpreply = calloc(strlen(str), sizeof(char*));
tmpreply = switchreply(str);
//printf("tmpreply: %s\n", tmpreply);
str = malloc(sizeof(char*)*strlen(tmpreply));
memcpy(str, tmpreply, strlen(tmpreply));
//str[strlen(str)] = '\0'; //DEBUG
//printf("str: %s\n", str); //DEBUG
return str;
}
else if(strcmp(tmp, "/TODO") == 0){
char* ses = malloc(sizeof(char*));
memset(ses, 0, strlen(ses));
memcpy(ses, "work in progress", 17);
return ses;
}
}
return "No suitable reply";
}
int main(int argc, char **argv){
if(argc < 2){
printf("Usage: ./server port");
exit(0);
}
int serverfd;
serverfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in server;
server.sin_port = htons(atoi(argv[1]));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
if(bind(serverfd, (struct sockaddr *)&server, sizeof(server)) < 0){
perror("Bind() error: ");
fflush(stderr);
}
//"UDP message receiver" variables declarations
int bytes; //Reads how many bytes the funcion recvfrom has read
struct sockaddr_in from;
char* buffer = malloc(sizeof(char*)); //String to which save the client message
memset(buffer, 0, strlen(buffer)); //and set it to zero
socklen_t fromlen = sizeof(struct sockaddr_in);
const char stdrep[] = "Message Received: "; //This string will always be
//printed upon receiving a message
char* reply = malloc(sizeof(char*)); //This is where the return value of
//stdreply() will be stored
memset(reply, 0, strlen(reply)); //and set it zero
//This while will keep "listening" for udp messages
while((bytes = recvfrom(serverfd, buffer, 1024, 0, (struct sockaddr *)&from, &fromlen)) > 0){
//From teacher's example. Write to stdout
write(1, stdrep, strlen(stdrep));
write(1, buffer, bytes);
//Detect a basically empty string (if the client has pressed only enter)
if(buffer[0] == '\n'){
bytes = sendto(serverfd, "You pressed only enter!\n", 18, 0, (struct sockaddr *)&from, fromlen);
}
//Act according to the client message
reply = stdreply(buffer);
bytes = sendto(serverfd, reply, strlen(reply), 0, (struct sockaddr *)&from, fromlen);
if (bytes < 0){
perror("sendto: ");
fflush(stderr);
}
memset(buffer, 0, 1024);
memset(reply, 0, strlen(reply)); //The seg fault happens right here
fflush(stdout);
}
return 0;
}
There are plenty of problems in the code you are posting.
As #JonBolinger already noted, sizeof(char*) returns the size in bytes of a pointer to a char. On Intel platforms this will be either 4 or 8, depending on whether you are running on 32-bit or 64-bit. (So you end up allocating buffers of 4 or 8 bytes)
You consistently try to clear your dynamically-allocated buffers with memset(). malloc() will return memory filled with garbage, and you indicate how many bytes to clear by using strlen() on the returned buffer. strlen() will scan the buffer until it finds the first 0 character to compute the string's length. Since the buffer is filled with garbage, this can easily give you a value outside of the boundaries of your memory block and you will end up corrupting memory.
Every call to malloc() should be matched to a free() call, otherwise you will leak memory. This is especially important if your program is long-running.
When you are working with temporary local strings (strings that are not returned to the caller), it is very common practice to use a local char array instead of malloc(). This way, the buffer gets allocated on the stack and will be released automatically when your function exits scope. Just be sure to use 'safe' string functions like strncpy() that will accept as a parameter the length of the buffer, to avoid overwrites.
void Example(char* anotherString ) {
char tmpString[256]; // this will create a local buffer with capacity of 256 bytes
strncpy(tmpString, anotherString, sizeof(tmpString)); // copy string, without risk of overflowing the buffer
}
Warning: NEVER attempt to return a local temporary buffer as a result, remember that it will no longer exist when the function exits and although the returned value may initially have meaningful results, they will certainly be destroyed as soon as you call another function. Instead of this, another common practice when you need a string return value, instead of returning a string allocated with malloc() -that would need to be released with free() - you pass a local buffer that will hold the result as a parameter, like this:
void func1() {
char result[256];
func2(result, 256);
// after calling, result will carry "a returned string"
}
void func2(char* result, size_t bufferLen) {
strncpy(result, "a returned string", bufferLen);
}
I think your code would benefit greatly if you can transform it to using this style where applicable.
reply = stdreply(buffer);
This does not copy a string. It overwrites the pointer with a different one, losing the original pointer.
memset(reply, 0, strlen(reply));
This would clear the string if it were allocated with malloc. If it is a constant string like "No suitable reply" then it may be read-only, so it generates a segfault.
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;
}
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.
I am trying to send across a character array using a transmitter and a receiver program using raw sockets. I am able to get the correct number of bytes sent at the receiver side, but the values printed out are garbage. Could someone help me out here?
Transmitter:
int create_raw_socket(char *dev)
{
struct sockaddr_ll sll;
struct ifreq ifr;
int fd, ifi, rb;
bzero(&sll, sizeof(sll));
bzero(&ifr, sizeof(ifr));
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
assert(fd != -1);
strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
assert(ifi != -1);
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
rb = bind(fd, (struct sockaddr *)&sll,sizeof(sll));
assert(rb != -1);
return fd;
}
int SendPacket(char *dev ,unsigned char *send_packet, int packet_len)
{
int num_sent= 0;
int sockaddress = create_raw_socket(dev);
if((num_sent = write(sockaddress, &send_packet, packet_len)) != packet_len)
{
close(sockaddress);
return 0;
}
else
{
close(sockaddress);
return 1;
}
}
int main(int argc, char**argv)
{
int x,fd,s;
char *send_packet="HELLO";
int len = sizeof(send_packet);
while(1)
{
if(!SendPacket((argv[1]), send_packet, len))
perror("Error sending packet");
else
printf("Packet sent successfully with payload : %s\n" ,send_packet);
}
return 0;
}
Receiver :
int main(int argc, char **argv)
{
struct sockaddr addr;
int sock_fd, fromlen,s;
char buf[PACKET_LENGTH];
char *dev = argv[1];
while(1)
{
fromlen=sizeof(addr);
sock_fd = create_raw_socket(dev); /* Creating the raw socket */
int x= recvfrom(sock_fd,&buf,sizeof(buf),0,&addr,&fromlen);
printf("\n Number of bytes of data received is %d \n",x);
printf("\nPayload Received from client... is %s \n", buf);
close(sock_fd);
}
return 0;
}
Change
write(sockaddress, &send_packet, packet_len)
to
write(sockaddress, send_packet, packet_len)
send_packet is already the address of the buffer to be sent, if you take the address of this address (more precisely the address of the variable holding the address), you will read the wrong memory for the buffer
Similarly for recvfrom:
recvfrom(sock_fd, buf, sizeof(buf), 0, &addr, &fromlen)
You have several problems:
This line
if((num_sent = write(sockaddress, &send_packet, packet_len)) != packet_len)
Should say just send_packet instead of &send_packet. send_packet is a pointer that points to the desired packet data, so there's no need to take its address -- you don't want to write out the literal address of that pointer into the packet, that just simply won't work.
This is wrong:
char *send_packet="HELLO";
int len = sizeof(send_packet);
sizeof(send_packet) will always be the size of a pointer on your system, typically either 4 or 8 bytes. You really want to either declare send_packet as an array type (e.g. char send_packet[] = ...), or use strlen to compute its length at runtime (e.g. int len = strlen(send_packet) + 1;). In your case, you're either sending too little data (4 bytes) or too much data (8 bytes), both of which are problematic.
Your printf code in the client assumes that the data it receives is null-terminated, which it is not necessarily. You should either manually null-terminate the data before printing it (or using any other string functions, for that matter), or tell printf the limit of how much data to print. I'd suggest null-terminating it like so:
char buf[PACKET_LENGTH + 1]; // +1 for null terminator
int x = recvfrom(sock_fd,buf,PACKET_LENGTH,0,&addr,&fromlen);
if(x >= 0)
buf[x] = 0;
Your code has poor const correctness. SendPacket should take a const char* instead of char* parameter, and send_packet should either be declared as char[] or as const char*. The conversion from string literals to char* is deprecated and should be avoided in all new C code.
Using printf to print the buffer will print a string until the en of string character is reached. If you see the original string followed by garbage characters, this may be the reason.
You should probably introduce a 0 after the last byte returned by recvfrom, or you will print whatever value was in the memory that recvfrom did not overwrite. It could even try to access memory outside the buffer.
Try adding something like:
int x= recvfrom(sock_fd,&buf,sizeof(buf) - 1,0,&addr,&fromlen);
buf[x - 1] = 0;
Note: that changes the maximum size of what is read, it is just an example of how to do it.