passing file descriptors into unix sockets
This commit is contained in:
parent
2487bd6ad9
commit
4ff34a227f
270
drop/pass-socket_client.c
Normal file
270
drop/pass-socket_client.c
Normal file
@ -0,0 +1,270 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/stat.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define USOCK "./.socket"
|
||||
|
||||
#define handle_error(msg) \
|
||||
do { log_error (msg); exit(EXIT_FAILURE); } while (0)
|
||||
|
||||
#define handle_err(fun,msg)\
|
||||
do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0)
|
||||
|
||||
void log_format (const char* tag, const char* message, va_list args) {
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
|
||||
char * date =ctime(&now);
|
||||
date[strlen(date) - 1] = '\0';
|
||||
printf("%s:%s: ", date, tag);
|
||||
vprintf(message, args);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void log_error (const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
log_format("error", message, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_info (const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
log_format("info", message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_debug (const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
log_format("debug", message, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static
|
||||
int recvsockfd (int socket) // receive fd from socket
|
||||
{
|
||||
struct msghdr msg = {0};
|
||||
|
||||
/* On Mac OS X, the struct iovec is needed, even if it points to minimal data */
|
||||
char m_buffer[1];
|
||||
struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) };
|
||||
msg.msg_iov = &io;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
char c_buffer[256];
|
||||
msg.msg_control = c_buffer;
|
||||
msg.msg_controllen = sizeof(c_buffer);
|
||||
|
||||
if (recvmsg(socket, &msg, 0) < 0)
|
||||
handle_err ("recvsockfd", "Failed to receive message\n");
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
printf ("About to extract fd\n");
|
||||
int fd;
|
||||
memmove(&fd, CMSG_DATA(cmsg), sizeof(fd));
|
||||
printf ("Extracted fd %d\n", fd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int usock_connect (int *fd, const char *path)
|
||||
{
|
||||
assert (fd != NULL);
|
||||
assert (path != NULL);
|
||||
|
||||
if (fd == NULL) {
|
||||
handle_err ("usock_connect", "fd == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path == NULL) {
|
||||
handle_err ("usock_connect", "path == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sfd;
|
||||
struct sockaddr_un my_addr;
|
||||
socklen_t peer_addr_size;
|
||||
|
||||
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sfd == -1) {
|
||||
handle_err ("usock_connect", "sfd == -1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// clear structure
|
||||
memset(&my_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
my_addr.sun_family = AF_UNIX;
|
||||
strncpy(my_addr.sun_path, path, strlen (path));
|
||||
|
||||
peer_addr_size = sizeof(struct sockaddr_un);
|
||||
if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
|
||||
handle_err ("usock_connect", "connect == -1");
|
||||
perror("connect()");
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
*fd = sfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usock_init (int *fd, const char *path)
|
||||
{
|
||||
assert (fd != NULL);
|
||||
assert (path != NULL);
|
||||
|
||||
if (fd == NULL) {
|
||||
handle_err ("usock_init", "fd == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path == NULL) {
|
||||
handle_err ("usock_init", "path == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sfd;
|
||||
struct sockaddr_un my_addr;
|
||||
socklen_t peer_addr_size;
|
||||
|
||||
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sfd == -1) {
|
||||
handle_err ("usock_init", "sfd == -1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// clear structure
|
||||
memset(&my_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
my_addr.sun_family = AF_UNIX;
|
||||
strncpy(my_addr.sun_path, path, strlen (path));
|
||||
|
||||
// TODO FIXME
|
||||
// delete the unix socket if already created
|
||||
|
||||
peer_addr_size = sizeof(struct sockaddr_un);
|
||||
|
||||
if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
|
||||
handle_err ("usock_init", "bind == -1");
|
||||
perror("bind()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (sfd, 5) == -1) {
|
||||
handle_err ("usock_init", "listen == -1");
|
||||
perror("listen()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*fd = sfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usock_accept (int fd, int *pfd)
|
||||
{
|
||||
assert (pfd != NULL);
|
||||
|
||||
if (pfd == NULL) {
|
||||
handle_err ("usock_accept", "pfd == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un peer_addr;
|
||||
memset (&peer_addr, 0, sizeof (struct sockaddr_un));
|
||||
socklen_t peer_addr_size = 0;
|
||||
|
||||
*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size);
|
||||
if (*pfd < 0) {
|
||||
handle_err ("usock_accept", "accept < 0");
|
||||
perror("listen()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usock_close (int fd)
|
||||
{
|
||||
int ret;
|
||||
ret = close (fd);
|
||||
if (ret < 0) {
|
||||
handle_err ("usock_close", "close ret < 0");
|
||||
perror ("closing");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usock_remove (const char *path)
|
||||
{
|
||||
return unlink (path);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int tcpsockfd;
|
||||
int usockfd;
|
||||
// check the number of args on command line
|
||||
if(argc != 1)
|
||||
{
|
||||
fprintf (stderr, "USAGE: %s\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Connection to the unix socket\n");
|
||||
|
||||
// 1. unix socket connection
|
||||
int ret = usock_connect (&usockfd, USOCK);
|
||||
if (ret != 0) {
|
||||
fprintf (stderr, "error: usock_connect\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Receiving the tcp socket\n");
|
||||
|
||||
// 2. receive the tcp socket
|
||||
tcpsockfd = recvsockfd (usockfd);
|
||||
|
||||
printf("Sending 'hello world' to the tcp socket\n");
|
||||
|
||||
// 3. send a message to check the connection is effective
|
||||
if (write(tcpsockfd, "hello world\n", strlen("hello world\n")) == -1) {
|
||||
perror("write");
|
||||
close(tcpsockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Disconnection of both sockets\n");
|
||||
|
||||
// 4. close sockets
|
||||
close(usockfd);
|
||||
close(tcpsockfd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
322
drop/pass-socket_server.c
Normal file
322
drop/pass-socket_server.c
Normal file
@ -0,0 +1,322 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/stat.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define USOCK "./.socket"
|
||||
|
||||
#define handle_error(msg) \
|
||||
do { log_error (msg); exit(EXIT_FAILURE); } while (0)
|
||||
|
||||
#define handle_err(fun,msg)\
|
||||
do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0)
|
||||
|
||||
void log_format (const char* tag, const char* message, va_list args) {
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
|
||||
char * date =ctime(&now);
|
||||
date[strlen(date) - 1] = '\0';
|
||||
printf("%s:%s: ", date, tag);
|
||||
vprintf(message, args);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void log_error (const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
log_format("error", message, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_info (const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
log_format("info", message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_debug (const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
log_format("debug", message, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int build_socket (char *servername, char * serverport)
|
||||
{
|
||||
int sockfd;
|
||||
struct sockaddr_in6 server;
|
||||
socklen_t addrlen;
|
||||
|
||||
// socket factory
|
||||
if((sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
perror("socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// init remote addr structure and other params
|
||||
server.sin6_family = AF_INET6;
|
||||
server.sin6_port = htons(atoi(serverport));
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
|
||||
// get addr from command line and convert it
|
||||
if(inet_pton(AF_INET6, servername, &server.sin6_addr) != 1)
|
||||
{
|
||||
perror("inet_pton");
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Trying to connect to the remote host\n");
|
||||
if(connect(sockfd, (struct sockaddr *) &server, addrlen) == -1)
|
||||
{
|
||||
perror("connect");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
int usock_connect (int *fd, const char *path)
|
||||
{
|
||||
assert (fd != NULL);
|
||||
assert (path != NULL);
|
||||
|
||||
if (fd == NULL) {
|
||||
handle_err ("usock_connect", "fd == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path == NULL) {
|
||||
handle_err ("usock_connect", "path == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sfd;
|
||||
struct sockaddr_un my_addr;
|
||||
socklen_t peer_addr_size;
|
||||
|
||||
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sfd == -1) {
|
||||
handle_err ("usock_connect", "sfd == -1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// clear structure
|
||||
memset(&my_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
my_addr.sun_family = AF_UNIX;
|
||||
strncpy(my_addr.sun_path, path, strlen (path));
|
||||
|
||||
peer_addr_size = sizeof(struct sockaddr_un);
|
||||
if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
|
||||
handle_err ("usock_connect", "connect == -1");
|
||||
perror("connect()");
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
*fd = sfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usock_init (int *fd, const char *path)
|
||||
{
|
||||
assert (fd != NULL);
|
||||
assert (path != NULL);
|
||||
|
||||
if (fd == NULL) {
|
||||
handle_err ("usock_init", "fd == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path == NULL) {
|
||||
handle_err ("usock_init", "path == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sfd;
|
||||
struct sockaddr_un my_addr;
|
||||
socklen_t peer_addr_size;
|
||||
|
||||
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sfd == -1) {
|
||||
handle_err ("usock_init", "sfd == -1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// clear structure
|
||||
memset(&my_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
my_addr.sun_family = AF_UNIX;
|
||||
strncpy(my_addr.sun_path, path, strlen (path));
|
||||
|
||||
// TODO FIXME
|
||||
// delete the unix socket if already created
|
||||
|
||||
peer_addr_size = sizeof(struct sockaddr_un);
|
||||
|
||||
if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
|
||||
handle_err ("usock_init", "bind == -1");
|
||||
perror("bind()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (sfd, 5) == -1) {
|
||||
handle_err ("usock_init", "listen == -1");
|
||||
perror("listen()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*fd = sfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usock_accept (int fd, int *pfd)
|
||||
{
|
||||
assert (pfd != NULL);
|
||||
|
||||
if (pfd == NULL) {
|
||||
handle_err ("usock_accept", "pfd == NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un peer_addr;
|
||||
memset (&peer_addr, 0, sizeof (struct sockaddr_un));
|
||||
socklen_t peer_addr_size = 0;
|
||||
|
||||
*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size);
|
||||
if (*pfd < 0) {
|
||||
handle_err ("usock_accept", "accept < 0");
|
||||
perror("listen()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usock_close (int fd)
|
||||
{
|
||||
int ret;
|
||||
ret = close (fd);
|
||||
if (ret < 0) {
|
||||
handle_err ("usock_close", "close ret < 0");
|
||||
perror ("closing");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usock_remove (const char *path)
|
||||
{
|
||||
return unlink (path);
|
||||
}
|
||||
|
||||
int build_unix_socket (char * path)
|
||||
{
|
||||
int remotefd, localfd;
|
||||
|
||||
usock_init (&localfd, path);
|
||||
usock_accept (localfd, &remotefd);
|
||||
|
||||
return remotefd;
|
||||
}
|
||||
|
||||
static
|
||||
void sendfd (int socket, int fd) // send fd by socket
|
||||
{
|
||||
struct msghdr msg = { 0 };
|
||||
char buf[CMSG_SPACE(sizeof(fd))];
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
|
||||
/* On Mac OS X, the struct iovec is needed, even if it points to minimal data */
|
||||
struct iovec io = { .iov_base = "", .iov_len = 1 };
|
||||
|
||||
msg.msg_iov = &io;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = buf;
|
||||
msg.msg_controllen = sizeof(buf);
|
||||
|
||||
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
|
||||
memmove(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
if (sendmsg(socket, &msg, 0) < 0)
|
||||
handle_err("sendfd", "Failed to send message\n");
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
// check the number of args on command line
|
||||
if(argc != 3)
|
||||
{
|
||||
fprintf (stderr, "USAGE: %s @server port_num\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
char *servername = argv[1];
|
||||
char *serverport = argv[2];
|
||||
|
||||
printf("Connection to the tcp socket\n");
|
||||
// 1. socket creation (tcp), connection to the server
|
||||
int sockfd = build_socket (servername, serverport);
|
||||
|
||||
printf("Sending 'coucou' to the tcp socket\n");
|
||||
// send a message to check the connection is effective
|
||||
if (write(sockfd, "coucou\n", strlen("coucou\n")) == -1) {
|
||||
perror("write");
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("Connection to the unix socket\n");
|
||||
// 2. socket creation (unix)
|
||||
int usockfd = build_unix_socket (USOCK);
|
||||
|
||||
printf ("Passing the tcp socket to the unix socket\n");
|
||||
// 3. tcp socket passing to the client
|
||||
sendfd (usockfd, sockfd);
|
||||
|
||||
// send a message to check the connection is (still) effective
|
||||
if (write(sockfd, "bye\n", strlen("bye\n")) == -1) {
|
||||
perror("write");
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Disconnection\n");
|
||||
|
||||
// 4. close sockets
|
||||
close(usockfd);
|
||||
close(sockfd);
|
||||
|
||||
usock_remove (USOCK);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user