cc -o recv recv.c fdtrans.c
別ウインドウで次の順番で起動し、recv画面にキー入力。
① send起動
② recv起動
【fdtrans.c】
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <string.h>
//#include "vncgw.h"
//#include "../android/jni/vncserver.h"
//extern web_gate_settings_t settings;
#define UNIX_DOMAIN_PATH_NAME_REQ "/var/local/netreg/request"
#define UNIX_DOMAIN_PATH_NAME_RES "/var/local/netreg/response"
int listen_un(const char* id )
{
char path[48];
int soc,c_soc;
struct sockaddr_un u_addr;
if( (soc = socket(PF_UNIX, SOCK_SEQPACKET, 0)) < 0 ) {
printf( "ERROR Socket in listen_un %s\n", strerror(errno));
return -1;
}
strcpy( path, UNIX_DOMAIN_PATH_NAME_REQ );
strncat( path, id, 16 );
memset(&u_addr, 0, sizeof(u_addr));
u_addr.sun_family = AF_UNIX;
u_addr.sun_path[0] = '\0'; /* abstract namespace */
strncpy(u_addr.sun_path + 1, path, sizeof(u_addr.sun_path));
// handler_msg( "unix domain path (ACCEPT)= %s\n", u_addr.sun_path + 1 );
if( bind(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR Bind 1 in listen_un() %s\n", strerror(errno));
c_soc = connect_un( id );
/* // add by takahab 20180724
struct timeval timeout;
fd_set rfds;
char buf[2048];
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO( &rfds );
FD_SET( c_soc, &rfds );
select(c_soc+1, &rfds, NULL, NULL, &timeout);
if (FD_ISSET(c_soc, &rfds)) {
errno = 0;
recv(c_soc, buf, sizeof(buf), 0);
printf( "Done Dummy reading Beause UNIX DOMAIN SOCKET broken %s\n", strerror(errno));
}
// add by takahab 20180724 */
close( c_soc );
sleep(1);
errno = 0;
if( bind(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR Bind 2 in listen_un() %s\n", strerror(errno));
close( soc );
return -1;
}
}
if( listen( soc, 1 ) < 0 ) {
printf( "ERROR listen in listen_un() %s\n", strerror(errno));
close( soc );
return -1;
}
struct sockaddr_un c_addr;
socklen_t c_len = sizeof(c_addr);
// handler_msg("Accept in Linsten_un() soc=%d\n", soc);
if ( (c_soc = accept(soc, (struct sockaddr*)&c_addr, &c_len)) < 0 ) {
printf( "ERROR Accept in listen_un() %s\n", strerror(errno));
close( soc );
return -1;
}
// handler_msg( "accept form %s len:%d c_soc:%d\n", c_addr.sun_path + 1, c_len, c_soc );
close( soc );
return c_soc;
}
int connect_un(const char* id )
{
char path[48];
int soc;
struct sockaddr_un u_addr;
if( (soc = socket(PF_UNIX, SOCK_SEQPACKET, 0)) < 0 ) {
printf( "ERROR Socket in connect_un() %s\n", strerror(errno));
return -1;
}
strcpy( path, UNIX_DOMAIN_PATH_NAME_RES );
strncat( path, id, 16 );
memset(&u_addr, 0, sizeof(u_addr));
u_addr.sun_family = AF_UNIX;
u_addr.sun_path[0] = '\0'; /* abstract namespace */
strncpy(u_addr.sun_path + 1, path, sizeof(u_addr.sun_path));
// handler_msg( "unix domain path (CONNECT)= %s\n", u_addr.sun_path + 1);
if( bind(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR Bind in connect_un() %s\n", strerror(errno));
close( soc );
return -1;
}
strcpy( path, UNIX_DOMAIN_PATH_NAME_REQ );
strncat( path, id, 16 );
memset(&u_addr, 0, sizeof(u_addr));
u_addr.sun_family = AF_UNIX;
u_addr.sun_path[0] = '\0'; /* abstract namespace */
strncpy(u_addr.sun_path + 1, path, sizeof(u_addr.sun_path));
if ( connect(soc, (struct sockaddr*)&u_addr, sizeof(u_addr)) < 0 ) {
printf( "ERROR connect in connect_un() %s\n", strerror(errno));
close( soc );
return -1;
}
return soc;
}
int recv_un(int soc, void* pid, size_t pid_len)
{
struct msghdr msg;
struct iovec iov;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
iov.iov_base = pid;
iov.iov_len = pid_len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
msg.msg_flags = MSG_WAITALL;
if ( recvmsg(soc, &msg, 0) < 0 ) {
printf( "ERROR Recvmsg in recv_un() %s\n", strerror(errno));
return -1;
}
struct cmsghdr *cmsg = (struct cmsghdr*)cmsgbuf;
return *((int *)CMSG_DATA(cmsg));
}
int send_un(int soc, int fd, void* pid, int pid_len)
{
struct iovec iov;
char buf[CMSG_SPACE(sizeof(int))];
iov.iov_base = pid;
iov.iov_len = pid_len;
struct cmsghdr *cmsg = (struct cmsghdr*)buf;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(cmsg)) = fd;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
msg.msg_flags = 0;
if (sendmsg(soc, &msg, 0) < 0) {
printf( "ERROR Sendmsg when sending fd in send_un() %s soc=%d\n", strerror(errno),soc);
return -1;
}
return 0;
}
int send_fdesc(int fd, const char* id )
{
int soc, ret;
pid_t pid;
// handshake_headers_t headers;
soc = listen_un( id );
pid = getpid();
if( soc >= 0 ) {
// memset( &headers, 0 , sizeof( headers ));
// strcpy( headers.version, PROXY_HANDSHAKE_VERSION );
// headers.cmd = PROXY_HANDSHAKE_CMD;
// strcpy(headers.protocols, PROXY_HANDSHAKE_PROTOCOL );
//
// headers.type = PROXY_HANDSHAKE_TYPE_REQ;
// handshakeToTarget( fd, &headers);
ret = send_un(soc, fd, &pid, sizeof(pid));
if( ret != -1 ) {
printf( "Send to fd:%d from pid:%d\n", fd, pid );
}
}
close (soc);
perror( "close(soc) in send_fdesc()");
// handler_msg( "Go to close:%d\n", soc );
return ret;
}
int recv_fdesc( const char* id )
{
int soc, ret, fd;
int pid = 0;
soc = connect_un( id );
if( soc >= 0 ) {
fd = recv_un(soc, &pid, sizeof(pid));
// handler_msg( "Answer from pid %d( fd:%d)\n", pid, fd );
}
close( soc );
// handler_msg( "Go to close:%d\n", soc );
return fd;
}
テストプログラム
【送り手 send.c】
#include <stdio.h>
int main(void)
{
send_fdesc( 1, "/7716618000486" );
perror("end");
return 0;
}
【受け手 recv.c 】
int main(void)
{
int fd = recv_fdesc( "/7716618000486" );
printf("Recieve file descriptor %d\n", fd);
char buf[1024];
ssize_t len;
while( (len = read(0, buf, sizeof(buf))) > 0 ) {
write(fd, buf, len);
}
}
write(fd, buf, len);
}
}