# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
# include <string.h>
# include <unistd.h>
# include <assert.h>
# include <errno.h>
# include <sys/mman.h>
# include <sys/socket.h>
# include <sys/un.h>
# include "ipc.h"
int ipc_connect ( const char * socket_path ) {
int err ;
# ifdef __APPLE__
int sock = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
# else
int sock = socket ( AF_UNIX , SOCK_SEQPACKET , 0 ) ;
# endif
if ( sock < 0 ) return - 1 ;
struct sockaddr_un addr = {
. sun_family = AF_UNIX ,
} ;
snprintf ( addr . sun_path , sizeof ( addr . sun_path ) , " %s " , socket_path ) ;
err = connect ( sock , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( err ! = 0 ) {
close ( sock ) ;
return - 1 ;
}
return sock ;
}
int ipc_bind ( const char * socket_path ) {
int err ;
unlink ( socket_path ) ;
# ifdef __APPLE__
int sock = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
# else
int sock = socket ( AF_UNIX , SOCK_SEQPACKET , 0 ) ;
# endif
struct sockaddr_un addr = {
. sun_family = AF_UNIX ,
} ;
snprintf ( addr . sun_path , sizeof ( addr . sun_path ) , " %s " , socket_path ) ;
err = bind ( sock , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
assert ( err = = 0 ) ;
err = listen ( sock , 3 ) ;
assert ( err = = 0 ) ;
return sock ;
}
int ipc_sendrecv_with_fds ( bool send , int fd , void * buf , size_t buf_size , int * fds , int num_fds ,
int * out_num_fds ) {
char control_buf [ CMSG_SPACE ( sizeof ( int ) * num_fds ) ] ;
memset ( control_buf , 0 , CMSG_SPACE ( sizeof ( int ) * num_fds ) ) ;
struct iovec iov = {
. iov_base = buf ,
. iov_len = buf_size ,
} ;
struct msghdr msg = {
. msg_iov = & iov ,
. msg_iovlen = 1 ,
} ;
if ( num_fds > 0 ) {
assert ( fds ) ;
msg . msg_control = control_buf ;
msg . msg_controllen = CMSG_SPACE ( sizeof ( int ) * num_fds ) ;
}
if ( send ) {
if ( num_fds ) {
struct cmsghdr * cmsg = CMSG_FIRSTHDR ( & msg ) ;
assert ( cmsg ) ;
cmsg - > cmsg_level = SOL_SOCKET ;
cmsg - > cmsg_type = SCM_RIGHTS ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( int ) * num_fds ) ;
memcpy ( CMSG_DATA ( cmsg ) , fds , sizeof ( int ) * num_fds ) ;
// printf("send clen %d -> %d\n", num_fds, cmsg->cmsg_len);
}
return sendmsg ( fd , & msg , 0 ) ;
} else {
int r = recvmsg ( fd , & msg , 0 ) ;
if ( r < 0 ) return r ;
int recv_fds = 0 ;
if ( msg . msg_controllen > 0 ) {
struct cmsghdr * cmsg = CMSG_FIRSTHDR ( & msg ) ;
assert ( cmsg ) ;
assert ( cmsg - > cmsg_level = = SOL_SOCKET & & cmsg - > cmsg_type = = SCM_RIGHTS ) ;
recv_fds = ( cmsg - > cmsg_len - CMSG_LEN ( 0 ) ) ;
assert ( recv_fds > 0 & & ( recv_fds % sizeof ( int ) ) = = 0 ) ;
recv_fds / = sizeof ( int ) ;
// printf("recv clen %d -> %d\n", cmsg->cmsg_len, recv_fds);
// assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int) * num_fds));
assert ( fds & & recv_fds < = num_fds ) ;
memcpy ( fds , CMSG_DATA ( cmsg ) , sizeof ( int ) * recv_fds ) ;
}
if ( msg . msg_flags ) {
for ( int i = 0 ; i < recv_fds ; i + + ) {
close ( fds [ i ] ) ;
}
return - 1 ;
}
if ( fds ) {
assert ( out_num_fds ) ;
* out_num_fds = recv_fds ;
}
return r ;
}
}