Unix Domain Sockets datagram client with receive only - sockets

I have a simulator application which Unix Domain datagram sockets, which sends data to socket path for.ex /var/lib/XYZ.
sendto is returning -2 which is due to other end no peer is there(no other unix domian socket application is running)
I would like to write a datagram client/peer application using Unix Domain Sockets for receiving data from the server/simulator(which is sending data to /var/lib/XYZ).
My code is as follows:
#define BUF_SIZE 1024
#define SV_SOCK_PATH "/var/lib/XYZ"
#define SV_SOCK_PATH2 "/var/lib/ABC"
creation of Unix Domain sockets as below:
struct sockaddr_un svaddr, claddr;
....
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1)
printf("socket creation failed");
memset(&claddr, 0, sizeof(struct sockaddr_un));
claddr.sun_family = AF_UNIX;
strncpy(claddr.sun_path, SV_SOCK_PATH2, sizeof(claddr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1)
printf("bind failed");
/* Construct address of server */
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
while(1)
{
int len=sizeof(struct sockaddr_un);
numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, (struct sockaddr*)&svaddr,&len);
if (numBytes == -1)
printf("recvfrom error");
else{
printf("no of bytes received from server: %d",(int)numBytes);
printf("Response %d: %s\n", (int) numBytes, resp);
}
}
remove(claddr.sun_path);
//exit(EXIT_SUCCESS);
}
but the program is not receiving anything...is there anything missed out??

When it comes to datagrams, there is no real client or server. Either side attempting to send is responsible for addressing datagrams to the other. So, in your code, the setup is all wrong. You're apparently attempting to direct the "server" (but really not a server, just the other peer) to send to you via svaddr but that isn't how it works.
For a datagram AF_UNIX socket, the sender either needs to explicitly specify the receiver's address in a sendto call, or it needs to first connect its socket to the receiver's address. (In the latter case, it can then use send instead of sendto since the peer address has been specified via connect.)
You can't specify the sending peer's address in the recvfrom call. The socket address argument in the recvfrom is intended to return to you the address from which the datagram was sent. Whatever is in that variable will be overwritten on successful return from recvfrom.
One way datagram peer programs are often structured: the "server" creates a well-known path and binds to it, then a "client" creates its own endpoint and binds to it (constructing a unique socket address for itself), then the client can sendto the server's well-known socket. The server, by using recvfrom to obtain the client's address along with the datagram, can then use sendto along with the address to return a message to the client (without needing to connect its socket). This provides a sort of client-server paradigm on top of the fundamentally equal-peer orientation of the datagram socket.
Finally, I should mention that it's usually a good idea to use fully specified pathnames to ensure both peers are using the same address even if started from different directories. (Normally, with AF_UNIX, the address is a path name in the file system used to "rendezvous" between the two peers -- so without a full path "some_socket" is "./some_socket" in the current working directory. Some systems, such as linux, also support an abstract "hidden" namespace that doesn't require a full path, but you must use an initial null byte in the name to specify that.)

Related

Connected Unix SOCK_DGRAM sockets

I've followed the code in this answer to create a pair of programs which send and receive datagrams via a Unix socket.
What's awkward about this: On the side which creates the first socket (i.e. the "server"), I can't use calls to send, recv, read or write because there is no destination set (those calls fail with "Destination address required" error.
I've tried working around this by adding an initial call to recvfrom and using the address given back through there, but it never has the correct value (on OSX at least). It also doesn't work to use sendto since we don't know the client address.
The way which I have got it working is roughly following this process:
Start server program, which:
Calls socket and bind to create the server socket.
It waits here.
Start client program, which:
Calls socket and bind to create the client socket.
It knows the path to the server socket and calls connect.
This side is now set up correctly.
Server program:
Accepts the path to the client socket via stdin
Copies the path to a struct sockaddr_un and uses that to call connect (as in the linked answer).
This is pretty awkward! If I was doing this with SOCK_STREAM sockets, I could use listen and accept; the flow is much more straight-forward without the server needing to know the client's socket path.
Is there a more elegant way of getting these sockets connected?
SOCK_DGRAM (UDP) sockets are "Connectionless", so you cannot "connect" the two sockets. They only send packets to the designated destination address and the client simply captures it. So you'll to first decide if you are going to use a SOCK_DGRAM (UDP) or SOCK_STREAM (TCP).
If you are using UDP sockets the client side socket need not connect, you simply sendto the destination address (Server in this case) after creating and binding.
So if you need a dedicated connected connection you are better off using TCP socket. Or if you are using this over the internet the closest thing you can find for UDP is Hole punching.
One way to solve the problem:
Your messages probably have common header.
Add address information of sender to the header.
Then your server can respond to the correct client by using sendto.
Pseudo example:
void handle_my_message(const my_message_t *msg)
{
struct sockaddr_un client_address = msg->header.sender;
my_message_response_t response_msg;
... handle the message and fill the response...
// Send response message
sendto(fd, &response_msg, sizeof(response_msg), 0,
(struct sockaddr*)&client_address, sizeof(client_address));
}
This way your server programs does not need to keep book of connections.
Instead of struct sockaddr_un in the header you maybe should use something smaller and more portable format, that can be converted to struct sockaddr_un.
You should also bind the client side socket to an address. If the client socket is bound (i.e. has its own name), then you don't need an out-of-band mechanism to communicate the client's address to the server. The OS sends it along with each datagram.
Sample code for client (in python because it's quick and easy to prototype -- should be easy to translate to the equivalent C):
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
client_addr = "/tmp/ux_client"
if os.path.exists(client_addr):
os.remove(client_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(client_addr)
for n in range(5):
data = "Hello " + str(n)
data = data.encode()
print("Sent '{}' to {}".format(data, server_addr))
sock.sendto(data, server_addr)
data, addr = sock.recvfrom(16000)
print("Got '{}' back from {}".format(data, addr))
Furthermore, you can execute a connect on the client side. Since it's a datagram socket, that doesn't actually create a connection between the two but it does fix the address of the server endpoint, relieving you of the need to provide the server address on every send (i.e. you can use simple send rather than sendto).
For completeness, here's the echo server corresponding to the above:
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
if os.path.exists(server_addr):
# Bind will fail if endpoint exists
os.remove(server_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(server_addr)
while True:
data, addr = sock.recvfrom(16000)
print("Got '{}' from {}".format(data, addr))
sock.sendto(data, addr)
EDIT
Hmm... I see now that you say you're already binding the client socket, and then connecting to the server side. But that means you simply need to have the server use recvfrom once initially to obtain the client's address. The OS will send the address along and you don't need to use an out-of-band mechanism.
The downside to connecting the socket is that if the client goes down, the server won't know that unless it attempts to send, but the client won't be able to reconnect because the server's socket is already connected. That's why datagram servers typically use recvfrom and sendto for all messages.
Updated server with initial recvfrom followed by connect:
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
if os.path.exists(server_addr):
# Bind will fail if endpoint exists
os.remove(server_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(server_addr)
client_addr = None
while True:
if client_addr:
data = sock.recv(16000)
else:
data, client_addr = sock.recvfrom(16000)
sock.connect(client_addr)
print("Got '{}' from {}".format(data, client_addr))
sock.send(data)
Updated client with connected socket.
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
client_addr = "/tmp/ux_client"
if os.path.exists(client_addr):
os.remove(client_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(client_addr)
sock.connect(server_addr)
for n in range(5):
data = ("Hello " + str(n)).encode()
print("Sent '{}'".format(data))
sock.send(data)
data = sock.recv(16000)
print("Got '{}' back".format(data))

Bidirectional communication using a single UNIX socket

I have the situation where a service running in the background makes itself available for ASCII-based commands via a socket (SOCK_DGRAM) placed on the file system. I am able to successfully send commands to this interface but cannot receive any response generated by the background service.
As I understand it, the reason I am not receiving the service's response is because the underlying IPC is not technically between two processes, but is rather between to addresses. As such, it is necessary to bind my endpoint to a particular address location so the service knows were to send its response. However, the problem is that I do not want to pollute the directory space with too many additional socket files.
That is to say, I can make this work by simply doing something like:
struct sockaddr_un local;
int len;
s = socket(AF_UNIX, SOCK_DGRAM, 0);
local.sun_family = AF_UNIX;
strcpy(local.sun_path, "/path/to/some/dir/mySocketFile");
len = strlen(local.sun_path) + sizeof(local.sun_family);
bind(s, (struct sockaddr *)&local, len);
//Send commands to control interface of background service
And all is well, because by binding to mySocketFile the service has an address to which is will respond.
In short, is there a way to communicate to the service through its available socket interface and receive the response without binding the local endpoint such that it creates another socket-type file on the file system? i.e. some kind of a nameless socket, of sorts?
Of course, if anyone spots any misconceptions or misunderstandings in my logic please point them out.
If the client does not bind its socket to an filesystem address, it still has a notional address assigned by the system (which may exist in the filesystem in /tmp somewhere, or may not exist in the filesystem at all, depends on the OS). The server can get this address by using the recvfrom(2) call to receive the incoming packets from clients -- this call takes additional sockaddr * and socklen_t * arguments that it fills in with the client socket address. You then use sendto(2) to send the reply back to the client.

how should I send messages from server to client in WinSock's UDP?

I am learning WinSock UDP. Most tutorials I've seen ask me to:
On server side:
SOCKET socked = socket(PF_INET, SOCK_DGRAM, 0)
bind(...);
for(;;) { recvfrom(..); }
On client side:
SOCKET socked = socket(PF_INET, SOCK_DGRAM, 0);
sendto(...);
But I wonder how can I do other way, send data from server to client. I don't know client's port (I figured out it vary every sendto call), and I want to be able to connect client behihd NAT to server and still recive data from server.
How it is done in modern games?
There are two questions in there.
Finding the address
The function recvfrom is declared:
int recvfrom(
__in SOCKET s,
__out char *buf,
__in int len,
__in int flags,
__out struct sockaddr *from, /* <--- */
__inout_opt int *fromlen /* <--- */
);
So you can use from and fromlen in sendto.
sendto(..., (SOCKADDR *)from, *fromlen);
NAT
The NAT-box should automatically allow the server to "answer" to the datagram sent by the client. So, the mere fact that the client sent a datagram causes the NAT-box to ephemerally (a few minutes?) open a port to allow traffic return.

IP address in TCP sockets

I have a root node(server) connected to many other nodes(clients) through TCP sockets. I want to send some data from server to client, but the data is different for each node and depends on the ip address of that node.
Thus I should have ip address of each node connected to server. How can I have that information?
When you call accept(2) you can choose to retrieve the address of the client.
int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
You need to store those addresses and then send(2) to each what you need to send.
So the workflow should be something like this:
Keep a list of connected clients. Initially the list is empty, of course
When you accept a connection, push its details into that list (the address and the socket returned by accept(2)).
When you need to send something to every client, simply walk the list and send it (using the stored socket)
The one tricky part is that socklen_t *restrict address_len is a value-result argument, so you need to be careful with that.
This is a more nuanced question than it first appears.
If the clients are sitting behind a NAT, you may get the same IP from more than one client. This is perfectly natural and expected behavior. If you need to distinguish between multiple clients behind the same NAT, you'll need some other form of unique client id (say, IP address and port).
As long as you have access to the list of file descriptors for the connected TCP sockets, it is easy to retrieve the addresses of the remote hosts. The key is the getpeername() system call, which allows you to find out the address of the remote end of a socket. Sample C code:
// This is ugly, but simpler than the alternative
union {
struct sockaddr sa;
struct sockaddr_in sa4;
struct sockaddr_storage sas;
} address;
socklen_t size = sizeof(address);
// Assume the file descriptor is in the var 'fd':
if (getpeername(fd, &address.sa, &size) < 0) {
// Deal with error here...
}
if (address.sa.family == AF_INET) {
// IP address now in address.sa4.sin_addr, port in address.sa4.sin_port
} else {
// Some other kind of socket...
}

sendto not working on VxWorks

I asked this question before and had no resolution (still having the problem). I am stumped because the function returned without error and NO DATA was sent! This code works on Linux ... the VxWorks version does not work (sendto does not send, though it returns without an ERROR).
The synopsis - I am writing a simple echo server - The server successfully receives
the data (from an x86 box) and claims it successfully SENT it back.
However NO DATA is received on the client (netcat on an x86). This
code is running on VxWorks 5.4 on a PowerPC box ...
I is the UDP data being buffered somehow?
Could another task be preventing sendto from sending? (NOT to get off on a wild goose chase here, but I taskspawn my application with a normal priority, i.e. below critical tasks like the network task etc etc ... so this is fine).
Could VxWorks be buffering my UDP data?
I HAVE setup my routing table ... pinging works!
There is NO firewall AFAIK ...
What are the nuances of sendto and what would prevent my data from
reaching the client ...
while(1)
{
readlen = recvfrom(sock, buf, BUFLEN, 0, (struct sockaddr *) &client_address, &slen);
if (readlen == ERROR)
{
printf("RECVFROM FAILED()/n");
return (ERROR);
}
printf("Received %d bytes FROM %s:%d\nData: %s\n\n",
readlen, inet_ntoa(client_address.sin_addr),
ntohs(client_address.sin_port), buf);
// Send it to right back to the client using the open UDP socket
// but send it to OUTPORT
client_address.sin_port = htons(OUTPORT);
// Remember slen is a value (not an address ... in, NOT in-out)
sendlen = sendto(sock, buf, BUFLEN, 0, (struct sockaddr*)&client_address, slen);
// more code ....
}
I trust ERROR is defined as -1, right? Then are you checking the return value of the sendto(2) call? What about the errno(3) value?
One obvious problem I see in the code is that you give BUFLEN as length of the message to be sent, while it should actually be readlen - the number of bytes you received.