C sockaddr function call for sendto? - c

I'm currently setting up a UDP socket for a school assignment but I can't figure out how to properly send sockaddr as a parameter into a function. The input arguments for SendData is defined the same way they are in the sendto function.
void SendData(int fileDescriptor, const struct sockaddr_in *destAddrUdp, unsigned char buffer[MAXMSG])
{
/* crc */
int strlength = strlen(buffer);
unsigned char SCRC = CRC(buffer, strlength-1);
buffer[strlength-1] = SCRC;
buffer[strlength] = '\0';
/* send */
if (sendto(fileDescriptor, buffer, strlen(buffer), 0, (struct sockaddr*) &destAddrUdp,sizeof(destAddrUdp)) < 0) {
fprintf(stderr, "Could not send data\n");
}
} `
When the below code is called from main it works however when it's called from SendData the return value from sendto is -1.
if (sendto(fileDescriptor, buffer, strlen(buffer), 0, (struct sockaddr*) &destAddrUdp,sizeof(destAddrUdp)) < 0) {
fprintf(stderr, "Could not send data\n");
}
If the program is compiled I get warning: passing argument 5 of ‘recvfrom’ from incompatible pointer type. on the sendto functioncall in SendData.
The function call for SendData in my main program is: SendData(sockfd, (struct sockaddr *) &destAddrUdp, buffer);
The main program in case it is relevant:
unsigned char SCRC;
unsigned char strlength;
unsigned char buffer[MAXMSG-5];
unsigned char header[MAXMSG];
struct rtp_struct *sendstruct;
/* option 2 */
struct sockaddr_in destAddrUdp;
int sockfd;
char dstHost[15];
printf("input host IP:\n>");
fgets(dstHost, 15, stdin);
/* Create socket */
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
fprintf(stderr, "Can't create UDP socket\n");
/* set configurations */
memset (&destAddrUdp, 0, sizeof(destAddrUdp)); //set zero
destAddrUdp.sin_family = AF_INET; //internet use
destAddrUdp.sin_addr.s_addr = inet_addr(dstHost); //set so anyone can connect
destAddrUdp.sin_port = htons(dstUdpPort); //set the port to use
/* Generate CRC table */
GenerateCRCTable();
/* get string and send */
while(1) {
printf("\n>");
fgets(buffer, MAXMSG, stdin);
if(strncmp(buffer,"quit\n",MAXMSG) != 0){ //if read string == quit, see else
strlength = strlen(buffer);
SCRC = CRC(buffer, strlength-1);
buffer[strlength-1] = SCRC;
buffer[strlength] = '\0';
SendData(sockfd, (struct sockaddr *) &destAddrUdp, buffer);
/*if (sendto(sockfd, buffer, strlength, 0, (struct sockaddr *) &destAddrUdp,sizeof(destAddrUdp)) < 0){
fprintf(stderr, "Could not send data\n");}*/
}
else {
close(sockfd);
exit(EXIT_SUCCESS);
}
}
}

In your SendData function, the parameter destAddrUdp has type const struct sockaddr_in *. When you then make this call:
sendto(fileDescriptor, buffer, strlen(buffer), 0,
(struct sockaddr*) &destAddrUdp, sizeof(destAddrUdp)
The expression &destAddrUdp has type const struct sockaddr_in **, so the pointer type is incompatible. Also, sizeof(destAddrUdp) is returning the size of a pointer, not the size of the struct.
You failed to account for the differing types of destAddrUdp in SendData and main. The correct call to sendto would be:
sendto(fileDescriptor, buffer, strlen(buffer), 0,
(struct sockaddr*) destAddrUdp, sizeof(*destAddrUdp)

The problem is the sizeof(destAddrUdp) and the (struct sockaddr*) &destAddrUdp.
In your main, destAddrUdp is an struct sockaddr_in, in your function however, its a sockaddr_in* so you can't use them equally. First, sizeof(destAddrUdp) in your function will give you the size of a pointer, second, &destAddrUdp in your function will give you a destAddrUdp**. Thats not what you want.
Try sendto(fileDescriptor, buffer, strlen(buffer), 0, (struct sockaddr*) destAddrUdp,sizeof(*destAddrUdp))

Related

Recvfrom() keeps returning wrong value

I call udpclient in main where i pass "this is a test" as the parameter message.
#define MAX_BUFFER 128
void udpclient(char *message, char *target_ip, int target_port){
///* address of server we trying to reach */
struct sockaddr_in targetaddress;
/* buffer to receive echo */
char buffer[MAX_BUFFER];
/* create socket */
int socketfd;
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if(socketfd == -1)
socketerror();
/* target server informations */
memset(&targetaddress, 0, sizeof(targetaddress));
targetaddress.sin_family = AF_INET;
targetaddress.sin_port = htons(target_port);
targetaddress.sin_addr.s_addr = inet_addr(target_ip);
After i send message to server, the server must reply "echo: this is a test", but recvfrom() for some reason is returning n = 8, so when i do write(1, buffer, n) it truncates buffer.
/* send message to targetaddress */
ssize_t n;
n = sendto(socketfd, message, sizeof(message), 0, (const struct sockaddr *) &targetaddress, sizeof(targetaddress));
if(n == -1)
udpsenderror();
printf("%i\n", n);
socklen_t addrlen;
addrlen = sizeof(targetaddress);
/* receive echo from targetaddress */
n = recvfrom(socketfd, buffer, MAX_BUFFER, 0, (struct sockaddr *) &targetaddress, &addrlen);
if(n == -1)
udpechoerror();
printf("%i\n", n);
write(1, "echo: ", 6);
write(1, buffer, n);
return;
}
Recvfrom() should be returning the lenght of message if i'm not mistaken, I don't know where i'm doing wrong! Help!?
n = sendto(socketfd, message, sizeof(message), 0, (const struct sockaddr *) &targetaddress, sizeof(targetaddress));
Since message is a char *, sizeof(message) gives the number of bytes a char * takes on your platform. Apparently, that's 8 bytes, so you sent an 8-byte message.

Bad address received from recvfrom: why?

I'm writing a function that is supposed to do some operations and then return (using its arguments) the address of the device that is interacting with (i.e. that used sendto) the recvfrom inside the function.
Here's how I call the function, instantiating cliaddr before.
struct sockaddr_in cliaddr;
memset((void *) &cliaddr, 0, sizeof(cliaddr));
rcv_string(sockfd, &return_string, &cliaddr);
// Here I'll need to use cliaddr, that's why I need it outside too
Here's the implementation of the function:
int rcv_string(int sockfd, char **return_string, struct sockaddr_in *sndaddr) {
// ...
char buff[PACKETSZ + 2];
memset(&buff, 0, sizeof(buff)); // Clean buffer
socklen_t *plen = malloc(sizeof(struct sockaddr *));
if ((recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *) sndaddr, plen)) < 0) {
perror("recvfrom");
return -1;
}
char *snd_ip = malloc(INET_ADDRSTRLEN * sizeof(char));
if (inet_ntop(AF_INET, &((*sndaddr).sin_addr.s_addr), snd_ip, INET_ADDRSTRLEN * sizeof(char)) == NULL) {
perror("inet_ntop");
return -1;
}
printf("Received '%s' from '%s'.\n", buff, snd_ip);
// ...
}
Now, even if the ip address of the sending device is 192.168.1.251 I get the following output:
Received '0packetx' from '0.0.0.0'.
The received buffer is formatted correctly, but the address is evidently wrong. Why? Does it have to do with the definition of the address variable outside the function?
EDIT
If after the memset of cliaddr I add also those 3 lines:
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliaddr.sin_port = htons(SERV_PORT);
I get a random behavior. Sometimes I get 0.0.0.0, sometimes 127.0.0.1 and sometimes the correct address (192.168.1.251).
you are passing the wrong length to recvfrom
socklen_t *plen = malloc(sizeof(struct sockaddr *));
if ((recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *) sndaddr, plen))
Why you malloc is a mystery, but you need
socklen_t *plen = malloc(sizeof(socklen_t));
*plen = sizeof(struct sockaddr_in );
much simpler is
socklen_t plen = sizeof(struct sockaddr_in);
if ((recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *) sndaddr, &plen))
It should work if you fill plen with valid sizeof data.
*plen = sizeof(struct sockaddr_in);
You can put that right before the recvfrom call.

invalid application of ‘sizeof’ and compilation error with struct data

I created a data type which I want to send over a socket.
I'm getting a compilation error and a segmentation fault error.
The compilation error I get is error: invalid application of ‘sizeof’ to incomplete type ‘struct udp_msg_t’ whereas the segmentation fault happens when I do the memcpy. What am I doing wrong?
Here is some of my code:
This is the struct I'm concerned about which I defined:
typedef struct udp_msg {
unsigned int udp_eid;
u_char udp_prefix;
unsigned int udp_loc;
} udp_msg_t;
In a method I assign the memory and the values:
void method(){
udp_msg_t * udp_msg;
udp_msg = (struct udp_msg_t * )calloc(1, sizeof(struct udp_msg_t));
udp_msg->udp_eid = eid.u.prefix4.s_addr;
udp_msg->udp_prefix = eid.prefixlen;
udp_msg->udp_loc = loc->rloc.rloc.s_addr;
send_rloc_udp_to_floodlight(udp_msg);
}
And this method actually sends the data over a socket:
int send_rloc_udp_to_floodlight(udp_msg_t message) {
struct sockaddr_in si_other;
int s, i, slen = sizeof(si_other);
char buffer[9];
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
printf("socket");
}
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(8888);
if (inet_aton("127.0.0.1", &si_other.sin_addr) == 0) {
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
memcpy(buffer, (char *) message.udp_eid, sizeof(unsigned int));
memcpy(&buffer[4], (char *) message.udp_prefix, sizeof(char));
memcpy(&buffer[5], (char *) message.udp_loc, sizeof(unsigned int));
//send the message
if (sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *) &si_other,
slen) == -1) {
printf("sendto()");
}
close(s);
return 0;
}
sizeof(struct udp_msg_t)
is incorrect - it should be either
sizeof(udp_msg_t)
or
sizeof(struct udp_msg)
Ditto for the cast:
(struct udp_msg_t * )
in front of the call to calloc, although this should just be removed, since it's redundant and potentially dangerous.
I was not getting the pointer value of the struct field properly. The correct was to do the memcpy is:
memcpy(buffer, (char *) &message.udp_eid, sizeof(unsigned int));

UDP Sockets in C - Sendto() Send failed : invalid arguments

I am trying to implement UDP sockets in C in a very simple/basic fashion. My programs are meant to send/receive files between terminals with one program running on each. I am having a problem with the sendto() function in my client code. Here is my code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include <errno.h>
#define BUFFER_SIZE 512
int main(int argc, char *argv[])
{
struct sockaddr_in client;
int sockfd, bytes, errno, slen = sizeof(client);
char buffer[BUFFER_SIZE];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
perror("Socket creation failed.");
return 0;
}
client.sin_addr.s_addr = INADDR_ANY;
client.sin_family = AF_INET;
client.sin_port = htons( 0 );
if( bind(sockfd, (struct sockaddr *)&client, sizeof(client)) == -1)
{
perror("Bind call failed.");
return 0;
}
while(1)
{
printf("Enter message : ");
fgets(buffer, BUFFER_SIZE, stdin);
printf("Message: %s\n", buffer);
bytes = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&client, sizeof(client));
printf("Bytes: %d\n", bytes);
if(bytes == -1)
{
printf("Error number: %d", errno);
perror("Send failed.");
return 0;
}
memset(buffer,'\0', BUFFER_SIZE);
if( recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &slen) == -1)
{
perror("Recieve failed.");
return 0;
}
puts(buffer);
}
close(sockfd);
return 0;
}
No matter what I enter into the buffer, I always get error number 22 from sendto() for invalid arguments. I have tried every solution or tweak I have come across but nothing seems to work.
Just add this piece of code after bind()
getsockname(sockfd, (struct sockaddr *)&client, &slen);
man page
DESCRIPTION
The getsockname() function returns the current address for the specified
socket.
The address_len parameter should be initialized to indicate the amount of
space pointed to by address. On return it contains the actual size of
the address returned (in bytes).
The address is truncated if the buffer provided is too small.
RETURN VALUES
The getsockname() function returns the value 0 if successful; otherwise
the value -1 is returned and the global variable errno is set to indicate
the error.

First DGRAM Has No IP

I have an odd problem with a UDP server I'm working on. The very first udp packet received has no information on the source of the packet. Subsequent udp packets all appear to be fine and correctly display the ip address from which the packet was received. I have no clue what is causing this behavior, probably some stupid mistake, or some obscure bug. I'm using on a Linux machine running Debian.
fd_set master;
fd_set read_fds;
int fdmax;
int i;
int bytes_sent;
int bytes_recv;
socklen_t addr_len;
struct sockaddr_storage their_addr;
// provides users information needed to connect
serv_info *server_info;
server_info = (serv_info*) serv_config;
// Create UDP listener socket
int info_sock = createDGRAMSocket(NULL, server_info->port, 1);
char buffer[1024];
int len;
int send_response;
FD_SET(info_sock, &master);
fdmax = info_sock;
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("Info started \n");
while (running) {
read_fds = master;
select(fdmax+1, &read_fds, NULL, NULL, NULL);
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("length %u: %s\n", bytes_recv, buffer);
send_response = 0;
switch (buffer[0]) {
// Handle different packet types
}
struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
if (send_response) {
bytes_sent = sendto(info_sock, buffer, len, 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr_storage));
if (bytes_sent < 0) {
printf("[ERROR] Packet Send Failed %d (%s) %d\n", bytes_sent, buffer, len);
}
}
}
}
};
close(info_sock);
You need to initialize addr_len to sizeof(their_addr). According to the man page:
The argument addrlen is a value-result argument, which the caller should initialize
before the call to the size of the buffer associated with src_addr, and
modified on return to indicate the actual size of the source address. The returned
address is truncated if the buffer provided is too small; in this case, addrlen will
return a value greater than was supplied to the call.
Since you aren't initializing addr_len it seems to be taking on a value of 0 (this is highly undefined behavior). In this case, recvfrom() will not fill in the their_addr buffer, but as the man page indicates addr_len will return a value greater than was supplied to the call. So after the first call addr_len is taking on a value that is allowing the next calls to recvfrom() to properly fill in the their_addr buffer. Relying on this is unsafe though.

Resources