Sending broadcast server -> client and sending back client -> server UDP C Socket - c

I want to ask if there is a possibility and if there is how do I send broadcast from my UDP server to client and after that send back response from client to server.
I need to implement an application where server sends broadcast on a subnetwork and clients are supposed to receive that message somehow and in that way would get server address so that they could send some messages back to server.
I created a socket with specified server port say 2000 and set setsockopt to SO_BROADCAST and sent some message with sendto but my client hangs on recvfrom forever. Seems like it does not receive anything from server's broadcasting. How to fix this?
SERVER:
struct sockaddr_in addr;
int socketfd,t=1;
socketfd = socket(PF_INET,SOCK_DGRAM,0);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons("2000");
addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
if (setsockopt(socketfd, SOL_SOCKET, SO_BROADCAST ,&t, sizeof(t)))
ERR("setsockopt");
if(bind(socketfd,(struct sockaddr*) &addr,sizeof(addr)) < 0)
ERR("bind");
char *buf = "HelloFromServer!";
if(sendto(socketfd, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr)) <= 0)
{
perror("something went wrong..");
return EXIT_FAILURE;
}
CLIENT:
struct sockaddr_in addr;
int socketfd,t=1;
socketfd = socket(PF_INET,SOCK_DGRAM,0);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons("2000");
addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
if (setsockopt(socketfd, SOL_SOCKET, SO_BROADCAST ,&t, sizeof(t)))
ERR("setsockopt");
char data[12];
struct sockaddr_in serv_addr;
socklen_t size=sizeof(serv_addr);
recvfrom(fd, (char *)data, sizeof(char[12]), 0, &serv_addr, &size);
And my client hangs on this recvfrom... and therefore I cannot get serv_addr to be stored so that I could send some message back to the server

Clients are supposed to receive that message somehow and in that way would get server address so that they could send some messages back to server.
I believe there is a problem here: for the clients to receive the message broadcasted by the server, they must first have the server's address. The only time that a socket can receive data/communications from an unknown address is a server using listen() on a port which has port forwarding set up (courtesy of the router). Thus, unless the clients already have the server address, it seems the client receiving the data would be impossible, hence the hanging on recvfrom().

The error in both server and client is in
addr.sin_port = htons("2000");
htons() takes an integer, not a string. Write
addr.sin_port = htons(2000);
instead.

Related

How to store a server address and port in a string variable

I'm creating a client/server socket and I need to get the sockets server IP using the sockaddr_in function getsocketname(). However, I'm not sure how to do this since I'm unable to do something like
struct sockaddr_in servAddr;
int IP = servAddr.getsockname(sock, (struct sockaddr *) %servAddr,sizeof(servAddr));
I believe getsockname() is used for the client side, not server, and only once a connection has been made successfully using a socket to a server you defined.
To explain, a possible flow to connect a client to a server is:
Create a socketfd var, like 'sock' in your case
Open the socketfd var with a socket(...) call
Create your own variable to store the server details, let's say:
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); // replace with actual server IP
serverAddr.sin_port = htons(80); // replace with actual port
Connect sockfd to the server specified with serverAddr using a connect(...) call
Get the client side IP and port for this connection using a getsockname(...) call
getsockname(socketfd, (struct sockaddr *) &clientAddr, sizeof(clientAddr));
char buffer[INET_ADDRSTRLEN]; // stores the client side IP address
inet_ntop(AF_INET, &clientAddr.sin_addr, buffer, sizeof(buffer));
int port = (int) ntohs(clientAddr.sin_port); // stores the client side port
printf("IP address: %s\n", buffer);
printf("Port: %d\n", port);

Socket connection from compiled c.cgi

On linux I want to connect to a demon, via a socket in a compiled c.cgi program (cgic), which is listening for incoming socket connections. I know the server works because it will responded to 'nc' commands. Assume the server is black-boxed, I can't change it. In my client program I have:
int sockfd;
int len;
struct sockaddr_in address;
int result;
char ch[] = "get=DeviceNo";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = 3042;
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *) &address, len);
Which returns with a "Connection Refused" error at this point. As a test I compiled the netcat into the .cgi program which does work:
system("echo '-r get=DeviceNo' | nc localhost 3042");
Am I missing something maybe how the socket class is handled within a .cgi? What should I do to try and get this socket to connect or what can I do to further troubleshoot my problem?
When working with sockaddr_in type, you need to know that both socket address sin_addr.s_addr and port sin_port must be in network byte order. Most likely your host is little-endian.
So you need to use inet_addr returns correct value, but for the socket address you need to use:
address.sin_port = htons(3042);

How to listen for UDP datagrams from a certain host using recvfrom?

I have a C code snippet that listens on UDP socket for incomming messages (and it works fine):
uint32_t udp_port = 101010; // example port
int sock_udp = socket(AF_INET, SOCK_DGRAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(udp_port);
bind(sock_udp, (struct sockaddr*) &server_address, (socklen_t) sizeof(server_address));
char buffer[20];
struct sockaddr_in sender_address;
socklen_t sender_len = (socklen_t) sizeof(struct sockaddr_in);
ssize_t rcv_len = recvfrom(sock_udp, buffer, sizeof(buffer), 0, (struct sockaddr * ) &sender_address, &sender_len);
After it I have information on the sender in sender_address structure and I can check addres, port etc. My question is: can I use recv, recvfrom or other similar function to listen for datagrams coming from a certain host? In other words, is it possible to drop datagrams from other sources without reading them?
You can "filter" and receive datagrams from a specified single source if you connect(2) the datagram socket.
If the socket sockfd is of type SOCK_DGRAM then addr is the address to
which datagrams are sent by default, and the only address from which
datagrams are received.
The standard phrases it a little different:
For SOCK_DGRAM sockets, the peer address identifies where all
datagrams are sent on subsequent send() functions, and limits the
remote sender for subsequent recv() functions

How to re bind a udp socket in Linux

I am an experienced Linux socket programmer and am writing a server application which has many outgoing interfaces. Now server socket binds to a random source port in the start of the process along with INADDR_ANY.
Later at some point when submitting response to a specific node, i need to assign a fixed source ip address. The standard way to do this is calling bind. However, bind is called once for the port number, successive calls fail with invalid argument error.
Creating a new socket is not really a good choice since i will have to be doing this very often upon responding to some clients.
I have also explored SO and a lot of socket options such as IP_FREEBIND, but it doesn't quite suite my scenario.
Perhaps using IP_PKT_INFO and setting source address might work unless it suffers the same problem i.e. not allowing a socket once bound to INADDRANY to rebind to a fixed source ip latter.
Is there a way to unbind an existing socket or an alternate way to setting source ip address in outgoing packet?
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(1500);
addr.sin_addr.s_addr = INADDR_ANY;
// first bind succeeds
if ( (status = bind(sock, (struct sockaddr *) &addr, sizeof(addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying address\n");
// second bind fails
if((status = bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr))) < 0)
printf("re bind error with ip %s\n", strerror(errno));
Any ideas in this regard will be highly appreciated. I have gone through considerable material on sockets, SO etc. but no success yet.
I finally found the solution myself so accepting my own answer (shameless but correct plugin), supplemented with code sample.
I originally wanted to rewrite source address of an outgoing packet without creating the socket again where the socket was already bound. Calling bind multiple times fail for this case, and (in my particular situation), i was not able to just have separate sockets for each source ip and use it.
I found some references in IP_PACKET_INFO but it was a pain to get it to work correctly. Following reference was helpful.
Setting source of udp socket
Sample Code
Here is a trivial application which creates a udp socket, binds it to a local port, then before sending a particular message, it appends the outgoing source ip address. Keeping in mind that in my case, i created a sudo interface and assigned it another ip. The send call will fail if this is not the case.
int status=-1;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in bind_addr;
memset(&bind_addr, 0, sizeof(struct sockaddr_in));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(44000); // locally bound port
if((status = bind(sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
// currently using addr as destination
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(80); // destination port
if (inet_aton("74.125.236.35", &(addr.sin_addr)) == 0)
printf("Failed copying remote address\n");
else
printf("Success copying remote address\n");
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying src address\n");
else
printf("Success copying src address\n");
char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];
char msg[10] = "hello";
int len = strlen(msg);
struct msghdr mh;
memset(&mh, 0, sizeof(mh));
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
struct iovec iov[1];
iov[0].iov_base = msg;
iov[0].iov_len = len;
mh.msg_name = &addr; // destination address of packet
mh.msg_namelen = sizeof(addr);
mh.msg_control = cmbuf;
mh.msg_controllen = sizeof(cmbuf);
mh.msg_flags = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
// after initializing msghdr & control data to
// CMSG_SPACE(sizeof(struct in_pktinfo))
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
//src_interface_index 0 allows choosing interface of the source ip specified
pktinfo->ipi_ifindex = 0;
pktinfo->ipi_spec_dst = src_addr.sin_addr;
int rc = sendmsg(sock, &mh, 0);
printf("Result %d\n", rc);
The key statement is
pktinfo->ipi_spec_dst = src_addr.sin_addr;
where we are specifying the source ip address to be used. The rest of things like cmsg struct etc. are merely used in order to be able to write ipoktinfo struct ourselves
There is no way to unbind and rebind an existing socket.
Why don't you create a socket for each interface instead? Since the UDP/IP protocol is connectionless, you can choose the source IP address by choosing which socket you use to send the reply with; there is no need to use the same socket the incoming datagram was received on.
The downsides are that you can no longer bind to the wildcard address, and you must use select(), poll(), multiple threads, or some other mechanism to receive datagrams from multiple sources concurrently. You'll also need some logic to efficiently pick the socket based on the client IP address.
In most cases, I suspect that adding a few route entries to route each remote IP address to the desired host IP address, and using a separate socket for each host IP address and port combination, solves the issues perfectly -- and using the very efficient kernel functionality to do so. While the behaviour may be an application requirement, I suspect it is better solved using the network interface configuration instead. Unfortunately, often the requirements are written by semi-functional idiots better suited for manual labor, and your hands are tied.. if so, I commiserate.
If you have a test network with workstations having multiple physical network interfaces, I can provide a simple example C99 test program you can use to verify the design works.

Have responses to UDP datagrams picked up by another process?

I'm trying to implement a basic UDP protocol wherein a Sender sends a UDP datagram to a Service, which then sends a response datagram back, using the source address and source port from the incoming datagram.
Normally you'd have the Sender also listen for the response on that port. But I want the response to be picked up by a separate program (the Listener) also running on that host. So:
On host A, Listener starts and binds to port 12345, and blocks on recvfrom.
On host A, Sender sends datagram to Service running on host B, setting the source address and port to host A, port 12345.
Service on host B sends a response to host A port 12345.
Response is picked up by Listener.
Setting the source address and port is done by binding to them. So I need both Sender and Listener to bind to the same port. Setting SO_REUSEADDR in both allows this. Note that I'm not using multicast here.
But the responses aren't reliably being picked up by Listener. There are two exceptions I've observed:
I find that if the Sender closes the socket immediately after sending the first datagram, then the response will get to the Listener.
Alternatively, if the Sender is started first and binds before the Listener, the responses will get picked up by the Listener.
I've been working from examples from the internet and haven't found documentation that clearly describes what should happen. But a few places I've seen have hinted that, for Unicast, only the most recent process to bind to the port will receive datagrams sent to it.
My question is, can I send UDP datagrams so that responses (sent using the source address and port) will be picked up by another process? If the above process can't be made to work, is there a way to set the source information on an outgoing datagram without binding to that port?
A few other points:
Each process should be started independently and be able to be restarted without interfering with the other. So I don't think I can have one open the socket and spawn the other.
I don't need to receive packets from both processes. One process only sends, and the other only receives.
Ideally, the solution would be portable enough to run on common Unixes and Windows.
Finally, if it's simply not possible then I'll fall back to using a single process to perform both functions. I'm not too stressed about it but I am interested in doing it if it is possible somehow. :-)
Networking code follows...
Sender code
void run(Options *options)
{
struct sockaddr_in si_me, si_other;
int s;
socklen_t slen = sizeof(si_other);
int reuse = 1;
struct hostent *he;
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0)
die("setsockopt");
// Bind to the "listen port", so that outgoing datagrams have the correct source information
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(options->listen_port);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (struct sockaddr *) &si_me, sizeof(si_me)) != 0)
die("bind");
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(options->service_port);
if (!(he = gethostbyname2(options->service_host, AF_INET)))
die("gethostbyname2");
memmove(&si_other.sin_addr.s_addr, he->h_addr, he->h_length);
while (1)
{
int len;
char *buf;
// Create outgoing message in buf
...
if (sendto(s, buf, len, 0, (struct sockaddr *) &si_other, slen) == -1)
die("sendto");
}
close(s);
}
Listener code
static void run(Options *options)
{
struct sockaddr_in si_me, si_other;
int s;
socklen_t slen = sizeof(si_other);
char buf[BUFLEN];
int reuse = 1;
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0)
die("setsockopt");
// Bind to the same "listen port" to pick up responses to datagrams sent by Sender
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(options->listen_port);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (struct sockaddr *) &si_me, sizeof(si_me)) == -1)
die("bind");
while (1)
{
int nr;
nr = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen);
if (nr == -1)
die("recvfrom");
// Process the received message
...
}
close(s);
}
A related question is Using netcat to send a UDP packet without binding, where one answer seems to suggest it should be possible using SO_SOCKADDR, but did not quite explain how it would work in my case.
is there a way to set the source information on an outgoing datagram
without binding to that port?
There is no portable way. A solution for Linux, using IP_PKTINFO, is this answer to How to re bind a udp socket in Linux.
1: You can send from different port on B
A binds 12345 sends to B:12345
B:12345 - process 1 - recv
B:12346 - process 2 - send to A:12345
2: You can construct packet with fake back address with raw sockets
First solution is better

Resources