why the sendto function needs the third parameter, in socket programming - c

I was new to socket program.
When learning the sendto function, as the prototype:
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
I get to know that the "message" has contain the target IP, and the dest_addr argument also specifies the target IP address.
Is there other usage of the dest_addr argument?

I think you are confusing "message" and "dest_addr".
Let's look at the prototype for sendto in expanded form:
ssize_t sendto (int sockfd,
const void *buf,
size_t length,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen);
sockfd - this is the socket you created with a call to socket()
buf - this is a pointer to an ARRAY OF BYTES (i.e. they could have made buf of type char* ). That is, this is the data that you want to send across the wire encapsulated in a UDP packet.
length - this is how many bytes are in that array. If you didn't pass "length", it wouldn't know if "buf" was 1 byte or 10000 bytes.
flags - Typically 0. This is advanced stuff
dest_addr - this is a pointer to the destination address. Typically you initialize a sockaddr_in instance and cast its pointer value to a sockaddr* type.
addrlen - the size of the dest_addr. typically, sizeof(sockaddr_in). Address length is variable because dest_addr could pointer to an IPV4 address (sockaddr_in type) or an IPV6 address (sockaddr_in6 type), or some other type.
Example of sending a packet from local port 9999 to remote host "1.2.3.4" on its port 8888. Error checking of return codes left out for brevity.
int s;
sockaddr_in addrDest;
sockaddr_in addrLocal;
char* msg = "Hello World";
// create the socket
s = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(9999);
addrLocal.sin_addr = INADDR_ANY; // zero-init sin_addr to tell it to use all available adapters on the local host
// associate this socket with local UDP port 9999
result = bind(s, (struct sockaddr*)&addrLocal, 0);
// send "Hello world" from local port 9999 to the host at 1.2.3.4 on its port 8888
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(8888);
addrDest.sin_addr.s_addr = inet_addr("1.2.3.4");
// strlen(msg)+1 for terminating null char
result = sendto(s, msg, strlen(msg)+1, 0, (struct sockaddr*)&addrDest, sizeof(addrDest));

No, Message Contains what you will send, here is an example:
int spatula_count = 3490;
char *secret_message = "The Cheese is in The Toaster";
int stream_socket, dgram_socket;
struct sockaddr_in dest;
int temp;
// first with TCP stream sockets:
// assume sockets are made and connected
//stream_socket = socket(...
//connect(stream_socket, ...
// convert to network byte order
temp = htonl(spatula_count);
// send data normally:
send(stream_socket, &temp, sizeof temp, 0);
// send secret message out of band:
send(stream_socket, secret_message, strlen(secret_message)+1, MSG_OOB);
// now with UDP datagram sockets:
//getaddrinfo(...
//dest = ... // assume "dest" holds the address of the destination
//dgram_socket = socket(...
// send secret message normally:
sendto(dgram_socket, secret_message, strlen(secret_message)+1, 0,
(struct sockaddr*)&dest, sizeof dest);

The message does not contain the destination address, only the payload bytes.
Unless you are using raw sockets... And you should not do that if you are new to socket programming.

Related

Unnamed unix domain socket has wrong address length

When reading the address of a sending unix datagram domain socket in this minimal example program, I am getting an address length of 0, but the man page for unix domain sockets specifies that:
unnamed: A stream socket that has not been bound to a pathname using
bind(2) has no name. Likewise, the two sockets created by socketā€
pair(2) are unnamed. When the address of an unnamed socket is
returned, its length is sizeof(sa_family_t), and sun_path should not
be inspected.
I was expecting the address length of an unnamed socket to be 2 based on this man page. Am I misinterpreting the man page, does the man page not apply to unix sockets of type SOCK_DGRAM or am I simply reading the length incorrectly?
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
// or for pathnamed socket
// const char SOCK_NAME[] = "/tmp/test.uds";
const char PAYLOAD[] = "Hello!";
int main() {
int rx_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (rx_sock < 0) {
perror("Create RX");
exit(1);
}
int tx_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (tx_sock < 0) {
perror("Create TX");
exit(1);
}
struct sockaddr_un bind_addr;
bind_addr.sun_family = AF_UNIX;
memcpy(bind_addr.sun_path, SOCK_NAME, sizeof(SOCK_NAME));
socklen_t bind_len = sizeof(sa_family_t) + sizeof(SOCK_NAME);
if (bind(rx_sock, (const struct sockaddr *)&bind_addr, bind_len) != 0) {
perror("Bind RX");
exit(1);
}
if (sendto(tx_sock, PAYLOAD, sizeof(PAYLOAD), 0, (const struct sockaddr *)&bind_addr, bind_len) < 0) {
perror("Sendto");
exit(1);
}
// For pathnamed socket
// unlink(SOCK_NAME);
struct sockaddr_un recv_addr;
socklen_t recv_len = sizeof(recv_addr);
char buffer[1024];
ssize_t rx_count = recvfrom(rx_sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&recv_addr, &recv_len);
if (rx_count < 0) {
perror("Recvfrom");
exit(1);
}
printf("Address size of TX on receiver side: %d\n", recv_len); // 0
recv_len = sizeof(recv_addr);
if (getsockname(tx_sock, (struct sockaddr *)&recv_addr, &recv_len) != 0) {
perror("getsockname");
exit(1);
}
printf("Address size of TX on sender side: %d\n", recv_len); // 2
}
You have an unnamed unbound Unix domain datagram socket tx_sock, and an Unix domain datagram socket rx_sock bound to an abstract address in bind_path.
Note: According to man 7 unix, unbound Unix domain stream sockets are unnamed in Linux, and their address lengths will be sizeof (sa_family_t). According to POSIX.1, unbound socket addresses are unspecified, so we really need to be careful about what we expect of unbound socket addresses and their lengths. In this particular case, in Linux, using the man page as a guide, an unbound Unix domain datagram socket has no address, so its length is zero. (It even makes sense: zero address length indicates you cannot reply to the sender. With an unbound stream socket, there is a connection back to the sender, but no other way to reply to the sender but the connection itself; that is why in that case the address length is then nonzero, sizeof (sa_family_t).)
Abstract Unix domain socket addresses are a Linux extension; they begin with a NUL byte (\0), and are not visible in the filesystem.
You use sendto(tx_sock, msg, msg_len, 0, bind_path, bind_path_len) to send a message.
You use recvfrom(rx_sock, buffer, sizeof buffer, 0, &recv_addr, &recv_addrlen) to receive the message (with recv_addrlen properly initialized to sizeof recv_addr).
Because tx_sock is not bound to any address, it is unnamed unbound: it has no address, cannot be replied to, and therefore recv_addrlen == 0.
If you add code to bind tx_sock to some other abstract address, you'll receive that address in recv_addr and recv_addrlen.
(I verified this behaviour with a test program using four threads, where each thread sends a message to each other thread, and prints all received messages and where they are from, with both standard addresses and abstract addresses. Everything works as documented.)
Of course you're getting a name length of zero.
The first value in your char array is 0, immediately terminating the string to a length of zero bytes:
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
unnamed: A stream socket that has not been bound to a pathname using bind(2) has no name.
does not apply, because you are using bind() to bind the socket:

Bind failed: : Address family not supported by protocol family - C

I've declared a struct sockaddr_in server in my main function.
I pass it into this function to return a socket file descriptor
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
int sockfd, len;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0){
perror("Failed to open socket: ");
exit(-1);
}
len = sizeof(server);
bzero(server, len);
server->sin_family= AF_INET;
inet_pton(AF_INET, ip_addr, &server->sin_addr);
server->sin_port= htons(port);
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){
perror("Bind failed: ");
exit(-1);
}
return sockfd;
}
The struct is passed into the function using this call
sockfd = openSocket(vector->ip_addr, vector->port, &server);
However I get the following error.
Bind failed: : Address family not supported by protocol family
len = sizeof(server);
This determines the size of the pointer. You want the size of the structure it points to, so this should be:
len = sizeof(*server);
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
[...]
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){
server is already declared as a pointer, so I think the & operator
isn't needed in the bind() call.
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
This is interesting - you use sockaddr_in which has the following properties you need to set:
sun_family -- This must equal AF_INET.
sin_addr -- This is another structure with an unsigned long named s_addr which you'll probably want to set to INADDR_ANY +.
sin_port -- This requires a server port which needs converting with htons(). (Make sure this port is not in use ++! My go-to port is 3333 for testing...)
It seems you're using inet_pton() but I'm not sure it has the same affect for setting sin_port. Other that it looks fine.
The other area is there might be an issue is this line:
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
The 0 on the end specifies [1]:
"Specifying a protocol of 0 causes socket() to use an unspecified default protocol appropriate for the requested socket type."
I could imagine a possibility where the unspecified default is either not correct for your Operating System or that there is no default. I would try SOCK_STREAM to test whether this works.
+ NOTE: This would technically need htonl() but my understanding an this does nothing for this particular case.
++ NOTE: If you are writing client and server applications remember to be careful about which owns the port.
[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/socket.html

Sendto returns -1 and errno 22 (Invalid argument), when set the multicast outgoing interface by ip_mreqn

I faced an issue, when I try to send to multicast group by setting the intended outgoing interface by the code bellow, Actually when the condition is TRUE (if(config.enable_if == 1)) the sendto system call returns error Invalid Argument, but if the condition was False sendto send data and doesn't generate any error.
Please Anyone has an idea, or should I modify anything in my code?
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local */
/* multicast capable interface. */
if(config.enable_if == 1){
mreqn.imr_ifindex = if_nametoindex("eth3");
rc = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
}
/* Initialize the group sockaddr structure with a */
/* group address of dynamic address and port dynamic port. */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr(config.mip);
groupSock.sin_port = htons(config.port);
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
rc = sendto(sd, (const char *)& databuf, datalen, 0, (const struct sockaddr*)&groupSock, sizeof (struct sockaddr));
printf("errno %d\n",errno);
One reason sendto fails is because you pass it a data pointer it does not expect. If you have char* databuf and you then do &databuf you get the address of the pointer, i.e. a pointer to a pointer, of type char**. If you remove the cast (which is not needed) then you will get at least a warning or maybe even an error when compiling.

when the first datagram is received, recvfrom() doesn't fill the structur `sockaddr`

I have two machines A and B in LAN
I have a UDP client on A
and a UDP server on B, like
for(;;){
n = recvfrom(sockfd, mesg, 10000, 0, (struct sockaddr *)&cliaddr, &len);
....}
I notice when the UDP client sends the first datagram
I can get the datagram data payload through mesg correctly
but the structure cliaddr is not filled, it is with the original value
e.g, if I use bzero(&cliaddr, sizeof(cliaddr));,
in gdb, I got
$1 = {sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0}, sin_zero =
"\000\000\000\000\000\000\000"}
what is the reason when the first datagram is received, recvfrom() doesn't fill the structure cliaddr?
for the sebsequent datagram, the valid info can be obtained.
Before calling recvfrom you must properly initialize the len argument.
E.g.
len = sizeof(struct sockaddr_in);
n = recvfrom(..., &len);
The recvfrom function uses the length to help determine what kind of structure the sockaddr pointer actually points to.

getpeername() Returns Wrong Data

I am writing my first sockets program on Linux and am trying to print the IP address and port of the peer I have connected to. I use getpeername() along with inet_ntop() and ntohs() to get the data out of the sockaddr_in struct. When I look at the results, I get an IP address that does not go to any server that I know of (ping fails) and says that I am listening to a port that netstat says is not being used.
What am I doing wrong? I should be getting 130.215.28.181:39000, but instead I am getting 209.94.72.137:18825 every time I run the program. Looking at netstat shows that I am indeed listening on port 39000.
Here is a snippet from my client program:
connect(sockfd,&serv_addr,sizeof(serv_addr))
// print welcome message
char ipstr[INET6_ADDRSTRLEN];
bzero(ipstr, 50);
struct sockaddr_in *address;
socklen_t address_len = sizeof(*address);
getpeername(sockfd, (struct sockaddr *) address, &address_len);
inet_ntop(AF_INET, &address->sin_addr, ipstr, sizeof(ipstr));
printf("Connection established successfully with %s:%i!\n", ipstr, ntohs(address->sin_port));
You're not allocating any memory for your sockaddr_in structure, you's just passing a pointer to some random memory location. Instead, allocate the address structure on the stack:
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int err = getpeername(sockfd, (struct sockaddr *) &addr, &addr_len);
if (err != 0) {
// error
}
You should also be checking the return value of every function that is documented to return an error code. In particular, both connect and getpeername return error codes that you should be checking.

Resources