I'm trying to create a unix domain socket server and client on Android in C++, using UDP. I need the client to send one message ("hi") to the server and from there on the server needs to send data to the client. I have successfully created the sockets on both sides, and I am able to receive a short message on the server from the client. However recvfrom(..) on the server does not populate the struct sockaddr *src_addr, socklen_t *addrlen arguments. And a subsequent sendto message using those src_addr and addrlen obviously fail (sendto returns -1).
Here's the code for the server :
int serverSocket = socket(PF_LOCAL, SOCK_DGRAM, 0);
int sendingBufferSize = OUTPUT_BUFFER_SIZE;
setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &sendingBufferSize, sizeof(sendingBufferSize));
struct sockaddr_un server;
memset(&server, 0, sizeof server);
server.sun_family = AF_LOCAL;
// the first byte of sun_path should be '\0' for abstract namespace
const char * socket_name = SOCKET_NAME;
server.sun_path[0] = '\0';
strcpy(server.sun_path + 1, socket_name);
socklen_t sockaddr_len = sizeof(server.sun_family) + strlen(socket_name) + 1;
if (bind(serverSocket, (struct sockaddr *) &server, sockaddr_len) < 0) {
close(serverSocket);
printf("Failed to bind the server socket\n");
return -1;
}
printf("- Socket binding successful on socket path %s len %d\n", &server.sun_path[1], sockaddr_len);
_serverSocket = serverSocket;
And later I receive a message from the client:
int opcode;
_clientAddressLength = sizeof(struct sockaddr_un);
int numOfBytes = recvfrom(_serverSocket, _messageBuffer, INPUT_BUFFER, 0, (struct sockaddr *)&_clientAddress, &_clientAddressLength);
if (numOfBytes != 0)
{
printf("Got a message from client\n");
memcpy(&opcode, _messageBuffer, sizeof(opcode)); // I'm getting what I expected
}
However _clientAddress is empty and _clientAddressLength is set to 0.
And later
int result = sendto(_serverSocket
, sendBuf
, sendBufSize
, 0
, (const sockaddr*)&_clientAddress
, _clientAddressLength);
returns -1
Thanks for your help guys!
EDIT:
Finally thanks to Nikolai N Fetissov's link and some digging I made it work. I'd like to post a fixed, 100% working example of bi-directional UDP communication over UNIX DOMAIN abstract namespace sockets. This is a copy of this http://www.toptip.ca/2013/01/unix-domain-socket-with-abstract-socket.html?m=1 link with a fixed bugs. For the future generations, as there aren't enough examples on this topic on the net.
server.cpp
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>`
#define SERVER_SOCKET "#UdsServer" // The # is replaced by 0 for abstract namespace
int main(void)
{
int socket_fd;
struct sockaddr_un server_address, client_address;
int bytes_received, bytes_sent, integer_buffer;
socklen_t address_length = sizeof(server_address.sun_family)+strlen(SERVER_SOCKET );
if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
perror("server: socket");
return -1;
}
memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
memcpy(server_address.sun_path, SERVER_SOCKET,sizeof(SERVER_SOCKET)-1);// the path is not a C string, and is not NULL turminated
server_address.sun_path[0] = 0;
if (bind(socket_fd,
(const struct sockaddr *) &server_address,
address_length) < 0)
{
perror("server: bind");
close(socket_fd);
return -1;
}
for (;;)
{
bytes_received = recvfrom(socket_fd,
&integer_buffer,
sizeof(integer_buffer),
0,
(struct sockaddr *) &client_address,
&address_length);
if(bytes_received != sizeof(integer_buffer))
{
printf("Error: recvfrom - %d.\n", bytes_received);
} else {
printf("received: %d.\n", integer_buffer);
integer_buffer += 10;
bytes_sent = sendto(socket_fd,
&integer_buffer,
sizeof(integer_buffer),
0,
(struct sockaddr *) &client_address,
address_length);
}
}
close(socket_fd);
return 0;
}
client.cpp
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define SERVER_SOCKET "#UdsServer"
#define CLIENT_SOCKET "#UdsClient"
int main(void)
{
int socket_fd;
struct sockaddr_un server_address, client_address;
int bytes_received, bytes_sent, integer_buffer;
socklen_t address_length = sizeof(server_address.sun_family) + strlen(CLIENT_SOCKET);`
if((socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
perror("client: socket");
return -1;
}
memset(&client_address, 0, sizeof(client_address));
client_address.sun_family = AF_UNIX;
memcpy(client_address.sun_path, CLIENT_SOCKET,sizeof(CLIENT_SOCKET )-1 );
client_address.sun_path[0] = 0;
if(bind(socket_fd,
(const struct sockaddr *) &client_address,
address_length) < 0)
{
perror("client: bind");
return -1;
}
memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
memcpy(server_address.sun_path, SERVER_SOCKET,sizeof(SERVER_SOCKET)-1);
server_address.sun_path[0] = 0;
integer_buffer = 1;
for (;;)
{
bytes_sent = sendto(socket_fd,
&integer_buffer,
sizeof(integer_buffer),
0,
(struct sockaddr *) &server_address,
address_length);
bytes_received = recvfrom(socket_fd,
&integer_buffer,
sizeof(integer_buffer),
0,
(struct sockaddr *) &server_address,
&address_length);
if (bytes_received != sizeof(integer_buffer))
{
printf("Error: recvfrom - %d.\n", bytes_received);
return -1;
}
printf("received: %d\n", integer_buffer);
integer_buffer += 1;
sleep(10);
}
close(socket_fd);
return 0;
}
I hope it helps, and if you see more bugs please let me know
sizeof (struct sockaddr_in)
? – David Schwartzperror()
before the close, not after it. You aren't checking for errors inrecvfrom()
correctly. – user207421